Add arrow to images in dropdown menus. Fold updateTextNode_ into render_.

This commit is contained in:
Neil Fraser
2016-11-06 21:19:07 -08:00
parent 98c341bcfb
commit 01ab0b4ab6
3 changed files with 110 additions and 112 deletions

View File

@@ -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.

View File

@@ -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);
};
/**

View File

@@ -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_();
};
/**