mirror of
https://github.com/google/blockly.git
synced 2026-01-10 18:37:09 +01:00
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:
@@ -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 */
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user