From 0bbdf34f38882658c85be166e8cb1a7dac527279 Mon Sep 17 00:00:00 2001 From: Katelyn Mann Date: Tue, 17 Jan 2017 17:29:19 -0800 Subject: [PATCH 1/2] fixing some merging bugs. Getting the drag surface to work, updating some function calls, etc. --- core/block.js | 2 +- core/block_drag_surface.js | 13 ++++++ core/block_render_svg_horizontal.js | 4 +- core/block_render_svg_vertical.js | 8 ++-- core/block_svg.js | 21 ++------- core/flyout_base.js | 71 ++++++++++++++++++++++++++--- core/flyout_horizontal.js | 44 ++++++++++-------- core/flyout_vertical.js | 18 +++++--- core/inject.js | 2 +- core/scrollbar.js | 19 +++++++- core/toolbox.js | 4 +- 11 files changed, 146 insertions(+), 60 deletions(-) diff --git a/core/block.js b/core/block.js index d785522166..87238f5bb7 100644 --- a/core/block.js +++ b/core/block.js @@ -626,7 +626,7 @@ Blockly.Block.prototype.setInsertionMarker = function(insertionMarker) { if (this.isInsertionMarker_) { this.setColour(Blockly.Colours.insertionMarker); this.setOpacity(Blockly.Colours.insertionMarkerOpacity); - Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyInsertionMarker'); } }; diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index 195e7e9e87..c883cfb2ef 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -109,6 +109,12 @@ Blockly.BlockDragSurfaceSvg.prototype.setBlocksAndShow = function(blocks) { // appendChild removes the blocks from the previous parent this.dragGroup_.appendChild(blocks); this.SVG_.style.display = 'block'; + // This allows blocks to be dragged outside of the blockly svg space. + // This should be reset to hidden at the end of the block drag. + // Note that this behavior is different from blockly where block disappear + // "under" the blockly area. + var injectionDiv = document.getElementsByClassName('injectionDiv')[0]; + injectionDiv.style.overflow = 'visible'; }; /** @@ -187,6 +193,13 @@ Blockly.BlockDragSurfaceSvg.prototype.clearAndHide = function(newSurface) { // appendChild removes the node from this.dragGroup_ newSurface.appendChild(this.getCurrentBlock()); this.SVG_.style.display = 'none'; + // Reset the overflow property back to hidden so that nothing appears outside + // of the blockly area. + // Note that this behavior is different from blockly. See note in + // setBlocksAndShow. + var injectionDiv = document.getElementsByClassName('injectionDiv')[0]; + injectionDiv.style.overflow = 'hidden'; + goog.asserts.assert(this.dragGroup_.childNodes.length == 0, 'Drag group was not cleared.'); }; diff --git a/core/block_render_svg_horizontal.js b/core/block_render_svg_horizontal.js index a732102ea4..5718a0294b 100644 --- a/core/block_render_svg_horizontal.js +++ b/core/block_render_svg_horizontal.js @@ -336,11 +336,11 @@ Blockly.BlockSvg.prototype.updateColour = function() { Blockly.BlockSvg.prototype.highlightForReplacement = function(add) { if (add) { this.svgPath_.setAttribute('filter', 'url(#blocklyReplacementGlowFilter)'); - Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.addClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } else { this.svgPath_.removeAttribute('filter'); - Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.removeClass_(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } }; diff --git a/core/block_render_svg_vertical.js b/core/block_render_svg_vertical.js index 50b911969f..18537b137a 100644 --- a/core/block_render_svg_vertical.js +++ b/core/block_render_svg_vertical.js @@ -510,11 +510,11 @@ Blockly.BlockSvg.prototype.updateColour = function() { Blockly.BlockSvg.prototype.highlightForReplacement = function(add) { if (add) { this.svgPath_.setAttribute('filter', 'url(#blocklyReplacementGlowFilter)'); - Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } else { this.svgPath_.removeAttribute('filter'); - Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.removeClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } }; @@ -533,11 +533,11 @@ Blockly.BlockSvg.prototype.highlightShapeForInput = function(conn, add) { var inputShape = this.inputShapes_[input.name]; if (add) { inputShape.setAttribute('filter', 'url(#blocklyReplacementGlowFilter)'); - Blockly.addClass_(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.addClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } else { inputShape.removeAttribute('filter'); - Blockly.removeClass_(/** @type {!Element} */ (this.svgGroup_), + Blockly.utils.removeClass(/** @type {!Element} */ (this.svgGroup_), 'blocklyReplaceable'); } }; diff --git a/core/block_svg.js b/core/block_svg.js index 1e8caeb756..306cfa808e 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -973,21 +973,6 @@ Blockly.BlockSvg.prototype.setDragging_ = function(adding) { } }; -/** - * Move this block to its workspace's drag surface, accounting for positioning. - * Generally should be called at the same time as setDragging_(true). - * @private - */ -Blockly.BlockSvg.prototype.moveToDragSurface_ = function() { - // The translation for drag surface blocks, - // is equal to the current relative-to-surface position, - // to keep the position in sync as it move on/off the surface. - var xy = this.getRelativeToSurfaceXY(); - this.clearTransformAttributes_(); - this.workspace.dragSurface.translateSurface(xy.x, xy.y); - // Execute the move on the top-level SVG component - this.workspace.dragSurface.setBlocksAndShow(this.getSvgRoot()); -}; /** * Move this block back to the workspace block canvas. @@ -999,7 +984,7 @@ Blockly.BlockSvg.prototype.moveOffDragSurface_ = function() { var xy = this.getRelativeToSurfaceXY(); this.clearTransformAttributes_(); this.translate(xy.x, xy.y, false); - this.workspace.dragSurface.clearAndHide(this.workspace.getCanvas()); + this.workspace.blockDragSurface_.clearAndHide(this.workspace.getCanvas()); }; /** @@ -1044,12 +1029,14 @@ Blockly.BlockSvg.prototype.onMouseMove_ = function(e) { // Switch to unrestricted dragging. Blockly.dragMode_ = Blockly.DRAG_FREE; Blockly.longStop_(); + + // IS THIS COMMENT RELEVANT STILL??? // Must move to drag surface before unplug(), // or else connections will calculate the wrong relative to surface XY // in tighten_(). Then blocks connected to this block move around on the // drag surface. By moving to the drag surface before unplug, connection // positions will be calculated correctly. - this.moveToDragSurface_(); + // Disable workspace resizing as an optimization. this.workspace.setResizesEnabled(false); // Clear WidgetDiv/DropDownDiv without animating, in case blocks are moved diff --git a/core/flyout_base.js b/core/flyout_base.js index 2c9bd4a962..312a2de153 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -186,6 +186,20 @@ Blockly.Flyout.onMouseMoveBlockWrapper_ = null; */ Blockly.Flyout.prototype.autoClose = true; +/** + * Whether the flyout is visible. + * @type {boolean} + * @private + */ +Blockly.Flyout.prototype.isVisible_ = false; + +/** + * Whether the workspace containing this flyout is visible. + * @type {boolean} + * @private + */ +Blockly.Flyout.prototype.containerVisible_ = true; + /** * Corner radius of the flyout background. * @type {number} @@ -292,13 +306,14 @@ Blockly.Flyout.prototype.dragMode_ = Blockly.DRAG_NONE; /** - * Creates the flyout's DOM. Only needs to be called once. + * Creates the flyout's DOM. Only needs to be called once. The flyout can + * either exist as its own element or be a nested inside a separate + * element. * @param {string} tagName The type of tag to put the flyout in. This * should be or . * @return {!Element} The flyout's SVG group. */ Blockly.Flyout.prototype.createDom = function(tagName) { - tagName = 'g'; /* @@ -308,7 +323,7 @@ Blockly.Flyout.prototype.createDom = function(tagName) { // Setting style to display:none to start. The toolbox and flyout // hide/show code will set up proper visibility and size later. this.svgGroup_ = Blockly.utils.createSvgElement(tagName, - {'class': 'blocklyFlyout'}, null); + {'class': 'blocklyFlyout', 'style' : 'display: none'}, null); this.svgBackground_ = Blockly.utils.createSvgElement('path', {'class': 'blocklyFlyoutBackground'}, this.svgGroup_); this.svgGroup_.appendChild(this.workspace_.createDom()); @@ -399,7 +414,51 @@ Blockly.Flyout.prototype.getWorkspace = function() { * @return {boolean} True if visible. */ Blockly.Flyout.prototype.isVisible = function() { - return this.svgGroup_ && this.svgGroup_.style.display == 'block'; + return this.isVisible_; +}; + +/** + * Set whether the flyout is visible. A value of true does not necessarily mean + * that the flyout is shown. It could be hidden because its container is hidden. + * @param {boolean} visible True if visible. + */ +Blockly.Flyout.prototype.setVisible = function(visible) { + var visibilityChanged = (visible != this.isVisible()); + + this.isVisible_ = visible; + if (visibilityChanged) { + this.updateDisplay_(); + } +}; + +/** + * Set whether this flyout's container is visible. + * @param {boolean} visible Whether the container is visible. + */ +Blockly.Flyout.prototype.setContainerVisible = function(visible) { + var visibilityChanged = (visible != this.containerVisible_); + this.containerVisible_ = visible; + if (visibilityChanged) { + this.updateDisplay_(); + } +}; + +/** + * Update the display property of the flyout based whether it thinks it should + * be visible and whether its containing workspace is visible. + * @private + */ +Blockly.Flyout.prototype.updateDisplay_ = function() { + var show = true; + if (!this.containerVisible_) { + show = false; + } else { + show = this.isVisible(); + } + this.svgGroup_.style.display = show ? 'block' : 'none'; + // Update the scrollbar's visiblity too since it should mimic the + // flyout's visibility. + this.scrollbar_.setContainerVisible(show); }; /** @@ -409,7 +468,7 @@ Blockly.Flyout.prototype.hide = function() { if (!this.isVisible()) { return; } - this.svgGroup_.style.display = 'none'; + this.setVisible(false); // Delete all the event listeners. for (var x = 0, listen; listen = this.listeners_[x]; x++) { Blockly.unbindEvent_(listen); @@ -442,7 +501,7 @@ Blockly.Flyout.prototype.show = function(xmlList) { Blockly.Procedures.flyoutCategory(this.workspace_.targetWorkspace); } - this.svgGroup_.style.display = 'block'; + this.setVisible(true); // Create the blocks to be shown in this flyout. var contents = []; var gaps = []; diff --git a/core/flyout_horizontal.js b/core/flyout_horizontal.js index ea96e5497f..8ac3525e3d 100644 --- a/core/flyout_horizontal.js +++ b/core/flyout_horizontal.js @@ -94,7 +94,8 @@ Blockly.HorizontalFlyout.prototype.getMetrics_ = function() { } var viewHeight = this.height_; if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_TOP) { - viewHeight += this.MARGIN - this.SCROLLBAR_PADDING; + viewHeight += this.MARGIN; +// viewHeight += this.MARGIN - this.SCROLLBAR_PADDING; } var viewWidth = this.width_ - 2 * this.SCROLLBAR_PADDING; @@ -148,15 +149,14 @@ Blockly.HorizontalFlyout.prototype.position = function() { return; } var edgeWidth = this.horizontalLayout_ ? - targetWorkspaceMetrics.viewWidth : this.width_; - edgeWidth -= this.CORNER_RADIUS; - if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_RIGHT) { - edgeWidth *= -1; - } + targetWorkspaceMetrics.viewWidth - 2 * this.CORNER_RADIUS : + this.width_ - this.CORNER_RADIUS; - this.setBackgroundPath_(edgeWidth, - this.horizontalLayout_ ? this.height_ : - targetWorkspaceMetrics.viewHeight); + var edgeHeight = this.horizontalLayout_ ? + this.height_ - this.CORNER_RADIUS : + targetWorkspaceMetrics.viewHeight - 2 * this.CORNER_RADIUS; + + this.setBackgroundPath_(edgeWidth, edgeHeight); var x = targetWorkspaceMetrics.absoluteLeft; if (this.toolboxPosition_ == Blockly.TOOLBOX_AT_RIGHT) { @@ -170,8 +170,6 @@ Blockly.HorizontalFlyout.prototype.position = function() { y -= this.height_; } - this.svgGroup_.setAttribute('transform', 'translate(' + x + ',' + y + ')'); - // Record the height for Blockly.Flyout.getMetrics_, or width if the layout is // horizontal. if (this.horizontalLayout_) { @@ -179,9 +177,16 @@ Blockly.HorizontalFlyout.prototype.position = function() { } else { this.height_ = targetWorkspaceMetrics.viewHeight; } - + + this.svgGroup_.setAttribute("width", this.width_); + this.svgGroup_.setAttribute("height", this.height_); + var transform = 'translate(' + x + 'px,' + y + 'px)'; + this.svgGroup_.style.transform = transform; + // Update the scrollbar (if one exists). if (this.scrollbar_) { + // Set the scrollbars origin to be the top left of the flyout. + this.scrollbar_.setOrigin(x, y); this.scrollbar_.resize(); } // The blocks need to be visible in order to be laid out and measured correctly, but we don't @@ -205,13 +210,13 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(width, height) if (atTop) { // Top. - path.push('h', width + this.CORNER_RADIUS); + path.push('h', width + 2 * this.CORNER_RADIUS); // Right. path.push('v', height); // Bottom. path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1, -this.CORNER_RADIUS, this.CORNER_RADIUS); - path.push('h', -1 * (width - this.CORNER_RADIUS)); + path.push('h', -1 * width); // Left. path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1, -this.CORNER_RADIUS, -this.CORNER_RADIUS); @@ -220,13 +225,13 @@ Blockly.HorizontalFlyout.prototype.setBackgroundPath_ = function(width, height) // Top. path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1, this.CORNER_RADIUS, -this.CORNER_RADIUS); - path.push('h', width - this.CORNER_RADIUS); + path.push('h', width); // Right. path.push('a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1, this.CORNER_RADIUS, this.CORNER_RADIUS); - path.push('v', height - this.CORNER_RADIUS); + path.push('v', height); // Bottom. - path.push('h', -width - this.CORNER_RADIUS); + path.push('h', -width - 2 * this.CORNER_RADIUS); // Left. path.push('z'); } @@ -390,7 +395,7 @@ Blockly.HorizontalFlyout.prototype.placeNewBlock_ = function(originBlock) { } // Figure out where the original block is on the screen, relative to the upper // left corner of the main workspace. - var xyOld = this.workspace_.getSvgXY(svgRootOld, targetWorkspace); + var xyOld = Blockly.utils.getInjectionDivXY_(svgRootOld); // Take into account that the flyout might have been scrolled horizontally // (separately from the main workspace). // Generally a no-op in vertical mode but likely to happen in horizontal @@ -434,7 +439,8 @@ Blockly.HorizontalFlyout.prototype.placeNewBlock_ = function(originBlock) { // upper left corner of the workspace. This may not be the same as the // original block because the flyout's origin may not be the same as the // main workspace's origin. - var xyNew = this.workspace_.getSvgXY(svgRootNew, targetWorkspace); + var xyNew = Blockly.utils.getInjectionDivXY_(svgRootNew); + // Scale the scroll (getSvgXY_ did not do this). xyNew.x += targetWorkspace.scrollX / targetWorkspace.scale - targetWorkspace.scrollX; diff --git a/core/flyout_vertical.js b/core/flyout_vertical.js index d013fb23ae..412e4a7561 100644 --- a/core/flyout_vertical.js +++ b/core/flyout_vertical.js @@ -116,8 +116,8 @@ Blockly.VerticalFlyout.prototype.init = function(targetWorkspace) { * Creates the flyout's DOM. Only needs to be called once. * @return {!Element} The flyout's SVG group. */ -Blockly.VerticalFlyout.prototype.createDom = function() { - Blockly.VerticalFlyout.superClass_.createDom.call(this); +Blockly.VerticalFlyout.prototype.createDom = function(tagName) { + Blockly.VerticalFlyout.superClass_.createDom.call(this, tagName); /* @@ -246,14 +246,20 @@ Blockly.VerticalFlyout.prototype.position = function() { var y = 0; } - this.svgGroup_.setAttribute('transform', 'translate(' + x + ',' + y + ')'); - // Record the height for Blockly.Flyout.getMetrics_ this.height_ = targetWorkspaceMetrics.viewHeight - y; this.setBackgroundPath_(this.width_, this.height_); + + this.svgGroup_.setAttribute("width", this.width_); + this.svgGroup_.setAttribute("height", this.height_); + var transform = 'translate(' + x + 'px,' + y + 'px)'; + this.svgGroup_.style.transform = transform; + // Update the scrollbar (if one exists). if (this.scrollbar_) { + // Set the scrollbars origin to be the top left of the flyout. + this.scrollbar_.setOrigin(x, y); this.scrollbar_.resize(); } // The blocks need to be visible in order to be laid out and measured @@ -593,7 +599,7 @@ Blockly.VerticalFlyout.prototype.placeNewBlock_ = function(originBlock) { // Figure out where the original block is on the screen, relative to the upper // left corner of the main workspace. // In what coordinates? Pixels? - var xyOld = this.workspace_.getSvgXY(svgRootOld, targetWorkspace); + var xyOld = Blockly.utils.getInjectionDivXY_(svgRootOld); // Take into account that the flyout might have been scrolled horizontally // (separately from the main workspace). @@ -651,7 +657,7 @@ Blockly.VerticalFlyout.prototype.placeNewBlock_ = function(originBlock) { // upper left corner of the workspace. This may not be the same as the // original block because the flyout's origin may not be the same as the // main workspace's origin. - var xyNew = this.workspace_.getSvgXY(svgRootNew, targetWorkspace); + var xyNew = Blockly.utils.getInjectionDivXY_(svgRootNew); // Scale the scroll (getSvgXY_ did not do this). xyNew.x += diff --git a/core/inject.js b/core/inject.js index 93e9897a05..b361988b5b 100644 --- a/core/inject.js +++ b/core/inject.js @@ -225,7 +225,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, workspac if (!options.hasCategories && options.languageTree) { // Add flyout as an that is a sibling of the workspace svg. - var flyout = mainWorkspace.addFlyout_('g'); + var flyout = mainWorkspace.addFlyout_('svg'); Blockly.utils.insertAfter_(flyout, svg); } diff --git a/core/scrollbar.js b/core/scrollbar.js index 9525cb13f5..f086613c48 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -235,6 +235,14 @@ Blockly.Scrollbar = function(workspace, horizontal, opt_pair) { */ Blockly.Scrollbar.prototype.origin_ = new goog.math.Coordinate(0, 0); +/** + * Whether or not the origin of the scrollbar has changed. Used + * to help decide whether or not the reflow/resize calls need to happen. + * @type {boolean} + * @private + */ +Blockly.Scrollbar.prototype.originHasChanged_ = true; + /** * The size of the area within which the scrollbar handle can move. * @type {number} @@ -401,7 +409,11 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) { } } - if (Blockly.Scrollbar.metricsAreEquivalent_(hostMetrics, + // If the origin has changed (e.g. the toolbox is moving from start to end) + // we want to continue with the resize even if workspace metrics haven't. + if (this.originHasChanged) { + this.originHasChanged = false; + } else if (Blockly.Scrollbar.metricsAreEquivalent_(hostMetrics, this.oldHostMetrics_)) { return; } @@ -828,5 +840,8 @@ Blockly.Scrollbar.prototype.set = function(value) { * @ param {number} y The y coordinate of the scrollbar's origin. */ Blockly.Scrollbar.prototype.setOrigin = function(x, y) { - this.origin_ = new goog.math.Coordinate(x, y); + if (x != this.origin_.x || y != this.origin_.y) { + this.origin_ = new goog.math.Coordinate(x, y); + this.originHasChanged_ = true; + } }; diff --git a/core/toolbox.js b/core/toolbox.js index d6d1c0de6a..733b2c4bc3 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -168,8 +168,8 @@ Blockly.Toolbox.prototype.createFlyout_ = function() { } this.flyout_.setParentToolbox(this); - goog.dom.insertSiblingAfter(this.flyout_.createDom('g'), - this.workspace_.svgGroup_); + goog.dom.insertSiblingAfter(this.flyout_.createDom('svg'), + this.workspace_.getParentSvg()); this.flyout_.init(workspace); }; From 260e42dcdf539091a75b22450f41df4b318b3a7c Mon Sep 17 00:00:00 2001 From: Katelyn Mann Date: Tue, 17 Jan 2017 17:50:42 -0800 Subject: [PATCH 2/2] make the trash can lid animate again and fix the cursor to show an x when things will be removed. --- core/block_svg.js | 4 +++- core/scrollbar.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 306cfa808e..b4884b8eff 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -1181,8 +1181,10 @@ Blockly.BlockSvg.prototype.updatePreviews = function(closestConnection, Blockly.localConnection_ = null; } + var wouldDeleteBlock = this.updateCursor_(e, closestConnection); + // Add an insertion marker or replacement marker if needed. - if (closestConnection && + if (!wouldDeleteBlock && closestConnection && closestConnection != Blockly.highlightedConnection_ && !closestConnection.sourceBlock_.isInsertionMarker()) { Blockly.highlightedConnection_ = closestConnection; diff --git a/core/scrollbar.js b/core/scrollbar.js index f086613c48..a8b34aaac3 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -411,8 +411,8 @@ Blockly.Scrollbar.prototype.resize = function(opt_metrics) { // If the origin has changed (e.g. the toolbox is moving from start to end) // we want to continue with the resize even if workspace metrics haven't. - if (this.originHasChanged) { - this.originHasChanged = false; + if (this.originHasChanged_) { + this.originHasChanged_ = false; } else if (Blockly.Scrollbar.metricsAreEquivalent_(hostMetrics, this.oldHostMetrics_)) { return;