From 0f3db47fa5cd1903b88eb6279feb3f291acdfce2 Mon Sep 17 00:00:00 2001 From: Sam El-Husseini Date: Mon, 13 Jul 2020 10:40:31 -0700 Subject: [PATCH] Use generics to derive SVG element type (#4036) * Encapsulate type in a generic to automatically derive type of SVG element when using createSvgElement --- core/block_animations.js | 3 +- core/block_drag_surface.js | 18 +-- core/block_svg.js | 4 +- core/bubble.js | 24 ++-- core/comment.js | 12 +- core/field.js | 34 +++-- core/field_angle.js | 74 ++++++----- core/field_dropdown.js | 17 +-- core/field_image.js | 17 ++- core/field_multilineinput.js | 22 ++-- core/flyout_base.js | 12 +- core/flyout_button.js | 12 +- core/grid.js | 12 +- core/icon.js | 3 +- core/inject.js | 22 ++-- core/mutator.js | 14 +- core/rendered_connection.js | 2 +- core/renderers/common/constants.js | 46 ++++--- core/renderers/common/debugger.js | 27 ++-- core/renderers/common/marker_svg.js | 28 ++-- core/renderers/common/path_object.js | 3 +- core/renderers/geras/path_object.js | 9 +- core/renderers/zelos/constants.js | 44 +++++-- core/renderers/zelos/marker_svg.js | 16 ++- core/renderers/zelos/path_object.js | 13 +- core/scrollbar.js | 13 +- core/toolbox.js | 3 +- core/trashcan.js | 24 ++-- core/utils/dom.js | 127 ++++++++++++++++++- core/warning.js | 28 ++-- core/workspace_comment_render_svg.js | 25 ++-- core/workspace_comment_svg.js | 4 +- core/workspace_drag_surface_svg.js | 3 +- core/workspace_svg.js | 17 ++- core/zoom_controls.js | 69 ++++++++-- tests/mocha/field_checkbox_test.js | 3 +- tests/mocha/field_label_serializable_test.js | 9 +- tests/mocha/field_label_test.js | 11 +- tests/rendering/svg_paths.html | 18 +-- 39 files changed, 564 insertions(+), 278 deletions(-) diff --git a/core/block_animations.js b/core/block_animations.js index 5c52a20c4..856b444fb 100644 --- a/core/block_animations.js +++ b/core/block_animations.js @@ -102,7 +102,8 @@ Blockly.blockAnimations.connectionUiEffect = function(block) { xy.x += (block.RTL ? -23 : 23) * scale; xy.y += 3 * scale; } - var ripple = Blockly.utils.dom.createSvgElement('circle', + var ripple = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CIRCLE, { 'cx': xy.x, 'cy': xy.y, diff --git a/core/block_drag_surface.js b/core/block_drag_surface.js index 31b8a4396..ed01b72fc 100644 --- a/core/block_drag_surface.js +++ b/core/block_drag_surface.js @@ -82,14 +82,16 @@ Blockly.BlockDragSurfaceSvg.prototype.createDom = function() { if (this.SVG_) { return; // Already created. } - this.SVG_ = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': Blockly.utils.dom.SVG_NS, - 'xmlns:html': Blockly.utils.dom.HTML_NS, - 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, - 'version': '1.1', - 'class': 'blocklyBlockDragSurface' - }, this.container_); - this.dragGroup_ = Blockly.utils.dom.createSvgElement('g', {}, this.SVG_); + this.SVG_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.SVG, { + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, + 'version': '1.1', + 'class': 'blocklyBlockDragSurface' + }, this.container_); + this.dragGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, this.SVG_); }; /** diff --git a/core/block_svg.js b/core/block_svg.js index ab2958368..2cd82cf3e 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -58,8 +58,8 @@ Blockly.BlockSvg = function(workspace, prototypeName, opt_id) { * @type {!SVGGElement} * @private */ - this.svgGroup_ = /** @type {!SVGGElement} */ ( - Blockly.utils.dom.createSvgElement('g', {}, null)); + this.svgGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); this.svgGroup_.translate_ = ''; /** diff --git a/core/bubble.js b/core/bubble.js index 7208d8492..51ce808ce 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -234,7 +234,8 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { [...content goes here...] */ - this.bubbleGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + this.bubbleGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); var filter = {'filter': 'url(#' + this.workspace_.getRenderer().getConstants().embossFilterId + ')'}; @@ -243,11 +244,14 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { // https://github.com/google/blockly/issues/99 filter = {}; } - var bubbleEmboss = Blockly.utils.dom.createSvgElement('g', + var bubbleEmboss = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, filter, this.bubbleGroup_); - this.bubbleArrow_ = Blockly.utils.dom.createSvgElement('path', {}, + this.bubbleArrow_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, {}, bubbleEmboss); - this.bubbleBack_ = Blockly.utils.dom.createSvgElement('rect', + this.bubbleBack_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyDraggable', 'x': 0, @@ -257,21 +261,25 @@ Blockly.Bubble.prototype.createDom_ = function(content, hasResize) { }, bubbleEmboss); if (hasResize) { - this.resizeGroup_ = Blockly.utils.dom.createSvgElement('g', + this.resizeGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': this.workspace_.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE'}, this.bubbleGroup_); var resizeSize = 2 * Blockly.Bubble.BORDER_WIDTH; - Blockly.utils.dom.createSvgElement('polygon', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.POLYGON, {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, this.resizeGroup_); - Blockly.utils.dom.createSvgElement('line', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.LINE, { 'class': 'blocklyResizeLine', 'x1': resizeSize / 3, 'y1': resizeSize - 1, 'x2': resizeSize - 1, 'y2': resizeSize / 3 }, this.resizeGroup_); - Blockly.utils.dom.createSvgElement('line', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.LINE, { 'class': 'blocklyResizeLine', 'x1': resizeSize * 2 / 3, diff --git a/core/comment.js b/core/comment.js index 54c102b08..5127042fe 100644 --- a/core/comment.js +++ b/core/comment.js @@ -90,13 +90,15 @@ Blockly.utils.object.inherits(Blockly.Comment, Blockly.Icon); */ Blockly.Comment.prototype.drawIcon_ = function(group) { // Circle. - Blockly.utils.dom.createSvgElement('circle', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CIRCLE, {'class': 'blocklyIconShape', 'r': '8', 'cx': '8', 'cy': '8'}, group); // Can't use a real '?' text character since different browsers and operating // systems render it differently. // Body of question mark. - Blockly.utils.dom.createSvgElement('path', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { 'class': 'blocklyIconSymbol', 'd': 'm6.8,10h2c0.003,-0.617 0.271,-0.962 0.633,-1.266 2.875,-2.405' + @@ -104,7 +106,8 @@ Blockly.Comment.prototype.drawIcon_ = function(group) { '-1.201,0.998 -1.201,1.528 -1.204,2.19z'}, group); // Dot of question mark. - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyIconSymbol', 'x': '6.8', @@ -133,7 +136,8 @@ Blockly.Comment.prototype.createEditor_ = function() { * For non-editable mode see Warning.textToDom_. */ - this.foreignObject_ = Blockly.utils.dom.createSvgElement('foreignObject', + this.foreignObject_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FOREIGNOBJECT, {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, null); diff --git a/core/field.js b/core/field.js index d1e501cc3..a9d54ff2f 100644 --- a/core/field.js +++ b/core/field.js @@ -298,8 +298,8 @@ Blockly.Field.prototype.init = function() { // Field has already been initialized once. return; } - this.fieldGroup_ = /** @type {!SVGGElement} **/ - (Blockly.utils.dom.createSvgElement('g', {}, null)); + this.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); if (!this.isVisible()) { this.fieldGroup_.style.display = 'none'; } @@ -336,17 +336,16 @@ Blockly.Field.prototype.initModel = function() { * @protected */ Blockly.Field.prototype.createBorderRect_ = function() { - this.borderRect_ = /** @type {!SVGRectElement} **/ - (Blockly.utils.dom.createSvgElement('rect', - { - 'rx': this.getConstants().FIELD_BORDER_RECT_RADIUS, - 'ry': this.getConstants().FIELD_BORDER_RECT_RADIUS, - 'x': 0, - 'y': 0, - 'height': this.size_.height, - 'width': this.size_.width, - 'class': 'blocklyFieldRect' - }, this.fieldGroup_)); + this.borderRect_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { + 'rx': this.getConstants().FIELD_BORDER_RECT_RADIUS, + 'ry': this.getConstants().FIELD_BORDER_RECT_RADIUS, + 'x': 0, + 'y': 0, + 'height': this.size_.height, + 'width': this.size_.width, + 'class': 'blocklyFieldRect' + }, this.fieldGroup_); }; /** @@ -356,11 +355,10 @@ Blockly.Field.prototype.createBorderRect_ = function() { * @protected */ Blockly.Field.prototype.createTextElement_ = function() { - this.textElement_ = /** @type {!SVGTextElement} **/ - (Blockly.utils.dom.createSvgElement('text', - { - 'class': 'blocklyText', - }, this.fieldGroup_)); + this.textElement_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.TEXT, { + 'class': 'blocklyText', + }, this.fieldGroup_); if (this.getConstants().FIELD_TEXT_BASELINE_CENTER) { this.textElement_.setAttribute('dominant-baseline', 'central'); } diff --git a/core/field_angle.js b/core/field_angle.js index 04133dbf4..bc7260051 100644 --- a/core/field_angle.js +++ b/core/field_angle.js @@ -236,7 +236,8 @@ Blockly.FieldAngle.prototype.configure_ = function(config) { Blockly.FieldAngle.prototype.initView = function() { Blockly.FieldAngle.superClass_.initView.call(this); // Add the degree symbol to the left of the number, even in RTL (issue #2380) - this.symbol_ = Blockly.utils.dom.createSvgElement('tspan', {}, null); + this.symbol_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.TSPAN, {}, null); this.symbol_.appendChild(document.createTextNode('\u00B0')); this.textElement_.appendChild(this.symbol_); }; @@ -283,41 +284,46 @@ Blockly.FieldAngle.prototype.showEditor_ = function(opt_e) { * @private */ Blockly.FieldAngle.prototype.dropdownCreate_ = function() { - var svg = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': Blockly.utils.dom.SVG_NS, - 'xmlns:html': Blockly.utils.dom.HTML_NS, - 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, - 'version': '1.1', - 'height': (Blockly.FieldAngle.HALF * 2) + 'px', - 'width': (Blockly.FieldAngle.HALF * 2) + 'px', - 'style': 'touch-action: none' - }, null); - var circle = Blockly.utils.dom.createSvgElement('circle', { - 'cx': Blockly.FieldAngle.HALF, - 'cy': Blockly.FieldAngle.HALF, - 'r': Blockly.FieldAngle.RADIUS, - 'class': 'blocklyAngleCircle' - }, svg); - this.gauge_ = Blockly.utils.dom.createSvgElement('path', { - 'class': 'blocklyAngleGauge' - }, svg); - this.line_ = Blockly.utils.dom.createSvgElement('line', { - 'x1': Blockly.FieldAngle.HALF, - 'y1': Blockly.FieldAngle.HALF, - 'class': 'blocklyAngleLine' - }, svg); + var svg = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.SVG, { + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, + 'version': '1.1', + 'height': (Blockly.FieldAngle.HALF * 2) + 'px', + 'width': (Blockly.FieldAngle.HALF * 2) + 'px', + 'style': 'touch-action: none' + }, null); + var circle = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CIRCLE, { + 'cx': Blockly.FieldAngle.HALF, + 'cy': Blockly.FieldAngle.HALF, + 'r': Blockly.FieldAngle.RADIUS, + 'class': 'blocklyAngleCircle' + }, svg); + this.gauge_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { + 'class': 'blocklyAngleGauge' + }, svg); + this.line_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.LINE, { + 'x1': Blockly.FieldAngle.HALF, + 'y1': Blockly.FieldAngle.HALF, + 'class': 'blocklyAngleLine' + }, svg); // Draw markers around the edge. for (var angle = 0; angle < 360; angle += 15) { - Blockly.utils.dom.createSvgElement('line', { - 'x1': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS, - 'y1': Blockly.FieldAngle.HALF, - 'x2': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS - - (angle % 45 == 0 ? 10 : 5), - 'y2': Blockly.FieldAngle.HALF, - 'class': 'blocklyAngleMarks', - 'transform': 'rotate(' + angle + ',' + - Blockly.FieldAngle.HALF + ',' + Blockly.FieldAngle.HALF + ')' - }, svg); + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.LINE, { + 'x1': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS, + 'y1': Blockly.FieldAngle.HALF, + 'x2': Blockly.FieldAngle.HALF + Blockly.FieldAngle.RADIUS - + (angle % 45 == 0 ? 10 : 5), + 'y2': Blockly.FieldAngle.HALF, + 'class': 'blocklyAngleMarks', + 'transform': 'rotate(' + angle + ',' + + Blockly.FieldAngle.HALF + ',' + Blockly.FieldAngle.HALF + ')' + }, svg); } // The angle picker is different from other fields in that it updates on diff --git a/core/field_dropdown.js b/core/field_dropdown.js index bdbe27f9e..73d106e63 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -212,8 +212,8 @@ Blockly.FieldDropdown.prototype.initView = function() { } this.createTextElement_(); - this.imageElement_ = /** @type {!SVGImageElement} */ - (Blockly.utils.dom.createSvgElement('image', {}, this.fieldGroup_)); + this.imageElement_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, {}, this.fieldGroup_); if (this.getConstants().FIELD_DROPDOWN_SVG_ARROW) { this.createSVGArrow_(); @@ -242,8 +242,8 @@ Blockly.FieldDropdown.prototype.shouldAddBorderRect_ = function() { * @protected */ Blockly.FieldDropdown.prototype.createTextArrow_ = function() { - this.arrow_ = /** @type {!SVGTSpanElement} */ - (Blockly.utils.dom.createSvgElement('tspan', {}, this.textElement_)); + this.arrow_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.TSPAN, {}, this.textElement_); this.arrow_.appendChild(document.createTextNode( this.sourceBlock_.RTL ? Blockly.FieldDropdown.ARROW_CHAR + ' ' : @@ -260,10 +260,11 @@ Blockly.FieldDropdown.prototype.createTextArrow_ = function() { * @protected */ Blockly.FieldDropdown.prototype.createSVGArrow_ = function() { - this.svgArrow_ = Blockly.utils.dom.createSvgElement('image', { - 'height': this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px', - 'width': this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px' - }, this.fieldGroup_); + this.svgArrow_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, { + 'height': this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px', + 'width': this.getConstants().FIELD_DROPDOWN_SVG_ARROW_SIZE + 'px' + }, this.fieldGroup_); this.svgArrow_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', this.getConstants().FIELD_DROPDOWN_SVG_ARROW_DATAURI); }; diff --git a/core/field_image.js b/core/field_image.js index d6474ea3b..d0ec555cb 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -176,15 +176,14 @@ Blockly.FieldImage.prototype.configure_ = function(config) { * @package */ Blockly.FieldImage.prototype.initView = function() { - this.imageElement_ = /** @type {!SVGImageElement} */ - (Blockly.utils.dom.createSvgElement( - 'image', - { - 'height': this.imageHeight_ + 'px', - 'width': this.size_.width + 'px', - 'alt': this.altText_ - }, - this.fieldGroup_)); + this.imageElement_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, + { + 'height': this.imageHeight_ + 'px', + 'width': this.size_.width + 'px', + 'alt': this.altText_ + }, + this.fieldGroup_); this.imageElement_.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', /** @type {string} */ (this.value_)); diff --git a/core/field_multilineinput.js b/core/field_multilineinput.js index 0660aa571..4b5ccd741 100644 --- a/core/field_multilineinput.js +++ b/core/field_multilineinput.js @@ -75,11 +75,10 @@ Blockly.FieldMultilineInput.fromJson = function(options) { */ Blockly.FieldMultilineInput.prototype.initView = function() { this.createBorderRect_(); - this.textGroup_ = /** @type {!SVGGElement} **/ - (Blockly.utils.dom.createSvgElement('g', - { - 'class': 'blocklyEditableText', - }, this.fieldGroup_)); + this.textGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, { + 'class': 'blocklyEditableText', + }, this.fieldGroup_); }; /** @@ -134,12 +133,13 @@ Blockly.FieldMultilineInput.prototype.render_ = function() { for (var i = 0; i < lines.length; i++) { var lineHeight = this.getConstants().FIELD_TEXT_HEIGHT + this.getConstants().FIELD_BORDER_RECT_Y_PADDING; - var span = Blockly.utils.dom.createSvgElement('text', { - 'class': 'blocklyText blocklyMultilineText', - x: this.getConstants().FIELD_BORDER_RECT_X_PADDING, - y: y + this.getConstants().FIELD_BORDER_RECT_Y_PADDING, - dy: this.getConstants().FIELD_TEXT_BASELINE - }, this.textGroup_); + var span = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.TEXT, { + 'class': 'blocklyText blocklyMultilineText', + x: this.getConstants().FIELD_BORDER_RECT_X_PADDING, + y: y + this.getConstants().FIELD_BORDER_RECT_Y_PADDING, + dy: this.getConstants().FIELD_TEXT_BASELINE + }, this.textGroup_); span.appendChild(document.createTextNode(lines[i])); y += lineHeight; } diff --git a/core/flyout_base.js b/core/flyout_base.js index 547035ad3..2d382a2be 100644 --- a/core/flyout_base.js +++ b/core/flyout_base.js @@ -223,8 +223,10 @@ Blockly.Flyout.prototype.dragAngleRange_ = 70; * 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 element nested inside a * separate svg element. - * @param {string} tagName The type of tag to put the flyout in. This - * should be or . + * @param {string| + * !Blockly.utils.dom.SvgElementType| + * !Blockly.utils.dom.SvgElementType} tagName The type of tag to + * put the flyout in. This should be or . * @return {!SVGElement} The flyout's SVG group. */ Blockly.Flyout.prototype.createDom = function(tagName) { @@ -238,7 +240,8 @@ Blockly.Flyout.prototype.createDom = function(tagName) { // hide/show code will set up proper visibility and size later. this.svgGroup_ = Blockly.utils.dom.createSvgElement(tagName, {'class': 'blocklyFlyout', 'style': 'display: none'}, null); - this.svgBackground_ = Blockly.utils.dom.createSvgElement('path', + this.svgBackground_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, {'class': 'blocklyFlyoutBackground'}, this.svgGroup_); this.svgGroup_.appendChild(this.workspace_.createDom()); this.workspace_.getThemeManager().subscribe( @@ -825,7 +828,8 @@ Blockly.Flyout.prototype.initFlyoutButton_ = function(button, x, y) { Blockly.Flyout.prototype.createRect_ = function(block, x, y, blockHW, index) { // Create an invisible rectangle under the block to act as a button. Just // using the block as a button is poor, since blocks have holes in them. - var rect = Blockly.utils.dom.createSvgElement('rect', + var rect = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'fill-opacity': 0, 'x': x, diff --git a/core/flyout_button.js b/core/flyout_button.js index 8585c7187..85a64f2e2 100644 --- a/core/flyout_button.js +++ b/core/flyout_button.js @@ -119,12 +119,14 @@ Blockly.FlyoutButton.prototype.createDom = function() { cssClass += ' ' + this.cssClass_; } - this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {'class': cssClass}, + this.svgGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': cssClass}, this.workspace_.getCanvas()); if (!this.isLabel_) { // Shadow rectangle (light source does not mirror in RTL). - var shadow = Blockly.utils.dom.createSvgElement('rect', + var shadow = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyFlyoutButtonShadow', 'rx': 4, 'ry': 4, 'x': 1, 'y': 1 @@ -132,7 +134,8 @@ Blockly.FlyoutButton.prototype.createDom = function() { this.svgGroup_); } // Background rectangle. - var rect = Blockly.utils.dom.createSvgElement('rect', + var rect = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': this.isLabel_ ? 'blocklyFlyoutLabelBackground' : 'blocklyFlyoutButtonBackground', @@ -140,7 +143,8 @@ Blockly.FlyoutButton.prototype.createDom = function() { }, this.svgGroup_); - var svgText = Blockly.utils.dom.createSvgElement('text', + var svgText = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.TEXT, { 'class': this.isLabel_ ? 'blocklyFlyoutLabelText' : 'blocklyText', 'x': 0, diff --git a/core/grid.js b/core/grid.js index 89b1a4ca8..afa48991d 100644 --- a/core/grid.js +++ b/core/grid.js @@ -196,22 +196,26 @@ Blockly.Grid.createDom = function(rnd, gridOptions, defs) { */ - var gridPattern = Blockly.utils.dom.createSvgElement('pattern', + var gridPattern = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATTERN, { 'id': 'blocklyGridPattern' + rnd, 'patternUnits': 'userSpaceOnUse' }, defs); if (gridOptions['length'] > 0 && gridOptions['spacing'] > 0) { - Blockly.utils.dom.createSvgElement('line', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.LINE, {'stroke': gridOptions['colour']}, gridPattern); if (gridOptions['length'] > 1) { - Blockly.utils.dom.createSvgElement('line', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.LINE, {'stroke': gridOptions['colour']}, gridPattern); } // x1, y1, x1, x2 properties will be set later in update. } else { // Edge 16 doesn't handle empty patterns - Blockly.utils.dom.createSvgElement('line', {}, gridPattern); + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.LINE, {}, gridPattern); } return gridPattern; }; diff --git a/core/icon.js b/core/icon.js index 0a180ce69..645f831ce 100644 --- a/core/icon.js +++ b/core/icon.js @@ -70,7 +70,8 @@ Blockly.Icon.prototype.createIcon = function() { ... */ - this.iconGroup_ = Blockly.utils.dom.createSvgElement('g', + this.iconGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyIconGroup'}, null); if (this.block_.isInFlyout) { Blockly.utils.dom.addClass( diff --git a/core/inject.js b/core/inject.js index 93651f834..d325ea617 100644 --- a/core/inject.js +++ b/core/inject.js @@ -113,20 +113,22 @@ Blockly.createDom_ = function(container, options) { ... */ - var svg = Blockly.utils.dom.createSvgElement('svg', { - 'xmlns': Blockly.utils.dom.SVG_NS, - 'xmlns:html': Blockly.utils.dom.HTML_NS, - 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, - 'version': '1.1', - 'class': 'blocklySvg', - 'tabindex': '0' - }, container); + var svg = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.SVG, { + 'xmlns': Blockly.utils.dom.SVG_NS, + 'xmlns:html': Blockly.utils.dom.HTML_NS, + 'xmlns:xlink': Blockly.utils.dom.XLINK_NS, + 'version': '1.1', + 'class': 'blocklySvg', + 'tabindex': '0' + }, container); /* ... filters go here ... */ - var defs = Blockly.utils.dom.createSvgElement('defs', {}, svg); + var defs = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.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/ @@ -164,7 +166,7 @@ Blockly.createMainWorkspace_ = function(svg, options, blockDragSurface, if (!wsOptions.hasCategories && wsOptions.languageTree) { // Add flyout as an that is a sibling of the workspace svg. - var flyout = mainWorkspace.addFlyout('svg'); + var flyout = mainWorkspace.addFlyout(Blockly.utils.dom.SvgElementType.SVG); Blockly.utils.dom.insertAfter(flyout, svg); } if (wsOptions.hasTrashcan) { diff --git a/core/mutator.js b/core/mutator.js index 884f1ca46..982c8174e 100644 --- a/core/mutator.js +++ b/core/mutator.js @@ -80,7 +80,8 @@ Blockly.Mutator.prototype.getWorkspace = function() { */ Blockly.Mutator.prototype.drawIcon_ = function(group) { // Square with rounded corners. - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyIconShape', 'rx': '4', @@ -90,7 +91,8 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) { }, group); // Gear teeth. - Blockly.utils.dom.createSvgElement('path', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { 'class': 'blocklyIconSymbol', 'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' + @@ -104,7 +106,7 @@ Blockly.Mutator.prototype.drawIcon_ = function(group) { group); // Axle hole. Blockly.utils.dom.createSvgElement( - 'circle', + Blockly.utils.dom.SvgElementType.CIRCLE, { 'class': 'blocklyIconShape', 'r': '2.7', @@ -138,7 +140,8 @@ Blockly.Mutator.prototype.createEditor_ = function() { [Workspace] */ - this.svgDialog_ = Blockly.utils.dom.createSvgElement('svg', + this.svgDialog_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.SVG, {'x': Blockly.Bubble.BORDER_WIDTH, 'y': Blockly.Bubble.BORDER_WIDTH}, null); // Convert the list of names into a list of XML objects for the flyout. @@ -181,7 +184,8 @@ Blockly.Mutator.prototype.createEditor_ = function() { // a top level svg. Instead of handling scale themselves, mutators // inherit scale from the parent workspace. // To fix this, scale needs to be applied at a different level in the dom. - var flyoutSvg = hasFlyout ? this.workspace_.addFlyout('g') : null; + var flyoutSvg = hasFlyout ? + this.workspace_.addFlyout(Blockly.utils.dom.SvgElementType.G) : null; var background = this.workspace_.createDom('blocklyMutatorBackground'); if (flyoutSvg) { diff --git a/core/rendered_connection.js b/core/rendered_connection.js index 811a0fe6b..b1d19fed8 100644 --- a/core/rendered_connection.js +++ b/core/rendered_connection.js @@ -301,7 +301,7 @@ Blockly.RenderedConnection.prototype.highlight = function() { var x = this.x - xy.x; var y = this.y - xy.y; Blockly.Connection.highlightedPath_ = Blockly.utils.dom.createSvgElement( - 'path', + Blockly.utils.dom.SvgElementType.PATH, { 'class': 'blocklyHighlightedConnectionPath', 'd': steps, diff --git a/core/renderers/common/constants.js b/core/renderers/common/constants.js index 434e5e3cd..d353dc1fc 100644 --- a/core/renderers/common/constants.js +++ b/core/renderers/common/constants.js @@ -1019,7 +1019,8 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg, ... filters go here ... */ - var defs = Blockly.utils.dom.createSvgElement('defs', {}, svg); + var defs = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.DEFS, {}, svg); /* @@ -1034,11 +1035,14 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg, k1="0" k2="1" k3="1" k4="0" /> */ - var embossFilter = Blockly.utils.dom.createSvgElement('filter', + var embossFilter = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FILTER, {'id': 'blocklyEmbossFilter' + this.randomIdentifier}, defs); - Blockly.utils.dom.createSvgElement('feGaussianBlur', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEGAUSSIANBLUR, {'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter); - var feSpecularLighting = Blockly.utils.dom.createSvgElement('feSpecularLighting', + var feSpecularLighting = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FESPECULARLIGHTING, { 'in': 'blur', 'surfaceScale': 1, @@ -1048,16 +1052,19 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg, 'result': 'specOut' }, embossFilter); - Blockly.utils.dom.createSvgElement('fePointLight', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEPOINTLIGHT, {'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting); - Blockly.utils.dom.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FECOMPOSITE, { 'in': 'specOut', 'in2': 'SourceAlpha', 'operator': 'in', 'result': 'specOut' }, embossFilter); - Blockly.utils.dom.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FECOMPOSITE, { 'in': 'SourceGraphic', 'in2': 'specOut', @@ -1077,22 +1084,26 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg, */ - var disabledPattern = Blockly.utils.dom.createSvgElement('pattern', + var disabledPattern = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATTERN, { 'id': 'blocklyDisabledPattern' + this.randomIdentifier, 'patternUnits': 'userSpaceOnUse', 'width': 10, 'height': 10 }, defs); - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, {'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern); - Blockly.utils.dom.createSvgElement('path', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, {'d': 'M 0 0 L 10 10 M 10 0 L 0 10', 'stroke': '#cc0'}, disabledPattern); this.disabledPatternId = disabledPattern.id; this.disabledPattern_ = disabledPattern; if (Blockly.blockRendering.Debug) { - var debugFilter = Blockly.utils.dom.createSvgElement('filter', + var debugFilter = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FILTER, { 'id': 'blocklyDebugFilter' + this.randomIdentifier, 'height': '160%', @@ -1103,21 +1114,26 @@ Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg, defs); // Set all gaussian blur pixels to 1 opacity before applying flood var debugComponentTransfer = Blockly.utils.dom.createSvgElement( - 'feComponentTransfer', {'result': 'outBlur'}, debugFilter); - Blockly.utils.dom.createSvgElement('feFuncA', + Blockly.utils.dom.SvgElementType.FECOMPONENTTRANSFER, { + 'result': 'outBlur' + }, debugFilter); + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEFUNCA, { 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' }, debugComponentTransfer); // Color the highlight - Blockly.utils.dom.createSvgElement('feFlood', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEFLOOD, { 'flood-color': '#ff0000', 'flood-opacity': 0.5, 'result': 'outColor' }, debugFilter); - Blockly.utils.dom.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FECOMPOSITE, { 'in': 'outColor', 'in2': 'outBlur', 'operator': 'in', 'result': 'outGlow' diff --git a/core/renderers/common/debugger.js b/core/renderers/common/debugger.js index 0e5588b4b..0d3c0e46e 100644 --- a/core/renderers/common/debugger.js +++ b/core/renderers/common/debugger.js @@ -99,7 +99,8 @@ Blockly.blockRendering.Debug.prototype.drawSpacerRow = function(row, cursorY, is cursorY -= height; } - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'rowSpacerRect blockRenderDebug', 'x': isRtl ? -(row.xPos + row.width) : row.xPos, @@ -133,7 +134,8 @@ Blockly.blockRendering.Debug.prototype.drawSpacerElem = function(elem, rowHeight xPos = -(xPos + width); } var yPos = elem.centerline - elem.height / 2; - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'elemSpacerRect blockRenderDebug', 'x': xPos, @@ -161,7 +163,8 @@ Blockly.blockRendering.Debug.prototype.drawRenderedElem = function(elem, isRtl) xPos = -(xPos + elem.width); } var yPos = elem.centerline - elem.height / 2; - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'rowRenderingRect blockRenderDebug', 'x': xPos, @@ -177,7 +180,8 @@ Blockly.blockRendering.Debug.prototype.drawRenderedElem = function(elem, isRtl) if (Blockly.blockRendering.Types.isField(elem) && elem.field instanceof Blockly.FieldLabel) { var baseline = this.constants_.FIELD_TEXT_BASELINE; - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'rowRenderingRect blockRenderDebug', 'x': xPos, @@ -233,7 +237,8 @@ Blockly.blockRendering.Debug.prototype.drawConnection = function(conn) { colour = 'goldenrod'; fill = colour; } - this.debugElements_.push(Blockly.utils.dom.createSvgElement('circle', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CIRCLE, { 'class': 'blockRenderDebug', 'cx': conn.offsetInBlock_.x, @@ -256,7 +261,8 @@ Blockly.blockRendering.Debug.prototype.drawRenderedRow = function(row, cursorY, if (!Blockly.blockRendering.Debug.config.rows) { return; } - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'elemRenderingRect blockRenderDebug', 'x': isRtl ? -(row.xPos + row.width) : row.xPos, @@ -274,7 +280,8 @@ Blockly.blockRendering.Debug.prototype.drawRenderedRow = function(row, cursorY, } if (Blockly.blockRendering.Debug.config.connectedBlockBounds) { - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'connectedBlockWidth blockRenderDebug', 'x': isRtl ? -(row.xPos + row.widthWithConnectedBlocks) : row.xPos, @@ -328,7 +335,8 @@ Blockly.blockRendering.Debug.prototype.drawBoundingBox = function(info) { // Bounding box without children. var xPos = info.RTL ? -info.width : 0; var yPos = 0; - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blockBoundingBox blockRenderDebug', 'x': xPos, @@ -345,7 +353,8 @@ Blockly.blockRendering.Debug.prototype.drawBoundingBox = function(info) { if (Blockly.blockRendering.Debug.config.connectedBlockBounds) { // Bounding box with children. xPos = info.RTL ? -info.widthWithChildren : 0; - this.debugElements_.push(Blockly.utils.dom.createSvgElement('rect', + this.debugElements_.push(Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blockRenderDebug', 'x': xPos, diff --git a/core/renderers/common/marker_svg.js b/core/renderers/common/marker_svg.js index 2fda38c66..9f8414c13 100644 --- a/core/renderers/common/marker_svg.js +++ b/core/renderers/common/marker_svg.js @@ -124,8 +124,8 @@ Blockly.blockRendering.MarkerSvg.prototype.createDom = function() { Blockly.blockRendering.MarkerSvg.CURSOR_CLASS : Blockly.blockRendering.MarkerSvg.MARKER_CLASS; - this.svgGroup_ = - Blockly.utils.dom.createSvgElement('g', { + this.svgGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, { 'class': className }, null); @@ -588,7 +588,8 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { */ - this.markerSvg_ = Blockly.utils.dom.createSvgElement('g', + this.markerSvg_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, { 'width': this.constants_.CURSOR_WS_WIDTH, 'height': this.constants_.WS_CURSOR_HEIGHT @@ -596,7 +597,8 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { // A horizontal line used to represent a workspace coordinate or next // connection. - this.markerSvgLine_ = Blockly.utils.dom.createSvgElement('rect', + this.markerSvgLine_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'width': this.constants_.CURSOR_WS_WIDTH, 'height': this.constants_.WS_CURSOR_HEIGHT, @@ -605,7 +607,8 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { this.markerSvg_); // A filled in rectangle used to represent a stack. - this.markerSvgRect_ = Blockly.utils.dom.createSvgElement('rect', + this.markerSvgRect_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyVerticalMarker', 'rx': 10, 'ry': 10, @@ -614,7 +617,8 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { this.markerSvg_); // A filled in puzzle piece used to represent an input value. - this.markerInput_ = Blockly.utils.dom.createSvgElement('path', + this.markerInput_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { 'transform': '', 'style': 'display: none' @@ -623,7 +627,8 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { // A path used to represent a previous connection and a block, an output // connection and a block, or a block. - this.markerBlock_ = Blockly.utils.dom.createSvgElement('path', + this.markerBlock_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { 'transform': '', 'style': 'display: none', @@ -635,12 +640,15 @@ Blockly.blockRendering.MarkerSvg.prototype.createDomInternal_ = function() { // Markers and stack markers don't blink. if (this.isCursor()) { var blinkProperties = this.getBlinkProperties_(); - Blockly.utils.dom.createSvgElement('animate', blinkProperties, + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.ANIMATE, blinkProperties, this.markerSvgLine_); - Blockly.utils.dom.createSvgElement('animate', blinkProperties, + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.ANIMATE, blinkProperties, this.markerInput_); blinkProperties['attributeName'] = 'stroke'; - Blockly.utils.dom.createSvgElement('animate', blinkProperties, + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.ANIMATE, blinkProperties, this.markerBlock_); } diff --git a/core/renderers/common/path_object.js b/core/renderers/common/path_object.js index 602f27448..f3dc86beb 100644 --- a/core/renderers/common/path_object.js +++ b/core/renderers/common/path_object.js @@ -46,7 +46,8 @@ Blockly.blockRendering.PathObject = function(root, style, constants) { * @type {!SVGElement} * @package */ - this.svgPath = Blockly.utils.dom.createSvgElement('path', + this.svgPath = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, {'class': 'blocklyPath'}, this.svgRoot); /** diff --git a/core/renderers/geras/path_object.js b/core/renderers/geras/path_object.js index dd572aab7..6fbc8165d 100644 --- a/core/renderers/geras/path_object.js +++ b/core/renderers/geras/path_object.js @@ -48,7 +48,8 @@ Blockly.geras.PathObject = function(root, style, constants) { * @type {SVGElement} * @package */ - this.svgPathDark = Blockly.utils.dom.createSvgElement('path', + this.svgPathDark = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, {'class': 'blocklyPathDark', 'transform': 'translate(1,1)'}, this.svgRoot); @@ -57,7 +58,8 @@ Blockly.geras.PathObject = function(root, style, constants) { * @type {!SVGElement} * @package */ - this.svgPath = Blockly.utils.dom.createSvgElement('path', + this.svgPath = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, {'class': 'blocklyPath'}, this.svgRoot); /** @@ -65,7 +67,8 @@ Blockly.geras.PathObject = function(root, style, constants) { * @type {SVGElement} * @package */ - this.svgPathLight = Blockly.utils.dom.createSvgElement('path', + this.svgPathLight = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, {'class': 'blocklyPathLight'}, this.svgRoot); /** diff --git a/core/renderers/zelos/constants.js b/core/renderers/zelos/constants.js index acfe8c36e..518e36daa 100644 --- a/core/renderers/zelos/constants.js +++ b/core/renderers/zelos/constants.js @@ -806,10 +806,12 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg, ... filters go here ... */ - var defs = Blockly.utils.dom.createSvgElement('defs', {}, svg); + var defs = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.DEFS, {}, svg); // Using a dilate distorts the block shape. // Instead use a gaussian blur, and then set all alpha to 1 with a transfer. - var selectedGlowFilter = Blockly.utils.dom.createSvgElement('filter', + var selectedGlowFilter = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FILTER, { 'id': 'blocklySelectedGlowFilter' + this.randomIdentifier, 'height': '160%', @@ -818,7 +820,8 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg, x: '-40%' }, defs); - Blockly.utils.dom.createSvgElement('feGaussianBlur', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEGAUSSIANBLUR, { 'in': 'SourceGraphic', 'stdDeviation': this.SELECTED_GLOW_SIZE @@ -826,21 +829,26 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg, selectedGlowFilter); // Set all gaussian blur pixels to 1 opacity before applying flood var selectedComponentTransfer = Blockly.utils.dom.createSvgElement( - 'feComponentTransfer', {'result': 'outBlur'}, selectedGlowFilter); - Blockly.utils.dom.createSvgElement('feFuncA', + Blockly.utils.dom.SvgElementType.FECOMPONENTTRANSFER, { + 'result': 'outBlur' + }, selectedGlowFilter); + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEFUNCA, { 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' }, selectedComponentTransfer); // Color the highlight - Blockly.utils.dom.createSvgElement('feFlood', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEFLOOD, { 'flood-color': this.SELECTED_GLOW_COLOUR, 'flood-opacity': 1, 'result': 'outColor' }, selectedGlowFilter); - Blockly.utils.dom.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FECOMPOSITE, { 'in': 'outColor', 'in2': 'outBlur', 'operator': 'in', 'result': 'outGlow' @@ -851,7 +859,8 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg, // Using a dilate distorts the block shape. // Instead use a gaussian blur, and then set all alpha to 1 with a transfer. - var replacementGlowFilter = Blockly.utils.dom.createSvgElement('filter', + var replacementGlowFilter = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FILTER, { 'id': 'blocklyReplacementGlowFilter' + this.randomIdentifier, 'height': '160%', @@ -860,7 +869,8 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg, x: '-40%' }, defs); - Blockly.utils.dom.createSvgElement('feGaussianBlur', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEGAUSSIANBLUR, { 'in': 'SourceGraphic', 'stdDeviation': this.REPLACEMENT_GLOW_SIZE @@ -868,27 +878,33 @@ Blockly.zelos.ConstantProvider.prototype.createDom = function(svg, replacementGlowFilter); // Set all gaussian blur pixels to 1 opacity before applying flood var replacementComponentTransfer = Blockly.utils.dom.createSvgElement( - 'feComponentTransfer', {'result': 'outBlur'}, replacementGlowFilter); - Blockly.utils.dom.createSvgElement('feFuncA', + Blockly.utils.dom.SvgElementType.FECOMPONENTTRANSFER, { + 'result': 'outBlur' + }, replacementGlowFilter); + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEFUNCA, { 'type': 'table', 'tableValues': '0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1' }, replacementComponentTransfer); // Color the highlight - Blockly.utils.dom.createSvgElement('feFlood', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FEFLOOD, { 'flood-color': this.REPLACEMENT_GLOW_COLOUR, 'flood-opacity': 1, 'result': 'outColor' }, replacementGlowFilter); - Blockly.utils.dom.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FECOMPOSITE, { 'in': 'outColor', 'in2': 'outBlur', 'operator': 'in', 'result': 'outGlow' }, replacementGlowFilter); - Blockly.utils.dom.createSvgElement('feComposite', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.FECOMPOSITE, { 'in': 'SourceGraphic', 'in2': 'outGlow', 'operator': 'over', diff --git a/core/renderers/zelos/marker_svg.js b/core/renderers/zelos/marker_svg.js index 0b5d31f12..6b29d9b8d 100644 --- a/core/renderers/zelos/marker_svg.js +++ b/core/renderers/zelos/marker_svg.js @@ -111,17 +111,19 @@ Blockly.zelos.MarkerSvg.prototype.createDomInternal_ = function() { Blockly.zelos.MarkerSvg.superClass_.createDomInternal_.call(this); - this.markerCircle_ = Blockly.utils.dom.createSvgElement('circle', { - 'r': this.constants_.CURSOR_RADIUS, - 'style': 'display: none', - 'stroke-width': this.constants_.CURSOR_STROKE_WIDTH - }, - this.markerSvg_); + this.markerCircle_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CIRCLE, { + 'r': this.constants_.CURSOR_RADIUS, + 'style': 'display: none', + 'stroke-width': this.constants_.CURSOR_STROKE_WIDTH + }, + this.markerSvg_); // Markers and stack cursors don't blink. if (this.isCursor()) { var blinkProperties = this.getBlinkProperties_(); - Blockly.utils.dom.createSvgElement('animate', blinkProperties, + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.ANIMATE, blinkProperties, this.markerCircle_); } diff --git a/core/renderers/zelos/path_object.js b/core/renderers/zelos/path_object.js index 360f329af..a4d63c301 100644 --- a/core/renderers/zelos/path_object.js +++ b/core/renderers/zelos/path_object.js @@ -218,12 +218,13 @@ Blockly.zelos.PathObject.prototype.setOutlinePath = function(name, pathString) { */ Blockly.zelos.PathObject.prototype.getOutlinePath_ = function(name) { if (!this.outlines_[name]) { - this.outlines_[name] = Blockly.utils.dom.createSvgElement('path', { - 'class': 'blocklyOutlinePath', - // IE doesn't like paths without the data definition, set empty default - 'd': '' - }, - this.svgRoot); + this.outlines_[name] = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { + 'class': 'blocklyOutlinePath', + // IE doesn't like paths without the data definition, set empty default + 'd': '' + }, + this.svgRoot); } if (this.remainingOutlines_) { delete this.remainingOutlines_[name]; diff --git a/core/scrollbar.js b/core/scrollbar.js index 753e219de..832abaaa7 100644 --- a/core/scrollbar.js +++ b/core/scrollbar.js @@ -37,7 +37,7 @@ Blockly.ScrollbarPair = function(workspace) { this.vScroll = new Blockly.Scrollbar( workspace, false, true, 'blocklyMainWorkspaceScrollbar'); this.corner_ = Blockly.utils.dom.createSvgElement( - 'rect', + Blockly.utils.dom.SvgElementType.RECT, { 'height': Blockly.Scrollbar.scrollbarThickness, 'width': Blockly.Scrollbar.scrollbarThickness, @@ -610,13 +610,16 @@ Blockly.Scrollbar.prototype.createDom_ = function(opt_class) { className += ' ' + opt_class; } this.outerSvg_ = Blockly.utils.dom.createSvgElement( - 'svg', {'class': className}, null); - this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', {}, this.outerSvg_); + Blockly.utils.dom.SvgElementType.SVG, {'class': className}, null); + this.svgGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, this.outerSvg_); this.svgBackground_ = Blockly.utils.dom.createSvgElement( - 'rect', {'class': 'blocklyScrollbarBackground'}, this.svgGroup_); + Blockly.utils.dom.SvgElementType.RECT, { + 'class': 'blocklyScrollbarBackground' + }, this.svgGroup_); var radius = Math.floor((Blockly.Scrollbar.scrollbarThickness - 5) / 2); this.svgHandle_ = Blockly.utils.dom.createSvgElement( - 'rect', + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyScrollbarHandle', 'rx': radius, diff --git a/core/toolbox.js b/core/toolbox.js index 4e2f79904..080653d2d 100644 --- a/core/toolbox.js +++ b/core/toolbox.js @@ -201,7 +201,8 @@ Blockly.Toolbox.prototype.init = function() { } // Insert the flyout after the workspace. - Blockly.utils.dom.insertAfter(this.flyout_.createDom('svg'), svg); + Blockly.utils.dom.insertAfter( + this.flyout_.createDom(Blockly.utils.dom.SvgElementType.SVG), svg); this.flyout_.init(workspace); this.config_['cssCollapsedFolderIcon'] = diff --git a/core/trashcan.js b/core/trashcan.js index fcb2acc0c..0a743c509 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -258,21 +258,25 @@ Blockly.Trashcan.prototype.createDom = function() { clip-path="url(#blocklyTrashLidClipPath837493)"> */ - this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', + this.svgGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyTrash'}, null); var clip; var rnd = String(Math.random()).substring(2); - clip = Blockly.utils.dom.createSvgElement('clipPath', + clip = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CLIPPATH, {'id': 'blocklyTrashBodyClipPath' + rnd}, this.svgGroup_); - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'width': this.WIDTH_, 'height': this.BODY_HEIGHT_, 'y': this.LID_HEIGHT_ }, clip); - var body = Blockly.utils.dom.createSvgElement('image', + var body = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, { 'width': Blockly.SPRITE.width, 'x': -this.SPRITE_LEFT_, @@ -284,12 +288,15 @@ Blockly.Trashcan.prototype.createDom = function() { body.setAttributeNS(Blockly.utils.dom.XLINK_NS, 'xlink:href', this.workspace_.options.pathToMedia + Blockly.SPRITE.url); - clip = Blockly.utils.dom.createSvgElement('clipPath', + clip = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CLIPPATH, {'id': 'blocklyTrashLidClipPath' + rnd}, this.svgGroup_); - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, {'width': this.WIDTH_, 'height': this.LID_HEIGHT_}, clip); - this.svgLid_ = Blockly.utils.dom.createSvgElement('image', + this.svgLid_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, { 'width': Blockly.SPRITE.width, 'x': -this.SPRITE_LEFT_, @@ -322,7 +329,8 @@ Blockly.Trashcan.prototype.createDom = function() { */ Blockly.Trashcan.prototype.init = function(verticalSpacing) { if (this.workspace_.options.maxTrashcanContents > 0) { - Blockly.utils.dom.insertAfter(this.flyout.createDom('svg'), + Blockly.utils.dom.insertAfter( + this.flyout.createDom(Blockly.utils.dom.SvgElementType.SVG), this.workspace_.getParentSvg()); this.flyout.init(this.workspace_); } diff --git a/core/utils/dom.js b/core/utils/dom.js index 202889c05..ebe44964d 100644 --- a/core/utils/dom.js +++ b/core/utils/dom.js @@ -72,16 +72,135 @@ Blockly.utils.dom.cacheReference_ = 0; */ Blockly.utils.dom.canvasContext_ = null; +/** + * A name with the type of the SVG element stored in the generic. + * @param {string} tagName The SVG element tag name. + * @constructor + * @template T + */ +Blockly.utils.dom.SvgElementType = function(tagName) { + /** + * @type {string} + * @private + */ + this.tagName_ = tagName; +}; + +/** + * Returns the SVG element tag name. + * @return {string} The name. + * @override + */ +Blockly.utils.dom.SvgElementType.prototype.toString = function() { + return this.tagName_; +}; + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.ANIMATE = + new Blockly.utils.dom.SvgElementType('animate'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.CIRCLE = + new Blockly.utils.dom.SvgElementType('circle'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.CLIPPATH = + new Blockly.utils.dom.SvgElementType('clipPath'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.DEFS = + new Blockly.utils.dom.SvgElementType('defs'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FECOMPOSITE = + new Blockly.utils.dom.SvgElementType('feComposite'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FECOMPONENTTRANSFER = + new Blockly.utils.dom.SvgElementType('feComponentTransfer'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FEFLOOD = + new Blockly.utils.dom.SvgElementType('feFlood'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FEFUNCA = + new Blockly.utils.dom.SvgElementType('feFuncA'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FEGAUSSIANBLUR = + new Blockly.utils.dom.SvgElementType('feGaussianBlur'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FEPOINTLIGHT = + new Blockly.utils.dom.SvgElementType('fePointLight'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FESPECULARLIGHTING = + new Blockly.utils.dom.SvgElementType('feSpecularLighting'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FILTER = + new Blockly.utils.dom.SvgElementType('filter'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.FOREIGNOBJECT = + new Blockly.utils.dom.SvgElementType('foreignObject'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.G = + new Blockly.utils.dom.SvgElementType('g'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.IMAGE = + new Blockly.utils.dom.SvgElementType('image'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.LINE = + new Blockly.utils.dom.SvgElementType('line'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.PATH = + new Blockly.utils.dom.SvgElementType('path'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.PATTERN = + new Blockly.utils.dom.SvgElementType('pattern'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.POLYGON = + new Blockly.utils.dom.SvgElementType('polygon'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.RECT = + new Blockly.utils.dom.SvgElementType('rect'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.SVG = + new Blockly.utils.dom.SvgElementType('svg'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.TEXT = + new Blockly.utils.dom.SvgElementType('text'); + +/** @type {!Blockly.utils.dom.SvgElementType} */ +Blockly.utils.dom.SvgElementType.TSPAN = + new Blockly.utils.dom.SvgElementType('tspan'); + + /** * Helper method for creating SVG elements. - * @param {string} name Element's tag name. + * @param {string|Blockly.utils.dom.SvgElementType} name Element's tag name. * @param {!Object} attrs Dictionary of attribute names and values. * @param {Element=} opt_parent Optional parent on which to append the element. - * @return {!SVGElement} Newly created SVG element. + * @return {T} Newly created SVG element. The return type is {!SVGElement} if + * name is a string or a more specific type if it a member of + * Blockly.utils.dom.SvgElementType + * @template T */ Blockly.utils.dom.createSvgElement = function(name, attrs, opt_parent) { - var e = /** @type {!SVGElement} */ - (document.createElementNS(Blockly.utils.dom.SVG_NS, name)); + var e = /** @type {T} */ + (document.createElementNS(Blockly.utils.dom.SVG_NS, String(name))); for (var key in attrs) { e.setAttribute(key, attrs[key]); } diff --git a/core/warning.js b/core/warning.js index 915873706..474f15e24 100644 --- a/core/warning.js +++ b/core/warning.js @@ -46,7 +46,8 @@ Blockly.Warning.prototype.collapseHidden = false; */ Blockly.Warning.prototype.drawIcon_ = function(group) { // Triangle with rounded corners. - Blockly.utils.dom.createSvgElement('path', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { 'class': 'blocklyIconShape', 'd': 'M2,15Q-1,15 0.5,12L6.5,1.7Q8,-1 9.5,1.7L15.5,12Q17,15 14,15z' @@ -55,14 +56,16 @@ Blockly.Warning.prototype.drawIcon_ = function(group) { // Can't use a real '!' text character since different browsers and operating // systems render it differently. // Body of exclamation point. - Blockly.utils.dom.createSvgElement('path', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { 'class': 'blocklyIconSymbol', 'd': 'm7,4.8v3.16l0.27,2.27h1.46l0.27,-2.27v-3.16z' }, group); // Dot of exclamation point. - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyIconSymbol', 'x': '7', 'y': '11', 'height': '2', 'width': '2' @@ -77,18 +80,17 @@ Blockly.Warning.prototype.drawIcon_ = function(group) { * @private */ Blockly.Warning.textToDom_ = function(text) { - var paragraph = /** @type {!SVGTextElement} */ - (Blockly.utils.dom.createSvgElement( - 'text', - { - 'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents', - 'y': Blockly.Bubble.BORDER_WIDTH - }, - null) - ); + var paragraph = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.TEXT, + { + 'class': 'blocklyText blocklyBubbleText blocklyNoPointerEvents', + 'y': Blockly.Bubble.BORDER_WIDTH + }, + null); var lines = text.split('\n'); for (var i = 0; i < lines.length; i++) { - var tspanElement = Blockly.utils.dom.createSvgElement('tspan', + var tspanElement = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.TSPAN, {'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph); var textNode = document.createTextNode(lines[i]); tspanElement.appendChild(textNode); diff --git a/core/workspace_comment_render_svg.js b/core/workspace_comment_render_svg.js index ee997e161..2480cbc56 100644 --- a/core/workspace_comment_render_svg.js +++ b/core/workspace_comment_render_svg.js @@ -74,14 +74,16 @@ Blockly.WorkspaceCommentSvg.prototype.render = function() { this.createEditor_(); this.svgGroup_.appendChild(this.foreignObject_); - this.svgHandleTarget_ = Blockly.utils.dom.createSvgElement('rect', + this.svgHandleTarget_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyCommentHandleTarget', 'x': 0, 'y': 0 }); this.svgGroup_.appendChild(this.svgHandleTarget_); - this.svgRectTarget_ = Blockly.utils.dom.createSvgElement('rect', + this.svgRectTarget_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyCommentTarget', 'x': 0, @@ -136,7 +138,7 @@ Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() { */ this.foreignObject_ = Blockly.utils.dom.createSvgElement( - 'foreignObject', + Blockly.utils.dom.SvgElementType.FOREIGNOBJECT, { 'x': 0, 'y': Blockly.WorkspaceCommentSvg.TOP_OFFSET, @@ -171,25 +173,25 @@ Blockly.WorkspaceCommentSvg.prototype.createEditor_ = function() { */ Blockly.WorkspaceCommentSvg.prototype.addResizeDom_ = function() { this.resizeGroup_ = Blockly.utils.dom.createSvgElement( - 'g', + Blockly.utils.dom.SvgElementType.G, { 'class': this.RTL ? 'blocklyResizeSW' : 'blocklyResizeSE' }, this.svgGroup_); var resizeSize = Blockly.WorkspaceCommentSvg.RESIZE_SIZE; Blockly.utils.dom.createSvgElement( - 'polygon', + Blockly.utils.dom.SvgElementType.POLYGON, {'points': '0,x x,x x,0'.replace(/x/g, resizeSize.toString())}, this.resizeGroup_); Blockly.utils.dom.createSvgElement( - 'line', + Blockly.utils.dom.SvgElementType.LINE, { 'class': 'blocklyResizeLine', 'x1': resizeSize / 3, 'y1': resizeSize - 1, 'x2': resizeSize - 1, 'y2': resizeSize / 3 }, this.resizeGroup_); Blockly.utils.dom.createSvgElement( - 'line', + Blockly.utils.dom.SvgElementType.LINE, { 'class': 'blocklyResizeLine', 'x1': resizeSize * 2 / 3, 'y1': resizeSize - 1, @@ -203,12 +205,13 @@ Blockly.WorkspaceCommentSvg.prototype.addResizeDom_ = function() { */ Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { this.deleteGroup_ = Blockly.utils.dom.createSvgElement( - 'g', + Blockly.utils.dom.SvgElementType.G, { 'class': 'blocklyCommentDeleteIcon' }, this.svgGroup_); - this.deleteIconBorder_ = Blockly.utils.dom.createSvgElement('circle', + this.deleteIconBorder_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CIRCLE, { 'class': 'blocklyDeleteIconShape', 'r': '7', @@ -218,7 +221,7 @@ Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { this.deleteGroup_); // x icon. Blockly.utils.dom.createSvgElement( - 'line', + Blockly.utils.dom.SvgElementType.LINE, { 'x1': '5', 'y1': '10', 'x2': '10', 'y2': '5', @@ -227,7 +230,7 @@ Blockly.WorkspaceCommentSvg.prototype.addDeleteDom_ = function() { }, this.deleteGroup_); Blockly.utils.dom.createSvgElement( - 'line', + Blockly.utils.dom.SvgElementType.LINE, { 'x1': '5', 'y1': '5', 'x2': '10', 'y2': '10', diff --git a/core/workspace_comment_svg.js b/core/workspace_comment_svg.js index 4190074ba..62fbb93ed 100644 --- a/core/workspace_comment_svg.js +++ b/core/workspace_comment_svg.js @@ -64,11 +64,11 @@ Blockly.WorkspaceCommentSvg = function(workspace, content, height, width, * @private */ this.svgGroup_ = Blockly.utils.dom.createSvgElement( - 'g', {'class': 'blocklyComment'}, null); + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyComment'}, null); this.svgGroup_.translate_ = ''; this.svgRect_ = Blockly.utils.dom.createSvgElement( - 'rect', + Blockly.utils.dom.SvgElementType.RECT, { 'class': 'blocklyCommentRect', 'x': 0, diff --git a/core/workspace_drag_surface_svg.js b/core/workspace_drag_surface_svg.js index 3ee7454be..11a27c6af 100644 --- a/core/workspace_drag_surface_svg.js +++ b/core/workspace_drag_surface_svg.js @@ -62,7 +62,8 @@ Blockly.WorkspaceDragSurfaceSvg.prototype.createDom = function() { * /g> * */ - this.SVG_ = Blockly.utils.dom.createSvgElement('svg', + this.SVG_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.SVG, { 'xmlns': Blockly.utils.dom.SVG_NS, 'xmlns:html': Blockly.utils.dom.HTML_NS, diff --git a/core/workspace_svg.js b/core/workspace_svg.js index dfa2430ff..b1f996e13 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -711,7 +711,8 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { * * @type {SVGElement} */ - this.svgGroup_ = Blockly.utils.dom.createSvgElement('g', + this.svgGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyWorkspace'}, null); // Note that a alone does not receive mouse events--it must have a @@ -719,7 +720,8 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { // flyout, the workspace will not receive mouse events. if (opt_backgroundClass) { /** @type {SVGElement} */ - this.svgBackground_ = Blockly.utils.dom.createSvgElement('rect', + this.svgBackground_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, {'height': '100%', 'width': '100%', 'class': opt_backgroundClass}, this.svgGroup_); @@ -732,10 +734,12 @@ Blockly.WorkspaceSvg.prototype.createDom = function(opt_backgroundClass) { } } /** @type {SVGElement} */ - this.svgBlockCanvas_ = Blockly.utils.dom.createSvgElement('g', + this.svgBlockCanvas_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyBlockCanvas'}, this.svgGroup_); /** @type {SVGElement} */ - this.svgBubbleCanvas_ = Blockly.utils.dom.createSvgElement('g', + this.svgBubbleCanvas_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyBubbleCanvas'}, this.svgGroup_); if (!this.isFlyout) { @@ -897,7 +901,10 @@ Blockly.WorkspaceSvg.prototype.addZoomControls = function() { /** * Add a flyout element in an element with the given tag name. - * @param {string} tagName What type of tag the flyout belongs in. + * @param {string| + * !Blockly.utils.dom.SvgElementType| + * !Blockly.utils.dom.SvgElementType} tagName What type of tag the + * flyout belongs in. * @return {!Element} The element containing the flyout DOM. * @package */ diff --git a/core/zoom_controls.js b/core/zoom_controls.js index 98e431f7f..b69d3e128 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -53,6 +53,35 @@ Blockly.ZoomControls = function(workspace) { * @private */ this.onZoomOutWrapper_ = null; + + /** + * The vertical distance between the workspace bottom edge and the control. + * The value is initialized during `init`. + * @type {?number} + * @private + */ + this.verticalSpacing_ = null; + + /** + * The zoom in svg element. + * @type {SVGGElement} + * @private + */ + this.zoomInGroup_ = null; + + /** + * The zoom out svg element. + * @type {SVGGElement} + * @private + */ + this.zoomOutGroup_ = null; + + /** + * The zoom reset svg element. + * @type {SVGGElement} + * @private + */ + this.zoomResetGroup_ = null; }; /** @@ -110,8 +139,8 @@ Blockly.ZoomControls.prototype.top_ = 0; * @return {!SVGElement} The zoom controls SVG group. */ Blockly.ZoomControls.prototype.createDom = function() { - this.svgGroup_ = - Blockly.utils.dom.createSvgElement('g', {}, null); + this.svgGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); // Each filter/pattern needs a unique ID for the case of multiple Blockly // instances on a page. Browser behaviour becomes undefined otherwise. @@ -217,20 +246,24 @@ Blockly.ZoomControls.prototype.createZoomOutSvg_ = function(rnd) { clip-path="url(#blocklyZoomoutClipPath837493)"> */ - this.zoomOutGroup_ = Blockly.utils.dom.createSvgElement('g', + this.zoomOutGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyZoom'}, this.svgGroup_); - var clip = Blockly.utils.dom.createSvgElement('clipPath', + var clip = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CLIPPATH, { 'id': 'blocklyZoomoutClipPath' + rnd }, this.zoomOutGroup_); - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'width': 32, 'height': 32, }, clip); - var zoomoutSvg = Blockly.utils.dom.createSvgElement('image', + var zoomoutSvg = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, { 'width': Blockly.SPRITE.width, 'height': Blockly.SPRITE.height, @@ -264,20 +297,24 @@ Blockly.ZoomControls.prototype.createZoomInSvg_ = function(rnd) { clip-path="url(#blocklyZoominClipPath837493)"> */ - this.zoomInGroup_ = Blockly.utils.dom.createSvgElement('g', + this.zoomInGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyZoom'}, this.svgGroup_); - var clip = Blockly.utils.dom.createSvgElement('clipPath', + var clip = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CLIPPATH, { 'id': 'blocklyZoominClipPath' + rnd }, this.zoomInGroup_); - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'width': 32, 'height': 32, }, clip); - var zoominSvg = Blockly.utils.dom.createSvgElement('image', + var zoominSvg = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, { 'width': Blockly.SPRITE.width, 'height': Blockly.SPRITE.height, @@ -329,20 +366,24 @@ Blockly.ZoomControls.prototype.createZoomResetSvg_ = function(rnd) { clip-path="url(#blocklyZoomresetClipPath837493)"> */ - this.zoomResetGroup_ = Blockly.utils.dom.createSvgElement('g', + this.zoomResetGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {'class': 'blocklyZoom'}, this.svgGroup_); - var clip = Blockly.utils.dom.createSvgElement('clipPath', + var clip = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.CLIPPATH, { 'id': 'blocklyZoomresetClipPath' + rnd }, this.zoomResetGroup_); - Blockly.utils.dom.createSvgElement('rect', + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.RECT, { 'width': 32, 'height': 32 }, clip); - var zoomresetSvg = Blockly.utils.dom.createSvgElement('image', + var zoomresetSvg = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.IMAGE, { 'width': Blockly.SPRITE.width, 'height': Blockly.SPRITE.height, diff --git a/tests/mocha/field_checkbox_test.js b/tests/mocha/field_checkbox_test.js index 7eaac4d5a..f7ff4dac6 100644 --- a/tests/mocha/field_checkbox_test.js +++ b/tests/mocha/field_checkbox_test.js @@ -159,7 +159,8 @@ suite('Checkbox Fields', function() { suite('Customizations', function() { suite('Check Character', function() { function assertCharacter(field, char) { - field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + field.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); field.sourceBlock_ = { RTL: false, rendered: true, diff --git a/tests/mocha/field_label_serializable_test.js b/tests/mocha/field_label_serializable_test.js index 8b7954a68..8d6ad9864 100644 --- a/tests/mocha/field_label_serializable_test.js +++ b/tests/mocha/field_label_serializable_test.js @@ -91,7 +91,8 @@ suite('Label Serializable Fields', function() { suite('Customizations', function() { function assertHasClass(labelField, cssClass) { - labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); labelField.constants_ = { FIELD_TEXT_BASELINE_Y: 13 }; @@ -100,7 +101,8 @@ suite('Label Serializable Fields', function() { labelField.textElement_, cssClass)); } function assertDoesNotHaveClass(labelField, cssClass) { - labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); labelField.constants_ = { FIELD_TEXT_BASELINE_Y: 13 }; @@ -146,7 +148,8 @@ suite('Label Serializable Fields', function() { suite('setClass', function() { test('setClass', function() { var field = new Blockly.FieldLabelSerializable(); - field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + field.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); field.constants_ = { FIELD_TEXT_BASELINE_Y: 13 }; diff --git a/tests/mocha/field_label_test.js b/tests/mocha/field_label_test.js index 62a888aae..698f21f10 100644 --- a/tests/mocha/field_label_test.js +++ b/tests/mocha/field_label_test.js @@ -91,8 +91,8 @@ suite('Label Fields', function() { suite('Customizations', function() { function assertHasClass(labelField, cssClass) { - labelField.fieldGroup_ = - Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); labelField.constants_ = { FIELD_TEXT_BASELINE_Y: 13 }; @@ -101,8 +101,8 @@ suite('Label Fields', function() { labelField.textElement_, cssClass)); } function assertDoesNotHaveClass(labelField, cssClass) { - labelField.fieldGroup_ = - Blockly.utils.dom.createSvgElement('g', {}, null); + labelField.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); labelField.constants_ = { FIELD_TEXT_BASELINE_Y: 13 }; @@ -149,7 +149,8 @@ suite('Label Fields', function() { suite('setClass', function() { test('setClass', function() { var field = new Blockly.FieldLabel(); - field.fieldGroup_ = Blockly.utils.dom.createSvgElement('g', {}, null); + field.fieldGroup_ = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, {}, null); field.constants_ = { FIELD_TEXT_BASELINE_Y: 13 }; diff --git a/tests/rendering/svg_paths.html b/tests/rendering/svg_paths.html index 48223e37c..128eb6be5 100644 --- a/tests/rendering/svg_paths.html +++ b/tests/rendering/svg_paths.html @@ -45,17 +45,19 @@ limitations under the License. var svgSpace; function addPathAt(path, x, y) { - var group = Blockly.utils.dom.createSvgElement('g', + var group = Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.G, { 'transform': 'translate(' + (x + 50) + ', ' + y + ')' }, svgSpace); - Blockly.utils.dom.createSvgElement('path', { - 'd': 'M 0,0 ' + path, - 'marker-start': 'url(#startDot)', - 'marker-end': 'url(#endDot)', - 'class': 'pathDebugClass' - }, - group); + Blockly.utils.dom.createSvgElement( + Blockly.utils.dom.SvgElementType.PATH, { + 'd': 'M 0,0 ' + path, + 'marker-start': 'url(#startDot)', + 'marker-end': 'url(#endDot)', + 'class': 'pathDebugClass' + }, + group); return group;