diff --git a/core/block_svg.js b/core/block_svg.js
index c8ac13956..36b9dac54 100644
--- a/core/block_svg.js
+++ b/core/block_svg.js
@@ -75,23 +75,6 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) {
*/
this.pathObject = workspace.getRenderer().makePathObject(this.svgGroup_);
- // The next two paths are set only for backwards compatibility reasons.
- /**
- * The primary path of the block.
- * @type {SVGElement}
- * @private
- */
- this.svgPath_ = this.pathObject.svgPath || null;
-
- /**
- * The light path of the block.
- * @type {SVGElement}
- * @private
- */
- this.svgPathLight_ = this.pathObject.svgPathLight || null;
-
- this.svgPath_.tooltip = this;
-
/** @type {boolean} */
this.rendered = false;
@@ -114,7 +97,9 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) {
this.useDragSurface_ =
Blockly.utils.is3dSupported() && !!workspace.getBlockDragSurface();
- Blockly.Tooltip.bindMouseEvents(this.svgPath_);
+ var svgPath = this.pathObject.svgPath;
+ svgPath.tooltip = this;
+ Blockly.Tooltip.bindMouseEvents(svgPath);
Blockly.BlockSvg.superClass_.constructor.call(this,
workspace, prototypeName, opt_id);
@@ -1022,8 +1007,6 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) {
blockWorkspace.resizeContents();
// Sever JavaScript to DOM connections.
this.svgGroup_ = null;
- this.svgPath_ = null;
- this.svgPathLight_ = null;
Blockly.utils.dom.stopTextWidthCache();
};
@@ -1059,14 +1042,13 @@ Blockly.BlockSvg.prototype.updateDisabled = function() {
var added = Blockly.utils.dom.addClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled');
if (added) {
- this.svgPath_.setAttribute('fill',
- 'url(#' + this.workspace.options.disabledPatternId + ')');
+ this.pathObject.setDisabled(true, this.isShadow());
}
} else {
var removed = Blockly.utils.dom.removeClass(
/** @type {!Element} */ (this.svgGroup_), 'blocklyDisabled');
if (removed) {
- this.applyColour();
+ this.pathObject.setDisabled(false, this.isShadow());
}
}
var children = this.getChildren(false);
@@ -1253,14 +1235,7 @@ Blockly.BlockSvg.prototype.setHighlighted = function(highlighted) {
if (!this.rendered) {
return;
}
- if (highlighted) {
- this.svgPath_.setAttribute('filter',
- 'url(#' + this.workspace.options.embossFilterId + ')');
- this.svgPathLight_.style.display = 'none';
- } else {
- this.svgPath_.setAttribute('filter', 'none');
- this.svgPathLight_.style.display = 'inline';
- }
+ this.pathObject.setHighlighted(highlighted);
};
/**
diff --git a/core/bubble.js b/core/bubble.js
index c3713d4f8..4e139bdc3 100644
--- a/core/bubble.js
+++ b/core/bubble.js
@@ -232,7 +232,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
*/
this.bubbleGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null);
var filter =
- {'filter': 'url(#' + this.workspace_.options.embossFilterId + ')'};
+ {'filter': 'url(#' +
+ this.workspace_.getRenderer().getConstants().embossFilterId + ')'};
if (Blockly.utils.userAgent.JAVA_FX) {
// Multiple reports that JavaFX can't handle filters.
// https://github.com/google/blockly/issues/99
@@ -240,7 +241,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) {
}
var bubbleEmboss = Blockly.utils.dom.createSvgElement('g',
filter, this.bubbleGroup_);
- this.bubbleArrow_ = Blockly.utils.dom.createSvgElement('path', {}, bubbleEmboss);
+ this.bubbleArrow_ = Blockly.utils.dom.createSvgElement('path', {},
+ bubbleEmboss);
this.bubbleBack_ = Blockly.utils.dom.createSvgElement('rect',
{
'class': 'blocklyDraggable',
diff --git a/core/inject.js b/core/inject.js
index 805200e75..be46c684c 100644
--- a/core/inject.js
+++ b/core/inject.js
@@ -139,73 +139,6 @@ Blockly.createDom_ = function(container, options) {
// instances on a page. Browser behaviour becomes undefined otherwise.
// https://neil.fraser.name/news/2015/11/01/
var rnd = String(Math.random()).substring(2);
- /*
-
-
-
-
-
-
-
-
- */
- var embossFilter = Blockly.utils.dom.createSvgElement('filter',
- {'id': 'blocklyEmbossFilter' + rnd}, defs);
- Blockly.utils.dom.createSvgElement('feGaussianBlur',
- {'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter);
- var feSpecularLighting = Blockly.utils.dom.createSvgElement('feSpecularLighting',
- {
- 'in': 'blur',
- 'surfaceScale': 1,
- 'specularConstant': 0.5,
- 'specularExponent': 10,
- 'lighting-color': 'white',
- 'result': 'specOut'
- },
- embossFilter);
- Blockly.utils.dom.createSvgElement('fePointLight',
- {'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting);
- Blockly.utils.dom.createSvgElement('feComposite',
- {
- 'in': 'specOut',
- 'in2': 'SourceAlpha',
- 'operator': 'in',
- 'result': 'specOut'
- }, embossFilter);
- Blockly.utils.dom.createSvgElement('feComposite',
- {
- 'in': 'SourceGraphic',
- 'in2': 'specOut',
- 'operator': 'arithmetic',
- 'k1': 0,
- 'k2': 1,
- 'k3': 1,
- 'k4': 0
- }, embossFilter);
- options.embossFilterId = embossFilter.id;
- /*
-
-
-
-
- */
- var disabledPattern = Blockly.utils.dom.createSvgElement('pattern',
- {
- 'id': 'blocklyDisabledPattern' + rnd,
- 'patternUnits': 'userSpaceOnUse',
- 'width': 10,
- 'height': 10
- }, defs);
- Blockly.utils.dom.createSvgElement('rect',
- {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern);
- Blockly.utils.dom.createSvgElement('path',
- {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern);
- options.disabledPatternId = disabledPattern.id;
options.gridPattern = Blockly.Grid.createDom(rnd, options.gridOptions, defs);
return svg;
diff --git a/core/mutator.js b/core/mutator.js
index 3b1a1ff4b..006aea0b8 100644
--- a/core/mutator.js
+++ b/core/mutator.js
@@ -154,7 +154,6 @@ Blockly.Mutator.prototype.createEditor_ = function() {
// If you want to enable disabling, also remove the
// event filter from workspaceChanged_ .
disable: false,
- disabledPatternId: this.block_.workspace.options.disabledPatternId,
languageTree: quarkXml,
parentWorkspace: this.block_.workspace,
pathToMedia: this.block_.workspace.options.pathToMedia,
diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js
index bfc753f09..6aa0863f6 100644
--- a/core/renderers/common/constants.js
+++ b/core/renderers/common/constants.js
@@ -23,6 +23,7 @@
goog.provide('Blockly.blockRendering.ConstantProvider');
+goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.svgPaths');
@@ -134,6 +135,34 @@ Blockly.blockRendering.ConstantProvider = function() {
* @const
*/
this.JAGGED_TEETH_WIDTH = 6;
+
+ /**
+ * The ID of the emboss filter, or the empty string if no filter is set.
+ * @type {string}
+ * @package
+ */
+ this.embossFilterId = '';
+
+ /**
+ * The element to use for highlighting, or null if not set.
+ * @type {SVGElement}
+ * @private
+ */
+ this.embossFilter_ = null;
+
+ /**
+ * The ID of the disabled pattern, or the empty string if no pattern is set.
+ * @type {string}
+ * @package
+ */
+ this.disabledPatternId = '';
+
+ /**
+ * The element to use for disabled blocks, or null if not set.
+ * @type {SVGElement}
+ * @private
+ */
+ this.disabledPattern_ = null;
};
/**
@@ -180,6 +209,20 @@ Blockly.blockRendering.ConstantProvider.prototype.init = function() {
this.OUTSIDE_CORNERS = this.makeOutsideCorners();
};
+/**
+ * Dispose of this constants provider.
+ * Delete all DOM elements that this provider created.
+ * @package
+ */
+Blockly.blockRendering.ConstantProvider.prototype.dispose = function() {
+ if (this.embossFilter_) {
+ Blockly.utils.dom.removeNode(this.embossFilter_);
+ }
+ if (this.disabledPattern_) {
+ Blockly.utils.dom.removeNode(this.disabledPattern_);
+ }
+};
+
/**
* @return {!Object} An object containing sizing and path information about
* collapsed block indicators.
@@ -398,3 +441,91 @@ Blockly.blockRendering.ConstantProvider.prototype.shapeFor = function(
throw Error('Unknown connection type');
}
};
+
+/**
+ * Create any DOM elements that this renderer needs (filters, patterns, etc).
+ * @param {!SVGElement} svg The root of the workspace's SVG.
+ * @package
+ */
+Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg) {
+ /*
+
+ ... filters go here ...
+
+ */
+ var defs = Blockly.utils.dom.createSvgElement('defs', {}, svg);
+ // Each filter/pattern needs a unique ID for the case of multiple Blockly
+ // instances on a page. Browser behaviour becomes undefined otherwise.
+ // https://neil.fraser.name/news/2015/11/01/
+ var rnd = String(Math.random()).substring(2);
+ /*
+
+
+
+
+
+
+
+
+ */
+ var embossFilter = Blockly.utils.dom.createSvgElement('filter',
+ {'id': 'blocklyEmbossFilter' + rnd}, defs);
+ Blockly.utils.dom.createSvgElement('feGaussianBlur',
+ {'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter);
+ var feSpecularLighting = Blockly.utils.dom.createSvgElement('feSpecularLighting',
+ {
+ 'in': 'blur',
+ 'surfaceScale': 1,
+ 'specularConstant': 0.5,
+ 'specularExponent': 10,
+ 'lighting-color': 'white',
+ 'result': 'specOut'
+ },
+ embossFilter);
+ Blockly.utils.dom.createSvgElement('fePointLight',
+ {'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting);
+ Blockly.utils.dom.createSvgElement('feComposite',
+ {
+ 'in': 'specOut',
+ 'in2': 'SourceAlpha',
+ 'operator': 'in',
+ 'result': 'specOut'
+ }, embossFilter);
+ Blockly.utils.dom.createSvgElement('feComposite',
+ {
+ 'in': 'SourceGraphic',
+ 'in2': 'specOut',
+ 'operator': 'arithmetic',
+ 'k1': 0,
+ 'k2': 1,
+ 'k3': 1,
+ 'k4': 0
+ }, embossFilter);
+ this.embossFilterId = embossFilter.id;
+ this.embossFilter_ = embossFilter;
+
+ /*
+
+
+
+
+ */
+ var disabledPattern = Blockly.utils.dom.createSvgElement('pattern',
+ {
+ 'id': 'blocklyDisabledPattern' + rnd,
+ 'patternUnits': 'userSpaceOnUse',
+ 'width': 10,
+ 'height': 10
+ }, defs);
+ Blockly.utils.dom.createSvgElement('rect',
+ {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern);
+ Blockly.utils.dom.createSvgElement('path',
+ {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern);
+ this.disabledPatternId = disabledPattern.id;
+ this.disabledPattern_ = disabledPattern;
+};
diff --git a/core/renderers/common/i_path_object.js b/core/renderers/common/i_path_object.js
index fd81f8e03..8905a4bd4 100644
--- a/core/renderers/common/i_path_object.js
+++ b/core/renderers/common/i_path_object.js
@@ -25,15 +25,18 @@
goog.provide('Blockly.blockRendering.IPathObject');
+goog.requireType('Blockly.blockRendering.ConstantProvider');
goog.requireType('Blockly.Theme');
/**
* An interface for a block's path object.
* @param {!SVGElement} _root The root SVG element.
+ * @param {!Blockly.blockRendering.ConstantProvider} _constants The renderer's
+ * constants.
* @interface
*/
-Blockly.blockRendering.IPathObject = function(_root) {};
+Blockly.blockRendering.IPathObject = function(_root, _constants) {};
/**
* Apply the stored colours to the block's path, taking into account whether
@@ -55,3 +58,17 @@ Blockly.blockRendering.IPathObject.prototype.setStyle;
* @package
*/
Blockly.blockRendering.IPathObject.prototype.flipRTL;
+
+/**
+ * Set whether the block shows a highlight or not. Block highlighting is
+ * often used to visually mark blocks currently being executed.
+ * @param {boolean} highlighted True if highlighted.
+ */
+Blockly.blockRendering.IPathObject.prototype.setHighlighted;
+
+/**
+ * Set whether the block shows a disable pattern or not.
+ * @param {boolean} disabled True if disabled.
+ * @param {boolean} isShadow True if the block is a shadow block.
+ */
+Blockly.blockRendering.IPathObject.prototype.setDisabled;
diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js
index 493245289..a850686ff 100644
--- a/core/renderers/common/path_object.js
+++ b/core/renderers/common/path_object.js
@@ -24,6 +24,7 @@
goog.provide('Blockly.blockRendering.PathObject');
+goog.require('Blockly.blockRendering.ConstantProvider');
goog.require('Blockly.blockRendering.IPathObject');
goog.require('Blockly.Theme');
goog.require('Blockly.utils.dom');
@@ -33,11 +34,18 @@ goog.require('Blockly.utils.dom');
* An object that handles creating and setting each of the SVG elements
* used by the renderer.
* @param {!SVGElement} root The root SVG element.
+ * @param {!Blockly.blockRendering.ConstantProvider} constants The renderer's
+ * constants.
* @constructor
* @implements {Blockly.blockRendering.IPathObject}
* @package
*/
-Blockly.blockRendering.PathObject = function(root) {
+Blockly.blockRendering.PathObject = function(root, constants) {
+ /**
+ * The renderer's constant provider.
+ * @type {!Blockly.blockRendering.ConstantProvider}
+ */
+ this.constants_ = constants;
this.svgRoot = root;
/**
@@ -111,3 +119,33 @@ Blockly.blockRendering.PathObject.prototype.applyColour = function(isShadow) {
Blockly.blockRendering.PathObject.prototype.setStyle = function(blockStyle) {
this.style = blockStyle;
};
+
+/**
+ * Set whether the block shows a highlight or not. Block highlighting is
+ * often used to visually mark blocks currently being executed.
+ * @param {boolean} highlighted True if highlighted.
+ */
+Blockly.blockRendering.PathObject.prototype.setHighlighted = function(
+ highlighted) {
+ if (highlighted) {
+ this.svgPath.setAttribute('filter',
+ 'url(#' + this.constants_.embossFilterId + ')');
+ } else {
+ this.svgPath.setAttribute('filter', 'none');
+ }
+};
+
+/**
+ * Set whether the block shows a disable pattern or not.
+ * @param {boolean} disabled True if disabled.
+ * @param {boolean} isShadow True if the block is a shadow block.
+ */
+Blockly.blockRendering.PathObject.prototype.setDisabled = function(disabled,
+ isShadow) {
+ if (disabled) {
+ this.svgPath.setAttribute('fill',
+ 'url(#' + this.constants_.disabledPatternId + ')');
+ } else {
+ this.applyColour(isShadow);
+ }
+};
diff --git a/core/renderers/common/renderer.js b/core/renderers/common/renderer.js
index 49a83943a..c6f16677c 100644
--- a/core/renderers/common/renderer.js
+++ b/core/renderers/common/renderer.js
@@ -122,7 +122,9 @@ Blockly.blockRendering.Renderer.prototype.makeCursorDrawer = function(
* @package
*/
Blockly.blockRendering.Renderer.prototype.makePathObject = function(root) {
- return new Blockly.blockRendering.PathObject(root);
+ return new Blockly.blockRendering.PathObject(root,
+ /** @type {!Blockly.blockRendering.ConstantProvider} */ (this.constants_));
+
};
/**
diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js
index 701bc324a..8225268fc 100644
--- a/core/renderers/geras/path_object.js
+++ b/core/renderers/geras/path_object.js
@@ -24,7 +24,9 @@
goog.provide('Blockly.geras.PathObject');
+goog.require('Blockly.blockRendering.ConstantProvider');
goog.require('Blockly.blockRendering.IPathObject');
+goog.require('Blockly.geras.ConstantProvider');
goog.require('Blockly.Theme');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.object');
@@ -34,11 +36,19 @@ goog.require('Blockly.utils.object');
* An object that handles creating and setting each of the SVG elements
* used by the renderer.
* @param {!SVGElement} root The root SVG element.
+ * @param {!Blockly.blockRendering.ConstantProvider} constants The renderer's
+ * constants.
* @constructor
* @implements {Blockly.blockRendering.IPathObject}
* @package
*/
-Blockly.geras.PathObject = function(root) {
+Blockly.geras.PathObject = function(root, constants) {
+ /**
+ * The renderer's constant provider.
+ * @type {!Blockly.geras.ConstantProvider}
+ */
+ this.constants_ = /** @type {!Blockly.geras.ConstantProvider} */ (constants);
+
this.svgRoot = root;
// The order of creation for these next three matters, because that
@@ -140,3 +150,33 @@ Blockly.geras.PathObject.prototype.setStyle = function(blockStyle) {
Blockly.utils.colour.blend('#000', this.style.colourPrimary, 0.2) ||
this.colourDark;
};
+
+/**
+ * Set whether the block shows a highlight or not. Block highlighting is
+ * often used to visually mark blocks currently being executed.
+ * @param {boolean} highlighted True if highlighted.
+ */
+Blockly.geras.PathObject.prototype.setHighlighted = function(highlighted) {
+ if (highlighted) {
+ this.svgPath.setAttribute('filter',
+ 'url(#' + this.constants_.embossFilterId + ')');
+ this.svgPathLight.style.display = 'none';
+ } else {
+ this.svgPath.setAttribute('filter', 'none');
+ this.svgPathLight.style.display = 'inline';
+ }
+};
+
+/**
+ * Set whether the block shows a disable pattern or not.
+ * @param {boolean} disabled True if disabled.
+ * @param {boolean} isShadow True if the block is a shadow block.
+ */
+Blockly.geras.PathObject.prototype.setDisabled = function(disabled, isShadow) {
+ if (disabled) {
+ this.svgPath.setAttribute('fill',
+ 'url(#' + this.constants_.disabledPatternId + ')');
+ } else {
+ this.applyColour(isShadow);
+ }
+};
diff --git a/core/renderers/geras/renderer.js b/core/renderers/geras/renderer.js
index fcd5e516d..0a43bf18e 100644
--- a/core/renderers/geras/renderer.js
+++ b/core/renderers/geras/renderer.js
@@ -103,7 +103,8 @@ Blockly.geras.Renderer.prototype.makeDrawer_ = function(block, info) {
* @override
*/
Blockly.geras.Renderer.prototype.makePathObject = function(root) {
- return new Blockly.geras.PathObject(root);
+ return new Blockly.geras.PathObject(root,
+ /** @type {!Blockly.geras.ConstantProvider} */ (this.getConstants()));
};
/**
diff --git a/core/toolbox.js b/core/toolbox.js
index 59d2c2044..8b939eb61 100644
--- a/core/toolbox.js
+++ b/core/toolbox.js
@@ -179,7 +179,6 @@ Blockly.Toolbox.prototype.init = function() {
Blockly.Touch.clearTouchIdentifier(); // Don't block future drags.
}, /* opt_noCaptureIdentifier */ false, /* opt_noPreventDefault */ true);
var workspaceOptions = /** @type {!Blockly.Options} */ ({
- disabledPatternId: workspace.options.disabledPatternId,
parentWorkspace: workspace,
RTL: workspace.RTL,
oneBasedIndex: workspace.options.oneBasedIndex,
diff --git a/core/trashcan.js b/core/trashcan.js
index b676626a2..7eba792ea 100644
--- a/core/trashcan.js
+++ b/core/trashcan.js
@@ -62,7 +62,6 @@ Blockly.Trashcan = function(workspace) {
// Create flyout options.
var flyoutWorkspaceOptions = /** @type {!Blockly.Options} */ ({
scrollbars: true,
- disabledPatternId: this.workspace_.options.disabledPatternId,
parentWorkspace: this.workspace_,
RTL: this.workspace_.RTL,
oneBasedIndex: this.workspace_.options.oneBasedIndex,
diff --git a/core/workspace_svg.js b/core/workspace_svg.js
index 4876dd0e0..bf3f344d6 100644
--- a/core/workspace_svg.js
+++ b/core/workspace_svg.js
@@ -676,6 +676,7 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) {
var svgMarker = this.marker_.getDrawer().createDom();
this.svgGroup_.appendChild(svgMarker);
+ this.getRenderer().getConstants().createDom(this.svgGroup_);
return this.svgGroup_;
};
@@ -735,6 +736,8 @@ Blockly.WorkspaceSvg.prototype.dispose = function() {
this.grid_ = null;
}
+ this.renderer_.getConstants().dispose();
+
if (this.themeManager_) {
this.themeManager_.unsubscribe(this.svgBackground_);
}
@@ -808,7 +811,6 @@ Blockly.WorkspaceSvg.prototype.addZoomControls = function() {
*/
Blockly.WorkspaceSvg.prototype.addFlyout = function(tagName) {
var workspaceOptions = /** @type {!Blockly.Options} */ ({
- disabledPatternId: this.options.disabledPatternId,
parentWorkspace: this,
RTL: this.RTL,
oneBasedIndex: this.options.oneBasedIndex,