diff --git a/core/blockly.js b/core/blockly.js index c56224ba3..30de3b1cb 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -122,7 +122,7 @@ Blockly.EventData; /** * Returns the dimensions of the specified SVG image. - * @param {!Element} svg SVG image. + * @param {!SVGElement} svg SVG image. * @return {!Object} Contains width and height properties. */ Blockly.svgSize = function(svg) { @@ -177,11 +177,11 @@ Blockly.svgResize = function(workspace) { * Handle a key-down on SVG drawing surface. Does nothing if the main workspace * is not visible. * @param {!Event} e Key down event. - * @private + * @package */ // TODO (https://github.com/google/blockly/issues/1998) handle cases where there // are multiple workspaces and non-main workspaces are able to accept input. -Blockly.onKeyDown_ = function(e) { +Blockly.onKeyDown = function(e) { var mainWorkspace = Blockly.mainWorkspace; if (Blockly.utils.isTargetInput(e) || @@ -343,13 +343,13 @@ Blockly.hideChaff = function(opt_allowToolbox) { // For now the trashcan flyout always autocloses because it overlays the // trashcan UI (no trashcan to click to close it). if (workspace.trashcan && - workspace.trashcan.flyout_) { - workspace.trashcan.flyout_.hide(); + workspace.trashcan.flyout) { + workspace.trashcan.flyout.hide(); } var toolbox = workspace.getToolbox(); if (toolbox && - toolbox.flyout_ && - toolbox.flyout_.autoClose) { + toolbox.getFlyout() && + toolbox.getFlyout().autoClose) { toolbox.clearSelection(); } } diff --git a/core/dropdowndiv.js b/core/dropdowndiv.js index 689d32a3e..68412dbee 100644 --- a/core/dropdowndiv.js +++ b/core/dropdowndiv.js @@ -259,11 +259,12 @@ Blockly.DropDownDiv.showPositionedByField = function(field, * @private */ Blockly.DropDownDiv.getScaledBboxOfBlock_ = function(block) { - var bBox = block.getSvgRoot().getBBox(); + var blockSvg = block.getSvgRoot(); + var bBox = blockSvg.getBBox(); var scale = block.workspace.scale; var scaledHeight = bBox.height * scale; var scaledWidth = bBox.width * scale; - var xy = Blockly.utils.style.getPageOffset(block.getSvgRoot()); + var xy = Blockly.utils.style.getPageOffset(blockSvg); return new Blockly.utils.Rect( xy.y, xy.y + scaledHeight, xy.x, xy.x + scaledWidth); }; diff --git a/core/flyout_base.js b/core/flyout_base.js index 35b353e6e..349322715 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -43,7 +43,8 @@ goog.require('Blockly.Xml'); /** * Class for a flyout. - * @param {!Object} workspaceOptions Dictionary of options for the workspace. + * @param {!Blockly.Options} workspaceOptions Dictionary of options for the + * workspace. * @constructor */ Blockly.Flyout = function(workspaceOptions) { @@ -228,15 +229,17 @@ Blockly.Flyout.prototype.createDom = function(tagName) { this.svgBackground_ = Blockly.utils.dom.createSvgElement('path', {'class': 'blocklyFlyoutBackground'}, this.svgGroup_); this.svgGroup_.appendChild(this.workspace_.createDom()); - this.workspace_.getThemeManager().subscribe(this.svgBackground_, 'flyout', 'fill'); - this.workspace_.getThemeManager().subscribe(this.svgBackground_, 'flyoutOpacity', 'fill-opacity'); + this.workspace_.getThemeManager().subscribe( + this.svgBackground_, 'flyout', 'fill'); + this.workspace_.getThemeManager().subscribe( + this.svgBackground_, 'flyoutOpacity', 'fill-opacity'); return this.svgGroup_; }; /** * Initializes the flyout. - * @param {!Blockly.Workspace} targetWorkspace The workspace in which to create - * new blocks. + * @param {!Blockly.WorkspaceSvg} targetWorkspace The workspace in which to + * create new blocks. */ Blockly.Flyout.prototype.init = function(targetWorkspace) { this.targetWorkspace_ = targetWorkspace; @@ -265,7 +268,7 @@ Blockly.Flyout.prototype.init = function(targetWorkspace) { this.targetWorkspace_.getGesture.bind(this.targetWorkspace_); // Get variables from the main workspace rather than the target workspace. - this.workspace_.variableMap_ = this.targetWorkspace_.getVariableMap(); + this.workspace_.setVariableMap(this.targetWorkspace_.getVariableMap()); this.workspace_.createPotentialVariableMap(); }; @@ -432,7 +435,7 @@ Blockly.Flyout.prototype.hide = function() { /** * Show and populate the flyout. - * @param {!Array|string} xmlList List of blocks to show. + * @param {!Array|!NodeList|string} xmlList List of blocks to show. * Variables and procedures have a custom set of blocks. */ Blockly.Flyout.prototype.show = function(xmlList) { @@ -575,6 +578,7 @@ Blockly.Flyout.prototype.clearOldBlocks_ = function() { * @param {!SVGElement} rect The invisible rectangle under the block that acts * as a mat for that block. * @protected + * @suppress {deprecated} Suppress deprecated bindEvent_ call. */ Blockly.Flyout.prototype.addBlockListeners_ = function(root, block, rect) { this.listeners_.push(Blockly.bindEventWithChecks_(root, 'mousedown', null, @@ -788,8 +792,8 @@ Blockly.Flyout.prototype.isScrollable = function() { /** * Copy a block from the flyout to the workspace and position it correctly. - * @param {!Blockly.Block} oldBlock The flyout block to copy. - * @return {!Blockly.Block} The new block in the main workspace. + * @param {!Blockly.BlockSvg} oldBlock The flyout block to copy. + * @return {!Blockly.BlockSvg} The new block in the main workspace. * @private */ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) { @@ -807,7 +811,8 @@ Blockly.Flyout.prototype.placeNewBlock_ = function(oldBlock) { // Using domToBlock instead of domToWorkspace means that the new block will be // placed at position (0, 0) in main workspace units. - var block = Blockly.Xml.domToBlock(xml, targetWorkspace); + var block = /** @type {!Blockly.BlockSvg} */ + (Blockly.Xml.domToBlock(xml, targetWorkspace)); var svgRootNew = block.getSvgRoot(); if (!svgRootNew) { throw Error('block is not rendered.'); diff --git a/core/gesture.js b/core/gesture.js index c8aadf03b..df369b9fe 100644 --- a/core/gesture.js +++ b/core/gesture.js @@ -315,6 +315,9 @@ Blockly.Gesture.prototype.updateDragDelta_ = function(currentXY) { * @private */ Blockly.Gesture.prototype.updateIsDraggingFromFlyout_ = function() { + if (!this.targetBlock_) { + return false; + } if (!this.flyout_.isBlockCreatable_(this.targetBlock_)) { return false; } @@ -621,7 +624,7 @@ Blockly.Gesture.prototype.cancel = function() { Blockly.Gesture.prototype.handleRightClick = function(e) { if (this.targetBlock_) { this.bringBlockToFront_(); - Blockly.hideChaff(this.flyout_); + Blockly.hideChaff(!!this.flyout_); this.targetBlock_.showContextMenu_(e); } else if (this.startBubble_) { this.startBubble_.showContextMenu_(e); diff --git a/core/inject.js b/core/inject.js index 2019bc1d9..1d9b72f8b 100644 --- a/core/inject.js +++ b/core/inject.js @@ -41,10 +41,10 @@ goog.require('Blockly.WorkspaceSvg'); /** * Inject a Blockly editor into the specified container element (usually a div). - * @param {!Element|string} container Containing element, or its ID, + * @param {Element|string} container Containing element, or its ID, * or a CSS selector. * @param {Object=} opt_options Optional dictionary of options. - * @return {!Blockly.Workspace} Newly created main workspace. + * @return {!Blockly.WorkspaceSvg} Newly created main workspace. */ Blockly.inject = function(container, opt_options) { Blockly.checkBlockColourConstants(); @@ -54,7 +54,7 @@ Blockly.inject = function(container, opt_options) { document.querySelector(container); } // Verify that the container is in document. - if (!Blockly.utils.dom.containsNode(document, container)) { + if (!container || !Blockly.utils.dom.containsNode(document, container)) { throw Error('Error: container is not in current document.'); } var options = new Blockly.Options(opt_options || {}); @@ -206,7 +206,7 @@ Blockly.createDom_ = function(container, options) { * for the blocks. * @param {!Blockly.WorkspaceDragSurfaceSvg} workspaceDragSurface Drag surface * SVG for the workspace. - * @return {!Blockly.Workspace} Newly created main workspace. + * @return {!Blockly.WorkspaceSvg} Newly created main workspace. * @private */ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, @@ -219,7 +219,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, if (!options.hasCategories && options.languageTree) { // Add flyout as an that is a sibling of the workspace svg. - var flyout = mainWorkspace.addFlyout_('svg'); + var flyout = mainWorkspace.addFlyout('svg'); Blockly.utils.dom.insertAfter(flyout, svg); } if (options.hasTrashcan) { @@ -385,7 +385,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, /** * Initialize Blockly with various handlers. - * @param {!Blockly.Workspace} mainWorkspace Newly created main workspace. + * @param {!Blockly.WorkspaceSvg} mainWorkspace Newly created main workspace. * @private */ Blockly.init_ = function(mainWorkspace) { @@ -393,7 +393,8 @@ Blockly.init_ = function(mainWorkspace) { var svg = mainWorkspace.getParentSvg(); // Suppress the browser's context menu. - Blockly.bindEventWithChecks_(svg.parentNode, 'contextmenu', null, + Blockly.bindEventWithChecks_( + /** @type {!Element} */ (svg.parentNode), 'contextmenu', null, function(e) { if (!Blockly.utils.isTargetInput(e)) { e.preventDefault(); @@ -411,13 +412,15 @@ Blockly.init_ = function(mainWorkspace) { Blockly.inject.bindDocumentEvents_(); if (options.languageTree) { - if (mainWorkspace.getToolbox()) { - mainWorkspace.getToolbox().init(mainWorkspace); - } else if (mainWorkspace.flyout_) { + var toolbox = mainWorkspace.getToolbox(); + var flyout = mainWorkspace.getFlyout(true); + if (toolbox) { + toolbox.init(); + } else if (flyout) { // Build a fixed flyout with the root blocks. - mainWorkspace.flyout_.init(mainWorkspace); - mainWorkspace.flyout_.show(options.languageTree.childNodes); - mainWorkspace.flyout_.scrollToStart(); + flyout.init(mainWorkspace); + flyout.show(options.languageTree.childNodes); + flyout.scrollToStart(); } } @@ -452,6 +455,7 @@ Blockly.init_ = function(mainWorkspace) { * Also, 'keydown' has to be on the whole document since the browser doesn't * understand a concept of focus on the SVG image. * @private + * @suppress {deprecated} Suppress deprecated bindEvent_ call. */ Blockly.inject.bindDocumentEvents_ = function() { if (!Blockly.documentEventsBound_) { @@ -463,7 +467,7 @@ Blockly.inject.bindDocumentEvents_ = function() { } } }); - Blockly.bindEventWithChecks_(document, 'keydown', null, Blockly.onKeyDown_); + Blockly.bindEventWithChecks_(document, 'keydown', null, Blockly.onKeyDown); // longStop needs to run to stop the context menu from showing up. It // should run regardless of what other touch event handlers have run. Blockly.bindEvent_(document, 'touchend', null, Blockly.longStop_); @@ -473,7 +477,8 @@ Blockly.inject.bindDocumentEvents_ = function() { Blockly.bindEventWithChecks_(window, 'orientationchange', document, function() { // TODO (#397): Fix for multiple Blockly workspaces. - Blockly.svgResize(Blockly.getMainWorkspace()); + Blockly.svgResize(/** @type {!Blockly.WorkspaceSvg} */ + (Blockly.getMainWorkspace())); }); } } diff --git a/core/mutator.js b/core/mutator.js index 8b6bbd7d8..af5d9e0b9 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -141,7 +141,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { } else { var quarkXml = null; } - var workspaceOptions = { + var workspaceOptions = /** @type {!Blockly.Options} */ ({ // If you want to enable disabling, also remove the // event filter from workspaceChanged_ . disable: false, @@ -156,7 +156,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { getMetrics: this.getFlyoutMetrics_.bind(this), setMetrics: null, renderer: this.block_.workspace.options.renderer - }; + }); this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions); this.workspace_.isMutator = true; this.workspace_.addChangeListener(Blockly.Events.disableOrphans); @@ -165,7 +165,7 @@ Blockly.Mutator.prototype.createEditor_ = function() { // a top level svg. Instead of handling scale themselves, mutators // inherit scale from the parent workspace. // To fix this, scale needs to be applied at a different level in the dom. - var flyoutSvg = this.workspace_.addFlyout_('g'); + var flyoutSvg = this.workspace_.addFlyout('g'); var background = this.workspace_.createDom('blocklyMutatorBackground'); // Insert the flyout after the but before the block canvas so that @@ -215,8 +215,9 @@ Blockly.Mutator.prototype.resizeBubble_ = function() { width = workspaceSize.width + workspaceSize.x; } var height = workspaceSize.height + doubleBorderWidth * 3; - if (this.workspace_.flyout_) { - var flyoutMetrics = this.workspace_.flyout_.getMetrics_(); + var flyout = this.workspace_.getFlyout(); + if (flyout) { + var flyoutMetrics = flyout.getMetrics_(); height = Math.max(height, flyoutMetrics.contentHeight + 20); } width += doubleBorderWidth * 3; @@ -260,9 +261,10 @@ Blockly.Mutator.prototype.setVisible = function(visible) { // Expose this mutator's block's ID on its top-level SVG group. this.bubble_.setSvgId(this.block_.id); var tree = this.workspace_.options.languageTree; + var flyout = this.workspace_.getFlyout(); if (tree) { - this.workspace_.flyout_.init(this.workspace_); - this.workspace_.flyout_.show(tree.childNodes); + flyout.init(this.workspace_); + flyout.show(tree.childNodes); } this.rootBlock_ = this.block_.decompose(this.workspace_); @@ -273,9 +275,9 @@ Blockly.Mutator.prototype.setVisible = function(visible) { // The root block should not be dragable or deletable. this.rootBlock_.setMovable(false); this.rootBlock_.setDeletable(false); - if (this.workspace_.flyout_) { - var margin = this.workspace_.flyout_.CORNER_RADIUS * 2; - var x = this.workspace_.getFlyout().getWidth() + margin; + if (flyout) { + var margin = flyout.CORNER_RADIUS * 2; + var x = flyout.getWidth() + margin; } else { var margin = 16; var x = margin; @@ -427,7 +429,7 @@ Blockly.Mutator.prototype.updateBlockStyle = function() { block.setStyle(block.getStyleName()); } - var flyoutBlocks = ws.flyout_.workspace_.getAllBlocks(false); + var flyoutBlocks = ws.getFlyout().workspace_.getAllBlocks(false); for (var i = 0; i < flyoutBlocks.length; i++) { var block = flyoutBlocks[i]; block.setStyle(block.getStyleName()); diff --git a/core/scrollbar.js b/core/scrollbar.js index 4042635e9..92ae14164 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -627,9 +627,12 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { 'ry': radius }, this.svgGroup_); - this.workspace_.getThemeManager().subscribe(this.svgHandle_, 'scrollbar', 'fill'); - this.workspace_.getThemeManager().subscribe(this.svgHandle_, 'scrollbarOpacity', 'fill-opacity'); - Blockly.utils.dom.insertAfter(this.outerSvg_, this.workspace_.getParentSvg()); + this.workspace_.getThemeManager().subscribe( + this.svgHandle_, 'scrollbar', 'fill'); + this.workspace_.getThemeManager().subscribe( + this.svgHandle_, 'scrollbarOpacity', 'fill-opacity'); + Blockly.utils.dom.insertAfter(this.outerSvg_, + this.workspace_.getParentSvg()); }; /** @@ -711,7 +714,8 @@ Blockly.Scrollbar.prototype.onMouseDownBar_ = function(e) { e.stopPropagation(); return; } - var mouseXY = Blockly.utils.mouseToSvg(e, this.workspace_.getParentSvg(), + var mouseXY = Blockly.utils.mouseToSvg(e, + this.workspace_.getParentSvg(), this.workspace_.getInverseScreenCTM()); var mouseLocation = this.horizontal_ ? mouseXY.x : mouseXY.y; diff --git a/core/toolbox.js b/core/toolbox.js index 046cfb345..448eded68 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -110,6 +110,13 @@ Blockly.Toolbox = function(workspace) { 'blocklyHorizontalTreeRtl' : 'blocklyHorizontalTree'); this.config_['cssTreeIcon'] = ''; } + + /** + * The toolbox flyout. + * @type {Blockly.Flyout} + * @private + */ + this.flyout_ = null; }; /** @@ -140,6 +147,8 @@ Blockly.Toolbox.prototype.lastCategory_ = null; /** * Initializes the toolbox. + * @throws {Error} If missing a require for both `Blockly.HorizontalFlyout` and + * `Blockly.VerticalFlyout`. */ Blockly.Toolbox.prototype.init = function() { var workspace = this.workspace_; @@ -178,11 +187,6 @@ Blockly.Toolbox.prototype.init = function() { toolboxPosition: workspace.options.toolboxPosition, renderer: workspace.options.renderer }; - /** - * @type {!Blockly.Flyout} - * @private - */ - this.flyout_ = null; if (workspace.horizontalLayout) { if (!Blockly.HorizontalFlyout) { throw Error('Missing require for Blockly.HorizontalFlyout'); @@ -194,9 +198,13 @@ Blockly.Toolbox.prototype.init = function() { } this.flyout_ = new Blockly.VerticalFlyout(workspaceOptions); } + if (!this.flyout_) { + throw Error('One of Blockly.VerticalFlyout or Blockly.Horizontal must be' + + 'required.'); + } + // Insert the flyout after the workspace. - Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), - this.workspace_.getParentSvg()); + Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), svg); this.flyout_.init(workspace); this.config_['cleardotPath'] = workspace.options.pathToMedia + '1x1.gif'; @@ -207,7 +215,7 @@ Blockly.Toolbox.prototype.init = function() { /** * Fill the toolbox with categories and blocks. - * @param {!Node} languageTree DOM tree of blocks. + * @param {Node} languageTree DOM tree of blocks. * @package */ Blockly.Toolbox.prototype.renderTree = function(languageTree) { @@ -225,8 +233,8 @@ Blockly.Toolbox.prototype.renderTree = function(languageTree) { if (languageTree) { this.tree_.blocks = []; this.hasColours_ = false; - var openNode = - this.syncTrees_(languageTree, this.tree_, this.workspace_.options.pathToMedia); + openNode = this.syncTrees_( + languageTree, this.tree_, this.workspace_.options.pathToMedia); if (this.tree_.blocks.length) { throw Error('Toolbox cannot have both blocks and categories ' + @@ -245,7 +253,8 @@ Blockly.Toolbox.prototype.renderTree = function(languageTree) { // Trees have an implicit orientation of vertical, so we only need to set this // when the toolbox is in horizontal mode. if (this.horizontalLayout_) { - Blockly.utils.aria.setState(/** @type {!Element} */ (this.tree_.getElement()), + Blockly.utils.aria.setState( + /** @type {!Element} */ (this.tree_.getElement()), Blockly.utils.aria.State.ORIENTATION, 'horizontal'); } }; @@ -353,7 +362,6 @@ Blockly.Toolbox.prototype.dispose = function() { this.tree_.dispose(); this.workspace_.getThemeManager().unsubscribe(this.HtmlDiv); Blockly.utils.dom.removeNode(this.HtmlDiv); - this.workspace_ = null; this.lastCategory_ = null; }; @@ -373,6 +381,14 @@ Blockly.Toolbox.prototype.getHeight = function() { return this.height; }; +/** + * Get the toolbox flyout. + * @return {Blockly.Flyout} The toolbox flyout. + */ +Blockly.Toolbox.prototype.getFlyout = function() { + return this.flyout_; +}; + /** * Move the toolbox to the edge. */ @@ -382,8 +398,7 @@ Blockly.Toolbox.prototype.position = function() { // Not initialized yet. return; } - var svg = this.workspace_.getParentSvg(); - var svgSize = Blockly.svgSize(svg); + var svgSize = Blockly.svgSize(this.workspace_.getParentSvg()); if (this.horizontalLayout_) { treeDiv.style.left = '0'; treeDiv.style.height = 'auto'; @@ -474,7 +489,8 @@ Blockly.Toolbox.prototype.syncTrees_ = function(treeIn, treeOut, pathToMedia) { // Separator between two categories. // treeOut.add(new Blockly.Toolbox.TreeSeparator( - /** @type {!Blockly.tree.BaseNode.Config} */ (this.treeSeparatorConfig_))); + /** @type {!Blockly.tree.BaseNode.Config} */ + (this.treeSeparatorConfig_))); break; } // Otherwise falls through. diff --git a/core/trashcan.js b/core/trashcan.js index a452d2004..fecc23a06 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -31,13 +31,13 @@ goog.require('Blockly.Xml'); /** * Class for a trash can. - * @param {!Blockly.Workspace} workspace The workspace to sit in. + * @param {!Blockly.WorkspaceSvg} workspace The workspace to sit in. * @constructor */ Blockly.Trashcan = function(workspace) { /** * The workspace the trashcan sits in. - * @type {!Blockly.Workspace} + * @type {!Blockly.WorkspaceSvg} * @private */ this.workspace_ = workspace; @@ -49,6 +49,12 @@ Blockly.Trashcan = function(workspace) { */ this.contents_ = []; + /** + * The trashcan flyout. + * @type {Blockly.Flyout} + * @package + */ + this.flyout = null; if (this.workspace_.options.maxTrashcanContents <= 0) { return; @@ -70,7 +76,7 @@ Blockly.Trashcan = function(workspace) { if (!Blockly.HorizontalFlyout) { throw Error('Missing require for Blockly.HorizontalFlyout'); } - this.flyout_ = new Blockly.HorizontalFlyout(flyoutWorkspaceOptions); + this.flyout = new Blockly.HorizontalFlyout(flyoutWorkspaceOptions); } else { flyoutWorkspaceOptions.toolboxPosition = this.workspace_.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT ? @@ -78,7 +84,7 @@ Blockly.Trashcan = function(workspace) { if (!Blockly.VerticalFlyout) { throw Error('Missing require for Blockly.VerticalFlyout'); } - this.flyout_ = new Blockly.VerticalFlyout(flyoutWorkspaceOptions); + this.flyout = new Blockly.VerticalFlyout(flyoutWorkspaceOptions); } this.workspace_.addChangeListener(this.onDelete_.bind(this)); }; @@ -284,9 +290,9 @@ Blockly.Trashcan.prototype.createDom = function() { */ Blockly.Trashcan.prototype.init = function(verticalSpacing) { if (this.workspace_.options.maxTrashcanContents > 0) { - Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), + Blockly.utils.dom.insertAfter(this.flyout.createDom('svg'), this.workspace_.getParentSvg()); - this.flyout_.init(this.workspace_); + this.flyout.init(this.workspace_); } this.verticalSpacing_ = this.MARGIN_BOTTOM_ + verticalSpacing; @@ -426,7 +432,7 @@ Blockly.Trashcan.prototype.click = function() { for (var i = 0, text; text = this.contents_[i]; i++) { xml[i] = Blockly.Xml.textToDom(text); } - this.flyout_.show(xml); + this.flyout.show(xml); }; /** diff --git a/core/workspace.js b/core/workspace.js index cefd46038..32cbbdd00 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -848,6 +848,15 @@ Blockly.Workspace.prototype.getVariableMap = function() { return this.variableMap_; }; +/** + * Set the map of all variables on the workspace. + * @param {Blockly.VariableMap} variableMap The variable map. + * @package + */ +Blockly.Workspace.prototype.setVariableMap = function(variableMap) { + this.variableMap_ = variableMap; +}; + /** * Database of all workspaces. * @private diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index 9e33f2ae7..70a5dd360 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -121,7 +121,7 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.translateSurface = function(x, y) { * @package */ Blockly.WorkspaceDragSurfaceSvg.prototype.getSurfaceTranslation = function() { - return Blockly.utils.getRelativeXY(this.SVG_); + return Blockly.utils.getRelativeXY(/** @type {!SVGElement} */ (this.SVG_)); }; /** @@ -136,8 +136,8 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { throw Error('Couldn\'t clear and hide the drag surface: missing ' + 'new surface.'); } - var blockCanvas = this.SVG_.childNodes[0]; - var bubbleCanvas = this.SVG_.childNodes[1]; + var blockCanvas = /** @type {!Element} */ (this.SVG_.childNodes[0]); + var bubbleCanvas = /** @type {!Element} */ (this.SVG_.childNodes[1]); if (!blockCanvas || !bubbleCanvas || !Blockly.utils.dom.hasClass(blockCanvas, 'blocklyBlockCanvas') || !Blockly.utils.dom.hasClass(bubbleCanvas, 'blocklyBubbleCanvas')) { diff --git a/core/workspace_dragger.js b/core/workspace_dragger.js index 67527322f..01b97955f 100644 --- a/core/workspace_dragger.js +++ b/core/workspace_dragger.js @@ -46,7 +46,7 @@ Blockly.WorkspaceDragger = function(workspace) { * The scroll position of the workspace at the beginning of the drag. * Coordinate system: pixel coordinates. * @type {!Blockly.utils.Coordinate} - * @private + * @protected */ this.startScrollXY_ = new Blockly.utils.Coordinate( workspace.scrollX, workspace.scrollY); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index dc8c3216f..b16fe82a6 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -136,6 +136,13 @@ Blockly.WorkspaceSvg = function(options, * @private */ this.renderer_ = Blockly.blockRendering.init(this.options.renderer || 'geras'); + + /** + * Cached parent SVG. + * @type {SVGElement} + * @private + */ + this.cachedParentSvg_ = null; }; Blockly.utils.object.inherits(Blockly.WorkspaceSvg, Blockly.Workspace); @@ -346,7 +353,7 @@ Blockly.WorkspaceSvg.prototype.isDragSurfaceActive_ = false; /** * The first parent div with 'injectionDiv' in the name, or null if not set. * Access this with getInjectionDiv. - * @type {!Element} + * @type {Element} * @private */ Blockly.WorkspaceSvg.prototype.injectionDiv_ = null; @@ -355,7 +362,7 @@ Blockly.WorkspaceSvg.prototype.injectionDiv_ = null; * Last known position of the page scroll. * This is used to determine whether we have recalculated screen coordinate * stuff since the page scrolled. - * @type {!Blockly.utils.Coordinate} + * @type {Blockly.utils.Coordinate} * @private */ Blockly.WorkspaceSvg.prototype.lastRecordedPageScroll_ = null; @@ -381,7 +388,7 @@ Blockly.WorkspaceSvg.prototype.toolboxCategoryCallbacks_ = {}; * workspace's context menu or edit the workspace-created set of menu options. * @param {!Array.} options List of menu options to add to. */ -Blockly.WorkspaceSvg.prototype.configureContextMenu = null; +Blockly.WorkspaceSvg.prototype.configureContextMenu; /** * In a flyout, the target workspace where blocks should be placed after a drag. @@ -545,7 +552,7 @@ Blockly.WorkspaceSvg.prototype.getSvgXY = function(element) { } x += xy.x * scale; y += xy.y * scale; - element = element.parentNode; + element = /** @type {!Element} */ (element.parentNode); } while (element && element != this.getParentSvg()); return new Blockly.utils.Coordinate(x, y); }; @@ -565,6 +572,8 @@ Blockly.WorkspaceSvg.prototype.getOriginOffsetInPixels = function() { /** * Return the injection div that is a parent of this workspace. * Walks the DOM the first time it's called, then returns a cached value. + * Note: We assume this is only called after the workspace has been injected + * into the DOM. * @return {!Element} The first parent div with 'injectionDiv' in the name. * @package */ @@ -579,10 +588,10 @@ Blockly.WorkspaceSvg.prototype.getInjectionDiv = function() { this.injectionDiv_ = element; break; } - element = element.parentNode; + element = /** @type {!Element} */ (element.parentNode); } } - return this.injectionDiv_; + return /** @type {!Element} */ (this.injectionDiv_); }; /** @@ -790,9 +799,9 @@ Blockly.WorkspaceSvg.prototype.addZoomControls = function() { * Add a flyout element in an element with the given tag name. * @param {string} tagName What type of tag the flyout belongs in. * @return {!Element} The element containing the flyout DOM. - * @private + * @package */ -Blockly.WorkspaceSvg.prototype.addFlyout_ = function(tagName) { +Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) { var workspaceOptions = { disabledPatternId: this.options.disabledPatternId, parentWorkspace: this, @@ -825,15 +834,16 @@ Blockly.WorkspaceSvg.prototype.addFlyout_ = function(tagName) { * Getter for the flyout associated with this workspace. This flyout may be * owned by either the toolbox or the workspace, depending on toolbox * configuration. It will be null if there is no flyout. + * @param {boolean=} opt_own Only return the workspace's own flyout if True. * @return {Blockly.Flyout} The flyout on this workspace. * @package */ -Blockly.WorkspaceSvg.prototype.getFlyout = function() { - if (this.flyout_) { +Blockly.WorkspaceSvg.prototype.getFlyout = function(opt_own) { + if (this.flyout_ || opt_own) { return this.flyout_; } if (this.toolbox_) { - return this.toolbox_.flyout_; + return this.toolbox_.getFlyout(); } return null; }; @@ -935,21 +945,22 @@ Blockly.WorkspaceSvg.prototype.getBubbleCanvas = function() { /** * Get the SVG element that contains this workspace. - * @return {SVGElement} SVG element. + * Note: We assume this is only called after the workspace has been injected + * into the DOM. + * @return {!SVGElement} SVG element. */ Blockly.WorkspaceSvg.prototype.getParentSvg = function() { - if (this.cachedParentSvg_) { - return this.cachedParentSvg_; - } - var element = this.svgGroup_; - while (element) { - if (element.tagName == 'svg') { - this.cachedParentSvg_ = element; - return element; + if (!this.cachedParentSvg_) { + var element = this.svgGroup_; + while (element) { + if (element.tagName == 'svg') { + this.cachedParentSvg_ = element; + break; + } + element = /** @type {!SVGElement} */ (element.parentNode); } - element = /** @type {!SVGElement} */ (element.parentNode); } - return null; + return /** @type {!SVGElement} */ (this.cachedParentSvg_); }; /** @@ -1283,7 +1294,7 @@ Blockly.WorkspaceSvg.prototype.pasteWorkspaceComment_ = function(xmlComment) { */ Blockly.WorkspaceSvg.prototype.refreshToolboxSelection = function() { var ws = this.isFlyout ? this.targetWorkspace : this; - if (ws && !ws.currentGesture_ && ws.toolbox_ && ws.toolbox_.flyout_) { + if (ws && !ws.currentGesture_ && ws.toolbox_ && ws.toolbox_.getFlyout()) { ws.toolbox_.refreshSelection(); } }; @@ -1889,9 +1900,9 @@ Blockly.WorkspaceSvg.prototype.zoomToFit = function() { // the flyout, and the area we want to fit them includes the portion of // the workspace that is behind the flyout. if (this.horizontalLayout) { - workspaceHeight += this.flyout_.height_; + workspaceHeight += this.flyout_.getHeight(); // Convert from pixels to workspace coordinates. - blocksHeight += this.flyout_.height_ / this.scale; + blocksHeight += this.flyout_.getHeight() / this.scale; } else { workspaceWidth += this.flyout_.getWidth(); // Convert from pixels to workspace coordinates. @@ -2353,6 +2364,17 @@ Blockly.WorkspaceSvg.setTopLevelWorkspaceMetrics_ = function(xyRatio) { this.translate(x, y); }; +/** + * Finds the top-level blocks and returns them. Blocks are optionally sorted + * by position; top to bottom (with slight LTR or RTL bias). + * @param {boolean} ordered Sort the list if true. + * @return {!Array.} The top-level block objects. + * @override + */ +Blockly.WorkspaceSvg.prototype.getTopBlocks = function(ordered) { + return Blockly.WorkspaceSvg.superClass_.getTopBlocks.call(this, ordered); +}; + /** * Update whether this workspace has resizes enabled. * If enabled, workspace will resize when appropriate.