mirror of
https://github.com/google/blockly.git
synced 2026-01-07 17:10:11 +01:00
* Encapsulate type in a generic to automatically derive type of SVG element when using createSvgElement
305 lines
7.8 KiB
JavaScript
305 lines
7.8 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Class for a button in the flyout.
|
|
* @author fenichel@google.com (Rachel Fenichel)
|
|
*/
|
|
'use strict';
|
|
|
|
goog.provide('Blockly.FlyoutButton');
|
|
|
|
goog.require('Blockly.Css');
|
|
goog.require('Blockly.utils');
|
|
goog.require('Blockly.utils.Coordinate');
|
|
goog.require('Blockly.utils.dom');
|
|
|
|
|
|
/**
|
|
* Class for a button in the flyout.
|
|
* @param {!Blockly.WorkspaceSvg} workspace The workspace in which to place this
|
|
* button.
|
|
* @param {!Blockly.WorkspaceSvg} targetWorkspace The flyout's target workspace.
|
|
* @param {!Blockly.utils.toolbox.Button|!Blockly.utils.toolbox.Label} json
|
|
* The JSON specifying the label/button.
|
|
* @param {boolean} isLabel Whether this button should be styled as a label.
|
|
* @constructor
|
|
* @package
|
|
*/
|
|
Blockly.FlyoutButton = function(workspace, targetWorkspace, json, isLabel) {
|
|
// Labels behave the same as buttons, but are styled differently.
|
|
|
|
/**
|
|
* @type {!Blockly.WorkspaceSvg}
|
|
* @private
|
|
*/
|
|
this.workspace_ = workspace;
|
|
|
|
/**
|
|
* @type {!Blockly.WorkspaceSvg}
|
|
* @private
|
|
*/
|
|
this.targetWorkspace_ = targetWorkspace;
|
|
|
|
/**
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
this.text_ = json['text'];
|
|
|
|
/**
|
|
* @type {!Blockly.utils.Coordinate}
|
|
* @private
|
|
*/
|
|
this.position_ = new Blockly.utils.Coordinate(0, 0);
|
|
|
|
/**
|
|
* Whether this button should be styled as a label.
|
|
* @type {boolean}
|
|
* @private
|
|
*/
|
|
this.isLabel_ = isLabel;
|
|
|
|
/**
|
|
* The key to the function called when this button is clicked.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
this.callbackKey_ = json['callbackKey'] ||
|
|
/* Check the lower case version too to satisfy IE */
|
|
json['callbackkey'];
|
|
|
|
/**
|
|
* If specified, a CSS class to add to this button.
|
|
* @type {?string}
|
|
* @private
|
|
*/
|
|
this.cssClass_ = json['web-class'] || null;
|
|
|
|
/**
|
|
* Mouse up event data.
|
|
* @type {?Blockly.EventData}
|
|
* @private
|
|
*/
|
|
this.onMouseUpWrapper_ = null;
|
|
};
|
|
|
|
/**
|
|
* The horizontal margin around the text in the button.
|
|
*/
|
|
Blockly.FlyoutButton.MARGIN_X = 5;
|
|
|
|
/**
|
|
* The vertical margin around the text in the button.
|
|
*/
|
|
Blockly.FlyoutButton.MARGIN_Y = 2;
|
|
|
|
/**
|
|
* The width of the button's rect.
|
|
* @type {number}
|
|
*/
|
|
Blockly.FlyoutButton.prototype.width = 0;
|
|
|
|
/**
|
|
* The height of the button's rect.
|
|
* @type {number}
|
|
*/
|
|
Blockly.FlyoutButton.prototype.height = 0;
|
|
|
|
/**
|
|
* Create the button elements.
|
|
* @return {!SVGElement} The button's SVG group.
|
|
*/
|
|
Blockly.FlyoutButton.prototype.createDom = function() {
|
|
var cssClass = this.isLabel_ ? 'blocklyFlyoutLabel' : 'blocklyFlyoutButton';
|
|
if (this.cssClass_) {
|
|
cssClass += ' ' + this.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(
|
|
Blockly.utils.dom.SvgElementType.RECT,
|
|
{
|
|
'class': 'blocklyFlyoutButtonShadow',
|
|
'rx': 4, 'ry': 4, 'x': 1, 'y': 1
|
|
},
|
|
this.svgGroup_);
|
|
}
|
|
// Background rectangle.
|
|
var rect = Blockly.utils.dom.createSvgElement(
|
|
Blockly.utils.dom.SvgElementType.RECT,
|
|
{
|
|
'class': this.isLabel_ ?
|
|
'blocklyFlyoutLabelBackground' : 'blocklyFlyoutButtonBackground',
|
|
'rx': 4, 'ry': 4
|
|
},
|
|
this.svgGroup_);
|
|
|
|
var svgText = Blockly.utils.dom.createSvgElement(
|
|
Blockly.utils.dom.SvgElementType.TEXT,
|
|
{
|
|
'class': this.isLabel_ ? 'blocklyFlyoutLabelText' : 'blocklyText',
|
|
'x': 0,
|
|
'y': 0,
|
|
'text-anchor': 'middle'
|
|
},
|
|
this.svgGroup_);
|
|
var text = Blockly.utils.replaceMessageReferences(this.text_);
|
|
if (this.workspace_.RTL) {
|
|
// Force text to be RTL by adding an RLM.
|
|
text += '\u200F';
|
|
}
|
|
svgText.textContent = text;
|
|
if (this.isLabel_) {
|
|
this.svgText_ = svgText;
|
|
this.workspace_.getThemeManager().subscribe(this.svgText_,
|
|
'flyoutForegroundColour', 'fill');
|
|
}
|
|
|
|
var fontSize = Blockly.utils.style.getComputedStyle(svgText, 'fontSize');
|
|
var fontWeight = Blockly.utils.style.getComputedStyle(svgText, 'fontWeight');
|
|
var fontFamily = Blockly.utils.style.getComputedStyle(svgText, 'fontFamily');
|
|
this.width = Blockly.utils.dom.getFastTextWidthWithSizeString(svgText,
|
|
fontSize, fontWeight, fontFamily);
|
|
var fontMetrics = Blockly.utils.dom.measureFontMetrics(text, fontSize,
|
|
fontWeight, fontFamily);
|
|
this.height = fontMetrics.height;
|
|
|
|
if (!this.isLabel_) {
|
|
this.width += 2 * Blockly.FlyoutButton.MARGIN_X;
|
|
this.height += 2 * Blockly.FlyoutButton.MARGIN_Y;
|
|
shadow.setAttribute('width', this.width);
|
|
shadow.setAttribute('height', this.height);
|
|
}
|
|
rect.setAttribute('width', this.width);
|
|
rect.setAttribute('height', this.height);
|
|
|
|
svgText.setAttribute('x', this.width / 2);
|
|
svgText.setAttribute('y', this.height / 2 - fontMetrics.height / 2 +
|
|
fontMetrics.baseline);
|
|
|
|
this.updateTransform_();
|
|
|
|
this.onMouseUpWrapper_ = Blockly.bindEventWithChecks_(
|
|
this.svgGroup_, 'mouseup', this, this.onMouseUp_);
|
|
return this.svgGroup_;
|
|
};
|
|
|
|
/**
|
|
* Correctly position the flyout button and make it visible.
|
|
*/
|
|
Blockly.FlyoutButton.prototype.show = function() {
|
|
this.updateTransform_();
|
|
this.svgGroup_.setAttribute('display', 'block');
|
|
};
|
|
|
|
/**
|
|
* Update SVG attributes to match internal state.
|
|
* @private
|
|
*/
|
|
Blockly.FlyoutButton.prototype.updateTransform_ = function() {
|
|
this.svgGroup_.setAttribute('transform',
|
|
'translate(' + this.position_.x + ',' + this.position_.y + ')');
|
|
};
|
|
|
|
/**
|
|
* Move the button to the given x, y coordinates.
|
|
* @param {number} x The new x coordinate.
|
|
* @param {number} y The new y coordinate.
|
|
*/
|
|
Blockly.FlyoutButton.prototype.moveTo = function(x, y) {
|
|
this.position_.x = x;
|
|
this.position_.y = y;
|
|
this.updateTransform_();
|
|
};
|
|
|
|
/**
|
|
* Location of the button.
|
|
* @return {!Blockly.utils.Coordinate} x, y coordinates.
|
|
* @package
|
|
*/
|
|
Blockly.FlyoutButton.prototype.getPosition = function() {
|
|
return this.position_;
|
|
};
|
|
|
|
/**
|
|
* Get the button's target workspace.
|
|
* @return {!Blockly.WorkspaceSvg} The target workspace of the flyout where this
|
|
* button resides.
|
|
*/
|
|
Blockly.FlyoutButton.prototype.getTargetWorkspace = function() {
|
|
return this.targetWorkspace_;
|
|
};
|
|
|
|
/**
|
|
* Dispose of this button.
|
|
*/
|
|
Blockly.FlyoutButton.prototype.dispose = function() {
|
|
if (this.onMouseUpWrapper_) {
|
|
Blockly.unbindEvent_(this.onMouseUpWrapper_);
|
|
}
|
|
if (this.svgGroup_) {
|
|
Blockly.utils.dom.removeNode(this.svgGroup_);
|
|
}
|
|
if (this.svgText_) {
|
|
this.workspace_.getThemeManager().unsubscribe(this.svgText_);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Do something when the button is clicked.
|
|
* @param {!Event} e Mouse up event.
|
|
* @private
|
|
*/
|
|
Blockly.FlyoutButton.prototype.onMouseUp_ = function(e) {
|
|
var gesture = this.targetWorkspace_.getGesture(e);
|
|
if (gesture) {
|
|
gesture.cancel();
|
|
}
|
|
|
|
if (this.isLabel_ && this.callbackKey_) {
|
|
console.warn('Labels should not have callbacks. Label text: ' + this.text_);
|
|
} else if (!this.isLabel_ && !(this.callbackKey_ &&
|
|
this.targetWorkspace_.getButtonCallback(this.callbackKey_))) {
|
|
console.warn('Buttons should have callbacks. Button text: ' + this.text_);
|
|
} else if (!this.isLabel_) {
|
|
this.targetWorkspace_.getButtonCallback(this.callbackKey_)(this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* CSS for buttons and labels. See css.js for use.
|
|
*/
|
|
Blockly.Css.register([
|
|
/* eslint-disable indent */
|
|
'.blocklyFlyoutButton {',
|
|
'fill: #888;',
|
|
'cursor: default;',
|
|
'}',
|
|
|
|
'.blocklyFlyoutButtonShadow {',
|
|
'fill: #666;',
|
|
'}',
|
|
|
|
'.blocklyFlyoutButton:hover {',
|
|
'fill: #aaa;',
|
|
'}',
|
|
|
|
'.blocklyFlyoutLabel {',
|
|
'cursor: default;',
|
|
'}',
|
|
|
|
'.blocklyFlyoutLabelBackground {',
|
|
'opacity: 0;',
|
|
'}',
|
|
/* eslint-enable indent */
|
|
]);
|