File "constants.js"
Full path: /usr/home/mndrn/domains/mndrn.ru/public_html/block-hill/blockly/core/renderers/common/constants.js
File size: 33.89 KiB (34707 bytes)
MIME-type: text/plain
Charset: utf-8
/**
* @license
* Copyright 2019 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview An object that provides constants for rendering blocks.
* @author [email protected] (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.blockRendering.ConstantProvider');
goog.require('Blockly.constants');
goog.require('Blockly.utils');
goog.require('Blockly.utils.colour');
goog.require('Blockly.utils.dom');
goog.require('Blockly.utils.Svg');
goog.require('Blockly.utils.svgPaths');
goog.require('Blockly.utils.userAgent');
goog.requireType('Blockly.blockRendering.Debug');
/**
* An object that provides constants for rendering blocks.
* @constructor
* @package
*/
Blockly.blockRendering.ConstantProvider = function() {
/**
* The size of an empty spacer.
* @type {number}
*/
this.NO_PADDING = 0;
/**
* The size of small padding.
* @type {number}
*/
this.SMALL_PADDING = 3;
/**
* The size of medium padding.
* @type {number}
*/
this.MEDIUM_PADDING = 5;
/**
* The size of medium-large padding.
* @type {number}
*/
this.MEDIUM_LARGE_PADDING = 8;
/**
* The size of large padding.
* @type {number}
*/
this.LARGE_PADDING = 10;
/**
* Offset from the top of the row for placing fields on inline input rows
* and statement input rows.
* Matches existing rendering (in 2019).
* @type {number}
*/
this.TALL_INPUT_FIELD_OFFSET_Y = this.MEDIUM_PADDING;
/**
* The height of the puzzle tab used for input and output connections.
* @type {number}
*/
this.TAB_HEIGHT = 15;
/**
* The offset from the top of the block at which a puzzle tab is positioned.
* @type {number}
*/
this.TAB_OFFSET_FROM_TOP = 5;
/**
* Vertical overlap of the puzzle tab, used to make it look more like a puzzle
* piece.
* @type {number}
*/
this.TAB_VERTICAL_OVERLAP = 2.5;
/**
* The width of the puzzle tab used for input and output connections.
* @type {number}
*/
this.TAB_WIDTH = 8;
/**
* The width of the notch used for previous and next connections.
* @type {number}
*/
this.NOTCH_WIDTH = 15;
/**
* The height of the notch used for previous and next connections.
* @type {number}
*/
this.NOTCH_HEIGHT = 4;
/**
* The minimum width of the block.
* @type {number}
*/
this.MIN_BLOCK_WIDTH = 12;
this.EMPTY_BLOCK_SPACER_HEIGHT = 16;
/**
* The minimum height of a dummy input row.
* @type {number}
*/
this.DUMMY_INPUT_MIN_HEIGHT = this.TAB_HEIGHT;
/**
* The minimum height of a dummy input row in a shadow block.
* @type {number}
*/
this.DUMMY_INPUT_SHADOW_MIN_HEIGHT = this.TAB_HEIGHT;
/**
* Rounded corner radius.
* @type {number}
*/
this.CORNER_RADIUS = 8;
/**
* Offset from the left side of a block or the inside of a statement input to
* the left side of the notch.
* @type {number}
*/
this.NOTCH_OFFSET_LEFT = 15;
/**
* Additional offset added to the statement input's width to account for the
* notch.
* @type {number}
*/
this.STATEMENT_INPUT_NOTCH_OFFSET = this.NOTCH_OFFSET_LEFT;
this.STATEMENT_BOTTOM_SPACER = 0;
this.STATEMENT_INPUT_PADDING_LEFT = 20;
/**
* Vertical padding between consecutive statement inputs.
* @type {number}
*/
this.BETWEEN_STATEMENT_PADDING_Y = 4;
/**
* The top row's minimum height.
* @type {number}
*/
this.TOP_ROW_MIN_HEIGHT = this.MEDIUM_PADDING;
/**
* The top row's minimum height if it precedes a statement.
* @type {number}
*/
this.TOP_ROW_PRECEDES_STATEMENT_MIN_HEIGHT = this.LARGE_PADDING;
/**
* The bottom row's minimum height.
* @type {number}
*/
this.BOTTOM_ROW_MIN_HEIGHT = this.MEDIUM_PADDING;
/**
* The bottom row's minimum height if it follows a statement input.
* @type {number}
*/
this.BOTTOM_ROW_AFTER_STATEMENT_MIN_HEIGHT = this.LARGE_PADDING;
/**
* Whether to add a 'hat' on top of all blocks with no previous or output
* connections. Can be overridden by 'hat' property on Theme.BlockStyle.
* @type {boolean}
*/
this.ADD_START_HATS = false;
/**
* Height of the top hat.
* @type {number}
*/
this.START_HAT_HEIGHT = 15;
/**
* Width of the top hat.
* @type {number}
*/
this.START_HAT_WIDTH = 100;
this.SPACER_DEFAULT_HEIGHT = 15;
this.MIN_BLOCK_HEIGHT = 24;
this.EMPTY_INLINE_INPUT_PADDING = 14.5;
/**
* The height of an empty inline input.
* @type {number}
*/
this.EMPTY_INLINE_INPUT_HEIGHT = this.TAB_HEIGHT + 11;
this.EXTERNAL_VALUE_INPUT_PADDING = 2;
/**
* The height of an empty statement input. Note that in the old rendering this
* varies slightly depending on whether the block has external or inline inputs.
* In the new rendering this is consistent. It seems unlikely that the old
* behaviour was intentional.
* @type {number}
*/
this.EMPTY_STATEMENT_INPUT_HEIGHT = this.MIN_BLOCK_HEIGHT;
this.START_POINT = Blockly.utils.svgPaths.moveBy(0, 0);
/**
* Height of SVG path for jagged teeth at the end of collapsed blocks.
* @type {number}
*/
this.JAGGED_TEETH_HEIGHT = 12;
/**
* Width of SVG path for jagged teeth at the end of collapsed blocks.
* @type {number}
*/
this.JAGGED_TEETH_WIDTH = 6;
/**
* Point size of text.
* @type {number}
*/
this.FIELD_TEXT_FONTSIZE = 11;
/**
* Text font weight.
* @type {string}
*/
this.FIELD_TEXT_FONTWEIGHT = 'normal';
/**
* Text font family.
* @type {string}
*/
this.FIELD_TEXT_FONTFAMILY = 'sans-serif';
/**
* Height of text. This constant is dynamically set in ``setFontConstants_``
* to be the height of the text based on the font used.
* @type {number}
*/
this.FIELD_TEXT_HEIGHT = -1; // Dynamically set
/**
* Text baseline. This constant is dynamically set in ``setFontConstants_``
* to be the baseline of the text based on the font used.
* @type {number}
*/
this.FIELD_TEXT_BASELINE = -1; // Dynamically set
/**
* A field's border rect corner radius.
* @type {number}
*/
this.FIELD_BORDER_RECT_RADIUS = 4;
/**
* A field's border rect default height.
* @type {number}
*/
this.FIELD_BORDER_RECT_HEIGHT = 16;
/**
* A field's border rect X padding.
* @type {number}
*/
this.FIELD_BORDER_RECT_X_PADDING = 5;
/**
* A field's border rect Y padding.
* @type {number}
*/
this.FIELD_BORDER_RECT_Y_PADDING = 3;
/**
* The backing colour of a field's border rect.
* @type {string}
* @package
*/
this.FIELD_BORDER_RECT_COLOUR = '#fff';
/**
* A field's text element's dominant baseline.
* @type {boolean}
*/
this.FIELD_TEXT_BASELINE_CENTER =
!Blockly.utils.userAgent.IE && !Blockly.utils.userAgent.EDGE;
/**
* A dropdown field's border rect height.
* @type {number}
*/
this.FIELD_DROPDOWN_BORDER_RECT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT;
/**
* Whether or not a dropdown field should add a border rect when in a shadow
* block.
* @type {boolean}
*/
this.FIELD_DROPDOWN_NO_BORDER_RECT_SHADOW = false;
/**
* Whether or not a dropdown field's div should be coloured to match the
* block colours.
* @type {boolean}
*/
this.FIELD_DROPDOWN_COLOURED_DIV = false;
/**
* Whether or not a dropdown field uses a text or SVG arrow.
* @type {boolean}
*/
this.FIELD_DROPDOWN_SVG_ARROW = false;
/**
* A dropdown field's SVG arrow padding.
* @type {number}
*/
this.FIELD_DROPDOWN_SVG_ARROW_PADDING = this.FIELD_BORDER_RECT_X_PADDING;
/**
* A dropdown field's SVG arrow size.
* @type {number}
*/
this.FIELD_DROPDOWN_SVG_ARROW_SIZE = 12;
/**
* A dropdown field's SVG arrow datauri.
* @type {string}
*/
this.FIELD_DROPDOWN_SVG_ARROW_DATAURI =
'data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllci' +
'AxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMi43MSIgaG' +
'VpZ2h0PSI4Ljc5IiB2aWV3Qm94PSIwIDAgMTIuNzEgOC43OSI+PHRpdGxlPmRyb3Bkb3duLW' +
'Fycm93PC90aXRsZT48ZyBvcGFjaXR5PSIwLjEiPjxwYXRoIGQ9Ik0xMi43MSwyLjQ0QTIuND' +
'EsMi40MSwwLDAsMSwxMiw0LjE2TDguMDgsOC4wOGEyLjQ1LDIuNDUsMCwwLDEtMy40NSwwTD' +
'AuNzIsNC4xNkEyLjQyLDIuNDIsMCwwLDEsMCwyLjQ0LDIuNDgsMi40OCwwLDAsMSwuNzEuNz' +
'FDMSwwLjQ3LDEuNDMsMCw2LjM2LDBTMTEuNzUsMC40NiwxMiwuNzFBMi40NCwyLjQ0LDAsMC' +
'wxLDEyLjcxLDIuNDRaIiBmaWxsPSIjMjMxZjIwIi8+PC9nPjxwYXRoIGQ9Ik02LjM2LDcuNz' +
'lhMS40MywxLjQzLDAsMCwxLTEtLjQyTDEuNDIsMy40NWExLjQ0LDEuNDQsMCwwLDEsMC0yYz' +
'AuNTYtLjU2LDkuMzEtMC41Niw5Ljg3LDBhMS40NCwxLjQ0LDAsMCwxLDAsMkw3LjM3LDcuMz' +
'dBMS40MywxLjQzLDAsMCwxLDYuMzYsNy43OVoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=';
/**
* Whether or not to show a box shadow around the widget div. This is only a
* feature of full block fields.
* @type {boolean}
*/
this.FIELD_TEXTINPUT_BOX_SHADOW = false;
/**
* Whether or not the colour field should display its colour value on the
* entire block.
* @type {boolean}
*/
this.FIELD_COLOUR_FULL_BLOCK = false;
/**
* A colour field's default width.
* @type {number}
*/
this.FIELD_COLOUR_DEFAULT_WIDTH = 26;
/**
* A colour field's default height.
* @type {number}
*/
this.FIELD_COLOUR_DEFAULT_HEIGHT = this.FIELD_BORDER_RECT_HEIGHT;
/**
* A checkbox field's X offset.
* @type {number}
*/
this.FIELD_CHECKBOX_X_OFFSET = this.FIELD_BORDER_RECT_X_PADDING - 3;
/**
* A random identifier used to ensure a unique ID is used for each
* filter/pattern for the case of multiple Blockly instances on a page.
* @type {string}
* @package
*/
this.randomIdentifier = String(Math.random()).substring(2);
/**
* The ID of the emboss filter, or the empty string if no filter is set.
* @type {string}
* @package
*/
this.embossFilterId = '';
/**
* The <filter> 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 <pattern> element to use for disabled blocks, or null if not set.
* @type {SVGElement}
* @private
*/
this.disabledPattern_ = null;
/**
* The ID of the debug filter, or the empty string if no pattern is set.
* @type {string}
* @package
*/
this.debugFilterId = '';
/**
* The <filter> element to use for a debug highlight, or null if not set.
* @type {SVGElement}
* @private
*/
this.debugFilter_ = null;
/**
* The <style> element to use for injecting renderer specific CSS.
* @type {HTMLStyleElement}
* @private
*/
this.cssNode_ = null;
/**
* Cursor colour.
* @type {string}
* @package
*/
this.CURSOR_COLOUR = '#cc0a0a';
/**
* Immovable marker colour.
* @type {string}
* @package
*/
this.MARKER_COLOUR = '#4286f4';
/**
* Width of the horizontal cursor.
* @type {number}
* @package
*/
this.CURSOR_WS_WIDTH = 100;
/**
* Height of the horizontal cursor.
* @type {number}
* @package
*/
this.WS_CURSOR_HEIGHT = 5;
/**
* Padding around a stack.
* @type {number}
* @package
*/
this.CURSOR_STACK_PADDING = 10;
/**
* Padding around a block.
* @type {number}
* @package
*/
this.CURSOR_BLOCK_PADDING = 2;
/**
* Stroke of the cursor.
* @type {number}
* @package
*/
this.CURSOR_STROKE_WIDTH = 4;
/**
* Whether text input and colour fields fill up the entire source block.
* @type {boolean}
* @package
*/
this.FULL_BLOCK_FIELDS = false;
/**
* The main colour of insertion markers, in hex. The block is rendered a
* transparent grey by changing the fill opacity in CSS.
* @type {string}
* @package
*/
this.INSERTION_MARKER_COLOUR = '#000000';
/**
* The insertion marker opacity.
* @type {number}
* @package
*/
this.INSERTION_MARKER_OPACITY = 0.2;
/**
* Enum for connection shapes.
* @enum {number}
*/
this.SHAPES = {
PUZZLE: 1,
NOTCH: 2
};
};
/**
* Initialize shape objects based on the constants set in the constructor.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.init = function() {
/**
* An object containing sizing and path information about collapsed block
* indicators.
* @type {!Object}
*/
this.JAGGED_TEETH = this.makeJaggedTeeth();
/**
* An object containing sizing and path information about notches.
* @type {!Object}
*/
this.NOTCH = this.makeNotch();
/**
* An object containing sizing and path information about start hats
* @type {!Object}
*/
this.START_HAT = this.makeStartHat();
/**
* An object containing sizing and path information about puzzle tabs.
* @type {!Object}
*/
this.PUZZLE_TAB = this.makePuzzleTab();
/**
* An object containing sizing and path information about inside corners
* @type {!Object}
*/
this.INSIDE_CORNERS = this.makeInsideCorners();
/**
* An object containing sizing and path information about outside corners.
* @type {!Object}
*/
this.OUTSIDE_CORNERS = this.makeOutsideCorners();
};
/**
* Refresh constants properties that depend on the theme.
* @param {!Blockly.Theme} theme The current workspace theme.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.setTheme = function(
theme) {
/**
* The block styles map.
* @type {Object.<string, Blockly.Theme.BlockStyle>}
* @package
*/
this.blockStyles = {};
var blockStyles = theme.blockStyles;
for (var key in blockStyles) {
this.blockStyles[key] = this.validatedBlockStyle_(blockStyles[key]);
}
this.setDynamicProperties_(theme);
};
/**
* Sets dynamic properties that depend on other values or theme properties.
* @param {!Blockly.Theme} theme The current workspace theme.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.setDynamicProperties_ =
function(theme) {
/* eslint-disable indent */
this.setFontConstants_(theme);
this.setComponentConstants_(theme);
this.ADD_START_HATS = theme.startHats != null ? theme.startHats :
this.ADD_START_HATS;
}; /* eslint-enable indent */
/**
* Set constants related to fonts.
* @param {!Blockly.Theme} theme The current workspace theme.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.setFontConstants_ = function(
theme) {
this.FIELD_TEXT_FONTFAMILY =
theme.fontStyle && theme.fontStyle['family'] != undefined ?
theme.fontStyle['family'] : this.FIELD_TEXT_FONTFAMILY;
this.FIELD_TEXT_FONTWEIGHT =
theme.fontStyle && theme.fontStyle['weight'] != undefined ?
theme.fontStyle['weight'] : this.FIELD_TEXT_FONTWEIGHT;
this.FIELD_TEXT_FONTSIZE =
theme.fontStyle && theme.fontStyle['size'] != undefined ?
theme.fontStyle['size'] : this.FIELD_TEXT_FONTSIZE;
var fontMetrics = Blockly.utils.dom.measureFontMetrics('Hg',
this.FIELD_TEXT_FONTSIZE + 'pt',
this.FIELD_TEXT_FONTWEIGHT,
this.FIELD_TEXT_FONTFAMILY);
this.FIELD_TEXT_HEIGHT = fontMetrics.height;
this.FIELD_TEXT_BASELINE = fontMetrics.baseline;
};
/**
* Set constants from a theme's component styles.
* @param {!Blockly.Theme} theme The current workspace theme.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.setComponentConstants_ =
function(theme) {
/* eslint-disable indent */
this.CURSOR_COLOUR = theme.getComponentStyle('cursorColour') ||
this.CURSOR_COLOUR;
this.MARKER_COLOUR = theme.getComponentStyle('markerColour') ||
this.MARKER_COLOUR;
this.INSERTION_MARKER_COLOUR =
theme.getComponentStyle('insertionMarkerColour') ||
this.INSERTION_MARKER_COLOUR;
this.INSERTION_MARKER_OPACITY =
Number(theme.getComponentStyle('insertionMarkerOpacity')) ||
this.INSERTION_MARKER_OPACITY;
}; /* eslint-enable indent */
/**
* Get or create a block style based on a single colour value. Generate a name
* for the style based on the colour.
* @param {string} colour #RRGGBB colour string.
* @return {{style: !Blockly.Theme.BlockStyle, name: string}} An object
* containing the style and an autogenerated name for that style.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.getBlockStyleForColour =
function(colour) {
/* eslint-disable indent */
var name = 'auto_' + colour;
if (!this.blockStyles[name]) {
this.blockStyles[name] = this.createBlockStyle_(colour);
}
return {style: this.blockStyles[name], name: name};
}; /* eslint-enable indent */
/**
* Gets the BlockStyle for the given block style name.
* @param {?string} blockStyleName The name of the block style.
* @return {!Blockly.Theme.BlockStyle} The named block style, or a default style
* if no style with the given name was found.
*/
Blockly.blockRendering.ConstantProvider.prototype.getBlockStyle = function(
blockStyleName) {
return this.blockStyles[blockStyleName || ''] ||
(blockStyleName && blockStyleName.indexOf('auto_') == 0 ?
this.getBlockStyleForColour(blockStyleName.substring(5)).style :
this.createBlockStyle_('#000000'));
};
/**
* Create a block style object based on the given colour.
* @param {string} colour #RRGGBB colour string.
* @return {!Blockly.Theme.BlockStyle} A populated block style based on the
* given colour.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.createBlockStyle_ = function(
colour) {
return this.validatedBlockStyle_({
'colourPrimary': colour
});
};
/**
* Get a full block style object based on the input style object. Populate
* any missing values.
* @param {{
* colourPrimary:string,
* colourSecondary:(string|undefined),
* colourTertiary:(string|undefined),
* hat:(string|undefined)
* }} blockStyle A full or partial block style object.
* @return {!Blockly.Theme.BlockStyle} A full block style object, with all
* required properties populated.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.validatedBlockStyle_ =
function(blockStyle) {
/* eslint-disable indent */
// Make a new object with all of the same properties.
var valid = /** @type {!Blockly.Theme.BlockStyle} */ ({});
if (blockStyle) {
Blockly.utils.object.mixin(valid, blockStyle);
}
// Validate required properties.
var parsedColour = Blockly.utils.parseBlockColour(
valid['colourPrimary'] || '#000');
valid.colourPrimary = parsedColour.hex;
valid.colourSecondary = valid['colourSecondary'] ?
Blockly.utils.parseBlockColour(valid['colourSecondary']).hex :
this.generateSecondaryColour_(valid.colourPrimary);
valid.colourTertiary = valid['colourTertiary'] ?
Blockly.utils.parseBlockColour(valid['colourTertiary']).hex :
this.generateTertiaryColour_(valid.colourPrimary);
valid.hat = valid['hat'] || '';
return valid;
}; /* eslint-enable indent */
/**
* Generate a secondary colour from the passed in primary colour.
* @param {string} colour Primary colour.
* @return {string} The generated secondary colour.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.generateSecondaryColour_ =
function(colour) {
/* eslint-disable indent */
return Blockly.utils.colour.blend('#fff', colour, 0.6) || colour;
}; /* eslint-enable indent */
/**
* Generate a tertiary colour from the passed in primary colour.
* @param {string} colour Primary colour.
* @return {string} The generated tertiary colour.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.generateTertiaryColour_ =
function(colour) {
/* eslint-disable indent */
return Blockly.utils.colour.blend('#fff', colour, 0.3) || colour;
}; /* eslint-enable indent */
/**
* 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_);
}
if (this.debugFilter_) {
Blockly.utils.dom.removeNode(this.debugFilter_);
}
this.cssNode_ = null;
};
/**
* @return {!Object} An object containing sizing and path information about
* collapsed block indicators.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.makeJaggedTeeth = function() {
var height = this.JAGGED_TEETH_HEIGHT;
var width = this.JAGGED_TEETH_WIDTH;
var mainPath =
Blockly.utils.svgPaths.line(
[
Blockly.utils.svgPaths.point(width, height / 4),
Blockly.utils.svgPaths.point(-width * 2, height / 2),
Blockly.utils.svgPaths.point(width, height / 4)
]);
return {
height: height,
width: width,
path: mainPath
};
};
/**
* @return {!Object} An object containing sizing and path information about
* start hats.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.makeStartHat = function() {
var height = this.START_HAT_HEIGHT;
var width = this.START_HAT_WIDTH;
var mainPath =
Blockly.utils.svgPaths.curve('c',
[
Blockly.utils.svgPaths.point(30, -height),
Blockly.utils.svgPaths.point(70, -height),
Blockly.utils.svgPaths.point(width, 0)
]);
return {
height: height,
width: width,
path: mainPath
};
};
/**
* @return {!Object} An object containing sizing and path information about
* puzzle tabs.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.makePuzzleTab = function() {
var width = this.TAB_WIDTH;
var height = this.TAB_HEIGHT;
// The main path for the puzzle tab is made out of a few curves (c and s).
// Those curves are defined with relative positions. The 'up' and 'down'
// versions of the paths are the same, but the Y sign flips. Forward and back
// are the signs to use to move the cursor in the direction that the path is
// being drawn.
function makeMainPath(up) {
var forward = up ? -1 : 1;
var back = -forward;
var overlap = 2.5;
var halfHeight = height / 2;
var control1Y = halfHeight + overlap;
var control2Y = halfHeight + 0.5;
var control3Y = overlap; // 2.5
var endPoint1 = Blockly.utils.svgPaths.point(-width, forward * halfHeight);
var endPoint2 = Blockly.utils.svgPaths.point(width, forward * halfHeight);
return Blockly.utils.svgPaths.curve('c',
[
Blockly.utils.svgPaths.point(0, forward * control1Y),
Blockly.utils.svgPaths.point(-width, back * control2Y),
endPoint1
]) +
Blockly.utils.svgPaths.curve('s',
[
Blockly.utils.svgPaths.point(width, back * control3Y),
endPoint2
]);
}
// c 0,-10 -8,8 -8,-7.5 s 8,2.5 8,-7.5
var pathUp = makeMainPath(true);
// c 0,10 -8,-8 -8,7.5 s 8,-2.5 8,7.5
var pathDown = makeMainPath(false);
return {
type: this.SHAPES.PUZZLE,
width: width,
height: height,
pathDown: pathDown,
pathUp: pathUp
};
};
/**
* @return {!Object} An object containing sizing and path information about
* notches.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.makeNotch = function() {
var width = this.NOTCH_WIDTH;
var height = this.NOTCH_HEIGHT;
var innerWidth = 3;
var outerWidth = (width - innerWidth) / 2;
function makeMainPath(dir) {
return Blockly.utils.svgPaths.line(
[
Blockly.utils.svgPaths.point(dir * outerWidth, height),
Blockly.utils.svgPaths.point(dir * innerWidth, 0),
Blockly.utils.svgPaths.point(dir * outerWidth, -height)
]);
}
var pathLeft = makeMainPath(1);
var pathRight = makeMainPath(-1);
return {
type: this.SHAPES.NOTCH,
width: width,
height: height,
pathLeft: pathLeft,
pathRight: pathRight
};
};
/**
* @return {!Object} An object containing sizing and path information about
* inside corners.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.makeInsideCorners = function() {
var radius = this.CORNER_RADIUS;
var innerTopLeftCorner = Blockly.utils.svgPaths.arc('a', '0 0,0', radius,
Blockly.utils.svgPaths.point(-radius, radius));
var innerBottomLeftCorner = Blockly.utils.svgPaths.arc('a', '0 0,0', radius,
Blockly.utils.svgPaths.point(radius, radius));
return {
width: radius,
height: radius,
pathTop: innerTopLeftCorner,
pathBottom: innerBottomLeftCorner
};
};
/**
* @return {!Object} An object containing sizing and path information about
* outside corners.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.makeOutsideCorners = function() {
var radius = this.CORNER_RADIUS;
/**
* SVG path for drawing the rounded top-left corner.
* @const
*/
var topLeft =
Blockly.utils.svgPaths.moveBy(0, radius) +
Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
Blockly.utils.svgPaths.point(radius, -radius));
/**
* SVG path for drawing the rounded top-right corner.
* @const
*/
var topRight =
Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
Blockly.utils.svgPaths.point(radius, radius));
/**
* SVG path for drawing the rounded bottom-left corner.
* @const
*/
var bottomLeft = Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
Blockly.utils.svgPaths.point(-radius, -radius));
/**
* SVG path for drawing the rounded bottom-right corner.
* @const
*/
var bottomRight = Blockly.utils.svgPaths.arc('a', '0 0,1', radius,
Blockly.utils.svgPaths.point(-radius, radius));
return {
topLeft: topLeft,
topRight: topRight,
bottomRight: bottomRight,
bottomLeft: bottomLeft,
rightHeight: radius
};
};
/**
* Get an object with connection shape and sizing information based on the type
* of the connection.
* @param {!Blockly.RenderedConnection} connection The connection to find a
* shape object for
* @return {!Object} The shape object for the connection.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.shapeFor = function(
connection) {
switch (connection.type) {
case Blockly.INPUT_VALUE:
case Blockly.OUTPUT_VALUE:
return this.PUZZLE_TAB;
case Blockly.PREVIOUS_STATEMENT:
case Blockly.NEXT_STATEMENT:
return this.NOTCH;
default:
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.
* @param {string} tagName The name to use for the CSS style tag.
* @param {string} selector The CSS selector to use.
* @suppress {strictModuleDepCheck} Debug renderer only included in playground.
* @package
*/
Blockly.blockRendering.ConstantProvider.prototype.createDom = function(svg,
tagName, selector) {
this.injectCSS_(tagName, selector);
/*
<defs>
... filters go here ...
</defs>
*/
var defs = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.DEFS, {}, svg);
/*
<filter id="blocklyEmbossFilter837493">
<feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur" />
<feSpecularLighting in="blur" surfaceScale="1" specularConstant="0.5"
specularExponent="10" lighting-color="white"
result="specOut">
<fePointLight x="-5000" y="-10000" z="20000" />
</feSpecularLighting>
<feComposite in="specOut" in2="SourceAlpha" operator="in"
result="specOut" />
<feComposite in="SourceGraphic" in2="specOut" operator="arithmetic"
k1="0" k2="1" k3="1" k4="0" />
</filter>
*/
var embossFilter = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FILTER,
{'id': 'blocklyEmbossFilter' + this.randomIdentifier}, defs);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FEGAUSSIANBLUR,
{'in': 'SourceAlpha', 'stdDeviation': 1, 'result': 'blur'}, embossFilter);
var feSpecularLighting = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FESPECULARLIGHTING,
{
'in': 'blur',
'surfaceScale': 1,
'specularConstant': 0.5,
'specularExponent': 10,
'lighting-color': 'white',
'result': 'specOut'
},
embossFilter);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FEPOINTLIGHT,
{'x': -5000, 'y': -10000, 'z': 20000}, feSpecularLighting);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FECOMPOSITE,
{
'in': 'specOut',
'in2': 'SourceAlpha',
'operator': 'in',
'result': 'specOut'
}, embossFilter);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FECOMPOSITE,
{
'in': 'SourceGraphic',
'in2': 'specOut',
'operator': 'arithmetic',
'k1': 0,
'k2': 1,
'k3': 1,
'k4': 0
}, embossFilter);
this.embossFilterId = embossFilter.id;
this.embossFilter_ = embossFilter;
/*
<pattern id="blocklyDisabledPattern837493" patternUnits="userSpaceOnUse"
width="10" height="10">
<rect width="10" height="10" fill="#aaa" />
<path d="M 0 0 L 10 10 M 10 0 L 0 10" stroke="#cc0" />
</pattern>
*/
var disabledPattern = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.PATTERN,
{
'id': 'blocklyDisabledPattern' + this.randomIdentifier,
'patternUnits': 'userSpaceOnUse',
'width': 10,
'height': 10
}, defs);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.RECT,
{'width': 10, 'height': 10, 'fill': '#aaa'}, disabledPattern);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.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(
Blockly.utils.Svg.FILTER,
{
'id': 'blocklyDebugFilter' + this.randomIdentifier,
'height': '160%',
'width': '180%',
y: '-30%',
x: '-40%'
},
defs);
// Set all gaussian blur pixels to 1 opacity before applying flood
var debugComponentTransfer = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FECOMPONENTTRANSFER, {
'result': 'outBlur'
}, debugFilter);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.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(
Blockly.utils.Svg.FEFLOOD,
{
'flood-color': '#ff0000',
'flood-opacity': 0.5,
'result': 'outColor'
},
debugFilter);
Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.FECOMPOSITE,
{
'in': 'outColor', 'in2': 'outBlur',
'operator': 'in', 'result': 'outGlow'
},
debugFilter);
this.debugFilterId = debugFilter.id;
this.debugFilter_ = debugFilter;
}
};
/**
* Inject renderer specific CSS into the page.
* @param {string} tagName The name of the style tag to use.
* @param {string} selector The CSS selector to use.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.injectCSS_ = function(
tagName, selector) {
var cssArray = this.getCSS_(selector);
var cssNodeId = 'blockly-renderer-style-' + tagName;
this.cssNode_ =
/** @type {!HTMLStyleElement} */ (document.getElementById(cssNodeId));
var text = cssArray.join('\n');
if (this.cssNode_) {
// Already injected, update if the theme changed.
this.cssNode_.firstChild.textContent = text;
return;
}
// Inject CSS tag at start of head.
var cssNode =
/** @type {!HTMLStyleElement} */ (document.createElement('style'));
cssNode.id = cssNodeId;
var cssTextNode = document.createTextNode(text);
cssNode.appendChild(cssTextNode);
document.head.insertBefore(cssNode, document.head.firstChild);
this.cssNode_ = cssNode;
};
/**
* Get any renderer specific CSS to inject when the renderer is initialized.
* @param {string} selector CSS selector to use.
* @return {!Array.<string>} Array of CSS strings.
* @protected
*/
Blockly.blockRendering.ConstantProvider.prototype.getCSS_ = function(selector) {
return [
/* eslint-disable indent */
// Text.
selector + ' .blocklyText, ',
selector + ' .blocklyFlyoutLabelText {',
'font: ' + this.FIELD_TEXT_FONTWEIGHT + ' ' +
this.FIELD_TEXT_FONTSIZE + 'pt ' + this.FIELD_TEXT_FONTFAMILY + ';',
'}',
// Fields.
selector + ' .blocklyText {',
'fill: #fff;',
'}',
selector + ' .blocklyNonEditableText>rect,',
selector + ' .blocklyEditableText>rect {',
'fill: ' + this.FIELD_BORDER_RECT_COLOUR + ';',
'fill-opacity: .6;',
'stroke: none;',
'}',
selector + ' .blocklyNonEditableText>text,',
selector + ' .blocklyEditableText>text {',
'fill: #000;',
'}',
// Flyout labels.
selector + ' .blocklyFlyoutLabelText {',
'fill: #000;',
'}',
// Bubbles.
selector + ' .blocklyText.blocklyBubbleText {',
'fill: #000;',
'}',
// Editable field hover.
selector + ' .blocklyEditableText:not(.editing):hover>rect {',
'stroke: #fff;',
'stroke-width: 2;',
'}',
// Text field input.
selector + ' .blocklyHtmlInput {',
'font-family: ' + this.FIELD_TEXT_FONTFAMILY + ';',
'font-weight: ' + this.FIELD_TEXT_FONTWEIGHT + ';',
'}',
// Selection highlight.
selector + ' .blocklySelected>.blocklyPath {',
'stroke: #fc3;',
'stroke-width: 3px;',
'}',
// Connection highlight.
selector + ' .blocklyHighlightedConnectionPath {',
'stroke: #fc3;',
'}',
// Replaceable highlight.
selector + ' .blocklyReplaceable .blocklyPath {',
'fill-opacity: .5;',
'}',
selector + ' .blocklyReplaceable .blocklyPathLight,',
selector + ' .blocklyReplaceable .blocklyPathDark {',
'display: none;',
'}',
// Insertion marker.
selector + ' .blocklyInsertionMarker>.blocklyPath {',
'fill-opacity: ' + this.INSERTION_MARKER_OPACITY + ';',
'stroke: none;',
'}',
/* eslint-enable indent */
];
};