mirror of
https://github.com/google/blockly.git
synced 2026-01-09 18:10:08 +01:00
Add arrow to images in dropdown menus. Fold updateTextNode_ into render_.
This commit is contained in:
125
core/field.js
125
core/field.js
@@ -156,7 +156,7 @@ Blockly.Field.prototype.init = function() {
|
||||
Blockly.bindEventWithChecks_(this.fieldGroup_, 'mouseup', this,
|
||||
this.onMouseUp_);
|
||||
// Force a render.
|
||||
this.updateTextNode_();
|
||||
this.render_();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -285,33 +285,48 @@ Blockly.Field.prototype.getSvgRoot = function() {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Field.prototype.render_ = function() {
|
||||
if (this.visible_ && this.textElement_) {
|
||||
var key = this.textElement_.textContent + '\n' +
|
||||
this.textElement_.className.baseVal;
|
||||
if (Blockly.Field.cacheWidths_ && Blockly.Field.cacheWidths_[key]) {
|
||||
var width = Blockly.Field.cacheWidths_[key];
|
||||
} else {
|
||||
try {
|
||||
var width = this.textElement_.getComputedTextLength();
|
||||
} catch (e) {
|
||||
// MSIE 11 is known to throw "Unexpected call to method or property
|
||||
// access." if Blockly is hidden.
|
||||
var width = this.textElement_.textContent.length * 8;
|
||||
}
|
||||
if (Blockly.Field.cacheWidths_) {
|
||||
Blockly.Field.cacheWidths_[key] = width;
|
||||
}
|
||||
}
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.setAttribute('width',
|
||||
width + Blockly.BlockSvg.SEP_SPACE_X);
|
||||
}
|
||||
} else {
|
||||
var width = 0;
|
||||
if (!this.visible_) {
|
||||
this.size_.width = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace the text.
|
||||
goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
|
||||
var textNode = document.createTextNode(this.getDisplayText_());
|
||||
this.textElement_.appendChild(textNode);
|
||||
|
||||
var width = Blockly.Field.getCachedWidth(this.textElement_);
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.setAttribute('width',
|
||||
width + Blockly.BlockSvg.SEP_SPACE_X);
|
||||
}
|
||||
this.size_.width = width;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the width of a text element, caching it in the process.
|
||||
* @param {!Element} textElement An SVG 'text' element.
|
||||
* @retur {number} Width of element.
|
||||
*/
|
||||
Blockly.Field.getCachedWidth = function(textElement) {
|
||||
var key = textElement.textContent + '\n' + textElement.className.baseVal;
|
||||
if (Blockly.Field.cacheWidths_ && Blockly.Field.cacheWidths_[key]) {
|
||||
var width = Blockly.Field.cacheWidths_[key];
|
||||
} else {
|
||||
try {
|
||||
var width = textElement.getComputedTextLength();
|
||||
} catch (e) {
|
||||
// MSIE 11 is known to throw "Unexpected call to method or property
|
||||
// access." if Blockly is hidden.
|
||||
var width = textElement.textContent.length * 8;
|
||||
}
|
||||
if (Blockly.Field.cacheWidths_) {
|
||||
Blockly.Field.cacheWidths_[key] = width;
|
||||
}
|
||||
}
|
||||
return width;
|
||||
};
|
||||
|
||||
/**
|
||||
* Start caching field widths. Every call to this function MUST also call
|
||||
* stopCache. Caches must not survive between execution threads.
|
||||
@@ -358,6 +373,31 @@ Blockly.Field.prototype.getScaledBBox_ = function() {
|
||||
bBox.height * this.sourceBlock_.workspace.scale);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text from this field as displayed on screen. May differ from getText
|
||||
* due to ellipsis, and other formatting.
|
||||
* @return {string} Currently displayed text.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Field.prototype.getDisplayText_ = function() {
|
||||
var text = this.text_;
|
||||
if (!text) {
|
||||
// Prevent the field from disappearing if empty.
|
||||
return Blockly.Field.NBSP;
|
||||
}
|
||||
if (text.length > this.maxDisplayLength) {
|
||||
// Truncate displayed string and add an ellipsis ('...').
|
||||
text = text.substring(0, this.maxDisplayLength - 2) + '\u2026';
|
||||
}
|
||||
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
||||
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
||||
if (this.sourceBlock_.RTL) {
|
||||
// The SVG is LTR, force text to be RTL.
|
||||
text += '\u200F';
|
||||
}
|
||||
return text;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the text from this field.
|
||||
* @return {string} Current text.
|
||||
@@ -381,7 +421,8 @@ Blockly.Field.prototype.setText = function(text) {
|
||||
return;
|
||||
}
|
||||
this.text_ = text;
|
||||
this.updateTextNode_();
|
||||
// Set width to 0 to force a rerender of this field.
|
||||
this.size_.width = 0;
|
||||
|
||||
if (this.sourceBlock_ && this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_.render();
|
||||
@@ -389,40 +430,6 @@ Blockly.Field.prototype.setText = function(text) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the text node of this field to display the current text.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Field.prototype.updateTextNode_ = function() {
|
||||
if (!this.textElement_) {
|
||||
// Not rendered yet.
|
||||
return;
|
||||
}
|
||||
var text = this.text_;
|
||||
if (text.length > this.maxDisplayLength) {
|
||||
// Truncate displayed string and add an ellipsis ('...').
|
||||
text = text.substring(0, this.maxDisplayLength - 2) + '\u2026';
|
||||
}
|
||||
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
|
||||
text = text.replace(/\s/g, Blockly.Field.NBSP);
|
||||
if (this.sourceBlock_.RTL && text) {
|
||||
// The SVG is LTR, force text to be RTL.
|
||||
text += '\u200F';
|
||||
}
|
||||
if (!text) {
|
||||
// Prevent the field from disappearing if empty.
|
||||
text = Blockly.Field.NBSP;
|
||||
}
|
||||
|
||||
// Replace the text.
|
||||
goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
|
||||
var textNode = document.createTextNode(text);
|
||||
this.textElement_.appendChild(textNode);
|
||||
|
||||
// Cached width is obsolete. Clear it.
|
||||
this.size_.width = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* By default there is no difference between the human-readable text and
|
||||
* the language-neutral values. Subclasses (such as dropdown) may define this.
|
||||
|
||||
@@ -319,19 +319,11 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) {
|
||||
// Options are tuples of human-readable text and language-neutral values.
|
||||
if (options[i][1] == newValue) {
|
||||
var content = options[i][0];
|
||||
goog.dom.removeNode(this.imageElement_);
|
||||
if (typeof content == 'object') {
|
||||
this.imageJson_ = content;
|
||||
this.imageElement_ = Blockly.createSvgElement('image',
|
||||
{'y': 5,
|
||||
'height': content.height + 'px',
|
||||
'width': content.width + 'px'}, this.fieldGroup_);
|
||||
this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink',
|
||||
'xlink:href', content.src);
|
||||
this.setText(content.alt);
|
||||
} else {
|
||||
this.imageJson_ = null;
|
||||
this.imageElement_ = null;
|
||||
this.setText(content);
|
||||
}
|
||||
return;
|
||||
@@ -343,64 +335,63 @@ Blockly.FieldDropdown.prototype.setValue = function(newValue) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the text in this field. Trigger a rerender of the source block.
|
||||
* @param {?string} text New text.
|
||||
* Draws the border with the correct width.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.setText = function(text) {
|
||||
Blockly.FieldDropdown.prototype.render_ = function() {
|
||||
if (!this.visible_) {
|
||||
this.size_.width = 0;
|
||||
return;
|
||||
}
|
||||
if (this.sourceBlock_ && this.arrow_) {
|
||||
// Update arrow's colour.
|
||||
this.arrow_.style.fill = this.sourceBlock_.getColour();
|
||||
}
|
||||
if (text === null) {
|
||||
// No change if null.
|
||||
return;
|
||||
}
|
||||
this.text_ = text;
|
||||
if (this.imageJson_) {
|
||||
if (this.textElement_) {
|
||||
this.textElement_.style.display = 'none';
|
||||
}
|
||||
this.size_.height = Number(this.imageJson_.height) + 19;
|
||||
this.render_();
|
||||
} else {
|
||||
if (this.textElement_) {
|
||||
this.textElement_.style.display = 'block';
|
||||
}
|
||||
this.size_.height = Blockly.BlockSvg.MIN_BLOCK_Y;
|
||||
this.updateTextNode_();
|
||||
}
|
||||
// Unlike other editable fields, a dropdown can change height.
|
||||
if (this.borderRect_) {
|
||||
this.borderRect_.setAttribute('height', this.size_.height - 9);
|
||||
}
|
||||
goog.dom.removeChildren(/** @type {!Element} */ (this.textElement_));
|
||||
goog.dom.removeNode(this.imageElement_);
|
||||
this.imageElement_ = null;
|
||||
|
||||
if (this.textElement_) {
|
||||
if (this.imageJson_) {
|
||||
// Image option is selected.
|
||||
this.imageElement_ = Blockly.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_);
|
||||
var arrowWidth = Blockly.Field.getCachedWidth(this.arrow_);
|
||||
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);
|
||||
} else {
|
||||
this.textElement_.setAttribute('text-anchor', 'end');
|
||||
this.textElement_.setAttribute('x', this.size_.width + 1);
|
||||
}
|
||||
|
||||
} else {
|
||||
// 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.textElement_.setAttribute('text-anchor', 'start');
|
||||
this.textElement_.setAttribute('x', 0);
|
||||
|
||||
if (this.sourceBlock_ && this.sourceBlock_.rendered) {
|
||||
this.sourceBlock_.render();
|
||||
this.sourceBlock_.bumpNeighbours_();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws the border with the correct width.
|
||||
* @private
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.render_ = function() {
|
||||
if (!this.imageJson_) {
|
||||
Blockly.FieldDropdown.superClass_.render_.call(this);
|
||||
} else if (this.visible_ && this.borderRect_) {
|
||||
this.size_.width = Number(this.imageJson_.width);
|
||||
this.borderRect_.setAttribute('width',
|
||||
this.size_.width + Blockly.BlockSvg.SEP_SPACE_X);
|
||||
this.size_.height = Blockly.BlockSvg.MIN_BLOCK_Y;
|
||||
this.size_.width = Blockly.Field.getCachedWidth(this.textElement_);
|
||||
}
|
||||
this.borderRect_.setAttribute('height', this.size_.height - 9);
|
||||
this.borderRect_.setAttribute('width',
|
||||
this.size_.width + Blockly.BlockSvg.SEP_SPACE_X);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,7 +74,7 @@ Blockly.FieldLabel.prototype.init = function() {
|
||||
this.textElement_.tooltip = this.sourceBlock_;
|
||||
Blockly.Tooltip.bindMouseEvents(this.textElement_);
|
||||
// Force a render.
|
||||
this.updateTextNode_();
|
||||
this.render_();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user