mirror of
https://github.com/google/blockly.git
synced 2026-01-06 08:30:13 +01:00
Split the scrollbar and flyout out into their own SVG elements. They (#771)
* Split the scrollbar and flyout out into their own SVG elements. They are siblings of the workpsace SVG. This paves the way to make performance improvements to workspace dragging.
This commit is contained in:
11
core/css.js
11
core/css.js
@@ -136,6 +136,7 @@ Blockly.Css.CONTENT = [
|
||||
'background-color: #fff;',
|
||||
'outline: none;',
|
||||
'overflow: hidden;', /* IE overflows by default. */
|
||||
'position: absolute;',
|
||||
'display: block;',
|
||||
'}',
|
||||
|
||||
@@ -270,6 +271,10 @@ Blockly.Css.CONTENT = [
|
||||
'fill: #000;',
|
||||
'}',
|
||||
|
||||
'.blocklyFlyout {',
|
||||
'position: absolute;',
|
||||
'z-index: 20;',
|
||||
'}',
|
||||
'.blocklyFlyoutButton {',
|
||||
'fill: #888;',
|
||||
'cursor: default;',
|
||||
@@ -373,6 +378,12 @@ Blockly.Css.CONTENT = [
|
||||
'fill-opacity: .8;',
|
||||
'}',
|
||||
|
||||
'.blocklyScrollbarHorizontal, .blocklyScrollbarVertical {',
|
||||
'position: absolute;',
|
||||
'outline: none;',
|
||||
'z-index: 30;',
|
||||
'}',
|
||||
|
||||
'.blocklyScrollbarBackground {',
|
||||
'opacity: 0;',
|
||||
'}',
|
||||
|
||||
104
core/flyout.js
104
core/flyout.js
@@ -176,6 +176,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}
|
||||
@@ -260,18 +274,24 @@ Blockly.Flyout.prototype.dragMode_ = Blockly.DRAG_NONE;
|
||||
Blockly.Flyout.prototype.dragAngleRange_ = 70;
|
||||
|
||||
/**
|
||||
* 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 <svg> element or be a <g> nested inside a separate
|
||||
* <svg> element.
|
||||
* @param {string} tagName The type of tag to put the flyout in. This
|
||||
* should be <svg> or <g>.
|
||||
* @return {!Element} The flyout's SVG group.
|
||||
*/
|
||||
Blockly.Flyout.prototype.createDom = function() {
|
||||
Blockly.Flyout.prototype.createDom = function(tagName) {
|
||||
/*
|
||||
<g>
|
||||
<svg | g>
|
||||
<path class="blocklyFlyoutBackground"/>
|
||||
<g class="blocklyFlyout"></g>
|
||||
</g>
|
||||
</ svg | g>
|
||||
*/
|
||||
this.svgGroup_ = Blockly.utils.createSvgElement('g',
|
||||
{'class': 'blocklyFlyout'}, null);
|
||||
// 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', 'style': 'display: none'}, null);
|
||||
this.svgBackground_ = Blockly.utils.createSvgElement('path',
|
||||
{'class': 'blocklyFlyoutBackground'}, this.svgGroup_);
|
||||
this.svgGroup_.appendChild(this.workspace_.createDom());
|
||||
@@ -469,8 +489,6 @@ Blockly.Flyout.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_) {
|
||||
@@ -479,8 +497,15 @@ Blockly.Flyout.prototype.position = function() {
|
||||
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();
|
||||
}
|
||||
};
|
||||
@@ -623,7 +648,51 @@ Blockly.Flyout.prototype.wheel_ = function(e) {
|
||||
* @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);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -633,7 +702,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);
|
||||
@@ -666,7 +735,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 = [];
|
||||
@@ -1131,7 +1200,11 @@ Blockly.Flyout.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 = targetWorkspace.getSvgXY(svgRootOld);
|
||||
if (targetWorkspace.isMutator) {
|
||||
var xyOld = this.workspace_.getSvgXY(/** @type {!Element} */ (svgRootOld));
|
||||
} else {
|
||||
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
|
||||
@@ -1175,7 +1248,12 @@ Blockly.Flyout.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 = targetWorkspace.getSvgXY(svgRootNew);
|
||||
if (targetWorkspace.isMutator) {
|
||||
var xyNew = targetWorkspace.getSvgXY(/* @type {!Element} */(svgRootNew));
|
||||
} else {
|
||||
var xyNew = Blockly.utils.getInjectionDivXY_(svgRootNew);
|
||||
}
|
||||
|
||||
// Scale the scroll (getSvgXY_ did not do this).
|
||||
xyNew.x +=
|
||||
targetWorkspace.scrollX / targetWorkspace.scale - targetWorkspace.scrollX;
|
||||
|
||||
@@ -195,6 +195,13 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface) {
|
||||
var mainWorkspace = new Blockly.WorkspaceSvg(options, blockDragSurface);
|
||||
mainWorkspace.scale = options.zoomOptions.startScale;
|
||||
svg.appendChild(mainWorkspace.createDom('blocklyMainBackground'));
|
||||
|
||||
if (!options.hasCategories && options.languageTree) {
|
||||
// Add flyout as an <svg> that is a sibling of the workspace svg.
|
||||
var flyout = mainWorkspace.addFlyout_('svg');
|
||||
Blockly.utils.insertAfter_(flyout, svg);
|
||||
}
|
||||
|
||||
// A null translation will also apply the correct initial scale.
|
||||
mainWorkspace.translate(0, 0);
|
||||
mainWorkspace.markFocused();
|
||||
|
||||
@@ -130,8 +130,16 @@ Blockly.Mutator.prototype.createEditor_ = function() {
|
||||
};
|
||||
this.workspace_ = new Blockly.WorkspaceSvg(workspaceOptions);
|
||||
this.workspace_.isMutator = true;
|
||||
this.svgDialog_.appendChild(
|
||||
this.workspace_.createDom('blocklyMutatorBackground'));
|
||||
|
||||
// Mutator flyouts go inside the mutator workspace's <g> rather than in
|
||||
// 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 background = this.workspace_.createDom('blocklyMutatorBackground');
|
||||
background.appendChild(flyoutSvg);
|
||||
this.svgDialog_.appendChild(background);
|
||||
|
||||
return this.svgDialog_;
|
||||
};
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ Blockly.ScrollbarPair = function(workspace) {
|
||||
{'height': Blockly.Scrollbar.scrollbarThickness,
|
||||
'width': Blockly.Scrollbar.scrollbarThickness,
|
||||
'class': 'blocklyScrollbarBackground'}, null);
|
||||
Blockly.Scrollbar.insertAfter_(this.corner_, workspace.getBubbleCanvas());
|
||||
Blockly.utils.insertAfter_(this.corner_, workspace.getBubbleCanvas());
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -202,6 +202,8 @@ Blockly.Scrollbar = function(workspace, horizontal, opt_pair) {
|
||||
if (horizontal) {
|
||||
this.svgBackground_.setAttribute('height',
|
||||
Blockly.Scrollbar.scrollbarThickness);
|
||||
this.outerSvg_.setAttribute('height',
|
||||
Blockly.Scrollbar.scrollbarThickness);
|
||||
this.svgHandle_.setAttribute('height',
|
||||
Blockly.Scrollbar.scrollbarThickness - 5);
|
||||
this.svgHandle_.setAttribute('y', 2.5);
|
||||
@@ -211,6 +213,8 @@ Blockly.Scrollbar = function(workspace, horizontal, opt_pair) {
|
||||
} else {
|
||||
this.svgBackground_.setAttribute('width',
|
||||
Blockly.Scrollbar.scrollbarThickness);
|
||||
this.outerSvg_.setAttribute('width',
|
||||
Blockly.Scrollbar.scrollbarThickness);
|
||||
this.svgHandle_.setAttribute('width',
|
||||
Blockly.Scrollbar.scrollbarThickness - 5);
|
||||
this.svgHandle_.setAttribute('x', 2.5);
|
||||
@@ -224,6 +228,12 @@ Blockly.Scrollbar = function(workspace, horizontal, opt_pair) {
|
||||
this.onMouseDownHandleWrapper_ = Blockly.bindEventWithChecks_(this.svgHandle_,
|
||||
'mousedown', scrollbar, scrollbar.onMouseDownHandle_);
|
||||
};
|
||||
/**
|
||||
* The coordinate of the upper left corner of the scrollbar SVG.
|
||||
* @type {goog.math.Coordinate}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.origin_ = new goog.math.Coordinate(0, 0);
|
||||
|
||||
/**
|
||||
* The size of the area within which the scrollbar handle can move.
|
||||
@@ -253,6 +263,13 @@ Blockly.Scrollbar.prototype.handlePosition_ = 0;
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.isVisible_ = true;
|
||||
|
||||
/**
|
||||
* Whether the workspace containing this scrollbar is visible.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.containerVisible_ = true;
|
||||
|
||||
/**
|
||||
* Width of vertical scrollbar or height of horizontal scrollbar.
|
||||
* Increase the size of scrollbars on touch devices.
|
||||
@@ -303,7 +320,8 @@ Blockly.Scrollbar.prototype.dispose = function() {
|
||||
Blockly.unbindEvent_(this.onMouseDownHandleWrapper_);
|
||||
this.onMouseDownHandleWrapper_ = null;
|
||||
|
||||
goog.dom.removeNode(this.svgGroup_);
|
||||
goog.dom.removeNode(this.outerSvg_);
|
||||
this.outerSvg_ = null;
|
||||
this.svgGroup_ = null;
|
||||
this.svgBackground_ = null;
|
||||
this.svgHandle_ = null;
|
||||
@@ -338,9 +356,19 @@ Blockly.Scrollbar.prototype.setHandlePosition = function(newPosition) {
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.setScrollViewSize_ = function(newSize) {
|
||||
this.scrollViewSize_ = newSize;
|
||||
this.outerSvg_.setAttribute(this.lengthAttribute_, this.scrollViewSize_);
|
||||
this.svgBackground_.setAttribute(this.lengthAttribute_, this.scrollViewSize_);
|
||||
};
|
||||
|
||||
/**
|
||||
+ * Set whether this scrollbar's container is visible.
|
||||
+ * @param {boolean} visible Whether the container is visible.
|
||||
+ */
|
||||
Blockly.ScrollbarPair.prototype.setContainerVisible = function(visible) {
|
||||
this.hScroll.setContainerVisible(visible);
|
||||
this.vScroll.setContainerVisible(visible);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the position of the scrollbar's svg group.
|
||||
* @param {number} x The new x coordinate.
|
||||
@@ -350,8 +378,10 @@ Blockly.Scrollbar.prototype.setPosition = function(x, y) {
|
||||
this.position_.x = x;
|
||||
this.position_.y = y;
|
||||
|
||||
this.svgGroup_.setAttribute('transform',
|
||||
'translate(' + this.position_.x + ',' + this.position_.y + ')');
|
||||
var tempX = this.position_.x + this.origin_.x;
|
||||
var tempY = this.position_.y + this.origin_.y;
|
||||
var transform = 'translate(' + tempX + 'px,' + tempY + 'px)';
|
||||
this.outerSvg_.style.transform = transform;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -539,23 +569,26 @@ Blockly.Scrollbar.prototype.resizeContentVertical = function(hostMetrics) {
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.createDom_ = function() {
|
||||
/* Create the following DOM:
|
||||
<g class="blocklyScrollbarHorizontal">
|
||||
<rect class="blocklyScrollbarBackground" />
|
||||
<rect class="blocklyScrollbarHandle" rx="8" ry="8" />
|
||||
</g>
|
||||
<svg class="blocklyScrollbarHorizontal">
|
||||
<g>
|
||||
<rect class="blocklyScrollbarBackground" />
|
||||
<rect class="blocklyScrollbarHandle" rx="8" ry="8" />
|
||||
</g>
|
||||
</svg>
|
||||
*/
|
||||
var className = 'blocklyScrollbar' +
|
||||
(this.horizontal_ ? 'Horizontal' : 'Vertical');
|
||||
this.svgGroup_ = Blockly.utils.createSvgElement('g', {'class': className},
|
||||
this.outerSvg_ = Blockly.utils.createSvgElement('svg', {'class': className},
|
||||
null);
|
||||
this.svgGroup_ = Blockly.utils.createSvgElement('g', {}, this.outerSvg_);
|
||||
this.svgBackground_ = Blockly.utils.createSvgElement('rect',
|
||||
{'class': 'blocklyScrollbarBackground'}, this.svgGroup_);
|
||||
var radius = Math.floor((Blockly.Scrollbar.scrollbarThickness - 5) / 2);
|
||||
this.svgHandle_ = Blockly.utils.createSvgElement('rect',
|
||||
{'class': 'blocklyScrollbarHandle', 'rx': radius, 'ry': radius},
|
||||
this.svgGroup_);
|
||||
Blockly.Scrollbar.insertAfter_(this.svgGroup_,
|
||||
this.workspace_.getBubbleCanvas());
|
||||
Blockly.utils.insertAfter_(this.outerSvg_,
|
||||
this.workspace_.getParentSvg());
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -567,29 +600,57 @@ Blockly.Scrollbar.prototype.isVisible = function() {
|
||||
return this.isVisible_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set whether the scrollbar's container is visible and update
|
||||
* display accordingly if visibility has changed.
|
||||
* @param {boolean} visible Whether the container is visible
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.setContainerVisible = function(visible) {
|
||||
var visibilityChanged = (visible != this.containerVisible_);
|
||||
|
||||
this.containerVisible_ = visible;
|
||||
if (visibilityChanged) {
|
||||
this.updateDisplay_();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set whether the scrollbar is visible.
|
||||
* Only applies to non-paired scrollbars.
|
||||
* @param {boolean} visible True if visible.
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.setVisible = function(visible) {
|
||||
if (visible == this.isVisible()) {
|
||||
return;
|
||||
}
|
||||
var visibilityChanged = (visible != this.isVisible());
|
||||
|
||||
// Ideally this would also apply to scrollbar pairs, but that's a bigger
|
||||
// headache (due to interactions with the corner square).
|
||||
if (this.pair_) {
|
||||
throw 'Unable to toggle visibility of paired scrollbars.';
|
||||
}
|
||||
|
||||
this.isVisible_ = visible;
|
||||
if (visibilityChanged) {
|
||||
this.updateDisplay_();
|
||||
}
|
||||
};
|
||||
|
||||
if (visible) {
|
||||
this.svgGroup_.setAttribute('display', 'block');
|
||||
/**
|
||||
* Update visibility of scrollbar based on whether it thinks it should
|
||||
* be visible and whether its containing workspace is visible.
|
||||
* We cannot rely on the containing workspace being hidden to hide us
|
||||
* because it is not necessarily our parent in the dom.
|
||||
*/
|
||||
Blockly.Scrollbar.prototype.updateDisplay_ = function() {
|
||||
var show = true;
|
||||
// Check whether our parent/container is visible.
|
||||
if (!this.containerVisible_) {
|
||||
show = false;
|
||||
} else {
|
||||
// Hide the scrollbar.
|
||||
this.workspace_.setMetrics({x: 0, y: 0});
|
||||
this.svgGroup_.setAttribute('display', 'none');
|
||||
show = this.isVisible();
|
||||
}
|
||||
if (show) {
|
||||
this.outerSvg_.setAttribute('display', 'block');
|
||||
} else {
|
||||
this.outerSvg_.setAttribute('display', 'none');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -613,7 +674,7 @@ Blockly.Scrollbar.prototype.onMouseDownBar_ = function(e) {
|
||||
this.workspace_.getInverseScreenCTM());
|
||||
var mouseLocation = this.horizontal_ ? mouseXY.x : mouseXY.y;
|
||||
|
||||
var handleXY = this.workspace_.getSvgXY(this.svgHandle_);
|
||||
var handleXY = Blockly.utils.getInjectionDivXY_(this.svgHandle_);
|
||||
var handleStart = this.horizontal_ ? handleXY.x : handleXY.y;
|
||||
var handlePosition = this.handlePosition_;
|
||||
|
||||
@@ -744,21 +805,12 @@ Blockly.Scrollbar.prototype.set = function(value) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert a node after a reference node.
|
||||
* Contrast with node.insertBefore function.
|
||||
* @param {!Element} newNode New element to insert.
|
||||
* @param {!Element} refNode Existing element to precede new node.
|
||||
* @private
|
||||
* Set the origin of the upper left of the scrollbar. This if for times
|
||||
* when the scrollbar is used in an object whose origin isn't the same
|
||||
* as the main workspace (e.g. in a flyout.)
|
||||
* @ param {number} x The x coordinate of the scrollbar's origin.
|
||||
* @ param {number} y The y coordinate of the scrollbar's origin.
|
||||
*/
|
||||
Blockly.Scrollbar.insertAfter_ = function(newNode, refNode) {
|
||||
var siblingNode = refNode.nextSibling;
|
||||
var parentNode = refNode.parentNode;
|
||||
if (!parentNode) {
|
||||
throw 'Reference node has no parent.';
|
||||
}
|
||||
if (siblingNode) {
|
||||
parentNode.insertBefore(newNode, siblingNode);
|
||||
} else {
|
||||
parentNode.appendChild(newNode);
|
||||
}
|
||||
Blockly.Scrollbar.prototype.setOrigin = function(x, y) {
|
||||
this.origin_ = new goog.math.Coordinate(x, y);
|
||||
};
|
||||
|
||||
@@ -182,7 +182,8 @@ Blockly.Toolbox.prototype.init = function() {
|
||||
* @private
|
||||
*/
|
||||
this.flyout_ = new Blockly.Flyout(workspaceOptions);
|
||||
goog.dom.insertSiblingAfter(this.flyout_.createDom(), workspace.svgGroup_);
|
||||
goog.dom.insertSiblingAfter(this.flyout_.createDom('svg'),
|
||||
this.workspace_.getParentSvg());
|
||||
this.flyout_.init(workspace);
|
||||
|
||||
this.config_['cleardotPath'] = workspace.options.pathToMedia + '1x1.gif';
|
||||
|
||||
@@ -131,10 +131,14 @@ Blockly.utils.getRelativeXY = function(element) {
|
||||
}
|
||||
}
|
||||
|
||||
// Third, check for style="transform: translate3d(...)".
|
||||
// Then check for style = transform: translate(...) or translate3d(...)
|
||||
var style = element.getAttribute('style');
|
||||
if (style && style.indexOf('translate3d') > -1) {
|
||||
var styleComponents = style.match(Blockly.utils.getRelativeXY.XY_3D_REGEX_);
|
||||
if (style && style.indexOf('translate') > -1) {
|
||||
var styleComponents = style.match(Blockly.utils.getRelativeXY.XY_2D_REGEX_);
|
||||
// Try transform3d if 2d transform wasn't there.
|
||||
if (!styleComponents) {
|
||||
styleComponents = style.match(Blockly.utils.getRelativeXY.XY_3D_REGEX_);
|
||||
}
|
||||
if (styleComponents) {
|
||||
xy.x += parseFloat(styleComponents[1]);
|
||||
if (styleComponents[3]) {
|
||||
@@ -145,6 +149,51 @@ Blockly.utils.getRelativeXY = function(element) {
|
||||
return xy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the coordinates of the top-left corner of this element relative to
|
||||
* the div blockly was injected into.
|
||||
* @param {!Element} element SVG element to find the coordinates of. If this is
|
||||
* not a child of the div blockly was injected into, the behaviour is
|
||||
* undefined.
|
||||
* @return {!goog.math.Coordinate} Object with .x and .y properties.
|
||||
*/
|
||||
Blockly.utils.getInjectionDivXY_ = function(element) {
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var scale = 1;
|
||||
while (element) {
|
||||
var xy = Blockly.utils.getRelativeXY(element);
|
||||
var scale = Blockly.utils.getScale_(element);
|
||||
x = (x * scale) + xy.x;
|
||||
y = (y * scale) + xy.y;
|
||||
var classes = element.getAttribute('class') || '';
|
||||
if ((' ' + classes + ' ').indexOf(' injectionDiv ') != -1) {
|
||||
break;
|
||||
}
|
||||
element = element.parentNode;
|
||||
}
|
||||
return new goog.math.Coordinate(x, y);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the scale of this element.
|
||||
* @param {!Element} element The element to find the coordinates of.
|
||||
* @return {!number} number represending the scale applied to the element.
|
||||
* @private
|
||||
*/
|
||||
Blockly.utils.getScale_ = function(element) {
|
||||
var scale = 1;
|
||||
var transform = element.getAttribute('transform');
|
||||
if (transform) {
|
||||
var transformComponents =
|
||||
transform.match(Blockly.utils.getScale_.REGEXP_);
|
||||
if (transformComponents && transformComponents[0]) {
|
||||
scale = parseFloat(transformComponents[0]);
|
||||
}
|
||||
}
|
||||
return scale;
|
||||
};
|
||||
|
||||
/**
|
||||
* Static regex to pull the x,y values out of an SVG translate() directive.
|
||||
* Note that Firefox and IE (9,10) return 'translate(12)' instead of
|
||||
@@ -157,6 +206,15 @@ Blockly.utils.getRelativeXY = function(element) {
|
||||
Blockly.utils.getRelativeXY.XY_REGEX_ =
|
||||
/translate\(\s*([-+\d.e]+)([ ,]\s*([-+\d.e]+)\s*\))?/;
|
||||
|
||||
|
||||
/**
|
||||
* Static regex to pull the scale values out of a transform style property.
|
||||
* Accounts for same exceptions as XY_REGEXP_.
|
||||
* @type {!RegExp}
|
||||
* @private
|
||||
*/
|
||||
Blockly.utils.getScale_REGEXP_ = /scale\(\s*([-+\d.e]+)\s*\)/;
|
||||
|
||||
/**
|
||||
* Static regex to pull the x,y,z values out of a translate3d() style property.
|
||||
* Accounts for same exceptions as XY_REGEXP_.
|
||||
@@ -166,6 +224,15 @@ Blockly.utils.getRelativeXY.XY_REGEX_ =
|
||||
Blockly.utils.getRelativeXY.XY_3D_REGEX_ =
|
||||
/transform:\s*translate3d\(\s*([-+\d.e]+)px([ ,]\s*([-+\d.e]+)\s*)px([ ,]\s*([-+\d.e]+)\s*)px\)?/;
|
||||
|
||||
/**
|
||||
* Static regex to pull the x,y,z values out of a translate3d() style property.
|
||||
* Accounts for same exceptions as XY_REGEXP_.
|
||||
* @type {!RegExp}
|
||||
* @private
|
||||
*/
|
||||
Blockly.utils.getRelativeXY.XY_2D_REGEX_ =
|
||||
/transform:\s*translate\(\s*([-+\d.e]+)px([ ,]\s*([-+\d.e]+)\s*)px\)?/;
|
||||
|
||||
/**
|
||||
* Helper method for creating SVG elements.
|
||||
* @param {string} name Element's tag name.
|
||||
@@ -665,3 +732,23 @@ Blockly.utils.is3dSupported = function() {
|
||||
Blockly.utils.is3dSupported.cached_ = has3d !== 'none';
|
||||
return Blockly.utils.is3dSupported.cached_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Insert a node after a reference node.
|
||||
* Contrast with node.insertBefore function.
|
||||
* @param {!Element} newNode New element to insert.
|
||||
* @param {!Element} refNode Existing element to precede new node.
|
||||
* @private
|
||||
*/
|
||||
Blockly.utils.insertAfter_ = function(newNode, refNode) {
|
||||
var siblingNode = refNode.nextSibling;
|
||||
var parentNode = refNode.parentNode;
|
||||
if (!parentNode) {
|
||||
throw 'Reference node has no parent.';
|
||||
}
|
||||
if (siblingNode) {
|
||||
parentNode.insertBefore(newNode, siblingNode);
|
||||
} else {
|
||||
parentNode.appendChild(newNode);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -336,8 +336,6 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) {
|
||||
* @private
|
||||
*/
|
||||
this.toolbox_ = new Blockly.Toolbox(this);
|
||||
} else if (this.options.languageTree) {
|
||||
this.addFlyout_();
|
||||
}
|
||||
this.updateGridPattern_();
|
||||
this.recordDeleteAreas();
|
||||
@@ -430,10 +428,12 @@ Blockly.WorkspaceSvg.prototype.addZoomControls_ = function(bottom) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a flyout.
|
||||
* 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
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.addFlyout_ = function() {
|
||||
Blockly.WorkspaceSvg.prototype.addFlyout_ = function(tagName) {
|
||||
var workspaceOptions = {
|
||||
disabledPatternId: this.options.disabledPatternId,
|
||||
parentWorkspace: this,
|
||||
@@ -445,8 +445,28 @@ Blockly.WorkspaceSvg.prototype.addFlyout_ = function() {
|
||||
/** @type {Blockly.Flyout} */
|
||||
this.flyout_ = new Blockly.Flyout(workspaceOptions);
|
||||
this.flyout_.autoClose = false;
|
||||
var svgFlyout = this.flyout_.createDom();
|
||||
this.svgGroup_.insertBefore(svgFlyout, this.svgBlockCanvas_);
|
||||
|
||||
// Return the element so that callers can place it in their desired
|
||||
// spot in the dom. For exmaple, mutator flyouts do not go in the same place
|
||||
// as main workspace flyouts.
|
||||
return this.flyout_.createDom(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.
|
||||
* @return {Blockly.Flyout} The flyout on this workspace.
|
||||
* @package
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.getFlyout_ = function() {
|
||||
if (this.flyout_) {
|
||||
return this.flyout_;
|
||||
}
|
||||
if (this.toolbox_) {
|
||||
return this.toolbox_.flyout_;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -586,6 +606,19 @@ Blockly.WorkspaceSvg.prototype.getWidth = function() {
|
||||
* @param {boolean} isVisible True if workspace should be visible.
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.setVisible = function(isVisible) {
|
||||
|
||||
// Tell the scrollbar whether its container is visible so it can
|
||||
// tell when to hide itself.
|
||||
if (this.scrollbar) {
|
||||
this.scrollbar.setContainerVisible(isVisible);
|
||||
}
|
||||
|
||||
// Tell the flyout whether its container is visible so it can
|
||||
// tell when to hide itself.
|
||||
if (this.getFlyout_()) {
|
||||
this.getFlyout_().setContainerVisible(isVisible);
|
||||
}
|
||||
|
||||
this.getParentSvg().style.display = isVisible ? 'block' : 'none';
|
||||
if (this.toolbox_) {
|
||||
// Currently does not support toolboxes in mutators.
|
||||
|
||||
Reference in New Issue
Block a user