@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
1,421 lines (1,232 loc) • 113 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.
*/
// Provides control sap.m.Input.
sap.ui.define([
'./InputBase',
'sap/ui/core/Element',
'sap/ui/core/Item',
'sap/ui/core/Core',
'sap/ui/core/LabelEnablement',
'sap/ui/core/AccessKeysEnablement',
'./ColumnListItem',
'./GroupHeaderListItem',
'sap/ui/core/SeparatorItem',
'./Table',
'./library',
'sap/ui/core/IconPool',
'sap/ui/Device',
'./SuggestionsPopover',
'./Toolbar',
'./ToolbarSpacer',
'./Button',
"sap/ui/core/ResizeHandler",
"sap/ui/dom/containsOrEquals",
"sap/base/assert",
"sap/base/util/deepEqual",
"sap/m/inputUtils/wordStartsWithValue",
"sap/m/inputUtils/inputsDefaultFilter",
"sap/m/inputUtils/highlightDOMElements",
"sap/m/inputUtils/typeAhead",
"sap/ui/events/KeyCodes",
"sap/m/inputUtils/filterItems",
"sap/m/inputUtils/ListHelpers",
"sap/m/inputUtils/calculateSelectionStart",
"sap/m/inputUtils/selectionRange",
"./InputRenderer",
"sap/ui/base/ManagedObject",
"sap/ui/base/ManagedObjectObserver",
"sap/ui/core/Lib",
"sap/ui/dom/jquery/selectText" // provides jQuery.fn.selectText
],
function(
InputBase,
Element,
Item,
Core,
LabelEnablement,
AccessKeysEnablement,
ColumnListItem,
GroupHeaderListItem,
SeparatorItem,
Table,
library,
IconPool,
Device,
SuggestionsPopover,
Toolbar,
ToolbarSpacer,
Button,
ResizeHandler,
containsOrEquals,
assert,
deepEqual,
wordStartsWithValue,
inputsDefaultFilter,
highlightDOMElements,
typeAhead,
KeyCodes,
filterItems,
ListHelpers,
calculateSelectionStart,
selectionRange,
InputRenderer,
ManagedObject,
ManagedObjectObserver,
Library
) {
"use strict";
// shortcut for sap.m.ListType
var ListType = library.ListType;
// shortcut for sap.m.InputTextFormatMode
var InputTextFormatMode = library.InputTextFormatMode;
// shortcut for sap.m.InputType
var InputType = library.InputType;
// shortcut for sap.m.ListMode
var ListMode = library.ListMode;
// shortcut for sap.m.ListSeparators
var ListSeparators = library.ListSeparators;
/**
* Constructor for a new <code>Input</code>.
*
* @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
* Allows the user to enter and edit text or numeric values in one line.
*
* <h3>Overview</h3>
*
* You can enable the autocomplete suggestion feature and the value help option to easily enter a valid value.
*
* <h3>Guidelines</h3>
*
* <ul>
* <li> Always provide a meaningful label for any input field </li>
* <li> Limit the length of the input field. This will visually emphasize the constraints for the field. </li>
* <li> Do not use the <code>placeholder</code> property as a label.</li>
* <li> Use the <code>description</code> property only for small fields with no placeholders (i.e. for currencies).</li>
* </ul>
*
* <h3>Structure</h3>
*
* The controls inherits from {@link sap.m.InputBase} which controls the core properties like:
* <ul>
* <li> editable / read-only </li>
* <li> enabled / disabled</li>
* <li> placeholder</li>
* <li> text direction</li>
* <li> value states</li>
* </ul>
* To aid the user during input, you can enable value help (<code>showValueHelp</code>) or autocomplete (<code>showSuggestion</code>).
* <strong>Value help</strong> will open a new dialog where you can refine your input.
* <strong>Autocomplete</strong> has three types of suggestions:
* <ul>
* <li> Single value - a list of suggestions of type <code>sap.ui.core.Item</code> or <code>sap.ui.core.ListItem</code> </li>
* <li> Two values - a list of two suggestions (ID and description) of type <code>sap.ui.core.Item</code> or <code>sap.ui.core.ListItem</code> </li>
* <li> Tabular suggestions of type <code>sap.m.ColumnListItem</code> </li>
* </ul>
* The suggestions are stored in two aggregations <code>suggestionItems</code> (for single and double values) and <code>suggestionRows</code> (for tabular values).
*
* <h3>Usage</h3>
*
* <b>When to use:</b>
* Use the control for short inputs like emails, phones, passwords, fields for assisted value selection.
*
* <b>When not to use:</b>
* Don't use the control for long texts, dates, designated search fields, fields for multiple selection.
*
* <h3>Known Restrictions</h3>
*
* If <code>showValueHelp</code> or if <code>showSuggestion</code> is <code>true</code>, the native browser autofill will not fire a change event.
*
* <h4>Note:</h4>
* The control has the following behavior regarding the <code>selectedKey</code> and <code>value</code> properties:
* <ul>
* <li> On initial loading, if the control has a <code>selectedKey</code> set which corresponds to a matching item, and a set <code>value</code>, the <code>value</code> will be updated to the matching item's text. </li>
* <li> If a <code>selectedKey</code> is set and the user types an input which corresponds to an item's text, the <code>selectedKey</code> will be updated with the matching item's key. </li>
* <li> If a <code>selectedKey</code> is set and the user types an input which does not correspond to any item's text, the <code>selectedKey</code> will be set to an empty string ("") </li>
* <li> If a <code>selectedKey</code> is set and the user selects an item, the <code>selectedKey</code> will be updated to match the selected item's key. </li>
* <li> If a <code>selectedKey</code> is bound and the user types before the data is loaded, the user's input will be overwritten by the binding update. </li>
* </ul>
*
* @extends sap.m.InputBase
* @implements sap.ui.core.IAccessKeySupport
* @author SAP SE
* @version 1.117.4
*
* @constructor
* @public
* @alias sap.m.Input
* @see {@link fiori:https://experience.sap.com/fiori-design-web/input-field/ Input}
*/
var Input = InputBase.extend("sap.m.Input", /** @lends sap.m.Input.prototype */ {
metadata : {
interfaces : [
"sap.ui.core.IAccessKeySupport",
"sap.m.IToolbarInteractiveControl"
],
library : "sap.m",
properties : {
/**
* HTML type of the internal <code>input</code> tag (e.g. Text, Number, Email, Phone).
* The particular effect of this property differs depending on the browser and the current language settings,
* especially for the type Number.<br>
* This parameter is intended to be used with touch devices that use different soft keyboard layouts depending on the given input type.<br>
* Only the default value <code>sap.m.InputType.Text</code> may be used in combination with data model formats.
* <code>sap.ui.model</code> defines extended formats that are mostly incompatible with normal HTML
* representations for numbers and dates.
*/
type : {type : "sap.m.InputType", group : "Data", defaultValue : InputType.Text},
/**
* Maximum number of characters. Value '0' means the feature is switched off.
* This parameter is not compatible with the input type <code>sap.m.InputType.Number</code>.
* If the input type is set to <code>Number</code>, the <code>maxLength</code> value is ignored.
* If the <code>maxLength</code> is set after there is already a longer value, this value will not get truncated.
* The <code>maxLength</code> property has effect only when the value is modified by user interaction.
*/
maxLength : {type : "int", group : "Behavior", defaultValue : 0},
/**
* Only used if type=date and no datepicker is available.
* The data is displayed and the user input is parsed according to this format.
* <b>Note:</b> The value property is always of the form RFC 3339 (YYYY-MM-dd).
* @deprecated Since version 1.9.1.
* <code>sap.m.DatePicker</code>, <code>sap.m.TimePicker</code> or <code>sap.m.DateTimePicker</code> should be used for date/time inputs and formating.
*/
dateFormat : {type : "string", group : "Misc", defaultValue : 'YYYY-MM-dd', deprecated: true},
/**
* If set to true, a value help indicator will be displayed inside the control. When clicked the event "valueHelpRequest" will be fired.
* @since 1.16
*/
showValueHelp : {type : "boolean", group : "Behavior", defaultValue : false},
/**
* Set custom value help icon.
* @since 1.84.0
*/
valueHelpIconSrc : {type : "sap.ui.core.URI", group : "Behavior", defaultValue : "sap-icon://value-help"},
/**
* If this is set to true, suggest event is fired when user types in the input. Changing the suggestItems aggregation in suggest event listener will show suggestions within a popup. When runs on phone, input will first open a dialog where the input and suggestions are shown. When runs on a tablet, the suggestions are shown in a popup next to the input.
* @since 1.16.1
*/
showSuggestion : {type : "boolean", group : "Behavior", defaultValue : false},
/**
* If set to true, direct text input is disabled and the control will trigger the event "valueHelpRequest" for all user interactions. The properties "showValueHelp", "editable", and "enabled" must be set to true, otherwise the property will have no effect.
* In this scenario, the <code>showItems</code> API will not work.
* @since 1.21.0
*/
valueHelpOnly : {type : "boolean", group : "Behavior", defaultValue : false},
/**
* Defines whether to filter the provided suggestions before showing them to the user.
*/
filterSuggests : {type : "boolean", group : "Behavior", defaultValue : true},
/**
* If set, the value of this parameter will control the horizontal size of the suggestion list to display more data. This allows suggestion lists to be wider than the input field if there is enough space available. By default, the suggestion list is always as wide as the input field.
* <b>Note:</b> The value will be ignored if the actual width of the input field is larger than the specified parameter value.
* @since 1.21.1
*/
maxSuggestionWidth : {type : "sap.ui.core.CSSSize", group : "Appearance", defaultValue : null},
/**
* Minimum length of the entered text in input before suggest event is fired. The default value is 1 which means the suggest event is fired after user types in input.
*
* <b>Note:</b> When it's set to 0, suggest event is fired when input with no text gets focus. In this case no suggestion popup will open.
* @since 1.21.2
*/
startSuggestion : {type : "int", group : "Behavior", defaultValue : 1},
/**
* For tabular suggestions, this flag will show/hide the button at the end of the suggestion table that triggers the event "valueHelpRequest" when pressed. The default value is true.
*
* <b>Note:</b> If suggestions are not tabular or no suggestions are used, the button will not be displayed and this flag is without effect.
* @since 1.22.1
*/
showTableSuggestionValueHelp : {type : "boolean", group : "Behavior", defaultValue : true},
/**
* The description is a text after the input field, e.g. units of measurement, currencies.
*/
description: { type: "string", group: "Misc", defaultValue: null },
/**
* This property only takes effect if the description property is set. It controls the distribution of space between the input field and the description text. The default value is 50% leaving the other 50% for the description.
*/
fieldWidth: { type: "sap.ui.core.CSSSize", group: "Appearance", defaultValue: '50%' },
/**
* Indicates when the value gets updated with the user changes: At each keystroke (true) or first when the user presses enter or tabs out (false).
*
* <b>Note:</b> When set to true and the value of the Input control is bound to a model, the change event becomes obsolete and will not be fired, as the value in the model will be updated each time the user provides input. In such cases, subscription to the liveChange event is more appropriate, as it corresponds to the way the underlying model gets updated.
* @since 1.24
*/
valueLiveUpdate : {type : "boolean", group : "Behavior", defaultValue : false},
/**
* Defines the key of the selected item.
*
* <b>Note:</b> If duplicate keys exist, the first item matching the key is used.
* @since 1.44
*/
selectedKey: {type: "string", group: "Data", defaultValue: ""},
/**
* Defines the display text format mode.
* @since 1.44
*/
textFormatMode: {type: "sap.m.InputTextFormatMode", group: "Misc", defaultValue: InputTextFormatMode.Value},
/**
* Defines the display text formatter function.
* @since 1.44
*/
textFormatter: {type: "function", group: "Misc", defaultValue: null},
/**
* Defines the validation callback function called when a suggestion row gets selected.
* @since 1.44
*/
suggestionRowValidator: {type: "function", group: "Misc", defaultValue: null},
/**
* Specifies whether the suggestions highlighting is enabled.
* <b>Note:</b> Due to performance constraints, the functionality will be disabled above 200 items.
*
* @since 1.46
*/
enableSuggestionsHighlighting: {type: "boolean", group: "Behavior", defaultValue: true},
/**
* Enables the <code>autoPopinMode</code> of <code>sap.m.Table</code>, when the input has tabular suggestions.
* <b>Note:</b> The <code>autoPopinMode</code> overwrites the <code>demandPopin</code> and the
* <code>minScreenWidth</code> properties of the <code>sap.m.Column</code>.
* When setting, <code>enableTableAutoPopinMode</code>, from true to false,
* the application must reconfigure the <code>demandPopin</code> and
* <code>minScreenWidth</code> properties of the <code>sap.m.Column</code> control by itself.
* @since 1.89
*/
enableTableAutoPopinMode: {type: "boolean", group: "Behavior", defaultValue: false},
/**
* Specifies whether autocomplete is enabled.
* Works only if "showSuggestion" property is set to true.
* <b>Note:</b> The autocomplete feature is disabled on Android devices due to a OS specific issue.
* @since 1.61
*/
autocomplete: {type: "boolean", group: "Behavior", defaultValue: true},
/**
* Specifies whether clear icon is shown.
* Pressing the icon will clear input's value and fire the liveChange event.
* @since 1.94
*/
showClearIcon: { type: "boolean", defaultValue: false },
/**
* Specifies whether the clear icon should be shown/hidden on user interaction.
* @private
*/
effectiveShowClearIcon: { type: "boolean", defaultValue: false, visibility: "hidden" },
/**
* Specifies whether to display separators in tabular suggestions.
* @private
* @ui5-restricted sap.ui.comp.smartfield.SmartField
*/
separateSuggestions: { type: "boolean", defaultValue: true, visibility: "hidden" },
/**
* Indicates whether the access keys ref of the control should be highlighted.
* NOTE: this property is used only when access keys feature is turned on.
*
* @private
*/
highlightAccKeysRef: { type: "boolean", defaultValue: false, visibility: "hidden" },
/**
* Indicates which keyboard key should be pressed to focus the access key ref
* NOTE: this property is used only when access keys feature is turned on.
*
* @private
*/
accesskey: { type: "string", defaultValue: "", visibility: "hidden" }
},
defaultAggregation : "suggestionItems",
aggregations : {
/**
* Defines the items displayed in the suggestion popup. Changing this aggregation
* (by calling <code>addSuggestionItem</code>, <code>insertSuggestionItem</code>,
* <code>removeSuggestionItem</code>, <code>removeAllSuggestionItems</code>, or
* <code>destroySuggestionItems</code>) after <code>Input</code> is rendered
* opens/closes the suggestion popup.
*
* To display suggestions with two text values, add <code>sap.ui.core.ListItem</code>
* as <code>SuggestionItems</code> (since 1.21.1). For the selected
* <code>ListItem</code>, only the first value is returned to the input field.
*
* <b>Note:</b> Only <code>text</code> and <code>additionalText</code> property values
* of the item are displayed. For example, if an <code>icon</code> is set, it is
* ignored. To display more information per item (including icons), you can use the
* <code>suggestionRows</code> aggregation.
*
* <b>Note:</b> Disabled items are not visualized in the list with the suggestions,
* however they can still be accessed through the aggregation.
* <b>Note:</b> If <code>suggestionItems</code> & <code>suggestionRows</code> are set in parallel, the last aggeragtion to come would overwrite the previous ones.
*
* @since 1.16.1
*/
suggestionItems : {type : "sap.ui.core.Item", multiple : true, singularName : "suggestionItem"},
/**
* The suggestionColumns and suggestionRows are for tabular input suggestions. This aggregation allows for binding the table columns; for more details see the aggregation "suggestionRows".
* @since 1.21.1
*/
suggestionColumns : {type : "sap.m.Column", multiple : true, singularName : "suggestionColumn", bindable : "bindable", forwarding: {getter:"_getSuggestionsTable", aggregation: "columns"}},
/**
* The suggestionColumns and suggestionRows are for tabular input suggestions. This aggregation allows for binding the table cells.
* The items of this aggregation are to be bound directly or to set in the suggest event method.
* <b>Note:</b> If <code>suggestionItems</code> & <code>suggestionRows</code> are set in parallel, the last aggeragtion to come would overwrite the previous ones.
* @since 1.21.1
*/
suggestionRows : {type : "sap.m.ColumnListItem", altTypes: ["sap.m.GroupHeaderListItem"], multiple : true, singularName : "suggestionRow", bindable : "bindable", forwarding: {getter: "_getSuggestionsTable", aggregation: "items"}},
/**
* The suggestion popup (can be a Dialog or Popover); aggregation needed to also propagate the model and bindings to the content of the popover
*/
_suggestionPopup : {type : "sap.ui.core.Control", multiple: false, visibility: "hidden"},
/**
* The icon on the right side of the Input
*/
_valueHelpIcon : {type : "sap.ui.core.Icon", multiple: false, visibility: "hidden"}
},
associations: {
/**
* Sets or retrieves the selected item from the suggestionItems.
* @since 1.44
*/
selectedItem: {type: "sap.ui.core.Item", multiple: false},
/**
* Sets or retrieves the selected row from the suggestionRows.
* @since 1.44
*/
selectedRow: {type: "sap.m.ColumnListItem", multiple: false}
},
events : {
/**
* Fired when the value of the input is changed by user interaction - each keystroke, delete, paste, etc.
*
* <b>Note:</b> Browsing autocomplete suggestions does not fire the event.
*/
liveChange : {
parameters : {
/**
* The current value of the input, after a live change event.
*/
value : {type : "string"},
/**
* Indicates that ESC key triggered the event. <b>Note:</b> This parameter will not be sent unless the ESC key is pressed.
* @since 1.48
*/
escPressed : {type : "boolean"},
/**
* The value of the input before pressing ESC key. <b>Note:</b> This parameter will not be sent unless the ESC key is pressed.
* @since 1.48
*/
previousValue : {type : "string"}
}
},
/**
* When the value help indicator is clicked, this event will be fired.
* @since 1.16
*/
valueHelpRequest : {
parameters : {
/**
* The event parameter is set to true, when the button at the end of the suggestion table is clicked, otherwise false. It can be used to determine whether the "value help" trigger or the "show all items" trigger has been pressed.
*/
fromSuggestions : {type : "boolean"}
}
},
/**
* This event is fired when user types in the input and showSuggestion is set to true. Changing the suggestItems aggregation will show the suggestions within a popup.
* @since 1.16.1
*/
suggest : {
parameters : {
/**
* The current value which has been typed in the input.
*/
suggestValue : {type : "string"},
/**
* The suggestion list is passed to this event for convenience. If you use list-based or tabular suggestions, fill the suggestionList with the items you want to suggest. Otherwise, directly add the suggestions to the "suggestionItems" aggregation of the input control.
*/
suggestionColumns : {type : "sap.m.ListBase"}
}
},
/**
* This event is fired when suggestionItem shown in suggestion popup are selected. This event is only fired when showSuggestion is set to true and there are suggestionItems shown in the suggestion popup.
* @since 1.16.3
*/
suggestionItemSelected : {
parameters : {
/**
* This is the item selected in the suggestion popup for one and two-value suggestions. For tabular suggestions, this value will not be set.
*/
selectedItem : {type : "sap.ui.core.Item"},
/**
* This is the row selected in the tabular suggestion popup represented as a ColumnListItem. For one and two-value suggestions, this value will not be set.
*
* <b>Note:</b> The row result function to select a result value for the string is already executed at this time. To pick different value for the input field or to do follow up steps after the item has been selected.
* @since 1.21.1
*/
selectedRow : {type : "sap.m.ColumnListItem"}
}
},
/**
* This event is fired when user presses the <kbd>Enter</kbd> key on the input.
*
* <b>Notes:</b>
* <ul>
* <li>The event is fired independent of whether there was a change before or not. If a change was performed, the event is fired after the change event.</li>
* <li>The event is also fired when an item of the select list is selected via <kbd>Enter</kbd>.</li>
* <li>The event is only fired on an input which allows text input (<code>editable</code>, <code>enabled</code> and not <code>valueHelpOnly</code>).</li>
* </ul>
*
* @since 1.33.0
*/
submit : {
parameters: {
/**
* The new value of the input.
*/
value: { type: "string" }
}
}
},
designtime: "sap/m/designtime/Input.designtime"
},
renderer: InputRenderer
});
IconPool.insertFontFaceStyle();
/**
* The default filter function for tabular suggestions. It checks whether some item text begins with the typed value.
*
* @private
* @param {string} sValue the current filter string.
* @param {sap.m.ColumnListItem} oColumnListItem The filtered list item.
* @returns {boolean} true for items that start with the parameter sValue, false for non matching items.
*/
Input._DEFAULTFILTER_TABULAR = function(sValue, oColumnListItem) {
var aCells = oColumnListItem.getCells(),
i = 0;
for (; i < aCells.length; i++) {
if (aCells[i].getText) {
if (wordStartsWithValue(aCells[i].getText(), sValue)) {
return true;
}
}
}
return false;
};
/**
* The default result function for tabular suggestions. It returns the value of the first cell with a "text" property.
*
* @private
* @param {sap.m.ColumnListItem} oColumnListItem The selected list item.
* @returns {string} The value to be displayed in the input field.
*/
Input._DEFAULTRESULT_TABULAR = function (oColumnListItem) {
// If there are groups, the GroupHeaderListItems are also passed but they should be skipped by this function
if (!oColumnListItem || oColumnListItem.isA("sap.m.GroupHeaderListItem")) {
return "";
}
var aCells = oColumnListItem.getCells(),
i = 0;
for (; i < aCells.length; i++) {
// take first cell with a text method and compare value
if (aCells[i].getText) {
return aCells[i].getText();
}
}
return "";
};
/**
* Initializes the control.
*
* @private
*/
Input.prototype.init = function() {
InputBase.prototype.init.call(this);
// Counter for concurrent issues with setValue:
this._iSetCount = 0;
// TypeAhead's suggested text. It's always executed in the context of the "root" Input and never in the Dialog's instance!
this._sProposedItemText = null;
this._oRb = Library.getResourceBundleFor("sap.m");
// Instantiate the SuggestionsPopover only for the main input.
// If there's a Dialog where the Input gets duplicated, we should not recreate the Popover.
if (this.getId().indexOf("popup-input") === -1) {
this._createSuggestionsPopover();
}
// We need to set this to empty string as we are comparing it with sValue in the before rendering
// phase of the life cycle. Without this line, initially the condition fails and fires liveChange event
// even though there is no user input (check Input.prototype.onsapright).
this._setTypedInValue("");
// indicates whether input is clicked (on mobile) or the clear button
// used for identifying whether dialog should be open.
this._bClearButtonPressed = false;
// indicates whether input's popover has finished opening
// we asume that after open its content has been rendered => we don't have the power user scenario
this._bAfterOpenFinisihed = false;
AccessKeysEnablement.registerControl(this);
};
var setRefLabelsHighlightAccKeysRef = function (bHighlightAccKeysRef) {
var aRefLabels = LabelEnablement.getReferencingLabels(this);
aRefLabels.forEach(function(sLabelId) {
Core.byId(sLabelId).setProperty("highlightAccKeysRef", bHighlightAccKeysRef);
}, this);
};
Input.prototype.getAccessKeysFocusTarget = function () {
return this.getFocusDomRef();
};
Input.prototype.onAccKeysHighlightStart = function () {
setRefLabelsHighlightAccKeysRef.call(this, true);
};
Input.prototype.onAccKeysHighlightEnd = function () {
setRefLabelsHighlightAccKeysRef.call(this, false);
};
/**
* Destroys the Input.
*
* @private
*/
Input.prototype.exit = function() {
InputBase.prototype.exit.call(this);
this._deregisterEvents();
// clear delayed calls
this.cancelPendingSuggest();
if (this._iRefreshListTimeout) {
clearTimeout(this._iRefreshListTimeout);
this._iRefreshListTimeout = null;
}
this._destroySuggestionsTable();
if (this._getSuggestionsPopover()) {
this._oSuggestionPopup = null;
this._oSuggPopover.destroy();
this._oSuggPopover = null;
}
// Unregister custom events handlers after migration to semantic rendering
this.$().off("click");
};
/**
* Overwrites the onBeforeRendering.
*
* @public
*/
Input.prototype.onBeforeRendering = function() {
var sSelectedKey = this.getSelectedKey(),
bShowValueHelpIcon = this.getShowValueHelp() && this.getEnabled() && this.getEditable(),
bShowClearIcon = this.getProperty("effectiveShowClearIcon") && this.getEnabled() && this.getEditable(),
oIcon = this._oValueHelpIcon,
oSuggestionsPopover = this._getSuggestionsPopover(),
bSuggestionsPopoverIsOpen = oSuggestionsPopover && this._isSuggestionsPopoverOpen(),
oPopupInput = oSuggestionsPopover && oSuggestionsPopover.getInput(),
sValueStateHeaderText = bSuggestionsPopoverIsOpen ? oSuggestionsPopover._getValueStateHeader().getText() : null,
sValueStateHeaderValueState = bSuggestionsPopoverIsOpen ? oSuggestionsPopover._getValueStateHeader().getValueState() : "";
InputBase.prototype.onBeforeRendering.call(this);
if (this.getShowClearIcon()) {
this._getClearIcon().setProperty("visible", bShowClearIcon);
} else if (this._oClearButton) {
this._getClearIcon().setProperty("visible", false);
}
this._deregisterEvents();
if (sSelectedKey && !this.getSelectedItem() && this.getSuggestionItemByKey(sSelectedKey)) {
this.setSelectedKey(sSelectedKey);
}
if (this.getShowSuggestion()) {
if (this.getShowTableSuggestionValueHelp()) {
this._addShowMoreButton();
} else {
this._removeShowMoreButton();
}
// setting the property "type" of the Input inside the Suggestion popover
if (oPopupInput) {
oPopupInput.setType(this.getType());
}
}
if (bShowValueHelpIcon) {
// ensure the creation of an icon
oIcon = this._getValueHelpIcon();
oIcon.setVisible(true);
} else if (oIcon) {
// if the icon should not be shown and has never be initialized - do nothing
oIcon.setVisible(false);
}
if (!this.getWidth()) {
this.setWidth("100%");
}
if (this._hasTabularSuggestions()) {
this._getSuggestionsTable().setAutoPopinMode(this.getEnableTableAutoPopinMode());
this._getSuggestionsTable().setContextualWidth(this.getEnableTableAutoPopinMode() ? "Auto" : "Inherit");
}
if (bSuggestionsPopoverIsOpen && ((this.getValueStateText() && sValueStateHeaderText !== this.getValueStateText()) ||
(this.getValueState() !== sValueStateHeaderValueState) ||
(this.getFormattedValueStateText()))) {
/* If new value state, value state plain text or FormattedText is set
while the suggestions popover is open update the value state header.
If the input has FormattedText aggregation while the suggestions popover is open then
it's new, because the old is already switched to have the value state header as parent */
this._updateSuggestionsPopoverValueState();
}
};
/**
* Returns input display text.
*
* @private
* @param {sap.ui.core.Item} oItem The displayed item.
* @returns {string} The key for the text format mode.
*/
Input.prototype._getDisplayText = function(oItem) {
var fTextFormatter = this.getTextFormatter();
if (fTextFormatter) {
return fTextFormatter(oItem);
}
var sText = oItem.getText(),
sKey = oItem.getKey(),
textFormatMode = this.getTextFormatMode();
switch (textFormatMode) {
case InputTextFormatMode.Key:
return sKey;
case InputTextFormatMode.ValueKey:
return sText + ' (' + sKey + ')';
case InputTextFormatMode.KeyValue:
return '(' + sKey + ') ' + sText;
default:
return sText;
}
};
/**
* Handles value updates.
*
* @private
* @param {string} newValue The new selected value.
*/
Input.prototype._onValueUpdated = function (newValue) {
if (this._bSelectingItem || newValue === this._sSelectedValue) {
return;
}
var sKey = this.getSelectedKey(),
bHasSelectedItem,
oSuggestionsPopover = this._getSuggestionsPopover(),
oList = oSuggestionsPopover && oSuggestionsPopover.getItemsContainer();
if (!this._hasTabularSuggestions() && sKey === '') {
return;
}
if (this._hasTabularSuggestions()) {
bHasSelectedItem = this._getSuggestionsTable() && !!this._getSuggestionsTable().getSelectedItem();
} else {
bHasSelectedItem = oList && !!oList.getSelectedItem();
}
if (bHasSelectedItem) {
return;
}
this.setProperty("selectedKey", '', true);
this.setAssociation("selectedRow", null, true);
this.setAssociation("selectedItem", null, true);
};
/**
* Updates and synchronizes the <code>selectedItem</code> association and <code>selectedKey</code> properties.
*
* @private
* @param {sap.ui.core.Item | null} oItem Selected item.
* @param {boolean} bInteractionChange Specifies if the change is triggered by user interaction.
*/
Input.prototype.setSelectionItem = function (oItem, bInteractionChange) {
this._bSelectingItem = true;
if (!oItem) {
this.setAssociation("selectedItem", null, true);
this.setValue('');
return;
}
var iCount = this._iSetCount,
sNewValue;
this.setAssociation("selectedItem", oItem, true);
this.setProperty("selectedKey", oItem.getKey(), true);
// fire suggestion item select event
if (bInteractionChange) {
this.fireSuggestionItemSelected({
selectedItem: oItem
});
}
// choose which field should be used for the value
if (iCount !== this._iSetCount) {
// if the event handler modified the input value we take this one as new value
sNewValue = this.getValue();
} else {
sNewValue = this._getDisplayText(oItem);
}
this._sSelectedValue = sNewValue;
this.setSelectionUpdatedFromList(false);
this.updateInputField(sNewValue);
// don't continue if the input is destroyed after firing change event through updateInputField
if (this.bIsDestroyed) {
return;
}
if (!(this.isMobileDevice() && this.isA("sap.m.MultiInput"))) {
this._closeSuggestionPopup();
}
this._bSelectingItem = false;
this._resetTypeAhead();
};
/**
* Adds a sap.m.GroupHeaderListItem item to the aggregation named <code>suggestionRows</code>.
*
* @param {sap.ui.core.Item} oGroup Item of that group
* @param {sap.ui.core.SeparatorItem} oHeader The item to be added
* @param {boolean} bSuppressInvalidate Flag indicating whether invalidation should be suppressed
* @returns {sap.m.GroupHeaderListItem} The group header
* @private
*/
Input.prototype.addSuggestionRowGroup = function(oGroup, oHeader, bSuppressInvalidate) {
oHeader = oHeader || new GroupHeaderListItem({
title: ManagedObject.escapeSettingsValue(oGroup.text) || ManagedObject.escapeSettingsValue(oGroup.key)
});
this._createSuggestionPopupContent(true);
this.addAggregation("suggestionRows", oHeader, bSuppressInvalidate);
return oHeader;
};
/**
* Adds a sap.ui.core.SeparatorItem item to the aggregation named <code>suggestions</code>.
*
* @param {sap.ui.core.Item} oGroup Item of that group
* @param {sap.ui.core.SeparatorItem} oHeader The item to be added
* @param {boolean} bSuppressInvalidate Flag indicating whether invalidation should be suppressed
* @returns {sap.m.GroupHeaderListItem} The group header
* @private
*/
Input.prototype.addSuggestionItemGroup = function(oGroup, oHeader, bSuppressInvalidate) {
oHeader = oHeader || new SeparatorItem({
text: ManagedObject.escapeSettingsValue(oGroup.text) || ManagedObject.escapeSettingsValue(oGroup.key)
});
this._createSuggestionPopupContent(false);
this.addAggregation("suggestionItems", oHeader, bSuppressInvalidate);
return oHeader;
};
/**
* Sets the <code>selectedItem</code> association.
*
*
* @public
* @param {sap.ui.core.Item} [oItem=null] New value for the <code>selectedItem</code> association.
* If an ID of a <code>sap.ui.core.Item</code> is given, the item with this ID becomes the
* <code>selectedItem</code> association.
* Alternatively, a <code>sap.ui.core.Item</code> instance may be given or <code>null</code> to clear
* the selection.
* @returns {this} <code>this</code> to allow method chaining.
* @since 1.44
*/
Input.prototype.setSelectedItem = function(oItem) {
if (typeof oItem === "string") {
oItem = Element.registry.get(oItem);
}
if (oItem !== null && !(oItem instanceof Item)) {
return this;
}
this.setSelectionItem(oItem);
return this;
};
/**
* Sets the <code>selectedKey</code> property.
*
* Default value is an empty string <code>""</code> or <code>undefined</code>.
*
* @public
* @param {string} sKey New value for property <code>selectedKey</code>.
* If the provided <code>sKey</code> is an empty string <code>""</code> or <code>undefined</code>,
* the selection is cleared.
* If duplicate keys exist, the first item matching the key is selected.
* @returns {this} <code>this</code> to allow method chaining.
* @since 1.44
*/
Input.prototype.setSelectedKey = function(sKey) {
sKey = this.validateProperty("selectedKey", sKey);
this.setProperty("selectedKey", sKey, true);
if (this._hasTabularSuggestions()) {
return this;
}
if (!sKey) {
this.setSelectionItem();
return this;
}
var oItem = this.getSuggestionItemByKey(sKey);
this.setSelectionItem(oItem);
return this;
};
/**
* Gets the item with the given key from the aggregation <code>suggestionItems</code>.
* <b>Note:</b> If duplicate keys exist, the first item matching the key is returned.
*
* @public
* @param {string} sKey An item key that specifies the item to retrieve.
* @returns {sap.ui.core.Item} Suggestion item.
* @since 1.44
*/
Input.prototype.getSuggestionItemByKey = function(sKey) {
var aItems = this.getSuggestionItems() || [],
oItem,
i;
for (i = 0; i < aItems.length; i++) {
oItem = aItems[i];
if (oItem.getKey() === sKey) {
return oItem;
}
}
};
/**
* Gets <code>sap.m.FormattedText</code> aggregation based on its current parent.
* If the SuggestionPopover is open that is the <code>sap.m.ValueStateHeader</code>, otherwise is the Input itself.
*
* @private
* @returns {sap.m.FormattedText} Aggregation used for value state message that can contain links.
* @since 1.78
*/
Input.prototype._getFormattedValueStateText = function () {
var bSuggestionsPopoverIsOpen = this._isSuggestionsPopoverOpen(),
oValueStateHeaderFormattedText = bSuggestionsPopoverIsOpen ?
this._getSuggestionsPopover()._getValueStateHeader().getFormattedText() : null;
if (bSuggestionsPopoverIsOpen && oValueStateHeaderFormattedText) {
return oValueStateHeaderFormattedText;
} else {
return InputBase.prototype.getFormattedValueStateText.call(this);
}
};
/**
* Updates and synchronizes the <code>selectedRow</code> association and <code>selectedKey</code> properties.
*
* @private
* @param {sap.m.ColumnListItem} oListItem Selected item.
* @param {boolean} bInteractionChange Specifies if the change is triggered by user interaction.
*/
Input.prototype.setSelectionRow = function (oListItem, bInteractionChange) {
if (!oListItem) {
this.setAssociation("selectedRow", null, true);
return;
}
this._bSelectingItem = true;
var oItem,
fSuggestionRowValidator = this.getSuggestionRowValidator();
if (fSuggestionRowValidator) {
oItem = fSuggestionRowValidator(oListItem);
if (!(oItem instanceof Item)) {
oItem = null;
}
}
var iCount = this._iSetCount,
sKey = "",
sNewValue;
this.setAssociation("selectedRow", oListItem, true);
if (oItem) {
sKey = oItem.getKey();
}
this.setProperty("selectedKey", sKey, true);
// fire suggestion item select event
if (bInteractionChange) {
this.fireSuggestionItemSelected({
selectedRow: oListItem
});
}
// choose which field should be used for the value
if (iCount !== this._iSetCount) {
// if the event handler modified the input value we take this one as new value
sNewValue = this.getValue();
} else {
// for tabular suggestions we call a result filter function
if (oItem) {
sNewValue = this._getDisplayText(oItem);
} else {
sNewValue = this._getRowResultFunction()(oListItem);
}
}
this._sSelectedValue = sNewValue;
this.setSelectionUpdatedFromList(false);
this.updateInputField(sNewValue);
// don't continue if the input is destroyed after firing change event through updateInputField
if (this.bIsDestroyed) {
return;
}
if (!(this.isMobileDevice() && this.isA("sap.m.MultiInput") && this._isMultiLineMode)) {
this._closeSuggestionPopup();
}
this._bSelectingItem = false;
this._resetTypeAhead();
};
/**
* Sets the <code>selectedRow</code> association.
* Default value is <code>null</code>.
*
* @public
* @param {sap.m.ColumnListItem} oListItem New value for the <code>selectedRow</code> association.
* If an ID of a <code>sap.m.ColumnListItem</code> is given, the item with this ID becomes the
* <code>selectedRow</code> association.
* Alternatively, a <code>sap.m.ColumnListItem</code> instance may be given or <code>null</code> to clear
* the selection.
* @returns {this} <code>this</code> to allow method chaining.
* @since 1.44
*/
Input.prototype.setSelectedRow = function(oListItem) {
if (typeof oListItem === "string") {
oListItem = Element.registry.get(oListItem);
}
if (oListItem !== null && !(oListItem instanceof ColumnListItem)) {
return this;
}
this.setSelectionRow(oListItem);
return this;
};
/**
* Returns/Instantiates the value help icon control when needed.
*
* @private
* @returns {object} Value help icon of the input.
*/
Input.prototype._getValueHelpIcon = function () {
var that = this,
sIconSrc = this.getValueHelpIconSrc();
// for backward compatibility - leave this method to return the instance
if (!this._oValueHelpIcon) {
this._oValueHelpIcon = this.addEndIcon({
id: this.getId() + "-vhi",
src: sIconSrc,
useIconTooltip: false,
alt: this._oRb.getText("INPUT_VALUEHELP_BUTTON"),
decorative: false,
noTabStop: true,
press: function (oEvent) {
// if the property valueHelpOnly is set to true, the event is triggered in the ontap function
if (!that.getValueHelpOnly()) {
var oParent = this.getParent(),
$input;
if (Device.support.touch) {
// prevent opening the soft keyboard
$input = oParent.$('inner');
$input.attr('readonly', 'readonly');
oParent.focus();
$input.removeAttr('readonly');
} else {
oParent.focus();
}
that.bValueHelpRequested = true;
that._fireValueHelpRequest(false);
}
}
});
} else if (this._oValueHelpIcon.getSrc() !== sIconSrc) {
this._oValueHelpIcon.setSrc(sIconSrc);
}
return this._oValueHelpIcon;
};
Input.prototype._getClearIcon = function () {
var that = this;
if (this._oClearButton) {
return this._oClearButton;
}
this._oClearButton = this.addEndIcon({
src: IconPool.getIconURI("decline"),
noTabStop: true,
visible: false,
alt: this._oRb.getText("INPUT_CLEAR_ICON_ALT"),
useIconTooltip: false,
decorative: false,
press: function () {
if (that.getValue() !== "") {
that.setValue("");
that.fireChange({
value: ""
});
that.fireLiveChange({
value: ""
});
that._bClearButtonPressed = true;
setTimeout(function() {
if (Device.system.desktop) {
that.focus();
that._closeSuggestionPopup();
}
}, 0);
}
}
}, 0);
return this._oClearButton;
};
/**
* Fire valueHelpRequest event.
*
* @private
*/
Input.prototype._fireValueHelpRequest = function(bFromSuggestions) {
// The goal is to provide a value in the value help event, which can be used to filter the opened Value Help Dialog.
var sTypedInValue = "";
if (this.getShowSuggestion() && !this.isMobileDevice()) {
sTypedInValue = this._getTypedInValue() || "";
} else {
sTypedInValue = this.getDOMValue();
}
this.fireValueHelpRequest({
fromSuggestions: bFromSuggestions,
_userInputValue: sTypedInValue // NOTE: Private parameter for the SmartControls which need only the value entered by the user.
});
};
/**
* Fire valueHelpRequest event if conditions for ValueHelpOnly property are met.
*
* @private
*/
Input.prototype._fireValueHelpRequestForValueHelpOnly = function() {
// if all the named properties are set to true, the control triggers "valueHelpRequest" for all user interactions
if (this.getEnabled() && this.getEditable() && this.getShowValueHelp() && this.getValueHelpOnly()) {
if (Device.system.phone) {
this.focus();
}
this._fireValueHelpRequest(false);
}
};
/**
* Fire valueHelpRequest event on tap.
*
* @public
* @param {jQuery.Event} oEvent Ontap event.
*/
Input.prototype.ontap = function(oEvent) {
InputBase.prototype.ontap.call(this, oEvent);
if (this.isValueHelpOnlyOpener(oEvent.target)) {
this._fireValueHelpRequestForValueHelpOnly();
}
if (this.shouldSuggetionsPopoverOpenOnMobile(oEvent)) {
this._openSuggestionsPopover();
}
this._bClearButtonPressed = false;
};
/**
* A helper function calculating if the SuggestionsPopover should be opened on mobile.
*
* @protected
* @param {jQuery.Event} oEvent Ontap event.
* @returns {boolean} If the popover should be opened.
*/
Input.prototype.shouldSuggetionsPopoverOpenOnMobile = function(oEvent) {
return this.isMobileDevice()
&& this.getEditable()
&& this.getEnabled()
&& this.getShowSuggestion()
&& (!this._bClearButtonPressed)
&& oEvent.target.id !== this.getId() + "-vhi";
};
/**
* Sets a custom filter function for suggestions. The default is to check whether the first item text begins with the typed value. For one and two-value suggestions this callback function will operate on sap.ui.core.Item types, for tabular suggestions the function will operate on sap.m.ColumnListItem types.
*
* @public
* @param {function(string=, sap.ui.core.Item=, boolean=):boolean|undefined|function} fnFilter The filter function is called when displaying suggestion items and has two input parameters: the first one is the string that is currently typed in the input field and the second one is the item that is being filtered. Returning true will add this item to the popup, returning false will not display it.
* @returns {this} this pointer for chaining
* @since 1.16.1
*/
Input.prototype.setFilterFunction = function(fnFilter) {
// reset to default function when calling with null or undefined
if (fnFilter === null || fnFilter === undefined) {
this._fnFilter = inputsDefaultFilter;
return this;
}
// set custom function
assert(typeof (fnFilter) === "function", "Input.setFilterFunction: first argument fnFilter must be a function on " + this);
this._fnFilter = fnFilter;
return this;
};
/**
* Returns a custom or default filter function for list or tabular suggestions.
*
* If no custom filter is set, default filtering is set depending on the type of the suggestions.
*
* @private
* @param {boolean} bForceDefaultFiltering Whether or not to apply the default filter even if custom one is set
*
* @returns {function} The default filter function depending on the type of the suggestions.
*/
Input.prototype._getFilterFunction = function(bForceDefaultFiltering) {
if (typeof this._fnFilter === "function" && !bForceDefaultFiltering) {
return this._fnFilter;
}
return !this._hasTabularSuggestions() ? inputsDefaultFilter : Input._DEFAULTFILTER_TABULAR;
};
/**
* Sets a custom result filter function for tabular suggestions to select the text that is passed to the input field. Default is to check whether the first cell with a "text" property begins with the typed value. For one value and two-value suggestions this callback function is not called.
*
* @public
* @param {function(string=, sap.ui.core.Item=, boolean=):boolean|undefined|function} fnFilter The result function is called with one parameter: the sap.m.ColumnListItem that is selected. The function must return a result string that will be displayed as the input field's value.
* @returns {this} this pointer for chaining
* @since 1.21.1
*/
Input.prototype.setRowResultFunction = function(fnFilter) {
var sSelectedRow;
// reset to default function when calling with null or undefined
if (fnFilter === null || fnFilter === undefined) {
this._fnRowResultFilter = Input._DEFAULTRESULT_TABULAR;
return this;
}
// set custom function
assert(typeof (fnFilter) === "function", "Input.setRowResultFunction: first argument fnFilter must be a function on " + this);
this._fnRowResultFilter = fnFilter;
sSelectedRow = this.getSelectedRow();
if (sSelectedRow) {
this.setSelectedRow(sSelectedRow);
}
return this;
};
/**
* Returns a custom or default filter function for tabular suggestions to select the text that is passed to the input field.
*
* If no custom filter is set or default filtering is forced, this function will apply the default filter to the column item.
*
* @private
* @param {boolean} bForceDefaultFiltering Whether or not to apply the default filter even if custom one is set
*
* @returns {function} The row filtering function(s) to execute on the selected row item.
*/
Input.prototype._getRowResultFunction = function(bForceDefaultFiltering) {
if (typeof this._fnRowResultFilter === "function" && !bForceDefaultFiltering) {
return this._fnRowResultFilter;
}
return Input._DEFAULTRESULT_TABULAR;
};
/**
* Closes the suggestion list.
*
* @public
* @since 1.48
*/
Input.prototype.closeSuggestions = function() {
this._closeSuggestionPopup();
};
/**
* Selects the text of the InputDomRef in the given range.
*
* @private
* @param {int} iStart Start of selection.
* @param {iEnd} iEnd End of selection.
* @returns {this} this Input instance for chaining.
*/
Input.prototype._doSelect = function(iStart, iEnd) {
var oDomRef = this._$input[0];
if (oDomRef) {
// if no Dom-Ref - no selection (Maybe popup closed)
var $Ref = this._$input;
oDomRef.focus();
$Ref.selectText(iStart ? iStart : 0, iEnd ? iEnd : $Ref.val().length);
}
return this;
};
/**
* Helper method for distinguishing between incremental and non-incremental types of input.
*
* @private
* @returns {boolean} Is it incremental type.
*/
Input.prototype._isIncrementalType = function () {
var sTypeOfInput = this.getType();
if (sTypeOfInput === "Number" || sTypeOfInput === "Date" ||
sTypeOfInput === "Datetime" || sTypeOfInput === "Month" ||
sTypeOfInput === "Time" || sTypeOfInput === "Week") {
return true;
}
return false;
};
/**
* Keyboard handler for escape key.
*
* @public
* @param {jQuery.Event} oEvent Keyboard event.
*/
Input.prototype.onsapescape = function(oEvent) {
if (this._isSuggestionsPopoverOpen()) {
// mark the event as already handled
oEvent.originalEvent._sapui_handledByControl = true;
this._revertPopupSelection();
// revert autocompleted value on desktop