@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
1,070 lines (943 loc) • 30.7 kB
JavaScript
/*!
* UI development toolkit for HTML5 (OpenUI5)
* (c) Copyright 2009-2022 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
sap.ui.define([
'sap/ui/Device',
'sap/ui/base/Object',
'sap/ui/core/InvisibleText',
'sap/ui/core/ListItem',
'sap/ui/core/ResizeHandler',
'sap/m/library',
'sap/m/Bar',
'sap/m/Button',
'sap/m/ColumnListItem',
'sap/m/Dialog',
'sap/m/DisplayListItem',
'sap/m/List',
'sap/m/Popover',
'sap/m/StandardListItem',
'sap/m/Table',
'sap/m/Toolbar',
'sap/m/ToolbarSpacer',
"sap/base/security/encodeXML"
], function (
Device,
BaseObject,
InvisibleText,
ListItem,
ResizeHandler,
library,
Bar,
Button,
ColumnListItem,
Dialog,
DisplayListItem,
List,
Popover,
StandardListItem,
Table,
Toolbar,
ToolbarSpacer,
encodeXML
) {
"use strict";
// shortcut for sap.m.ListMode
var ListMode = library.ListMode;
// shortcut for sap.m.PlacementType
var PlacementType = library.PlacementType;
// shortcut for sap.m.ListType
var ListType = library.ListType;
/**
* Provides a popover that should be used with an input control which requires suggestions.
*
* @extends sap.ui.base.Object
*
* @param {sap.ui.core.Control} oControl The input control that instantiates this suggestions popover
* @constructor
* @private
* @alias sap.m.SuggestionsPopover
*
* @author SAP SE
* @version 1.60.39
*/
var SuggestionsPopover = BaseObject.extend("sap.m.SuggestionsPopover", /** @lends sap.m.SuggestionsPopover.prototype */ {
constructor: function (oInput) {
BaseObject.apply(this, arguments);
// stores a reference to the input control that instantiates the popover
this._oInput = oInput;
// adds event delegate for the arrow keys
this._oInput.addEventDelegate({
onsapup: function(oEvent) {
this._onsaparrowkey(oEvent, "up", 1);
},
onsapdown: function(oEvent) {
this._onsaparrowkey(oEvent, "down", 1);
},
onsappageup: function(oEvent) {
this._onsaparrowkey(oEvent, "up", 5);
},
onsappagedown: function(oEvent) {
this._onsaparrowkey(oEvent, "down", 5);
},
onsaphome: function(oEvent) {
if (this._oList) {
this._onsaparrowkey(oEvent, "up", this._oList.getItems().length);
}
},
onsapend: function(oEvent) {
if (this._oList) {
this._onsaparrowkey(oEvent, "down", this._oList.getItems().length);
}
}
}, this);
},
destroy: function () {
if (this._oPopover) {
this._oPopover.destroy();
this._oPopover = null;
}
// CSN# 1404088/2014: list is not destroyed when it has not been attached to the popup yet
if (this._oList) {
this._oList.destroy();
this._oList = null;
}
if (this._oSuggestionTable) {
this._oSuggestionTable.destroy();
this._oSuggestionTable = null;
}
if (this._oButtonToolbar) {
this._oButtonToolbar.destroy();
this._oButtonToolbar = null;
}
if (this._oShowMoreButton) {
this._oShowMoreButton.destroy();
this._oShowMoreButton = null;
}
}
});
/**
* Returns true if some word from the text starts with specific value.
*
* @private
* @param {string} sText The text of the word.
* @param {string} sValue The value which must be compared to the word.
* @returns {boolean} Indication if the word starts with the passed value.
*/
SuggestionsPopover._wordStartsWithValue = function(sText, sValue) {
var index;
while (sText) {
if (typeof sValue === "string" && sValue !== "" && sText.toLowerCase().startsWith(sValue.toLowerCase())) {
return true;
}
index = sText.indexOf(' ');
if (index == -1) {
break;
}
sText = sText.substring(index + 1);
}
return false;
};
/**
* The default filter function for one and two-value. It checks whether the item text begins with the typed value.
*
* @private
* @param {string} sValue the current filter string.
* @param {sap.ui.core.Item} oItem the filtered list item.
* @returns {boolean} true for items that start with the parameter sValue, false for non matching items.
*/
SuggestionsPopover._DEFAULTFILTER = function(sValue, oItem) {
if (oItem instanceof ListItem && SuggestionsPopover._wordStartsWithValue(oItem.getAdditionalText(), sValue)) {
return true;
}
return SuggestionsPopover._wordStartsWithValue(oItem.getText(), sValue);
};
/**
* 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.
*/
SuggestionsPopover._DEFAULTFILTER_TABULAR = function(sValue, oColumnListItem) {
var aCells = oColumnListItem.getCells(),
i = 0;
for (; i < aCells.length; i++) {
if (aCells[i].getText) {
if (SuggestionsPopover._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.
*/
SuggestionsPopover._DEFAULTRESULT_TABULAR = function (oColumnListItem) {
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 "";
};
/**
* Checks if the suggestions popover is currently opened.
*
* @return {boolean} whether the suggestions popover is currently opened
* @public
*/
SuggestionsPopover.prototype.isOpen = function () {
return this._oPopover && this._oPopover.isOpen();
};
/**
* Helper function that creates suggestion popup.
*/
SuggestionsPopover.prototype._createSuggestionPopup = function () {
var oInput = this._oInput;
var oMessageBundle = oInput._oRb;
if (oInput._bUseDialog) {
this._oPopupInput = new sap.m.Input(oInput.getId() + "-popup-input", {
width : "100%",
valueLiveUpdate: true,
showValueHelp: oInput.getShowValueHelp(),
valueHelpRequest: function(oEvent) {
// it is the same behavior as by ShowMoreButton:
oInput.fireValueHelpRequest({fromSuggestions: true});
oInput._iPopupListSelectedIndex = -1;
oInput._closeSuggestionPopup();
},
liveChange : function(oEvent) {
var sValue = oEvent.getParameter("newValue");
// call _getInputValue to apply the maxLength to the typed value
oInput.setDOMValue(oInput
._getInputValue(this._oPopupInput
.getValue()));
oInput._triggerSuggest(sValue);
// make sure the live change handler on the original input is also called
oInput.fireLiveChange({
value: sValue,
// backwards compatibility
newValue: sValue
});
}.bind(this)
}).addStyleClass("sapMInputSuggInDialog");
}
this._oPopover = !oInput._bUseDialog ?
(new Popover(oInput.getId() + "-popup", {
showArrow: false,
showHeader: false,
placement: PlacementType.Vertical,
initialFocus: oInput,
horizontalScrolling: true
}).attachAfterClose(function() {
oInput._updateSelectionFromList();
// only destroy items in simple suggestion mode
if (this._oList instanceof Table) {
this._oList.removeSelections(true);
} else {
this._oList.destroyItems();
}
this._deregisterResize();
}.bind(this)).attachBeforeOpen(function () {
oInput._sBeforeSuggest = oInput.getValue();
this._resizePopup();
this._registerResize();
}.bind(this)))
:
(new Dialog(oInput.getId() + "-popup", {
beginButton : new Button(oInput.getId()
+ "-popup-closeButton", {
text : oMessageBundle.getText("MSGBOX_CLOSE"),
press : function() {
oInput._closeSuggestionPopup();
}
}),
stretch : oInput._bFullScreen,
contentHeight : oInput._bFullScreen ? undefined : "20rem",
customHeader : new Bar(oInput.getId()
+ "-popup-header", {
contentMiddle : this._oPopupInput.addEventDelegate({onsapenter: function(){
if (!(sap.m.MultiInput && oInput instanceof sap.m.MultiInput)) {
oInput._closeSuggestionPopup();
}
}}, this)
}),
horizontalScrolling : false,
initialFocus : this._oPopupInput
}).attachBeforeOpen(function() {
// set the same placeholder and maxLength as the original input
this._oPopupInput.setPlaceholder(oInput.getPlaceholder());
this._oPopupInput.setMaxLength(oInput.getMaxLength());
}.bind(this)).attachBeforeClose(function () {
// call _getInputValue to apply the maxLength to the typed value
oInput.setDOMValue(oInput
._getInputValue(this._oPopupInput
.getValue()));
oInput.onChange();
if (oInput instanceof sap.m.MultiInput && oInput._bUseDialog) {
oInput._onDialogClose();
}
}.bind(this)).attachAfterClose(function() {
// only destroy items in simple suggestion mode
if (this._oList) {
if (Table && !(this._oList instanceof Table)) {
this._oList.destroyItems();
} else {
this._oList.removeSelections(true);
}
}
}.bind(this)).attachAfterOpen(function () {
var sValue = oInput.getValue();
this._oPopupInput.setValue(sValue);
oInput._triggerSuggest(sValue);
oInput._oSuggPopover._refreshListItems();
}.bind(this)));
this._oPopover.addStyleClass("sapMInputSuggestionPopup");
this._oPopover.addAriaLabelledBy(InvisibleText.getStaticId("sap.m", "INPUT_AVALIABLE_VALUES"));
// add popup to a hidden aggregation to also propagate the model and bindings to the content of the popover
oInput.setAggregation("_suggestionPopup", this._oPopover);
if (!oInput._bUseDialog) {
this._overwritePopover();
}
if (this._oList) {
this._oPopover.addContent(this._oList);
}
if (oInput.getShowTableSuggestionValueHelp()) {
this._addShowMoreButton();
}
};
/**
* Helper function that creates content for the suggestion popup.
*
* @param {boolean | null } bTabular Content for the popup.
*/
SuggestionsPopover.prototype._createSuggestionPopupContent = function (bTabular) {
var oInput = this._oInput;
// only initialize the content once
if (oInput._bIsBeingDestroyed || this._oList) {
return;
}
if (!oInput._hasTabularSuggestions() && !bTabular) {
this._oList = new List(oInput.getId() + "-popup-list", {
showNoData : false,
mode : ListMode.SingleSelectMaster,
rememberSelections : false,
itemPress : function(oEvent) {
var oListItem = oEvent.getParameter("listItem");
oInput.setSelectionItem(oListItem._oItem, true);
}
});
this._oList.addEventDelegate({
onAfterRendering: function () {
if (!oInput.getEnableSuggestionsHighlighting()) {
return;
}
this._highlightListText(oInput.getValue());
}.bind(this)
});
} else {
// tabular suggestions
// if no custom filter is set we replace the default filter function here
if (oInput._fnFilter === SuggestionsPopover._DEFAULTFILTER) {
oInput._fnFilter = SuggestionsPopover._DEFAULTFILTER_TABULAR;
}
// if not custom row result function is set we set the default one
if (!oInput._fnRowResultFilter) {
oInput._fnRowResultFilter = SuggestionsPopover._DEFAULTRESULT_TABULAR;
}
this._oList = this._getSuggestionsTable();
if (oInput.getShowTableSuggestionValueHelp()) {
this._addShowMoreButton(bTabular);
}
}
if (this._oPopover) {
if (oInput._bUseDialog) {
// this._oList needs to be manually rendered otherwise it triggers a rerendering of the whole
// dialog and may close the opened on screen keyboard
this._oPopover.addAggregation("content", this._oList, true);
var oRenderTarget = this._oPopover.$("scrollCont")[0];
if (oRenderTarget) {
var rm = sap.ui.getCore().createRenderManager();
rm.renderControl(this._oList);
rm.flush(oRenderTarget);
rm.destroy();
}
} else {
this._oPopover.addContent(this._oList);
}
}
};
/**
* Helper function that destroys suggestion popup.
*/
SuggestionsPopover.prototype._destroySuggestionPopup = function () {
if (this._oPopover) {
// if the table is not removed before destroying the popup the table is also destroyed (table needs to stay because we forward the column and row aggregations to the table directly, they would be destroyed as well)
if (this._oList instanceof Table) {
this._oPopover.removeAllContent();
// also remove the button/toolbar aggregation
this._removeShowMoreButton();
}
this._oPopover.destroy();
this._oPopover = null;
}
// CSN# 1404088/2014: list is not destroyed when it has not been attached to the popup yet
if (this._oList instanceof List) {
this._oList.destroy();
this._oList = null;
}
};
/**
* Adds a show more button to the footer of the tabular suggestion popup/dialog.
*
* @private
* @param{boolean} [bTabular] optional parameter to force override the tabular suggestions check
*/
SuggestionsPopover.prototype._addShowMoreButton = function(bTabular) {
if (!this._oPopover || !bTabular && !this._oInput._hasTabularSuggestions()) {
return;
}
if (this._oPopover instanceof Dialog) {
// phone variant, use endButton (beginButton is close)
var oShowMoreButton = this._getShowMoreButton();
this._oPopover.setEndButton(oShowMoreButton);
} else {
var oButtonToolbar = this._getButtonToolbar();
// desktop/tablet variant, use popover footer
this._oPopover.setFooter(oButtonToolbar);
}
};
/**
* Removes the show more button from the footer of the tabular suggestion popup/dialog.
*
* @private
*/
SuggestionsPopover.prototype._removeShowMoreButton = function() {
if (!this._oPopover || !this._oInput._hasTabularSuggestions()) {
return;
}
if (this._oPopover instanceof Dialog) {
this._oPopover.setEndButton(null);
} else {
this._oPopover.setFooter(null);
}
};
/**
* Gets show more button.
*
* @private
* @return {sap.m.Button} Show more button.
*/
SuggestionsPopover.prototype._getShowMoreButton = function() {
var oInput = this._oInput,
oMessageBundle = oInput._oRb;
return this._oShowMoreButton || (this._oShowMoreButton = new sap.m.Button({
text : oMessageBundle.getText("INPUT_SUGGESTIONS_SHOW_ALL"),
press : function() {
if (oInput.getShowTableSuggestionValueHelp()) {
oInput.fireValueHelpRequest({fromSuggestions: true});
oInput._iPopupListSelectedIndex = -1;
oInput._closeSuggestionPopup();
}
}
}));
};
/**
* Gets button toolbar.
*
* @private
* @return {sap.m.Toolbar} Button toolbar.
*/
SuggestionsPopover.prototype._getButtonToolbar = function() {
var oShowMoreButton = this._getShowMoreButton();
return this._oButtonToolbar || (this._oButtonToolbar = new Toolbar({
content: [
new ToolbarSpacer(),
oShowMoreButton
]
}));
};
/**
* Helper function that overwrites popover in the Input.
*/
SuggestionsPopover.prototype._overwritePopover = function () {
var oInput = this._oInput;
this._oPopover.open = function () {
this.openBy(oInput, false, true);
};
// remove animation from popover
this._oPopover.oPopup.setAnimations(function ($Ref, iRealDuration, fnOpened) {
fnOpened();
}, function($Ref, iRealDuration, fnClosed) {
fnClosed();
});
};
/**
* Resize the popup to the input width and makes sure that the input is never bigger than the popup.
*
* @private
*/
SuggestionsPopover.prototype._resizePopup = function() {
var oInput = this._oInput;
if (this._oList && this._oPopover) {
if (oInput.getMaxSuggestionWidth()) {
this._oPopover.setContentWidth(oInput.getMaxSuggestionWidth());
} else {
this._oPopover.setContentWidth((oInput.$().outerWidth()) + "px");
}
// resize suggestion popup to minimum size of the input field
setTimeout(function() {
if (this._oPopover && this._oPopover.isOpen() && this._oPopover.$().outerWidth() < oInput.$().outerWidth()) {
this._oPopover.setContentWidth((oInput.$().outerWidth()) + "px");
}
}.bind(this), 0);
}
};
/**
* Registers resize handler
*
* @private
*/
SuggestionsPopover.prototype._registerResize = function() {
if (!this._oInput._bFullScreen) {
this._sPopupResizeHandler = ResizeHandler.register(this._oInput, this._resizePopup.bind(this));
}
};
/**
* Removes resize handler
*
* @private
*/
SuggestionsPopover.prototype._deregisterResize = function() {
if (this._sPopupResizeHandler) {
this._sPopupResizeHandler = ResizeHandler.deregister(this._sPopupResizeHandler);
}
};
/**
* Helper function that refreshes list all items.
*/
SuggestionsPopover.prototype._refreshListItems = function () {
var oInput = this._oInput;
var bShowSuggestion = oInput.getShowSuggestion();
var oRb = oInput._oRb;
oInput._iPopupListSelectedIndex = -1;
if (!bShowSuggestion ||
!oInput._bShouldRefreshListItems ||
!oInput.getDomRef() ||
(!oInput._bUseDialog && !oInput.$().hasClass("sapMInputFocused"))) {
return false;
}
var oItem,
aItems = oInput.getSuggestionItems(),
aTabularRows = oInput.getSuggestionRows(),
sTypedChars = oInput.getDOMValue() || "",
oList = this._oList,
bFilter = oInput.getFilterSuggests(),
aHitItems = [],
iItemsLength = 0,
oPopup = this._oPopover,
oListItemDelegate = {
ontouchstart : function(oEvent) {
(oEvent.originalEvent || oEvent)._sapui_cancelAutoClose = true;
}
},
oListItem,
i;
// only destroy items in simple suggestion mode
if (this._oList) {
if (this._oList instanceof Table) {
oList.removeSelections(true);
} else {
//TODO: avoid flickering when !bFilter
oList.destroyItems();
}
}
// hide suggestions list/table if the number of characters is smaller than limit
if (sTypedChars.length < oInput.getStartSuggestion()) {
// when the input has no value, close the Popup when not runs on the phone because the opened dialog on phone shouldn't be closed.
if (!oInput._bUseDialog) {
oInput._iPopupListSelectedIndex = -1;
oInput.cancelPendingSuggest();
oPopup.close();
} else {
// hide table on phone when value is empty
if (oInput._hasTabularSuggestions() && this._oList) {
this._oList.addStyleClass("sapMInputSuggestionTableHidden");
}
}
oInput.$("SuggDescr").text(""); // clear suggestion text
oInput.$("inner").removeAttr("aria-haspopup");
oInput.$("inner").removeAttr("aria-activedescendant");
return false;
}
if (oInput._hasTabularSuggestions()) {
// show list on phone (is hidden when search string is empty)
if (oInput._bUseDialog && this._oList) {
this._oList.removeStyleClass("sapMInputSuggestionTableHidden");
}
// filter tabular items
for (i = 0; i < aTabularRows.length; i++) {
if (!bFilter || oInput._fnFilter(sTypedChars, aTabularRows[i])) {
aTabularRows[i].setVisible(true);
aHitItems.push(aTabularRows[i]);
} else {
aTabularRows[i].setVisible(false);
}
}
this._oSuggestionTable.invalidate();
} else {
// filter standard items
var bListItem = (aItems[0] instanceof ListItem ? true : false);
for (i = 0; i < aItems.length; i++) {
oItem = aItems[i];
if (!bFilter || oInput._fnFilter(sTypedChars, oItem)) {
if (bListItem) {
oListItem = new DisplayListItem(oItem.getId() + "-dli");
oListItem.setLabel(oItem.getText());
oListItem.setValue(oItem.getAdditionalText());
} else {
oListItem = new StandardListItem(oItem.getId() + "-sli");
oListItem.setTitle(oItem.getText());
}
oListItem.setType(oItem.getEnabled() ? ListType.Active : ListType.Inactive);
oListItem._oItem = oItem;
oListItem.addEventDelegate(oListItemDelegate);
aHitItems.push(oListItem);
}
}
}
iItemsLength = aHitItems.length;
var sAriaText = "";
if (iItemsLength > 0) {
// add items to list
if (iItemsLength == 1) {
sAriaText = oRb.getText("INPUT_SUGGESTIONS_ONE_HIT");
} else {
sAriaText = oRb.getText("INPUT_SUGGESTIONS_MORE_HITS", iItemsLength);
}
oInput.$("inner").attr("aria-haspopup", "true");
if (!oInput._hasTabularSuggestions()) {
for (i = 0; i < iItemsLength; i++) {
oList.addItem(aHitItems[i]);
}
}
if (!oInput._bUseDialog) {
if (oInput._sCloseTimer) {
clearTimeout(oInput._sCloseTimer);
oInput._sCloseTimer = null;
}
if (!oPopup.isOpen() && !oInput._sOpenTimer && (oInput.getValue().length >= oInput.getStartSuggestion())) {
oInput._sOpenTimer = setTimeout(function() {
oInput._sOpenTimer = null;
oPopup.open();
}, 0);
}
}
} else {
sAriaText = oRb.getText("INPUT_SUGGESTIONS_NO_HIT");
oInput.$("inner").removeAttr("aria-haspopup");
oInput.$("inner").removeAttr("aria-activedescendant");
if (!oInput._bUseDialog) {
if (oPopup.isOpen()) {
oInput._sCloseTimer = setTimeout(function() {
oInput._iPopupListSelectedIndex = -1;
oInput.cancelPendingSuggest();
oPopup.close();
}, 0);
}
} else {
// hide table on phone when there are no items to display
if (oInput._hasTabularSuggestions() && this._oList) {
this._oList.addStyleClass("sapMInputSuggestionTableHidden");
}
}
}
// update Accessibility text for suggestion
oInput.$("SuggDescr").text(sAriaText);
};
/**
* Keyboard handler helper.
*
* @private
* @param {jQuery.Event} oEvent Arrow key event.
* @param {string} sDir Arrow direction.
* @param {int} iItems Items to be changed.
*/
SuggestionsPopover.prototype._onsaparrowkey = function(oEvent, sDir, iItems) {
var oInput = this._oInput;
if (!oInput.getEnabled() || !oInput.getEditable()) {
return;
}
if (sDir !== "up" && sDir !== "down") {
return;
}
if (oInput._isIncrementalType()){
oEvent.setMarked();
}
if (!this._oPopover || !this._oPopover.isOpen()) {
return;
}
oEvent.preventDefault();
oEvent.stopPropagation();
var bFirst = false,
oList = this._oList,
aItems = oInput.getSuggestionItems(),
aListItems = oList.getItems(),
iSelectedIndex = oInput._iPopupListSelectedIndex,
sNewValue,
iOldIndex = iSelectedIndex;
if (sDir === "up" && iSelectedIndex === 0) {
// if key is 'up' and selected Item is first -> do nothing
return;
}
if (sDir == "down" && iSelectedIndex === aListItems.length - 1) {
//if key is 'down' and selected Item is last -> do nothing
return;
}
var iStopIndex;
if (iItems > 1) {
// if iItems would go over the borders, search for valid item in other direction
if (sDir == "down" && iSelectedIndex + iItems >= aListItems.length) {
sDir = "up";
iItems = 1;
aListItems[iSelectedIndex].setSelected(false);
iStopIndex = iSelectedIndex;
iSelectedIndex = aListItems.length - 1;
bFirst = true;
} else if (sDir == "up" && iSelectedIndex - iItems < 0){
sDir = "down";
iItems = 1;
aListItems[iSelectedIndex].setSelected(false);
iStopIndex = iSelectedIndex;
iSelectedIndex = 0;
bFirst = true;
}
}
// always select the first item from top when nothing is selected so far
if (iSelectedIndex === -1) {
iSelectedIndex = 0;
if (oInput._isSuggestionItemSelectable(aListItems[iSelectedIndex])) {
// if first item is visible, don't go into while loop
iOldIndex = iSelectedIndex;
bFirst = true;
} else {
// detect first visible item with while loop
sDir = "down";
}
}
if (sDir === "down") {
while (iSelectedIndex < aListItems.length - 1 && (!bFirst || !oInput._isSuggestionItemSelectable(aListItems[iSelectedIndex]))) {
aListItems[iSelectedIndex].setSelected(false);
iSelectedIndex = iSelectedIndex + iItems;
bFirst = true;
iItems = 1; // if wanted item is not selectable just search the next one
if (iStopIndex === iSelectedIndex) {
break;
}
}
} else {
while (iSelectedIndex > 0 && (!bFirst || !aListItems[iSelectedIndex].getVisible() || !oInput._isSuggestionItemSelectable(aListItems[iSelectedIndex]))) {
aListItems[iSelectedIndex].setSelected(false);
iSelectedIndex = iSelectedIndex - iItems;
bFirst = true;
iItems = 1; // if wanted item is not selectable just search the next one
if (iStopIndex === iSelectedIndex) {
break;
}
}
}
if (!oInput._isSuggestionItemSelectable(aListItems[iSelectedIndex])) {
// if no further visible item can be found -> do nothing (e.g. set the old item as selected again)
if (iOldIndex >= 0) {
aListItems[iOldIndex].setSelected(true).updateAccessibilityState();
oInput.$("inner").attr("aria-activedescendant", aListItems[iOldIndex].getId());
}
return;
} else {
aListItems[iSelectedIndex].setSelected(true).updateAccessibilityState();
oInput.$("inner").attr("aria-activedescendant", aListItems[iSelectedIndex].getId());
}
if (Device.system.desktop) {
this._scrollToItem(iSelectedIndex);
}
// make sure the value doesn't exceed the maxLength
if (ColumnListItem && aListItems[iSelectedIndex] instanceof ColumnListItem) {
// for tabular suggestions we call a result filter function
sNewValue = oInput._getInputValue(oInput._fnRowResultFilter(aListItems[iSelectedIndex]));
} else {
var bListItem = (aItems[0] instanceof ListItem ? true : false);
if (bListItem) {
// for two value suggestions we use the item label
sNewValue = oInput._getInputValue(aListItems[iSelectedIndex].getLabel());
} else {
// otherwise we use the item title
sNewValue = oInput._getInputValue(aListItems[iSelectedIndex].getTitle());
}
}
// setValue isn't used because here is too early to modify the lastValue of input
oInput.setDOMValue(sNewValue);
// memorize the value set by calling jQuery.val, because browser doesn't fire a change event when the value is set programmatically.
oInput._sSelectedSuggViaKeyboard = sNewValue;
oInput._doSelect();
oInput._iPopupListSelectedIndex = iSelectedIndex;
};
/**
* Scrolls to item.
*
* @private
* @param {int} iIndex Index of the item to scroll to.
*/
SuggestionsPopover.prototype._scrollToItem = function(iIndex) {
var oPopup = this._oPopover,
oList = this._oList,
oScrollDelegate,
oPopupRect,
oItemRect,
iTop,
iBottom;
if (!(oPopup instanceof Popover) || !oList) {
return;
}
oScrollDelegate = oPopup.getScrollDelegate();
if (!oScrollDelegate) {
return;
}
var oListItem = oList.getItems()[iIndex],
oListItemDom = oListItem && oListItem.getDomRef();
if (!oListItemDom) {
return;
}
oPopupRect = oPopup.getDomRef("cont").getBoundingClientRect();
oItemRect = oListItemDom.getBoundingClientRect();
iTop = oPopupRect.top - oItemRect.top;
iBottom = oItemRect.bottom - oPopupRect.bottom;
if (iTop > 0) {
oScrollDelegate.scrollTo(oScrollDelegate._scrollX, Math.max(oScrollDelegate._scrollY - iTop, 0));
} else if (iBottom > 0) {
oScrollDelegate.scrollTo(oScrollDelegate._scrollX, oScrollDelegate._scrollY + iBottom);
}
};
/**
* Gets suggestion table with lazy loading.
*
* @private
* @returns {sap.m.Table} Suggestion table.
*/
SuggestionsPopover.prototype._getSuggestionsTable = function() {
var oInput = this._oInput;
if (oInput._bIsBeingDestroyed) {
return;
}
if (!this._oSuggestionTable) {
this._oSuggestionTable = new Table(oInput.getId() + "-popup-table", {
mode: ListMode.SingleSelectMaster,
showNoData: false,
showSeparators: "All",
width: "100%",
enableBusyIndicator: false,
rememberSelections : false,
selectionChange: function (oEvent) {
var oSelectedListItem = oEvent.getParameter("listItem");
oInput.setSelectionRow(oSelectedListItem, true);
}
});
this._oSuggestionTable.addEventDelegate({
onAfterRendering: function () {
if (!oInput.getEnableSuggestionsHighlighting()) {
return;
}
this._highlightTableText(oInput.getValue());
}.bind(this)
});
// initially hide the table on phone
if (this._bUseDialog) {
this._oSuggestionTable.addStyleClass("sapMInputSuggestionTableHidden");
}
this._oSuggestionTable.updateItems = function() {
Table.prototype.updateItems.apply(oInput, arguments);
oInput._refreshItemsDelayed();
return oInput;
};
}
oInput._oSuggestionTable = this._oSuggestionTable; // for backward compatibility (used in some other controls)
return this._oSuggestionTable;
};
/**
* Creates highlighted text.
*
* @private
* @param {sap.m.Label} label Label within the input.
* @returns {string} newText Created text.
*/
SuggestionsPopover.prototype._createHighlightedText = function (label) {
var text = label.innerText,
value = this._oInput.getValue().toLowerCase(),
count = value.length,
lowerText = text.toLowerCase(),
subString,
newText = '';
if (!SuggestionsPopover._wordStartsWithValue(text, value)) {
return encodeXML(text);
}
var index = lowerText.indexOf(value);
// search for the first word which starts with these characters
if (index > 0) {
index = lowerText.indexOf(' ' + value) + 1;
}
if (index > -1) {
newText += encodeXML(text.substring(0, index));
subString = text.substring(index, index + count);
newText += '<span class="sapMInputHighlight">' + encodeXML(subString) + '</span>';
newText += encodeXML(text.substring(index + count));
} else {
newText = encodeXML(text);
}
return newText;
};
/**
* Highlights matched text in the suggestion list.
*
* @private
*/
SuggestionsPopover.prototype._highlightListText = function () {
if (!this._oInput.getEnableSuggestionsHighlighting()) {
return;
}
var i,
label,
labels = this._oList.$().find('.sapMDLILabel, .sapMSLITitleOnly, .sapMDLIValue');
for (i = 0; i < labels.length; i++) {
label = labels[i];
label.innerHTML = this._createHighlightedText(label);
}
};
/**
* Highlights matched text in the suggestion table.
*
* @private
*/
SuggestionsPopover.prototype._highlightTableText = function () {
if (!this._oInput.getEnableSuggestionsHighlighting()) {
return;
}
var i,
label,
labels = this._oSuggestionTable.$().find('tbody .sapMLabel');
for (i = 0; i < labels.length; i++) {
label = labels[i];
label.innerHTML = this._createHighlightedText(label);
}
};
return SuggestionsPopover;
});