Reorganized field view initialization.

This commit is contained in:
Beka Westberg
2019-05-27 14:31:15 -07:00
parent d3062bae65
commit f0d6fbd192
11 changed files with 123 additions and 143 deletions

View File

@@ -235,6 +235,9 @@ Blockly.Field.prototype.init = function() {
}
this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
this.initView();
this.updateEditable();
this.setTooltip();
this.bindEvents_();
this.initModel();
};
@@ -243,26 +246,54 @@ Blockly.Field.prototype.init = function() {
* @package
*/
Blockly.Field.prototype.initView = function() {
this.createBorderRect_();
this.createTextElement_();
};
/**
* Create a field border rect element. Not to be overridden by subclasses.
* Instead modify the result of the function inside initView, or create a
* separate function to call.
* @protected
*/
Blockly.Field.prototype.createBorderRect_ = function() {
this.borderRect_ = Blockly.utils.createSvgElement('rect',
{
'rx': 4,
'ry': 4,
'x': -Blockly.BlockSvg.SEP_SPACE_X / 2,
'y': 0,
'height': 16
'height': 16,
'width': this.size_.width + Blockly.BlockSvg.SEP_SPACE_X
}, this.fieldGroup_);
};
/**
* Create a field text element. Not to be overridden by subclasses. Instead
* modify the result of the function inside initView, or create a separate
* function to call.
* @protected
*/
Blockly.Field.prototype.createTextElement_ = function() {
this.textElement_ = Blockly.utils.createSvgElement('text',
{'class': 'blocklyText', 'y': this.size_.height - 12.5},
this.fieldGroup_);
var textNode = document.createTextNode('');
this.textElement_.appendChild(textNode);
{
'class': 'blocklyText',
'y': this.size_.height - 12.5
}, this.fieldGroup_);
this.textContent_ = document.createTextNode('');
this.textElement_.appendChild(this.textContent_);
};
this.updateEditable();
this.clickTarget_ = this.getSvgRoot();
/**
* Bind events to the field. Can be overridden by subclasses if they need to do
* custom input handling.
* @protected
*/
Blockly.Field.prototype.bindEvents_ = function() {
Blockly.Tooltip.bindMouseEvents(this.getClickTarget_());
this.mouseDownWrapper_ =
Blockly.bindEventWithChecks_(
this.clickTarget_, 'mousedown', this, this.onMouseDown_);
this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
};
/**
@@ -334,6 +365,14 @@ Blockly.Field.prototype.updateEditable = function() {
}
};
/**
* Check whether this field defines the showEditor_ function.
* @return {boolean} Whether this field is clickable.
*/
Blockly.Field.prototype.isClickable = function() {
return !!this.showEditor_ && (typeof this.showEditor_ === 'function');
};
/**
* Check whether this field is currently editable. Some fields are never
* EDITABLE (e.g. text labels). Other fields may be EDITABLE but may exist on
@@ -481,7 +520,7 @@ Blockly.Field.prototype.updateColour = function() {
* @protected
*/
Blockly.Field.prototype.render_ = function() {
this.textElement_.textContent = this.getDisplayText_();
this.textContent_.nodeValue = this.getDisplayText_();
this.updateSize_();
};
@@ -806,11 +845,15 @@ Blockly.Field.prototype.onMouseDown_ = function(e) {
/**
* Change the tooltip text for this field.
* @param {string|!Element} _newTip Text for tooltip or a parent element to
* link to for its tooltip.
* @param {string|function|!Element} newTip Text for tooltip or a parent
* element to link to for its tooltip.
*/
Blockly.Field.prototype.setTooltip = function(_newTip) {
// Non-abstract sub-classes may wish to implement this. See FieldLabel.
Blockly.Field.prototype.setTooltip = function(newTip) {
if (!newTip && newTip !== '') { // If null or undefined.
this.getClickTarget_().tooltip = this.sourceBlock_;
} else {
this.getClickTarget_().tooltip = newTip;
}
};
/**

View File

@@ -126,6 +126,7 @@ Blockly.FieldAngle.prototype.initView = function() {
// Add the degree symbol to the left of the number, even in RTL (issue #2380)
this.symbol_ = Blockly.utils.createSvgElement('tspan', {}, null);
this.symbol_.appendChild(document.createTextNode('\u00B0'));
this.textElement_.appendChild(this.symbol_);
};
/**
@@ -133,9 +134,7 @@ Blockly.FieldAngle.prototype.initView = function() {
* @private
*/
Blockly.FieldAngle.prototype.render_ = function() {
this.textElement_.textContent = this.getDisplayText_();
this.textElement_.appendChild(this.symbol_);
this.updateSize_();
Blockly.FieldAngle.superClass_.render_.call(this);
this.updateGraph_();
};

View File

@@ -78,6 +78,20 @@ Blockly.FieldCheckbox.WIDTH = 5;
*/
Blockly.FieldCheckbox.CHECK_CHAR = '\u2713';
/**
* Used to correctly position the check mark.
* @type {number}
* @const
*/
Blockly.FieldCheckbox.CHECK_X_OFFSET = -3;
/**
* Used to correctly position the check mark.
* @type {number}
* @const
*/
Blockly.FieldCheckbox.CHECK_Y_OFFSET = 14;
/**
* Serializable fields are saved by the XML renderer, non-serializable fields
* are not. Editable fields should also be serializable.
@@ -107,19 +121,13 @@ Blockly.FieldCheckbox.prototype.isDirty_ = false;
Blockly.FieldCheckbox.prototype.initView = function() {
Blockly.FieldCheckbox.superClass_.initView.call(this);
// The checkbox doesn't use the inherited text element.
// Instead it uses a custom checkmark element that is either visible or not.
this.checkElement_ = Blockly.utils.createSvgElement('text',
{'class': 'blocklyText blocklyCheckbox', 'x': -3, 'y': 14},
this.fieldGroup_);
var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);
this.checkElement_.appendChild(textNode);
this.checkElement_.style.display = this.value_ ? 'block' : 'none';
this.textElement_.setAttribute('x', Blockly.FieldCheckbox.CHECK_X_OFFSET);
this.textElement_.setAttribute('y', Blockly.FieldCheckbox.CHECK_Y_OFFSET);
Blockly.utils.addClass(this.textElement_, 'blocklyCheckbox');
if (this.borderRect_) {
this.borderRect_.setAttribute('width',
this.size_.width + Blockly.BlockSvg.SEP_SPACE_X);
}
var textNode = document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR);
this.textElement_.appendChild(textNode);
this.textElement_.style.display = this.value_ ? 'block' : 'none';
};
/**
@@ -154,8 +162,8 @@ Blockly.FieldCheckbox.prototype.doClassValidation_ = function(newValue) {
Blockly.FieldCheckbox.prototype.doValueUpdate_ = function(newValue) {
this.value_ = this.convertValueToBool_(newValue);
// Update visual.
if (this.checkElement_) {
this.checkElement_.style.display = this.value_ ? 'block' : 'none';
if (this.textElement_) {
this.textElement_.style.display = this.value_ ? 'block' : 'none';
}
};

View File

@@ -153,13 +153,10 @@ Blockly.FieldColour.prototype.DROPDOWN_BACKGROUND_COLOUR = 'white';
* @package
*/
Blockly.FieldColour.prototype.initView = function() {
Blockly.FieldColour.superClass_.initView.call(this);
this.size_ = new goog.math.Size(Blockly.FieldColour.DEFAULT_WIDTH,
Blockly.FieldColour.DEFAULT_HEIGHT);
this.createBorderRect_();
this.borderRect_.style['fillOpacity'] = 1;
this.borderRect_.setAttribute('width',
this.size_.width + Blockly.BlockSvg.SEP_SPACE_X);
this.borderRect_.style.fill = this.value_;
};

View File

@@ -95,6 +95,13 @@ Blockly.FieldDropdown.CHECKMARK_OVERHANG = 25;
*/
Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH = 0.45;
/**
* Used to position the imageElement_ correctly.
* @type {number}
* @const
*/
Blockly.FieldDropdown.IMAGE_Y_OFFSET = 5;
/**
* Android can't (in 2014) display "▾", so use "▼" instead.
*/
@@ -128,11 +135,19 @@ Blockly.FieldDropdown.prototype.imageJson_ = null;
Blockly.FieldDropdown.prototype.initView = function() {
Blockly.FieldDropdown.superClass_.initView.call(this);
// Add dropdown arrow: "option ▾" (LTR) or "▾ אופציה" (RTL)
this.arrow_ = Blockly.utils.createSvgElement('tspan', {}, null);
this.arrow_.appendChild(document.createTextNode(this.sourceBlock_.RTL ?
Blockly.FieldDropdown.ARROW_CHAR + ' ' :
' ' + Blockly.FieldDropdown.ARROW_CHAR));
this.imageElement_ = Blockly.utils.createSvgElement( 'image',
{
'y': Blockly.FieldDropdown.IMAGE_Y_OFFSET
}, this.fieldGroup_);
this.arrow_ = Blockly.utils.createSvgElement('tspan', {}, this.textElement_);
this.arrow_.appendChild(document.createTextNode(
Blockly.FieldDropdown.ARROW_CHAR));
if (this.sourceBlock_.RTL) {
this.textElement_.insertBefore(this.arrow_, this.textContent_);
} else {
this.textElement_.appendChild(this.arrow_);
}
};
/**
@@ -441,15 +456,6 @@ Blockly.FieldDropdown.prototype.updateColour = function() {
* @private
*/
Blockly.FieldDropdown.prototype.render_ = function() {
var child;
while ((child = this.textElement_.firstChild)) {
this.textElement_.removeChild(child);
}
if (this.imageElement_) {
Blockly.utils.removeNode(this.imageElement_);
this.imageElement_ = null;
}
if (this.imageJson_) {
this.renderSelectedImage_();
} else {
@@ -465,20 +471,18 @@ Blockly.FieldDropdown.prototype.render_ = function() {
* @private
*/
Blockly.FieldDropdown.prototype.renderSelectedImage_ = function() {
// Image option is selected.
this.imageElement_ = Blockly.utils.createSvgElement('image',
{
'y': 5,
'height': this.imageJson_.height + 'px',
'width': this.imageJson_.width + 'px'
}, this.fieldGroup_);
this.imageElement_.setAttributeNS(
'http://www.w3.org/1999/xlink', 'xlink:href', this.imageJson_.src);
// Insert dropdown arrow.
this.textElement_.appendChild(this.arrow_);
this.imageElement_.setAttribute('height', this.imageJson_.height);
this.imageElement_.setAttribute('width', this.imageJson_.width);
var arrowWidth = Blockly.Field.getCachedWidth(this.arrow_);
// TODO: Standardize sizing, need to talk to rachel and abby about rendering
// redux.
// I think really this means plus 10?
this.size_.height = Number(this.imageJson_.height) + 19;
this.size_.width = Number(this.imageJson_.width) + arrowWidth;
if (this.sourceBlock_.RTL) {
this.imageElement_.setAttribute('x', arrowWidth);
this.textElement_.setAttribute('x', -1);
@@ -493,19 +497,9 @@ Blockly.FieldDropdown.prototype.renderSelectedImage_ = function() {
* @private
*/
Blockly.FieldDropdown.prototype.renderSelectedText_ = function() {
// Text option is selected.
// Replace the text.
var textNode = document.createTextNode(this.getDisplayText_());
this.textElement_.appendChild(textNode);
// Insert dropdown arrow.
if (this.sourceBlock_.RTL) {
this.textElement_.insertBefore(this.arrow_, this.textElement_.firstChild);
} else {
this.textElement_.appendChild(this.arrow_);
}
this.textContent_.nodeValue = this.getDisplayText_();
this.textElement_.setAttribute('text-anchor', 'start');
this.textElement_.setAttribute('x', 0);
this.size_.height = Blockly.BlockSvg.MIN_BLOCK_Y;
this.size_.width = Blockly.Field.getCachedWidth(this.textElement_);
};

View File

@@ -66,7 +66,6 @@ Blockly.FieldImage = function(src, width, height,
this.height_ + 2 * Blockly.BlockSvg.INLINE_PADDING_Y);
this.flipRtl_ = opt_flipRtl;
this.tooltip_ = '';
this.text_ = opt_alt || '';
this.setValue(src || '');
@@ -127,17 +126,6 @@ Blockly.FieldImage.prototype.initView = function() {
this.fieldGroup_);
this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink',
'xlink:href', this.value_);
this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);
if (this.tooltip_) {
this.imageElement_.tooltip = this.tooltip_;
} else {
// Configure the field to be transparent with respect to tooltips.
this.setTooltip(this.sourceBlock_);
}
Blockly.Tooltip.bindMouseEvents(this.imageElement_);
this.maybeAddClickHandler_();
};
/**
@@ -151,31 +139,6 @@ Blockly.FieldImage.prototype.dispose = function() {
this.imageElement_ = null;
};
/**
* Bind events for a mouse down on the image, but only if a click handler has
* been defined.
* @private
*/
Blockly.FieldImage.prototype.maybeAddClickHandler_ = function() {
if (this.clickHandler_) {
this.mouseDownWrapper_ =
Blockly.bindEventWithChecks_(
this.fieldGroup_, 'mousedown', this, this.clickHandler_);
}
};
/**
* Change the tooltip text for this field.
* @param {string|!Element} newTip Text for tooltip or a parent element to
* link to for its tooltip.
*/
Blockly.FieldImage.prototype.setTooltip = function(newTip) {
this.tooltip_ = newTip;
if (this.imageElement_) {
this.imageElement_.tooltip = newTip;
}
};
/**
* Ensure that the input value (the source URL) is a string.
* @param {string=} newValue The input value

View File

@@ -50,7 +50,6 @@ Blockly.FieldLabel = function(opt_value, opt_class) {
opt_value = '';
}
this.setValue(opt_value);
this.tooltip_ = '';
};
goog.inherits(Blockly.FieldLabel, Blockly.Field);
@@ -80,24 +79,11 @@ Blockly.FieldLabel.prototype.EDITABLE = false;
* @package
*/
Blockly.FieldLabel.prototype.initView = function() {
this.textElement_ = Blockly.utils.createSvgElement('text',
{
'class': 'blocklyText',
'y': this.size_.height - 5
}, this.fieldGroup_);
var textNode = document.createTextNode('');
this.textElement_.appendChild(textNode);
this.createTextElement_();
this.textElement_.setAttribute('y', this.size_.height - 5);
if (this.class_) {
Blockly.utils.addClass(this.textElement_, this.class_);
}
if (this.tooltip_) {
this.textElement_.tooltip = this.tooltip_;
} else {
// Configure the field to be transparent with respect to tooltips.
this.textElement_.tooltip = this.sourceBlock_;
}
Blockly.Tooltip.bindMouseEvents(this.textElement_);
};
/**
@@ -123,16 +109,4 @@ Blockly.FieldLabel.prototype.doClassValidation_ = function(newValue) {
return String(newValue);
};
/**
* Change the tooltip text for this field.
* @param {string|!Element} newTip Text for tooltip or a parent element to
* link to for its tooltip.
*/
Blockly.FieldLabel.prototype.setTooltip = function(newTip) {
this.tooltip_ = newTip;
if (this.textElement_) {
this.textElement_.tooltip = newTip;
}
};
Blockly.Field.register('field_label', Blockly.FieldLabel);

View File

@@ -263,7 +263,7 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
}
// Bind events.
this.bindEvents_(htmlInput);
this.bindInputEvents_(htmlInput);
// Save it.
Blockly.FieldTextInput.htmlInput_ = htmlInput;
@@ -275,7 +275,7 @@ Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
* which event handlers will be bound.
* @private
*/
Blockly.FieldTextInput.prototype.bindEvents_ = function(htmlInput) {
Blockly.FieldTextInput.prototype.bindInputEvents_ = function(htmlInput) {
// Bind to keydown -- trap Enter without IME and Esc to hide.
htmlInput.onKeyDownWrapper_ =
Blockly.bindEventWithChecks_(
@@ -297,7 +297,7 @@ Blockly.FieldTextInput.prototype.bindEvents_ = function(htmlInput) {
* @param {!HTMLInputElement} htmlInput The html for this text input.
* @private
*/
Blockly.FieldTextInput.prototype.unbindEvents_ = function(htmlInput) {
Blockly.FieldTextInput.prototype.unbindInputEvents_ = function(htmlInput) {
Blockly.unbindEvent_(htmlInput.onKeyDownWrapper_);
Blockly.unbindEvent_(htmlInput.onKeyUpWrapper_);
Blockly.unbindEvent_(htmlInput.onKeyPressWrapper_);
@@ -413,7 +413,7 @@ Blockly.FieldTextInput.prototype.widgetDispose_ = function() {
}
// Remove htmlInput.
thisField.unbindEvents_(htmlInput);
thisField.unbindInputEvents_(htmlInput);
Blockly.FieldTextInput.htmlInput_ = null;
// Delete style properties.

View File

@@ -899,10 +899,10 @@ Blockly.Gesture.prototype.isBlockClick_ = function() {
* @private
*/
Blockly.Gesture.prototype.isFieldClick_ = function() {
var fieldEditable = this.startField_ ?
this.startField_.isCurrentlyEditable() : false;
return fieldEditable && !this.hasExceededDragRadius_ && (!this.flyout_ ||
!this.flyout_.autoClose);
var fieldClickable = this.startField_ ?
this.startField_.isClickable() : false;
return fieldClickable && !this.hasExceededDragRadius_ &&
(!this.flyout_ || !this.flyout_.autoClose);
};
/**

View File

@@ -165,7 +165,7 @@ Blockly.Tooltip.onMouseOver_ = function(e) {
}
// If the tooltip is an object, treat it as a pointer to the next object in
// the chain to look at. Terminate when a string or function is found.
var element = e.target;
var element = e.currentTarget;
while ((typeof element.tooltip != 'string') &&
(typeof element.tooltip != 'function')) {
element = element.tooltip;

View File

@@ -49,6 +49,7 @@ function test_gestureIsField_ClickInWorkspace() {
var block = new Blockly.Block(workspace);
var field = new Blockly.Field();
field.setSourceBlock(block);
field.showEditor_ = function() {};
var gesture = new Blockly.Gesture(e, workspace);
gesture.setStartField(field);
@@ -64,6 +65,7 @@ function gestureIsFieldClick_InFlyoutHelper(flyout, expectedResult){
var block = new Blockly.Block(workspace);
var field = new Blockly.Field();
field.setSourceBlock(block);
field.showEditor_ = function() {};
// Create gesture from the flyout
var gesture = new Blockly.Gesture(e, workspace.flyout_);
// Populate gesture with click start information