diff --git a/core/block_animations.js b/core/block_animations.js index b7296c037..f41c08527 100644 --- a/core/block_animations.js +++ b/core/block_animations.js @@ -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; } }; diff --git a/core/block_dragger.js b/core/block_dragger.js index cc7648e7c..e28ad351f 100644 --- a/core/block_dragger.js +++ b/core/block_dragger.js @@ -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} + * @type {Array} * @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} The list of all icons and their locations. + * @return {!Array} 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. diff --git a/core/block_svg.js b/core/block_svg.js index 5b66d7ba9..777dc1230 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -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)} + * @type {undefined|?function(!Array)} */ 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} Context menu options or null if no menu. + * @return {?Array} + * 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'); diff --git a/core/browser_events.js b/core/browser_events.js index 3a33cbbcc..aac2066d3 100644 --- a/core/browser_events.js +++ b/core/browser_events.js @@ -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 diff --git a/core/bubble.js b/core/bubble.js index 0ab9bc10b..d2a332788 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -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, diff --git a/core/bubble_dragger.js b/core/bubble_dragger.js index f806841ef..775375936 100644 --- a/core/bubble_dragger.js +++ b/core/bubble_dragger.js @@ -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); diff --git a/core/clipboard.js b/core/clipboard.js index 5d6d9526a..3673ecdf6 100644 --- a/core/clipboard.js +++ b/core/clipboard.js @@ -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; }; diff --git a/core/comment.js b/core/comment.js index 251385ded..f53569f04 100644 --- a/core/comment.js +++ b/core/comment.js @@ -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'); diff --git a/core/common.js b/core/common.js index 29a4af214..235af2e6f 100644 --- a/core/common.js +++ b/core/common.js @@ -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. ` + diff --git a/core/contextmenu.js b/core/contextmenu.js index b2fa7c265..715e8a2e2 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -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} options Array of menu options. + * @param {!Array} + * 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} options Array of menu options. + * @param {!Array} + * 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 */ diff --git a/core/contextmenu_registry.js b/core/contextmenu_registry.js index 42130dbfc..99c4f8edf 100644 --- a/core/contextmenu_registry.js +++ b/core/contextmenu_registry.js @@ -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. diff --git a/core/events/events_block_move.js b/core/events/events_block_move.js index 41e11a646..147fa677e 100644 --- a/core/events/events_block_move.js +++ b/core/events/events_block_move.js @@ -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_() { diff --git a/core/extensions.js b/core/extensions.js index a05e05d61..7b7108d86 100644 --- a/core/extensions.js +++ b/core/extensions.js @@ -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. diff --git a/core/field.js b/core/field.js index a70d08944..f91cb33b4 100644 --- a/core/field.js +++ b/core/field.js @@ -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_(); } } diff --git a/core/field_angle.js b/core/field_angle.js index ed7bf07c0..b85a08450 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -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)); diff --git a/core/field_colour.js b/core/field_colour.js index 02095f25b..9a96e3307 100644 --- a/core/field_colour.js +++ b/core/field_colour.js @@ -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); diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 98d2c14d7..117743aa1 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -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; } } } diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 0e9ec36e5..74100f3d3 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -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); diff --git a/core/field_textinput.js b/core/field_textinput.js index 25a8a15f5..2c4f8b719 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -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); diff --git a/core/flyout_base.js b/core/flyout_base.js index ef44c4236..e2f8704da 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -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, gaps:!Array}} */ ( - 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, gaps:Array}} The list of contents - * and gaps needed to lay out the flyout. + * @return {{contents:!Array, gaps:!Array}} 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} contents The blocks and buttons to lay out. + * @param {!Array} contents The blocks and buttons to lay + * out. * @param {!Array} 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; diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index d405da96d..b95b5eda2 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -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} contents The blocks and buttons to lay out. + * @param {!Array} contents The blocks and buttons to lay + * out. * @param {!Array} 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]); } } } diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index 631cd705d..fc64de561 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -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} contents The blocks and buttons to lay out. + * @param {!Array} contents The blocks and buttons to lay + * out. * @param {!Array} 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]; } } } diff --git a/core/insertion_marker_manager.js b/core/insertion_marker_manager.js index 20155bc84..3047bd3bd 100644 --- a/core/insertion_marker_manager.js +++ b/core/insertion_marker_manager.js @@ -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) { diff --git a/core/interfaces/i_metrics_manager.js b/core/interfaces/i_metrics_manager.js index a281fedf9..b68afffa0 100644 --- a/core/interfaces/i_metrics_manager.js +++ b/core/interfaces/i_metrics_manager.js @@ -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; diff --git a/core/mutator.js b/core/mutator.js index 08b36533e..db2f1867f 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -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()); } diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 23ab17d33..2187a7cd1 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -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; diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 49ace7025..b936c88ed 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -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) { diff --git a/core/renderers/common/debugger.js b/core/renderers/common/debugger.js index 4d30a390c..45b10d944 100644 --- a/core/renderers/common/debugger.js +++ b/core/renderers/common/debugger.js @@ -441,7 +441,7 @@ class Debug { /** * Configuration object containing booleans to enable and disable debug * rendering of specific rendering components. - * @type {!Object} + * @struct */ Debug.config = { rowSpacers: true, diff --git a/core/renderers/common/drawer.js b/core/renderers/common/drawer.js index f901f9403..914e1fea0 100644 --- a/core/renderers/common/drawer.js +++ b/core/renderers/common/drawer.js @@ -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'; diff --git a/core/renderers/common/marker_svg.js b/core/renderers/common/marker_svg.js index 89331862f..b3b52002e 100644 --- a/core/renderers/common/marker_svg.js +++ b/core/renderers/common/marker_svg.js @@ -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); } } diff --git a/core/renderers/geras/highlight_constants.js b/core/renderers/geras/highlight_constants.js index 4cd6703ec..9b896aa25 100644 --- a/core/renderers/geras/highlight_constants.js +++ b/core/renderers/geras/highlight_constants.js @@ -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 */ diff --git a/core/renderers/measurables/connection.js b/core/renderers/measurables/connection.js index 105c6692d..5f9a58cb1 100644 --- a/core/renderers/measurables/connection.js +++ b/core/renderers/measurables/connection.js @@ -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} */ diff --git a/core/renderers/measurables/inline_input.js b/core/renderers/measurables/inline_input.js index 68b19f672..4dd4f2b3f 100644 --- a/core/renderers/measurables/inline_input.js +++ b/core/renderers/measurables/inline_input.js @@ -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; } } diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index 98dcf3abd..a1f4ee9ee 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -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; diff --git a/core/renderers/zelos/drawer.js b/core/renderers/zelos/drawer.js index 18e4d6623..9f36c6297 100644 --- a/core/renderers/zelos/drawer.js +++ b/core/renderers/zelos/drawer.js @@ -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 + diff --git a/core/renderers/zelos/info.js b/core/renderers/zelos/info.js index b1f84ada7..977a16527 100644 --- a/core/renderers/zelos/info.js +++ b/core/renderers/zelos/info.js @@ -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. diff --git a/core/renderers/zelos/marker_svg.js b/core/renderers/zelos/marker_svg.js index 3e0e3360f..303be4fcc 100644 --- a/core/renderers/zelos/marker_svg.js +++ b/core/renderers/zelos/marker_svg.js @@ -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); } } } diff --git a/core/scrollbar.js b/core/scrollbar.js index 7d991e334..1f32476d3 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -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, diff --git a/core/shortcut_registry.js b/core/shortcut_registry.js index 77716d656..ec10907b3 100644 --- a/core/shortcut_registry.js +++ b/core/shortcut_registry.js @@ -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 */ diff --git a/core/sprites.js b/core/sprites.js index be6d579df..41f3e21d3 100644 --- a/core/sprites.js +++ b/core/sprites.js @@ -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 = { diff --git a/core/toolbox/category.js b/core/toolbox/category.js index b534e97e4..28a971d1b 100644 --- a/core/toolbox/category.js +++ b/core/toolbox/category.js @@ -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; } } diff --git a/core/toolbox/toolbox.js b/core/toolbox/toolbox.js index 22f52e524..9ca7af684 100644 --- a/core/toolbox/toolbox.js +++ b/core/toolbox/toolbox.js @@ -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_(); diff --git a/core/toolbox/toolbox_item.js b/core/toolbox/toolbox_item.js index 9a520c1cc..7e88ee181 100644 --- a/core/toolbox/toolbox_item.js +++ b/core/toolbox/toolbox_item.js @@ -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 */ diff --git a/core/utils.js b/core/utils.js index 7b014733c..e44718309 100644 --- a/core/utils.js +++ b/core/utils.js @@ -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. diff --git a/core/utils/dom.js b/core/utils/dom.js index e97ebf5c1..422e137ae 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -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; diff --git a/core/utils/style.js b/core/utils/style.js index 88162a3d7..ca3306af5 100644 --- a/core/utils/style.js +++ b/core/utils/style.js @@ -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; diff --git a/core/utils/svg_math.js b/core/utils/svg_math.js index 60751a490..d761f0c7b 100644 --- a/core/utils/svg_math.js +++ b/core/utils/svg_math.js @@ -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; diff --git a/core/utils/toolbox.js b/core/utils/toolbox.js index 947aebe09..943e32fa0 100644 --- a/core/utils/toolbox.js +++ b/core/utils/toolbox.js @@ -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) { diff --git a/core/workspace_audio.js b/core/workspace_audio.js index 4b06ee8cd..cef610329 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -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; diff --git a/core/workspace_comment.js b/core/workspace_comment.js index 2e25f6bf3..a8992a1e9 100644 --- a/core/workspace_comment.js +++ b/core/workspace_comment.js @@ -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) { diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index e726a1da4..c686e5760 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -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(); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 0ec4058d2..81990bd9b 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -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()); diff --git a/core/xml.js b/core/xml.js index 17c61eeed..cd5b9ebb9 100644 --- a/core/xml.js +++ b/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; diff --git a/tests/deps.js b/tests/deps.js index 317703f1a..f5b83a45e 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -12,13 +12,13 @@ goog.addDependency('../../core/block.js', ['Blockly.Block'], ['Blockly.ASTNode', goog.addDependency('../../core/block_animations.js', ['Blockly.blockAnimations'], ['Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/block_drag_surface.js', ['Blockly.BlockDragSurfaceSvg'], ['Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.svgMath'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/block_dragger.js', ['Blockly.BlockDragger'], ['Blockly.Events.BlockDrag', 'Blockly.Events.BlockMove', 'Blockly.Events.utils', 'Blockly.IBlockDragger', 'Blockly.InsertionMarkerManager', 'Blockly.blockAnimations', 'Blockly.bumpObjects', 'Blockly.common', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/block_svg.js', ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.ConnectionType', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events.BlockMove', 'Blockly.Events.Selected', 'Blockly.Events.utils', 'Blockly.FieldLabel', 'Blockly.IASTNodeLocationSvg', 'Blockly.IBoundedElement', 'Blockly.ICopyable', 'Blockly.IDraggable', 'Blockly.MarkerManager', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.common', 'Blockly.config', 'Blockly.constants', 'Blockly.internalConstants', 'Blockly.serialization.blocks', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.svgMath', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/block_svg.js', ['Blockly.BlockSvg'], ['Blockly.ASTNode', 'Blockly.Block', 'Blockly.ConnectionType', 'Blockly.ContextMenu', 'Blockly.ContextMenuRegistry', 'Blockly.Events.BlockMove', 'Blockly.Events.Selected', 'Blockly.Events.utils', 'Blockly.FieldLabel', 'Blockly.IASTNodeLocationSvg', 'Blockly.IBoundedElement', 'Blockly.ICopyable', 'Blockly.IDraggable', 'Blockly.MarkerManager', 'Blockly.Msg', 'Blockly.RenderedConnection', 'Blockly.TabNavigateCursor', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.blockAnimations', 'Blockly.browserEvents', 'Blockly.common', 'Blockly.config', 'Blockly.constants', 'Blockly.internalConstants', 'Blockly.serialization.blocks', 'Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.svgMath'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/blockly.js', ['Blockly'], ['Blockly.ASTNode', 'Blockly.BasicCursor', 'Blockly.Block', 'Blockly.BlockDragSurfaceSvg', 'Blockly.BlockDragger', 'Blockly.BlockSvg', 'Blockly.BlocklyOptions', 'Blockly.Bubble', 'Blockly.BubbleDragger', 'Blockly.CollapsibleToolboxCategory', 'Blockly.Comment', 'Blockly.ComponentManager', 'Blockly.Connection', 'Blockly.ConnectionChecker', 'Blockly.ConnectionDB', 'Blockly.ConnectionType', 'Blockly.ContextMenu', 'Blockly.ContextMenuItems', 'Blockly.ContextMenuRegistry', 'Blockly.Css', 'Blockly.Cursor', 'Blockly.DeleteArea', 'Blockly.DragTarget', 'Blockly.Events', 'Blockly.Events.BlockCreate', 'Blockly.Events.FinishedLoading', 'Blockly.Events.Ui', 'Blockly.Events.UiBase', 'Blockly.Events.VarCreate', 'Blockly.Extensions', 'Blockly.Field', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabel', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.Flyout', 'Blockly.FlyoutButton', 'Blockly.FlyoutMetricsManager', 'Blockly.Generator', 'Blockly.Gesture', 'Blockly.Grid', 'Blockly.HorizontalFlyout', 'Blockly.IASTNodeLocation', 'Blockly.IASTNodeLocationSvg', 'Blockly.IASTNodeLocationWithBlock', 'Blockly.IAutoHideable', 'Blockly.IBlockDragger', 'Blockly.IBoundedElement', 'Blockly.IBubble', 'Blockly.ICollapsibleToolboxItem', 'Blockly.IComponent', 'Blockly.IConnectionChecker', 'Blockly.IContextMenu', 'Blockly.ICopyable', 'Blockly.IDeletable', 'Blockly.IDeleteArea', 'Blockly.IDragTarget', 'Blockly.IDraggable', 'Blockly.IFlyout', 'Blockly.IKeyboardAccessible', 'Blockly.IMetricsManager', 'Blockly.IMovable', 'Blockly.IPositionable', 'Blockly.IRegistrable', 'Blockly.IRegistrableField', 'Blockly.ISelectable', 'Blockly.ISelectableToolboxItem', 'Blockly.IStyleable', 'Blockly.IToolbox', 'Blockly.IToolboxItem', 'Blockly.Icon', 'Blockly.Input', 'Blockly.InsertionMarkerManager', 'Blockly.Marker', 'Blockly.MarkerManager', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.MetricsManager', 'Blockly.Msg', 'Blockly.Mutator', 'Blockly.Names', 'Blockly.Options', 'Blockly.Procedures', 'Blockly.RenderedConnection', 'Blockly.Scrollbar', 'Blockly.ScrollbarPair', 'Blockly.ShortcutItems', 'Blockly.ShortcutRegistry', 'Blockly.TabNavigateCursor', 'Blockly.Theme', 'Blockly.ThemeManager', 'Blockly.Themes', 'Blockly.Toolbox', 'Blockly.ToolboxCategory', 'Blockly.ToolboxItem', 'Blockly.ToolboxSeparator', 'Blockly.Tooltip', 'Blockly.Touch', 'Blockly.TouchGesture', 'Blockly.Trashcan', 'Blockly.VariableMap', 'Blockly.VariableModel', 'Blockly.Variables', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.WidgetDiv', 'Blockly.Workspace', 'Blockly.WorkspaceAudio', 'Blockly.WorkspaceComment', 'Blockly.WorkspaceCommentSvg', 'Blockly.WorkspaceDragSurfaceSvg', 'Blockly.WorkspaceDragger', 'Blockly.WorkspaceSvg', 'Blockly.Xml', 'Blockly.ZoomControls', 'Blockly.blockAnimations', 'Blockly.blockRendering', 'Blockly.blocks', 'Blockly.browserEvents', 'Blockly.bumpObjects', 'Blockly.clipboard', 'Blockly.common', 'Blockly.config', 'Blockly.constants', 'Blockly.dialog', 'Blockly.dropDownDiv', 'Blockly.fieldRegistry', 'Blockly.geras', 'Blockly.inject', 'Blockly.inputTypes', 'Blockly.internalConstants', 'Blockly.minimalist', 'Blockly.registry', 'Blockly.serialization.ISerializer', 'Blockly.serialization.blocks', 'Blockly.serialization.exceptions', 'Blockly.serialization.priorities', 'Blockly.serialization.registry', 'Blockly.serialization.variables', 'Blockly.serialization.workspaces', 'Blockly.thrasos', 'Blockly.uiPosition', 'Blockly.utils', 'Blockly.utils.colour', 'Blockly.utils.deprecation', 'Blockly.utils.global', 'Blockly.utils.svgMath', 'Blockly.utils.toolbox', 'Blockly.zelos'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/blockly_options.js', ['Blockly.BlocklyOptions'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/blocks.js', ['Blockly.blocks'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/browser_events.js', ['Blockly.browserEvents'], ['Blockly.Touch', 'Blockly.utils.global', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/bubble.js', ['Blockly.Bubble'], ['Blockly.IBubble', 'Blockly.Scrollbar', 'Blockly.Touch', 'Blockly.Workspace', 'Blockly.browserEvents', 'Blockly.utils.Coordinate', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/bubble_dragger.js', ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.ComponentManager', 'Blockly.Events.CommentMove', 'Blockly.Events.utils', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.utils.svgMath'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/bubble_dragger.js', ['Blockly.BubbleDragger'], ['Blockly.Bubble', 'Blockly.ComponentManager', 'Blockly.Events.CommentMove', 'Blockly.Events.utils', 'Blockly.WorkspaceCommentSvg', 'Blockly.constants', 'Blockly.utils.Coordinate', 'Blockly.utils.svgMath'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/bump_objects.js', ['Blockly.bumpObjects'], ['Blockly.Events.utils', 'Blockly.utils.math'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/clipboard.js', ['Blockly.clipboard'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/comment.js', ['Blockly.Comment'], ['Blockly.Bubble', 'Blockly.Css', 'Blockly.Events.BlockChange', 'Blockly.Events.BubbleOpen', 'Blockly.Events.utils', 'Blockly.Icon', 'Blockly.Warning', 'Blockly.browserEvents', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); @@ -69,9 +69,9 @@ goog.addDependency('../../core/events/utils.js', ['Blockly.Events.utils'], ['Blo goog.addDependency('../../core/events/workspace_events.js', ['Blockly.Events.FinishedLoading'], ['Blockly.Events.Abstract', 'Blockly.Events.utils', 'Blockly.registry'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/extensions.js', ['Blockly.Extensions'], ['Blockly.FieldDropdown', 'Blockly.utils.parsing'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field.js', ['Blockly.Field'], ['Blockly.Events.BlockChange', 'Blockly.Events.utils', 'Blockly.Gesture', 'Blockly.IASTNodeLocationSvg', 'Blockly.IASTNodeLocationWithBlock', 'Blockly.IKeyboardAccessible', 'Blockly.IRegistrable', 'Blockly.MarkerManager', 'Blockly.Tooltip', 'Blockly.WidgetDiv', 'Blockly.Xml', 'Blockly.browserEvents', 'Blockly.dropDownDiv', 'Blockly.utils.Rect', 'Blockly.utils.Sentinel', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.parsing', 'Blockly.utils.style', 'Blockly.utils.userAgent', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/field_angle.js', ['Blockly.FieldAngle'], ['Blockly.Css', 'Blockly.Field', 'Blockly.FieldTextInput', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.dropDownDiv', 'Blockly.fieldRegistry', 'Blockly.utils.KeyCodes', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/field_angle.js', ['Blockly.FieldAngle'], ['Blockly.BlockSvg', 'Blockly.Css', 'Blockly.Field', 'Blockly.FieldTextInput', 'Blockly.WidgetDiv', 'Blockly.browserEvents', 'Blockly.dropDownDiv', 'Blockly.fieldRegistry', 'Blockly.utils.KeyCodes', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_checkbox.js', ['Blockly.FieldCheckbox'], ['Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/field_colour.js', ['Blockly.FieldColour'], ['Blockly.Css', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.browserEvents', 'Blockly.dropDownDiv', 'Blockly.fieldRegistry', 'Blockly.utils.KeyCodes', 'Blockly.utils.Size', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.idGenerator'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/field_colour.js', ['Blockly.FieldColour'], ['Blockly.BlockSvg', 'Blockly.Css', 'Blockly.Events.BlockChange', 'Blockly.Field', 'Blockly.browserEvents', 'Blockly.dropDownDiv', 'Blockly.fieldRegistry', 'Blockly.utils.KeyCodes', 'Blockly.utils.Size', 'Blockly.utils.aria', 'Blockly.utils.colour', 'Blockly.utils.dom', 'Blockly.utils.idGenerator'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_dropdown.js', ['Blockly.FieldDropdown'], ['Blockly.Field', 'Blockly.Menu', 'Blockly.MenuItem', 'Blockly.dropDownDiv', 'Blockly.fieldRegistry', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.aria', 'Blockly.utils.dom', 'Blockly.utils.parsing', 'Blockly.utils.string', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_image.js', ['Blockly.FieldImage'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.Size', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.parsing'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/field_label.js', ['Blockly.FieldLabel'], ['Blockly.Field', 'Blockly.fieldRegistry', 'Blockly.utils.dom', 'Blockly.utils.parsing'], {'lang': 'es6', 'module': 'goog'}); @@ -245,7 +245,7 @@ goog.addDependency('../../core/utils/rect.js', ['Blockly.utils.Rect'], [], {'lan goog.addDependency('../../core/utils/sentinel.js', ['Blockly.utils.Sentinel'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/size.js', ['Blockly.utils.Size'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/string.js', ['Blockly.utils.string'], [], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/utils/style.js', ['Blockly.utils.style'], ['Blockly.utils.Coordinate', 'Blockly.utils.Size'], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/utils/style.js', ['Blockly.utils.style'], ['Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Size'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/svg.js', ['Blockly.utils.Svg'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/svg_math.js', ['Blockly.utils.svgMath'], ['Blockly.utils.Coordinate', 'Blockly.utils.Rect', 'Blockly.utils.Size', 'Blockly.utils.deprecation', 'Blockly.utils.global', 'Blockly.utils.style', 'Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/svg_paths.js', ['Blockly.utils.svgPaths'], [], {'lang': 'es6', 'module': 'goog'}); diff --git a/tests/mocha/field_angle_test.js b/tests/mocha/field_angle_test.js index 1639eb206..d6feefbb0 100644 --- a/tests/mocha/field_angle_test.js +++ b/tests/mocha/field_angle_test.js @@ -111,9 +111,9 @@ suite('Angle Fields', function() { suite('Validators', function() { setup(function() { this.field = new Blockly.FieldAngle(1); - this.field.htmlInput_ = Object.create(null); - this.field.htmlInput_.oldValue_ = '1'; - this.field.htmlInput_.untypedDefaultValue_ = 1; + this.field.htmlInput_ = document.createElement('input'); + this.field.htmlInput_.setAttribute('data-old-value', '1'); + this.field.htmlInput_.setAttribute('data-untyped-default-value', '1'); this.stub = sinon.stub(this.field, 'resizeEditor_'); }); teardown(function() { diff --git a/tests/mocha/field_number_test.js b/tests/mocha/field_number_test.js index fd23cc661..b0d002399 100644 --- a/tests/mocha/field_number_test.js +++ b/tests/mocha/field_number_test.js @@ -187,9 +187,9 @@ suite('Number Fields', function() { suite('Validators', function() { setup(function() { this.field = new Blockly.FieldNumber(1); - this.field.htmlInput_ = Object.create(null); - this.field.htmlInput_.oldValue_ = '1'; - this.field.htmlInput_.untypedDefaultValue_ = 1; + this.field.htmlInput_ = document.createElement('input'); + this.field.htmlInput_.setAttribute('data-old-value', '1'); + this.field.htmlInput_.setAttribute('data-untyped-default-value', '1'); this.stub = sinon.stub(this.field, 'resizeEditor_'); }); teardown(function() { diff --git a/tests/mocha/field_textinput_test.js b/tests/mocha/field_textinput_test.js index efd01d702..f46afe09b 100644 --- a/tests/mocha/field_textinput_test.js +++ b/tests/mocha/field_textinput_test.js @@ -105,9 +105,9 @@ suite('Text Input Fields', function() { suite('Validators', function() { setup(function() { this.field = new Blockly.FieldTextInput('value'); - this.field.htmlInput_ = Object.create(null); - this.field.htmlInput_.oldValue_ = 'value'; - this.field.htmlInput_.untypedDefaultValue_ = 'value'; + this.field.htmlInput_ = document.createElement('input'); + this.field.htmlInput_.setAttribute('data-old-value', 'value'); + this.field.htmlInput_.setAttribute('data-untyped-default-value', 'value'); this.stub = sinon.stub(this.field, 'resizeEditor_'); }); teardown(function() { diff --git a/tests/mocha/procedures_test.js b/tests/mocha/procedures_test.js index 6d7888a9f..6c44554e4 100644 --- a/tests/mocha/procedures_test.js +++ b/tests/mocha/procedures_test.js @@ -484,11 +484,11 @@ suite('Procedures', function() { }); test('Simple, Input', function() { const defInput = this.defBlock.getField('NAME'); - defInput.htmlInput_ = Object.create(null); - defInput.htmlInput_.oldValue_ = 'proc name'; - defInput.htmlInput_.untypedDefaultValue_ = 'proc name'; + defInput.htmlInput_ = document.createElement('input'); + defInput.htmlInput_.setAttribute('data-old-value', 'proc name'); + defInput.htmlInput_.setAttribute('data-untyped-default-value', 'proc name'); - defInput.htmlInput_.value = defInput.htmlInput_.oldValue_ + '2'; + defInput.htmlInput_.value = defInput.htmlInput_.getAttribute('data-old-value') + '2'; defInput.onHtmlInputChange_(null); chai.assert.equal( this.defBlock.getFieldValue('NAME'), 'proc name2'); @@ -497,9 +497,9 @@ suite('Procedures', function() { }); test('lower -> CAPS', function() { const defInput = this.defBlock.getField('NAME'); - defInput.htmlInput_ = Object.create(null); - defInput.htmlInput_.oldValue_ = 'proc name'; - defInput.htmlInput_.untypedDefaultValue_ = 'proc name'; + defInput.htmlInput_ = document.createElement('input'); + defInput.htmlInput_.setAttribute('data-old-value', 'proc name'); + defInput.htmlInput_.setAttribute('data-untyped-default-value', 'proc name'); defInput.htmlInput_.value = 'PROC NAME'; defInput.onHtmlInputChange_(null); @@ -512,9 +512,9 @@ suite('Procedures', function() { this.defBlock.setFieldValue('PROC NAME', 'NAME'); this.callBlock.setFieldValue('PROC NAME', 'NAME'); const defInput = this.defBlock.getField('NAME'); - defInput.htmlInput_ = Object.create(null); - defInput.htmlInput_.oldValue_ = 'PROC NAME'; - defInput.htmlInput_.untypedDefaultValue_ = 'PROC NAME'; + defInput.htmlInput_ = document.createElement('input'); + defInput.htmlInput_.setAttribute('data-old-value', 'PROC NAME'); + defInput.htmlInput_.setAttribute('data-untyped-default-value', 'PROC NAME'); defInput.htmlInput_.value = 'proc name'; defInput.onHtmlInputChange_(null); @@ -525,11 +525,11 @@ suite('Procedures', function() { }); test('Whitespace', function() { const defInput = this.defBlock.getField('NAME'); - defInput.htmlInput_ = Object.create(null); - defInput.htmlInput_.oldValue_ = 'proc name'; - defInput.htmlInput_.untypedDefaultValue_ = 'proc name'; + defInput.htmlInput_ = document.createElement('input'); + defInput.htmlInput_.setAttribute('data-old-value', 'proc name'); + defInput.htmlInput_.setAttribute('data-untyped-default-value', 'proc name'); - defInput.htmlInput_.value = defInput.htmlInput_.oldValue_ + ' '; + defInput.htmlInput_.value = defInput.htmlInput_.getAttribute('data-old-value') + ' '; defInput.onHtmlInputChange_(null); chai.assert.equal( this.defBlock.getFieldValue('NAME'), 'proc name'); @@ -538,13 +538,13 @@ suite('Procedures', function() { }); test('Whitespace then Text', function() { const defInput = this.defBlock.getField('NAME'); - defInput.htmlInput_ = Object.create(null); - defInput.htmlInput_.oldValue_ = 'proc name'; - defInput.htmlInput_.untypedDefaultValue_ = 'proc name'; + defInput.htmlInput_ = document.createElement('input'); + defInput.htmlInput_.setAttribute('data-old-value', 'proc name'); + defInput.htmlInput_.setAttribute('data-untyped-default-value', 'proc name'); - defInput.htmlInput_.value = defInput.htmlInput_.oldValue_ + ' '; + defInput.htmlInput_.value = defInput.htmlInput_.getAttribute('data-old-value') + ' '; defInput.onHtmlInputChange_(null); - defInput.htmlInput_.value = defInput.htmlInput_.oldValue_ + '2'; + defInput.htmlInput_.value = defInput.htmlInput_.getAttribute('data-old-value') + '2'; defInput.onHtmlInputChange_(null); chai.assert.equal( this.defBlock.getFieldValue('NAME'), 'proc name 2'); @@ -553,9 +553,9 @@ suite('Procedures', function() { }); test('Set Empty', function() { const defInput = this.defBlock.getField('NAME'); - defInput.htmlInput_ = Object.create(null); - defInput.htmlInput_.oldValue_ = 'proc name'; - defInput.htmlInput_.untypedDefaultValue_ = 'proc name'; + defInput.htmlInput_ = document.createElement('input'); + defInput.htmlInput_.setAttribute('data-old-value', 'proc name'); + defInput.htmlInput_.setAttribute('data-untyped-default-value', 'proc name'); defInput.htmlInput_.value = ''; defInput.onHtmlInputChange_(null); @@ -568,9 +568,9 @@ suite('Procedures', function() { }); test('Set Empty, and Create New', function() { const defInput = this.defBlock.getField('NAME'); - defInput.htmlInput_ = Object.create(null); - defInput.htmlInput_.oldValue_ = 'proc name'; - defInput.htmlInput_.untypedDefaultValue_ = 'proc name'; + defInput.htmlInput_ = document.createElement('input'); + defInput.htmlInput_.setAttribute('data-old-value', 'proc name'); + defInput.htmlInput_.setAttribute('data-untyped-default-value', 'proc name'); defInput.htmlInput_.value = ''; defInput.onHtmlInputChange_(null);