Added maxLines config option to MultilineInput (#4477)

* Added maxLines config option

* Made maxLines_ protected

* Added parentheses

* fontsize fix

* Enabled scrollbars at overflow of y axis

* Added ellipsis handling for overflow Y

* Deleted unused variable

* Added an explanation comment
This commit is contained in:
Gagik Papikyan
2021-01-08 00:53:51 +03:00
committed by GitHub
parent edebb58483
commit e4decd8f08

View File

@@ -51,10 +51,33 @@ Blockly.FieldMultilineInput = function(opt_value, opt_validator, opt_config) {
* @type {SVGGElement}
*/
this.textGroup_ = null;
/**
* Defines the maximum number of lines of field.
* If exceeded, scrolling functionality is enabled.
* @type {number}
* @protected
*/
this.maxLines_ = Infinity;
/**
* Whether Y overflow is currently occuring.
* @type {boolean}
* @protected
*/
this.isOverflowedY_ = false;
};
Blockly.utils.object.inherits(Blockly.FieldMultilineInput,
Blockly.FieldTextInput);
/**
* @override
*/
Blockly.FieldMultilineInput.prototype.configure_ = function(config) {
Blockly.FieldMultilineInput.superClass_.configure_.call(this, config);
config.maxLines && this.setMaxLines(config.maxLines);
};
/**
* Construct a FieldMultilineInput from a JSON arg object,
* dereferencing any string table references.
@@ -121,17 +144,20 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
}
var lines = textLines.split('\n');
textLines = '';
for (var i = 0; i < lines.length; i++) {
var displayLinesNumber = this.isOverflowedY_ ? this.maxLines_ : lines.length;
for (var i = 0; i < displayLinesNumber; i++) {
var text = lines[i];
if (text.length > this.maxDisplayLength) {
// Truncate displayed string and add an ellipsis ('...').
text = text.substring(0, this.maxDisplayLength - 4) + '...';
} else if (this.isOverflowedY_ && i === displayLinesNumber - 1) {
text = text.substring(0, text.length - 3) + '...';
}
// Replace whitespace with non-breaking spaces so the text doesn't collapse.
text = text.replace(/\s/g, Blockly.Field.NBSP);
textLines += text;
if (i !== lines.length - 1) {
if (i !== displayLinesNumber - 1) {
textLines += '\n';
}
}
@@ -142,6 +168,20 @@ Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() {
return textLines;
};
/**
* Called by setValue if the text input is valid. Updates the value of the
* field, and updates the text of the field if it is not currently being
* edited (i.e. handled by the htmlInput_). Is being redefined here to update
* overflow state of the field.
* @param {*} newValue The value to be saved. The default validator guarantees
* that this is a string.
* @protected
*/
Blockly.FieldMultilineInput.prototype.doValueUpdate_ = function(newValue) {
Blockly.FieldMultilineInput.superClass_.doValueUpdate_.call(this, newValue);
this.isOverflowedY_ = this.value_.split('\n').length > this.maxLines_;
};
/**
* Updates the text of the textElement.
* @protected
@@ -170,6 +210,15 @@ Blockly.FieldMultilineInput.prototype.render_ = function() {
y += lineHeight;
}
if (this.isBeingEdited_) {
var htmlInput = /** @type {!HTMLElement} */(this.htmlInput_);
if (this.isOverflowedY_) {
Blockly.utils.dom.addClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
} else {
Blockly.utils.dom.removeClass(htmlInput, 'blocklyHtmlTextAreaInputOverflowedY');
}
}
this.updateSize_();
if (this.isBeingEdited_) {
@@ -211,6 +260,34 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
totalHeight += this.getConstants().FIELD_TEXT_HEIGHT +
(i > 0 ? this.getConstants().FIELD_BORDER_RECT_Y_PADDING : 0);
}
if (this.isBeingEdited_) {
// The default width is based on the longest line in the display text,
// but when it's being edited, width should be calculated based on the
// absolute longest line, even if it would be truncated after editing.
// Otherwise we would get wrong editor width when there are more
// lines than this.maxLines_.
var actualEditorLines = this.value_.split('\n');
var dummyTextElement = Blockly.utils.dom.createSvgElement(
Blockly.utils.Svg.TEXT,{'class': 'blocklyText blocklyMultilineText'});
var fontSize = this.getConstants().FIELD_TEXT_FONTSIZE;
var fontWeight = this.getConstants().FIELD_TEXT_FONTWEIGHT;
var fontFamily = this.getConstants().FIELD_TEXT_FONTFAMILY;
for (var i = 0; i < actualEditorLines.length; i++) {
if (actualEditorLines[i].length > this.maxDisplayLength) {
actualEditorLines[i] = actualEditorLines[i].substring(0, this.maxDisplayLength);
}
dummyTextElement.textContent = actualEditorLines[i];
var lineWidth = Blockly.utils.dom.getFastTextWidth(
dummyTextElement, fontSize, fontWeight, fontFamily);
if (lineWidth > totalWidth) {
totalWidth = lineWidth;
}
}
var scrollbarWidth = this.htmlInput_.offsetWidth - this.htmlInput_.clientWidth;
totalWidth += scrollbarWidth;
}
if (this.borderRect_) {
totalHeight += this.getConstants().FIELD_BORDER_RECT_Y_PADDING * 2;
totalWidth += this.getConstants().FIELD_BORDER_RECT_X_PADDING * 2;
@@ -223,6 +300,21 @@ Blockly.FieldMultilineInput.prototype.updateSize_ = function() {
this.positionBorderRect_();
};
/**
* Show the inline free-text editor on top of the text.
* Overrides the default behaviour to force rerender in order to
* correct block size, based on editor text.
* @param {Event=} _opt_e Optional mouse event that triggered the field to open,
* or undefined if triggered programmatically.
* @param {boolean=} opt_quietInput True if editor should be created without
* focus. Defaults to false.
* @override
*/
Blockly.FieldMultilineInput.prototype.showEditor_ = function(_opt_e, opt_quietInput) {
Blockly.FieldMultilineInput.superClass_.showEditor_.call(this, _opt_e, opt_quietInput);
this.forceRerender();
};
/**
* Create the text input editor widget.
* @return {!HTMLTextAreaElement} The newly created text input editor.
@@ -266,6 +358,26 @@ Blockly.FieldMultilineInput.prototype.widgetCreate_ = function() {
return htmlInput;
};
/**
* Sets the maxLines config for this field.
* @param {number} maxLines Defines the maximum number of lines allowed,
* before scrolling functionality is enabled.
*/
Blockly.FieldMultilineInput.prototype.setMaxLines = function(maxLines) {
if (typeof maxLines === 'number' && maxLines > 0 && maxLines !== this.maxLines_) {
this.maxLines_ = maxLines;
this.forceRerender();
}
};
/**
* Returns the maxLines config of this field.
* @return {number} The maxLines config value.
*/
Blockly.FieldMultilineInput.prototype.getMaxLines = function() {
return this.maxLines_;
};
/**
* Handle key down to the editor. Override the text input definition of this
* so as to not close the editor when enter is typed in.
@@ -289,6 +401,9 @@ Blockly.Css.register([
'overflow: hidden;',
'height: 100%;',
'text-align: left;',
'}',
'.blocklyHtmlTextAreaInputOverflowedY {',
'overflow-y: scroll;',
'}'
/* eslint-enable indent */
]);