Files
blockly/core/flyout_button.js
2016-12-08 13:05:19 -08:00

236 lines
6.3 KiB
JavaScript

/**
* @license
* Visual Blocks Editor
*
* Copyright 2016 Google Inc.
* https://developers.google.com/blockly/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Class for a button in the flyout.
* @author fenichel@google.com (Rachel Fenichel)
*/
'use strict';
goog.provide('Blockly.FlyoutButton');
goog.require('goog.dom');
goog.require('goog.math.Coordinate');
/**
* 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 {!Element} xml The XML specifying the label/button.
* @param {boolean} isLabel Whether this button should be styled as a label.
* @constructor
*/
Blockly.FlyoutButton = function(workspace, targetWorkspace, xml, isLabel) {
// Labels behave the same as buttons, but are styled differently.
/**
* @type {!Blockly.WorkspaceSvg}
* @private
*/
this.workspace_ = workspace;
/**
* @type {!Blockly.Workspace}
* @private
*/
this.targetWorkspace_ = targetWorkspace;
/**
* @type {string}
* @private
*/
this.text_ = xml.getAttribute('text');
/**
* @type {!goog.math.Coordinate}
* @private
*/
this.position_ = new goog.math.Coordinate(0, 0);
/**
* Whether this button should be styled as a label.
* @type {boolean}
* @private
*/
this.isLabel_ = isLabel;
/**
* Function to call when this button is clicked.
* @type {function(!Blockly.FlyoutButton)}
* @private
*/
this.callback_ = null;
var callbackKey = xml.getAttribute('callbackKey');
if (this.isLabel_ && callbackKey) {
console.warn('Labels should not have callbacks. Label text: ' + this.text_);
} else if (!this.isLabel_ &&
!(callbackKey && targetWorkspace.getButtonCallback(callbackKey))) {
console.warn('Buttons should have callbacks. Button text: ' + this.text_);
} else {
this.callback_ = targetWorkspace.getButtonCallback(callbackKey);
}
/**
* If specified, a CSS class to add to this button.
* @type {?string}
* @private
*/
this.cssClass_ = xml.getAttribute('web-class') || null;
};
/**
* The margin around the text in the button.
*/
Blockly.FlyoutButton.MARGIN = 5;
/**
* 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 {!Element} 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.createSvgElement('g', {'class': cssClass},
this.workspace_.getCanvas());
if (!this.isLabel_) {
// Shadow rectangle (light source does not mirror in RTL).
var shadow = Blockly.utils.createSvgElement('rect',
{'class': 'blocklyFlyoutButtonShadow',
'rx': 4, 'ry': 4, 'x': 1, 'y': 1},
this.svgGroup_);
}
// Background rectangle.
var rect = Blockly.utils.createSvgElement('rect',
{'class': this.isLabel_ ?
'blocklyFlyoutLabelBackground' : 'blocklyFlyoutButtonBackground',
'rx': 4, 'ry': 4},
this.svgGroup_);
var svgText = Blockly.utils.createSvgElement('text',
{'class': this.isLabel_ ? 'blocklyFlyoutLabelText' : 'blocklyText',
'x': 0, 'y': 0, 'text-anchor': 'middle'},
this.svgGroup_);
svgText.textContent = this.text_;
this.width = svgText.getComputedTextLength() +
2 * Blockly.FlyoutButton.MARGIN;
this.height = 20; // Can't compute it :(
if (!this.isLabel_) {
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 - Blockly.FlyoutButton.MARGIN);
this.updateTransform_();
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_();
};
/**
* 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.svgGroup_) {
goog.dom.removeNode(this.svgGroup_);
this.svgGroup_ = null;
}
this.workspace_ = null;
this.targetWorkspace_ = null;
};
/**
* Do something when the button is clicked.
* @param {!Event} e Mouse up event.
*/
Blockly.FlyoutButton.prototype.onMouseUp = function(e) {
// Don't scroll the page.
e.preventDefault();
// Don't propagate mousewheel event (zooming).
e.stopPropagation();
// Stop binding to mouseup and mousemove events--flyout mouseup would normally
// do this, but we're skipping that.
Blockly.Flyout.terminateDrag_();
// Call the callback registered to this button.
if (this.callback_) {
this.callback_(this);
}
};