Update flyout metrics to work with the new metrics manager (#4684)

This commit is contained in:
alschmiedt
2021-03-09 17:09:49 -08:00
committed by GitHub
parent 8b0488d71e
commit 869e4eb366
8 changed files with 239 additions and 219 deletions

View File

@@ -21,6 +21,7 @@ goog.require('Blockly.Events');
goog.require('Blockly.Events.BlockCreate');
/** @suppress {extraRequire} */
goog.require('Blockly.Events.VarCreate');
goog.require('Blockly.FlyoutMetricsManager');
/** @suppress {extraRequire} */
goog.require('Blockly.Gesture');
goog.require('Blockly.ScrollbarPair');
@@ -41,7 +42,6 @@ goog.requireType('Blockly.FlyoutButton');
goog.requireType('Blockly.IDeleteArea');
goog.requireType('Blockly.IFlyout');
goog.requireType('Blockly.Options');
goog.requireType('Blockly.utils.Metrics');
goog.requireType('Blockly.utils.Rect');
@@ -55,9 +55,6 @@ goog.requireType('Blockly.utils.Rect');
* @implements {Blockly.IFlyout}
*/
Blockly.Flyout = function(workspaceOptions) {
workspaceOptions.getMetrics =
/** @type {function():!Blockly.utils.Metrics} */ (
this.getMetrics_.bind(this));
workspaceOptions.setMetrics = this.setMetrics_.bind(this);
/**
@@ -65,6 +62,9 @@ Blockly.Flyout = function(workspaceOptions) {
* @protected
*/
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
this.workspace_.setMetricsManager(
new Blockly.FlyoutMetricsManager(this.workspace_, this));
this.workspace_.isFlyout = true;
// Keep the workspace visibility consistent with the flyout's visibility.
this.workspace_.setVisible(this.isVisible_);
@@ -425,6 +425,8 @@ Blockly.Flyout.prototype.updateDisplay_ = function() {
Blockly.Flyout.prototype.positionAt_ = function(width, height, x, y) {
this.svgGroup_.setAttribute("width", width);
this.svgGroup_.setAttribute("height", height);
this.workspace_.setCachedParentSvgSize(width, height);
if (this.svgGroup_.tagName == 'svg') {
var transform = 'translate(' + x + 'px,' + y + 'px)';
Blockly.utils.dom.setCssTransform(this.svgGroup_, transform);
@@ -1038,15 +1040,6 @@ Blockly.Flyout.prototype.position;
*/
Blockly.Flyout.prototype.isDragTowardWorkspace;
/**
* Return an object with all the metrics required to size scrollbars for the
* flyout.
* @return {Blockly.utils.Metrics} Contains size and position metrics of the
* flyout.
* @protected
*/
Blockly.Flyout.prototype.getMetrics_;
/**
* Sets the translation of the flyout to match the scrollbars.
* @param {!{x:number,y:number}} xyRatio Contains a y property which is a float

View File

@@ -27,7 +27,6 @@ goog.require('Blockly.WidgetDiv');
goog.requireType('Blockly.Options');
goog.requireType('Blockly.utils.Coordinate');
goog.requireType('Blockly.utils.Metrics');
/**
@@ -43,73 +42,6 @@ Blockly.HorizontalFlyout = function(workspaceOptions) {
};
Blockly.utils.object.inherits(Blockly.HorizontalFlyout, Blockly.Flyout);
/**
* Return an object with all the metrics required to size scrollbars for the
* flyout. The following properties are computed:
* .viewHeight: Height of the visible rectangle,
* .viewWidth: Width of the visible rectangle,
* .contentHeight: Height of the contents,
* .contentWidth: Width of the contents,
* .scrollHeight: Height of the scroll area,
* .scrollWidth: Width of the scroll area,
* .viewTop: Offset of top edge of visible rectangle from parent,
* .contentTop: Offset of the top-most content from the y=0 coordinate,
* .scrollTop: Offset of the scroll area top from the y=0 coordinate,
* .absoluteTop: Top-edge of view.
* .viewLeft: Offset of the left edge of visible rectangle from parent,
* .contentLeft: Offset of the left-most content from the x=0 coordinate,
* .scrollLeft: Offset of the scroll area left from the x=0 coordinate,
* .absoluteLeft: Left-edge of view.
* @return {Blockly.utils.Metrics} Contains size and position metrics of the
* flyout.
* @protected
*/
Blockly.HorizontalFlyout.prototype.getMetrics_ = function() {
if (!this.isVisible()) {
// Flyout is hidden.
return null;
}
try {
var optionBox = this.workspace_.getCanvas().getBBox();
} catch (e) {
// Firefox has trouble with hidden elements (Bug 528969).
var optionBox = {height: 0, y: 0, width: 0, x: 0};
}
var absoluteTop = this.SCROLLBAR_PADDING;
var absoluteLeft = this.SCROLLBAR_PADDING;
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.BOTTOM) {
absoluteTop = 0;
}
var viewHeight = this.height_;
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP) {
viewHeight -= this.SCROLLBAR_PADDING;
}
var viewWidth = this.width_ - 2 * this.SCROLLBAR_PADDING;
var metrics = {
contentHeight: optionBox.height * this.workspace_.scale,
contentWidth: optionBox.width * this.workspace_.scale,
contentTop: optionBox.y,
contentLeft: optionBox.x,
scrollHeight: (optionBox.height + 2 * this.MARGIN) * this.workspace_.scale,
scrollWidth: (optionBox.width + 2 * this.MARGIN) * this.workspace_.scale,
scrollTop: optionBox.y - this.MARGIN,
scrollLeft: optionBox.x - this.MARGIN,
viewHeight: viewHeight,
viewWidth: viewWidth,
viewTop: -this.workspace_.scrollY,
viewLeft: -this.workspace_.scrollX,
absoluteTop: absoluteTop,
absoluteLeft: absoluteLeft
};
return metrics;
};
/**
* Sets the translation of the flyout to match the scrollbars.
* @param {!{x:number,y:number}} xyRatio Contains a y property which is a float
@@ -118,20 +50,23 @@ Blockly.HorizontalFlyout.prototype.getMetrics_ = function() {
* @protected
*/
Blockly.HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
var metrics = this.getMetrics_();
// This is a fix to an apparent race condition.
if (!metrics) {
if (!this.isVisible()) {
return;
}
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
if (typeof xyRatio.x == 'number') {
this.workspace_.scrollX =
-(metrics.scrollLeft +
(metrics.scrollWidth - metrics.viewWidth) * xyRatio.x);
-(scrollMetrics.left +
(scrollMetrics.width - viewMetrics.width) * xyRatio.x);
}
this.workspace_.translate(this.workspace_.scrollX + metrics.absoluteLeft,
this.workspace_.scrollY + metrics.absoluteTop);
this.workspace_.translate(this.workspace_.scrollX + absoluteMetrics.left,
this.workspace_.scrollY + absoluteMetrics.top);
};
/**
@@ -148,22 +83,24 @@ Blockly.HorizontalFlyout.prototype.getX = function() {
* @return {number} Y coordinate.
*/
Blockly.HorizontalFlyout.prototype.getY = function() {
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
if (!this.isVisible()) {
return 0;
}
var metricsManager = this.targetWorkspace.getMetricsManager();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var toolboxMetrics = metricsManager.getToolboxMetrics();
var y = 0;
var atTop = this.toolboxPosition_ == Blockly.utils.toolbox.Position.TOP;
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a category toolbox.
if (targetWorkspaceMetrics.toolboxHeight) {
if (toolboxMetrics.height) {
if (atTop) {
y = targetWorkspaceMetrics.toolboxHeight;
y = toolboxMetrics.height;
} else {
y = targetWorkspaceMetrics.viewHeight - this.height_;
y = viewMetrics.height - this.height_;
}
// Simple (flyout-only) toolbox.
} else {
@@ -171,7 +108,7 @@ Blockly.HorizontalFlyout.prototype.getY = function() {
y = 0;
} else {
// The simple flyout does not cover the workspace.
y = targetWorkspaceMetrics.viewHeight;
y = viewMetrics.height;
}
}
// Trashcan flyout is opposite the main flyout.
@@ -183,8 +120,7 @@ Blockly.HorizontalFlyout.prototype.getY = function() {
// to align the bottom edge of the flyout with the bottom edge of the
// blocklyDiv, we calculate the full height of the div minus the height
// of the flyout.
y = targetWorkspaceMetrics.viewHeight +
targetWorkspaceMetrics.absoluteTop - this.height_;
y = viewMetrics.height + absoluteMetrics.top - this.height_;
}
}
@@ -201,7 +137,7 @@ Blockly.HorizontalFlyout.prototype.position = function() {
var metricsManager = this.targetWorkspace.getMetricsManager();
var targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
// Record the width for Blockly.Flyout.getMetrics_.
// Record the width for workspace metrics.
this.width_ = targetWorkspaceViewMetrics.width;
var edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
@@ -275,8 +211,11 @@ Blockly.HorizontalFlyout.prototype.wheel_ = function(e) {
var delta = scrollDelta.x || scrollDelta.y;
if (delta) {
var metrics = this.getMetrics_();
var pos = (metrics.viewLeft - metrics.scrollLeft) + delta;
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var pos = (viewMetrics.left - scrollMetrics.left) + delta;
this.workspace_.scrollbar.setX(pos);
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
Blockly.WidgetDiv.hide();
@@ -420,7 +359,7 @@ Blockly.HorizontalFlyout.prototype.reflowInternal_ = function() {
this.targetWorkspace.scrollX, this.targetWorkspace.scrollY + flyoutHeight);
}
// Record the height for .getMetrics_ and .position.
// Record the height for workspace metrics and .position.
this.height_ = flyoutHeight;
this.position();
}

View File

@@ -27,7 +27,6 @@ goog.require('Blockly.WidgetDiv');
goog.requireType('Blockly.Options');
goog.requireType('Blockly.utils.Coordinate');
goog.requireType('Blockly.utils.Metrics');
/**
@@ -48,70 +47,6 @@ Blockly.utils.object.inherits(Blockly.VerticalFlyout, Blockly.Flyout);
*/
Blockly.VerticalFlyout.registryName = 'verticalFlyout';
/**
* Return an object with all the metrics required to size scrollbars for the
* flyout. The following properties are computed:
* .viewHeight: Height of the visible rectangle,
* .viewWidth: Width of the visible rectangle,
* .contentHeight: Height of the contents,
* .contentWidth: Width of the contents,
* .viewTop: Offset of top edge of visible rectangle from parent,
* .contentTop: Offset of the top-most content from the y=0 coordinate,
* .scrollTop: Offset of the scroll area top from the y=0 coordinate,
* .absoluteTop: Top-edge of view.
* .viewLeft: Offset of the left edge of visible rectangle from parent,
* .contentLeft: Offset of the left-most content from the x=0 coordinate,
* .scrollLeft: Offset of the scroll area left from the x=0 coordinate,
* .absoluteLeft: Left-edge of view.
* @return {Blockly.utils.Metrics} Contains size and position metrics of the
* flyout.
* @protected
*/
Blockly.VerticalFlyout.prototype.getMetrics_ = function() {
if (!this.isVisible()) {
// Flyout is hidden.
return null;
}
try {
var optionBox = this.workspace_.getCanvas().getBBox();
} catch (e) {
// Firefox has trouble with hidden elements (Bug 528969).
var optionBox = {height: 0, y: 0, width: 0, x: 0};
}
// Padding for the end of the scrollbar.
var absoluteTop = this.SCROLLBAR_PADDING;
var absoluteLeft = 0;
var viewHeight = this.height_ - 2 * this.SCROLLBAR_PADDING;
var viewWidth = this.width_;
if (!this.RTL) {
viewWidth -= this.SCROLLBAR_PADDING;
}
var metrics = {
contentHeight: optionBox.height * this.workspace_.scale,
contentWidth: optionBox.width * this.workspace_.scale,
contentTop: optionBox.y,
contentLeft: optionBox.x,
scrollHeight: (optionBox.height + 2 * this.MARGIN) * this.workspace_.scale,
scrollWidth: (optionBox.width + 2 * this.MARGIN) * this.workspace_.scale,
scrollTop: optionBox.y - this.MARGIN,
scrollLeft: optionBox.x - this.MARGIN,
viewHeight: viewHeight,
viewWidth: viewWidth,
viewTop: -this.workspace_.scrollY,
viewLeft: -this.workspace_.scrollX,
absoluteTop: absoluteTop,
absoluteLeft: absoluteLeft
};
return metrics;
};
/**
* Sets the translation of the flyout to match the scrollbars.
* @param {!{x:number,y:number}} xyRatio Contains a y property which is a float
@@ -120,18 +55,21 @@ Blockly.VerticalFlyout.prototype.getMetrics_ = function() {
* @protected
*/
Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
var metrics = this.getMetrics_();
// This is a fix to an apparent race condition.
if (!metrics) {
if (!this.isVisible()) {
return;
}
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
if (typeof xyRatio.y == 'number') {
this.workspace_.scrollY =
-(metrics.scrollTop +
(metrics.scrollHeight - metrics.viewHeight) * xyRatio.y);
-(scrollMetrics.top +
(scrollMetrics.height - viewMetrics.height) * xyRatio.y);
}
this.workspace_.translate(this.workspace_.scrollX + metrics.absoluteLeft,
this.workspace_.scrollY + metrics.absoluteTop);
this.workspace_.translate(this.workspace_.scrollX + absoluteMetrics.left,
this.workspace_.scrollY + absoluteMetrics.top);
};
/**
@@ -139,22 +77,23 @@ Blockly.VerticalFlyout.prototype.setMetrics_ = function(xyRatio) {
* @return {number} X coordinate.
*/
Blockly.VerticalFlyout.prototype.getX = function() {
var targetWorkspaceMetrics = this.targetWorkspace.getMetrics();
if (!targetWorkspaceMetrics) {
// Hidden components will return null.
if (!this.isVisible()) {
return 0;
}
var metricsManager = this.targetWorkspace.getMetricsManager();
var absoluteMetrics = metricsManager.getAbsoluteMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var toolboxMetrics = metricsManager.getToolboxMetrics();
var x = 0;
// If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
if (this.targetWorkspace.toolboxPosition == this.toolboxPosition_) {
// If there is a category toolbox.
if (targetWorkspaceMetrics.toolboxWidth) {
if (toolboxMetrics.width) {
if (this.toolboxPosition_ == Blockly.utils.toolbox.Position.LEFT) {
x = targetWorkspaceMetrics.toolboxWidth;
x = toolboxMetrics.width;
} else {
x = targetWorkspaceMetrics.viewWidth - this.width_;
x = viewMetrics.width - this.width_;
}
// Simple (flyout-only) toolbox.
} else {
@@ -162,7 +101,7 @@ Blockly.VerticalFlyout.prototype.getX = function() {
x = 0;
} else {
// The simple flyout does not cover the workspace.
x = targetWorkspaceMetrics.viewWidth;
x = viewMetrics.width;
}
}
// Trashcan flyout is opposite the main flyout.
@@ -174,8 +113,7 @@ Blockly.VerticalFlyout.prototype.getX = function() {
// to align the right edge of the flyout with the right edge of the
// blocklyDiv, we calculate the full width of the div minus the width
// of the flyout.
x = targetWorkspaceMetrics.viewWidth +
targetWorkspaceMetrics.absoluteLeft - this.width_;
x = viewMetrics.width + absoluteMetrics.left - this.width_;
}
}
@@ -201,7 +139,7 @@ Blockly.VerticalFlyout.prototype.position = function() {
var metricsManager = this.targetWorkspace.getMetricsManager();
var targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
// Record the height for Blockly.Flyout.getMetrics_
// Record the height for workspace metrics.
this.height_ = targetWorkspaceViewMetrics.height;
var edgeWidth = this.width_ - this.CORNER_RADIUS;
@@ -264,8 +202,11 @@ Blockly.VerticalFlyout.prototype.wheel_ = function(e) {
var scrollDelta = Blockly.utils.getScrollDeltaPixels(e);
if (scrollDelta.y) {
var metrics = this.getMetrics_();
var pos = (metrics.viewTop - metrics.scrollTop) + scrollDelta.y;
var metricsManager = this.workspace_.getMetricsManager();
var scrollMetrics = metricsManager.getScrollMetrics();
var viewMetrics = metricsManager.getViewMetrics();
var pos = (viewMetrics.top - scrollMetrics.top) + scrollDelta.y;
this.workspace_.scrollbar.setY(pos);
// When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
Blockly.WidgetDiv.hide();
@@ -426,7 +367,7 @@ Blockly.VerticalFlyout.prototype.reflowInternal_ = function() {
this.targetWorkspace.scrollX + flyoutWidth, this.targetWorkspace.scrollY);
}
// Record the width for .getMetrics_ and .position.
// Record the width for workspace metrics and .position.
this.width_ = flyoutWidth;
this.position();
}

View File

@@ -10,6 +10,7 @@
*/
'use strict';
goog.provide('Blockly.FlyoutMetricsManager');
goog.provide('Blockly.MetricsManager');
goog.require('Blockly.IMetricsManager');
@@ -121,7 +122,8 @@ Blockly.MetricsManager.prototype.getDimensionsPx_ = function(elem) {
* @public
*/
Blockly.MetricsManager.prototype.getFlyoutMetrics = function(opt_own) {
var flyoutDimensions = this.getDimensionsPx_(this.workspace_.getFlyout(opt_own));
var flyoutDimensions =
this.getDimensionsPx_(this.workspace_.getFlyout(opt_own));
return {
width: flyoutDimensions.width,
height: flyoutDimensions.height,
@@ -439,8 +441,7 @@ Blockly.MetricsManager.prototype.getMetrics = function() {
var absoluteMetrics = this.getAbsoluteMetrics();
var viewMetrics = this.getViewMetrics();
var contentMetrics = this.getContentMetrics();
var scrollMetrics =
this.getScrollMetrics(false, viewMetrics, contentMetrics);
var scrollMetrics = this.getScrollMetrics(false, viewMetrics, contentMetrics);
return {
contentHeight: contentMetrics.height,
@@ -476,3 +477,116 @@ Blockly.MetricsManager.prototype.getMetrics = function() {
Blockly.registry.register(
Blockly.registry.Type.METRICS_MANAGER, Blockly.registry.DEFAULT,
Blockly.MetricsManager);
/**
* Calculates metrics for a flyout's workspace.
* The metrics are mainly used to size scrollbars for the flyout.
* @param {!Blockly.WorkspaceSvg} workspace The flyout's workspace.
* @param {!Blockly.IFlyout} flyout The flyout.
* @extends {Blockly.MetricsManager}
* @constructor
*/
Blockly.FlyoutMetricsManager = function(workspace, flyout) {
/**
* The flyout that owns the workspace to calculate metrics for.
* @type {!Blockly.IFlyout}
* @protected
*/
this.flyout_ = flyout;
Blockly.FlyoutMetricsManager.superClass_.constructor.call(this, workspace);
};
Blockly.utils.object.inherits(
Blockly.FlyoutMetricsManager, Blockly.MetricsManager);
/**
* Gets the bounding box of the blocks on the flyout's workspace.
* This is in workspace coordinates.
* @returns {!SVGRect|{height: number, y: number, width: number, x: number}} The
* bounding box of the blocks on the workspace.
* @private
*/
Blockly.FlyoutMetricsManager.prototype.getBoundingBox_ = function() {
try {
var blockBoundingBox = this.workspace_.getCanvas().getBBox();
} catch (e) {
// Firefox has trouble with hidden elements (Bug 528969).
// 2021 Update: It looks like this was fixed around Firefox 77 released in
// 2020.
var blockBoundingBox = {height: 0, y: 0, width: 0, x: 0};
}
return blockBoundingBox;
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getContentMetrics = function(
opt_getWorkspaceCoordinates) {
// The bounding box is in workspace coordinates.
var blockBoundingBox = this.getBoundingBox_();
var scale = opt_getWorkspaceCoordinates ? 1 : this.workspace_.scale;
return {
height: blockBoundingBox.height * scale,
width: blockBoundingBox.width * scale,
top: blockBoundingBox.y * scale,
left: blockBoundingBox.x * scale,
};
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getScrollMetrics = function(
opt_getWorkspaceCoordinates, opt_viewMetrics, opt_contentMetrics) {
var contentMetrics = opt_contentMetrics || this.getContentMetrics();
var margin = this.flyout_.MARGIN;
var scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1;
return {
height: (contentMetrics.height + 2 * margin) / scale,
width: (contentMetrics.width + 2 * margin) / scale,
top: contentMetrics.top - margin / scale,
left: contentMetrics.left - margin / scale,
};
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getViewMetrics = function(
opt_getWorkspaceCoordinates) {
var svgMetrics = this.getSvgMetrics();
var scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1;
if (this.flyout_.horizontalLayout) {
var viewWidth = svgMetrics.width - 2 * this.flyout_.SCROLLBAR_PADDING;
var viewHeight = svgMetrics.height - this.flyout_.SCROLLBAR_PADDING;
} else {
var viewWidth = svgMetrics.width - this.flyout_.SCROLLBAR_PADDING;
var viewHeight = svgMetrics.height - 2 * this.flyout_.SCROLLBAR_PADDING;
}
return {
height: viewHeight / scale,
width: viewWidth / scale,
top: -this.workspace_.scrollY / scale,
left: -this.workspace_.scrollX / scale,
};
};
/**
* @override
*/
Blockly.FlyoutMetricsManager.prototype.getAbsoluteMetrics = function() {
var scrollbarPadding = this.flyout_.SCROLLBAR_PADDING;
if (this.flyout_.horizontalLayout) {
// The viewWidth is svgWidth - 2 * scrollbarPadding. We want to put half
// of that padding to the left of the blocks.
return {top: 0, left: scrollbarPadding};
} else {
// The viewHeight is svgHeight - 2 * scrollbarPadding. We want to put half
// of that padding to the top of the blocks.
return {top: scrollbarPadding, left: 0};
}
};

View File

@@ -241,8 +241,8 @@ Blockly.Mutator.prototype.resizeBubble_ = function() {
var height = workspaceSize.height + doubleBorderWidth * 3;
var flyout = this.workspace_.getFlyout();
if (flyout) {
var flyoutMetrics = flyout.getMetrics_();
height = Math.max(height, flyoutMetrics.scrollHeight + 20);
var flyoutScrollMetrics = this.workspace_.getMetricsManager().getScrollMetrics();
height = Math.max(height, flyoutScrollMetrics.height + 20);
width += flyout.getWidth();
}
if (this.block_.RTL) {

View File

@@ -107,42 +107,42 @@ Blockly.utils.Metrics.prototype.absoluteLeft;
/**
* Height of the Blockly div (the view + the toolbox, simple of otherwise).
* @type {number|undefined}
* @type {number}
*/
Blockly.utils.Metrics.prototype.svgHeight;
/**
* Width of the Blockly div (the view + the toolbox, simple or otherwise).
* @type {number|undefined}
* @type {number}
*/
Blockly.utils.Metrics.prototype.svgWidth;
/**
* Width of the toolbox, if it exists. Otherwise zero.
* @type {number|undefined}
* @type {number}
*/
Blockly.utils.Metrics.prototype.toolboxWidth;
/**
* Height of the toolbox, if it exists. Otherwise zero.
* @type {number|undefined}
* @type {number}
*/
Blockly.utils.Metrics.prototype.toolboxHeight;
/**
* Top, bottom, left or right. Use TOOLBOX_AT constants to compare.
* @type {number|undefined}
* @type {number}
*/
Blockly.utils.Metrics.prototype.toolboxPosition;
/**
* Width of the flyout if it is always open. Otherwise zero.
* @type {number|undefined}
* @type {number}
*/
Blockly.utils.Metrics.prototype.flyoutWidth;
/**
* Height of the flyout if it is always open. Otherwise zero.
* @type {number|undefined}
* @type {number}
*/
Blockly.utils.Metrics.prototype.flyoutHeight;

View File

@@ -532,6 +532,16 @@ Blockly.WorkspaceSvg.prototype.getMetricsManager = function() {
};
/**
* Sets the metrics manager for the workspace.
* @param {!Blockly.IMetricsManager} metricsManager The metrics manager.
* @package
*/
Blockly.WorkspaceSvg.prototype.setMetricsManager = function(metricsManager) {
this.metricsManager_ = metricsManager;
this.getMetrics = this.metricsManager_.getMetrics.bind(this.metricsManager_);
};
/*
* Gets the plugin manager for this workspace.
* @return {!Blockly.PluginManager} The plugin manager.
* @public

View File

@@ -34,13 +34,14 @@ suite('Flyout', function() {
suite('simple flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
this.targetMetricsManager = this.flyout.targetWorkspace.getMetricsManager();
});
test('y is always 0', function() {
chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout should be 0');
});
test('x is right of workspace if flyout at right', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewWidth: 100,
sinon.stub(this.targetMetricsManager, 'getViewMetrics').returns({
width: 100,
});
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.RIGHT;
@@ -62,25 +63,30 @@ suite('Flyout', function() {
toolbox: toolbox
});
this.flyout = this.workspace.getToolbox().getFlyout();
this.targetMetricsManager = this.flyout.targetWorkspace.getMetricsManager();
});
teardown(function() {
workspaceTeardown.call(this, this.workspace);
});
test('x is aligned with toolbox at left', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxWidth: 20,
sinon.stub(this.targetMetricsManager, 'getToolboxMetrics').returns({
width: 20,
});
this.flyout.setVisible(true);
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.LEFT;
this.flyout.toolboxPosition_ = Blockly.utils.toolbox.Position.LEFT;
chai.assert.equal(this.flyout.getX(), 20, 'x should be aligned with toolbox');
});
test('x is aligned with toolbox at right', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxWidth: 20,
viewWidth: 100,
sinon.stub(this.targetMetricsManager, 'getToolboxMetrics').returns({
width: 20,
});
sinon.stub(this.targetMetricsManager, 'getViewMetrics').returns({
width: 100,
});
this.flyout.width_ = 10;
this.flyout.setVisible(true);
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.RIGHT;
this.flyout.toolboxPosition_ = Blockly.utils.toolbox.Position.RIGHT;
@@ -92,6 +98,7 @@ suite('Flyout', function() {
suite('trashcan flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
this.targetMetricsManager = this.flyout.targetWorkspace.getMetricsManager();
});
test('x is 0 if trashcan on left', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
@@ -104,10 +111,14 @@ suite('Flyout', function() {
});
test('trashcan on right covers right edge of workspace', function() {
this.flyout.width_ = 20;
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewWidth: 100,
absoluteLeft: 10,
sinon.stub(this.targetMetricsManager, 'getAbsoluteMetrics').returns({
left: 10,
});
sinon.stub(this.targetMetricsManager, 'getViewMetrics').returns({
width: 100,
});
this.flyout.setVisible(true);
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.LEFT;
this.flyout.toolboxPosition_ = Blockly.utils.toolbox.Position.RIGHT;
@@ -130,6 +141,7 @@ suite('Flyout', function() {
suite('simple flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
this.targetMetricsManager = this.flyout.targetWorkspace.getMetricsManager();
});
test('x is always 0', function() {
chai.assert.equal(this.flyout.getX(), 0, 'x coordinate in horizontal flyout should be 0');
@@ -144,8 +156,8 @@ suite('Flyout', function() {
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.BOTTOM;
this.flyout.toolboxPosition_ = Blockly.utils.toolbox.Position.BOTTOM;
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewHeight: 50,
sinon.stub(this.targetMetricsManager, 'getViewMetrics').returns({
height: 50,
});
chai.assert.equal(this.flyout.getY(), 50, 'y should be below the workspace');
});
@@ -159,25 +171,31 @@ suite('Flyout', function() {
horizontalLayout: true,
});
this.flyout = this.workspace.getToolbox().getFlyout();
this.targetMetricsManager =
this.flyout.targetWorkspace.getMetricsManager();
});
teardown(function() {
workspaceTeardown.call(this, this.workspace);
});
test('y is aligned with toolbox at top', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxHeight: 20,
sinon.stub(this.targetMetricsManager, 'getToolboxMetrics').returns({
height: 20,
});
this.flyout.setVisible(true);
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.TOP;
this.flyout.toolboxPosition_ = Blockly.utils.toolbox.Position.TOP;
chai.assert.equal(this.flyout.getY(), 20, 'y should be aligned with toolbox');
});
test('y is aligned with toolbox at bottom', function() {
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
toolboxHeight: 20,
viewHeight: 100,
sinon.stub(this.targetMetricsManager, 'getToolboxMetrics').returns({
height: 20,
});
sinon.stub(this.targetMetricsManager, 'getViewMetrics').returns({
height: 100,
});
this.flyout.height_ = 30;
this.flyout.setVisible(true);
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.BOTTOM;
this.flyout.toolboxPosition_ = Blockly.utils.toolbox.Position.BOTTOM;
@@ -189,6 +207,8 @@ suite('Flyout', function() {
suite('trashcan flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
this.targetMetricsManager =
this.flyout.targetWorkspace.getMetricsManager();
});
test('y is 0 if trashcan at top', function() {
this.flyout.targetWorkspace.toolboxPosition =
@@ -200,10 +220,13 @@ suite('Flyout', function() {
this.flyout.targetWorkspace.toolboxPosition =
Blockly.utils.toolbox.Position.TOP;
this.flyout.toolboxPosition_ = Blockly.utils.toolbox.Position.BOTTOM;
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewHeight: 50,
absoluteTop: 10,
sinon.stub(this.targetMetricsManager, 'getAbsoluteMetrics').returns({
top: 10,
});
sinon.stub(this.targetMetricsManager, 'getViewMetrics').returns({
height: 50,
});
this.flyout.setVisible(true);
this.flyout.height_ = 20;
chai.assert.equal(this.flyout.getY(), 40, 'y + height should be aligned with bottom');
});