@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
542 lines (480 loc) • 16.5 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2009-2023 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
sap.ui.define([
"./library",
"sap/ui/core/Control",
"sap/ui/core/IconPool",
"sap/m/TextArea",
"sap/m/Button",
"./FeedInputRenderer",
"sap/ui/thirdparty/jquery",
"sap/base/security/URLListValidator",
"sap/base/security/sanitizeHTML",
"sap/m/Avatar",
"sap/m/AvatarShape",
"sap/m/AvatarSize"
],
function(library, Control, IconPool, TextArea, Button, FeedInputRenderer, jQuery, URLListValidator, sanitizeHTML0, Avatar,
AvatarShape, AvatarSize) {
"use strict";
// shortcut for sap.m.ButtonType
var ButtonType = library.ButtonType;
var MAX_ROWS = 15,
MIN_ROWS = 2,
UNLIMITED_ROWS = 0;
/**
* Constructor for a new FeedInput.
*
* @param {string} [sId] id for the new control, generated automatically if no id is given
* @param {object} [mSettings] initial settings for the new control
*
* @class
* The Feed Input allows the user to enter text for a new feed entry and then post it.
* @extends sap.ui.core.Control
*
* @author SAP SE
* @version 1.117.4
*
* @constructor
* @public
* @since 1.22
* @alias sap.m.FeedInput
*/
var FeedInput = Control.extend("sap.m.FeedInput", /** @lends sap.m.FeedInput.prototype */ {
metadata : {
library : "sap.m",
designtime: "sap/m/designtime/FeedInput.designtime",
properties : {
/**
* Set this flag to "false" to disable both text input and post button.
*/
enabled : {type : "boolean", group : "Behavior", defaultValue : true},
/**
* Defines the number of visible text lines for the control.
* <b>Note:</b> Minimum value is 2, maximum value is 15.
*/
rows : {type : "int", group : "Appearance", defaultValue : 2},
/**
* Determines whether the characters, exceeding the maximum allowed character count, are visible in the input field.
*
* If set to <code>false</code>, the user is not allowed to enter more characters than what is set in the <code>maxLength</code> property.
* If set to <code>true</code>, the characters exceeding the <code>maxLength</code> value are selected on paste and the counter below
* the input field displays their number.
*/
showExceededText: {type: "boolean", group: "Behavior", defaultValue: false},
/**
* The maximum length (the maximum number of characters) for the feed's input value. By default this is not limited.
*/
maxLength : {type : "int", group : "Behavior", defaultValue : 0},
/**
* Indicates the ability of the control to automatically grow and shrink dynamically with its content.
*/
growing : {type : "boolean", group : "Behavior", defaultValue : false},
/**
* Defines the maximum number of lines that the control can grow.
* Value is set to 0 by default, which means an unlimited numbers of rows.
* <b>Note:</b> Minimum value to set is equal to the <code>rows</code> property value, maximum value is 15.
*/
growingMaxLines : {type : "int", group : "Behavior", defaultValue : 0},
/**
* The placeholder text shown in the input area as long as the user has not entered any text value.
*/
placeholder : {type : "string", group : "Appearance", defaultValue : "Post something here"},
/**
* The text value of the feed input. As long as the user has not entered any text the post button is disabled
*/
value : {type : "string", group : "Data", defaultValue : null},
/**
* Icon to be displayed as a graphical element within the feed input. This can be an image or an icon from the icon font.
*/
icon : {type : "sap.ui.core.URI", group : "Data", defaultValue : null},
/**
* Defines the shape of the icon.
* @since 1.88
*/
iconDisplayShape: { type: "sap.m.AvatarShape", defaultValue: AvatarShape.Circle},
/**
* Defines the initials of the icon.
* @since 1.88
*/
iconInitials: { type: "string", defaultValue: "" },
/**
* Defines the size of the icon.
* @since 1.88
*/
iconSize: { type: "sap.m.AvatarSize", defaultValue: AvatarSize.M},
/**
* If set to "true" (default), icons will be displayed. In case no icon is provided the standard placeholder will be displayed. if set to "false" icons are hidden
*/
showIcon : {type : "boolean", group : "Behavior", defaultValue : true},
/**
* Some mobile devices support higher resolution images while others do not. Therefore, you should provide image resources for all relevant densities.
* If the property is set to "true", one or more requests are sent to the server to try and get the perfect density version of an image. If an image of a certain density is not available, the image control falls back to the default image, which should be provided.
*
* If you do not have higher resolution images, you should set the property to "false" to avoid unnecessary round-trips.
*
* Please be aware that this property is relevant only for images and not for icons.
*
* Deprecated as of version 1.88. Image is replaced by avatar.
*/
iconDensityAware : {type : "boolean", group : "Appearance", defaultValue : true},
/**
* Sets a new tooltip for Submit button. The tooltip can either be a simple string (which in most cases will be rendered as the title attribute of this element)
* or an instance of sap.ui.core.TooltipBase.
* If a new tooltip is set, any previously set tooltip is deactivated.
* The default value is set language dependent.
* @since 1.28
*/
buttonTooltip : {type : "sap.ui.core.TooltipBase", group : "Accessibility", defaultValue : "Submit"},
/**
* Text for Picture which will be read by screenreader.
* If a new ariaLabelForPicture is set, any previously set ariaLabelForPicture is deactivated.
* Deprecated as of version 1.88. This will not have any effect in code now.
*/
ariaLabelForPicture : {type : "string", group : "Accessibility", defaultValue : null}
},
aggregations : {
/**
* Defines the inner avatar control.
*/
_avatar: { type: "sap.m.Avatar", multiple: false, visibility: "hidden" }
},
events : {
/**
* The Post event is triggered when the user has entered a value and pressed the post button. After firing this event, the value is reset.
*/
post : {
parameters : {
/**
* The value of the feed input before reseting it.
*/
value : {type : "string"}
}
}
}
},
renderer: FeedInputRenderer
});
/*
* These are the rules for the FormattedText
*/
var _defaultRenderingRules = {
// rules for the allowed attributes
ATTRIBS: {
'style': 1,
'class': 1,
'a::href': 1,
'a::target': 1
},
// rules for the allowed tags
ELEMENTS: {
// Text Module Tags
'a': { cssClass: 'sapMLnk' },
'abbr': 1,
'blockquote': 1,
'br': 1,
'cite': 1,
'code': 1,
'em': 1,
'h1': { cssClass: 'sapMTitle sapMTitleStyleH1' },
'h2': { cssClass: 'sapMTitle sapMTitleStyleH2' },
'h3': { cssClass: 'sapMTitle sapMTitleStyleH3' },
'h4': { cssClass: 'sapMTitle sapMTitleStyleH4' },
'h5': { cssClass: 'sapMTitle sapMTitleStyleH5' },
'h6': { cssClass: 'sapMTitle sapMTitleStyleH6' },
'p': 1,
'pre': 1,
'strong': 1,
'span': 1,
'u': 1,
// List Module Tags
'dl': 1,
'dt': 1,
'dd': 1,
'ol': 1,
'ul': 1,
'li': 1
}
};
/**
* Holds the internal list of allowed and evaluated HTML elements and attributes
* @private
*/
FeedInput.prototype._renderingRules = _defaultRenderingRules;
/**
* Sanitizes attributes on an HTML tag.
*
* @param {string} tagName An HTML tag name in lower case
* @param {array} attribs An array of alternating names and values
* @return {array} The sanitized attributes as a list of alternating names and values. Value <code>null</code> removes the attribute.
* @private
*/
function fnSanitizeAttribs(tagName, attribs) {
var attr,
value,
addTarget = tagName === "a";
// add UI5 specific classes when appropriate
var cssClass = (this._renderingRules.ELEMENTS[tagName] && this._renderingRules.ELEMENTS[tagName].cssClass) ? this._renderingRules.ELEMENTS[tagName].cssClass : "";
for (var i = 0; i < attribs.length; i += 2) {
// attribs[i] is the name of the tag's attribute.
// attribs[i+1] is its corresponding value.
// (i.e. <span class="foo"> -> attribs[i] = "class" | attribs[i+1] = "foo")
attr = attribs[i];
value = attribs[i + 1];
if (!this._renderingRules.ATTRIBS[attr] && !this._renderingRules.ATTRIBS[tagName + "::" + attr]) {
attribs[i + 1] = null;
continue;
}
// sanitize hrefs
if (attr == "href") { // a::href
if (!URLListValidator.validate(value)) {
attribs[i + 1] = "#";
addTarget = false;
}
}
if (attr == "target") { // a::target already exists
addTarget = false;
}
// add UI5 classes to the user defined
if (cssClass && attr.toLowerCase() == "class") {
attribs[i + 1] = cssClass + " " + value;
cssClass = "";
}
}
if (addTarget) {
attribs.push("target");
attribs.push("_blank");
}
// add UI5 classes, if not done before
if (cssClass) {
attribs.push("class");
attribs.push(cssClass);
}
return attribs;
}
function fnPolicy(tagName, attribs) {
return fnSanitizeAttribs.call(this, tagName, attribs);
}
/**
* Sanitizes HTML tags and attributes according to a given policy.
*
* @param {string} sText The HTML to sanitize
* @return {string} The sanitized HTML
* @private
*/
FeedInput.prototype._sanitizeHTML = function (sText) {
return sanitizeHTML0(sText, {
tagPolicy: fnPolicy.bind(this),
uriRewriter: function (sUrl) {
// by default, we use the URLListValidator to check the URLs
if (URLListValidator.validate(sUrl)) {
return sUrl;
}
}
});
};
/////////////////////////////////// Lifecycle /////////////////////////////////////////////////////////
/**
* Overrides sap.ui.core.Element.init
*/
FeedInput.prototype.init = function () {
// override text defaults
var oBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m");
this.setProperty("placeholder", oBundle.getText("FEEDINPUT_PLACEHOLDER"), true);
this.setProperty("buttonTooltip", oBundle.getText("FEEDINPUT_SUBMIT"), true);
};
/**
* Overrides sap.ui.core.Element.exit
*/
FeedInput.prototype.exit = function () {
if (this._oTextArea) {
this._oTextArea.destroy();
}
if (this._oButton) {
this._oButton.destroy();
}
if (this.oAvatar) {
this.oAvatar.destroy();
}
};
/////////////////////////////////// Properties /////////////////////////////////////////////////////////
FeedInput.prototype.setRows = function (iRows) {
var iMaxLines = this.getProperty("growingMaxLines");
if (iRows > MAX_ROWS) {
iRows = MAX_ROWS;
} else if (iRows < MIN_ROWS) {
iRows = MIN_ROWS;
}
if (iRows > iMaxLines && iMaxLines !== 0) {
this.setProperty("growingMaxLines", iRows, true);
this._getTextArea().setGrowingMaxLines(iRows);
}
this.setProperty("rows", iRows, true);
this._getTextArea().setRows(iRows);
return this;
};
FeedInput.prototype.setShowExceededText = function (bValue) {
this.setProperty("showExceededText", bValue, true);
this._getTextArea().setShowExceededText(bValue);
return this;
};
FeedInput.prototype.setMaxLength = function (iMaxLength) {
this.setProperty("maxLength", iMaxLength, true);
this._getTextArea().setMaxLength(iMaxLength);
return this;
};
FeedInput.prototype.setGrowing = function (bGrowing) {
this.setProperty("growing", bGrowing, true);
this._getTextArea().setGrowing(bGrowing);
return this;
};
FeedInput.prototype.setGrowingMaxLines = function (iMaxLines) {
var iRows = this.getProperty("rows");
if (iMaxLines !== UNLIMITED_ROWS) {
if (iMaxLines < iRows) {
iMaxLines = iRows;
} else if (iMaxLines > MAX_ROWS) {
iMaxLines = MAX_ROWS;
}
}
this.setProperty("growingMaxLines", iMaxLines, true);
this._getTextArea().setGrowingMaxLines(iMaxLines);
return this;
};
FeedInput.prototype.setValue = function (sValue) {
this.setProperty("value", sValue, true);
this._getTextArea().setValue(sValue);
this._enablePostButton();
return this;
};
FeedInput.prototype.setPlaceholder = function (sValue) {
this.setProperty("placeholder", sValue, true);
this._getTextArea().setPlaceholder(sValue);
return this;
};
FeedInput.prototype.setEnabled = function (bEnabled) {
this.setProperty("enabled", bEnabled, true);
//Dynamically adding or removing the css
if (this.getDomRef("outerContainer")) {
if (bEnabled) {
this.getDomRef("outerContainer").classList.remove("sapMFeedInDisabled");
} else {
this.getDomRef("outerContainer").classList.add("sapMFeedInDisabled");
}
}
this._getTextArea().setEnabled(bEnabled);
this._enablePostButton();
return this;
};
FeedInput.prototype.setButtonTooltip = function (vButtonTooltip) {
this.setProperty("buttonTooltip", vButtonTooltip, true);
this._getPostButton().setTooltip(vButtonTooltip);
return this;
};
/////////////////////////////////// Private /////////////////////////////////////////////////////////
/**
* Access and initialization for the text area
* @returns {sap.m.TextArea} The text area
*/
FeedInput.prototype._getTextArea = function () {
var that = this;
if (!this._oTextArea) {
this._oTextArea = new TextArea(this.getId() + "-textArea", {
value : this.getValue(),
maxLength : this.getMaxLength(),
placeholder : this.getPlaceholder(),
growing : this.getGrowing(),
growingMaxLines : this.getGrowingMaxLines(),
showExceededText : this.getShowExceededText(),
rows : this.getRows(),
liveChange : jQuery.proxy(function (oEvt) {
var sValue = oEvt.getParameter("value");
this.setProperty("value", sValue, true); // update myself without re-rendering
this._enablePostButton();
}, this)
});
this._oTextArea.setParent(this);
this._oTextArea.addEventDelegate({
onAfterRendering: function () {
that.$("counterContainer").empty();
that.$("counterContainer").html(that._oTextArea.getAggregation("_counter").$());
}
});
}
return this._oTextArea;
};
/**
* Access and initialization for the button
* @returns {sap.m.Button} The button
*/
FeedInput.prototype._getPostButton = function () {
if (!this._oButton) {
this._oButton = new Button(this.getId() + "-button", {
enabled : false,
type : ButtonType.Default,
icon : "sap-icon://paper-plane",
tooltip : this.getButtonTooltip(),
press : jQuery.proxy(function () {
this._oTextArea.focus();
this.firePost({
value : this._sanitizeHTML(this.getValue())
});
this.setValue(null);
}, this)
});
this._oButton.setParent(this);
}
return this._oButton;
};
/**
* Enable post button depending on the current value
*/
FeedInput.prototype._enablePostButton = function () {
var bPostButtonEnabled = this._isControlEnabled();
var oButton = this._getPostButton();
oButton.setEnabled(bPostButtonEnabled);
};
/**
* Verifies if the control is enabled or not
* @returns {boolean} True if control is enabled
*/
FeedInput.prototype._isControlEnabled = function() {
var sValue = this.getValue();
return this.getEnabled() && (typeof sValue === "string" || sValue instanceof String) && sValue.trim().length > 0;
};
/**
* Lazy load feed icon image.
*
* @private
* @returns {sap.m.Avatar} The Avatar control
*/
FeedInput.prototype._getAvatar = function() {
var sIconSrc = this.getIcon();
var sId = this.getId() + '-icon';
this.oAvatar = this.getAggregation("_avatar");
if (!this.oAvatar) {
this.oAvatar = new Avatar({
id: sId,
src: sIconSrc,
displayShape: this.getIconDisplayShape(),
initials: this.getIconInitials(),
displaySize: this.getIconSize()
}).addStyleClass("sapMFeedInImage");
if (sIconSrc) {
this.oAvatar.addStyleClass("sapMFeedInImageBgColor");
}
} else {
this.oAvatar
.setSrc(sIconSrc)
.setDisplayShape(this.getIconDisplayShape())
.setInitials(this.getIconInitials())
.setDisplaySize(this.getIconSize());
}
this.setAggregation("_avatar", this.oAvatar);
return this.oAvatar;
};
return FeedInput;
});