@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
618 lines (520 loc) • 17.3 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2026 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
sap.ui.define([
"sap/base/i18n/Formatting",
"sap/base/i18n/date/CalendarType",
"sap/ui/core/Lib",
"sap/ui/core/Control",
"sap/ui/model/type/Date",
"sap/ui/model/odata/type/ODataType",
"sap/ui/core/format/DateFormat",
"sap/ui/core/LocaleData",
"sap/ui/core/Locale",
"./library",
"./Button",
"sap/ui/core/date/UI5Date",
"./TimePickerInternalsRenderer"
],
function(
Formatting,
CalendarType,
Library,
Control,
SimpleDateType,
ODataType,
DateFormat,
LocaleData,
Locale,
library,
Button,
UI5Date,
TimePickerInternalsRenderer
) {
"use strict";
var DEFAULT_STEP = 1,
ButtonType = library.ButtonType;
/**
* Constructor for a new <code>TimePickerInternals</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
* TimePicker related internal class used inside the controls in {@link sap.m.TimePicker} that handle time editing.
* @extends sap.ui.core.Control
*
* @author SAP SE
* @version 1.146.0
*
* @constructor
* @private
* @since 1.90
* @alias sap.m.TimePickerInternals
*/
var TimePickerInternals = Control.extend("sap.m.TimePickerInternals", /** @lends sap.m.TimePickerInternals.prototype */ {
metadata : {
library : "sap.m",
properties : {
/**
* Defines the locale used to parse string values representing time.
*
* Determines the locale, used to interpret the string, supplied by the
* <code>value</code> property.
*
* Example: AM in the string "09:04 AM" is locale (language) dependent.
* The format comes from the browser language settings if not set explicitly.
* Used in combination with 12 hour <code>displayFormat</code> containing 'a', which
* stands for day period string.
*/
localeId: {type : "string", group: "Data"},
/**
* Defines the time <code>displayFormat</code> of the clocks.
* The <code>displayFormat</code> comes from the browser language settings if not set explicitly.
*
*/
displayFormat: {type: "string", group: "Appearance"},
/**
* Sets the minutes clock step. The step must be at least 1
*/
minutesStep: {type: "int", group: "Misc", defaultValue: DEFAULT_STEP},
/**
* Sets the seconds clock step. The step must be at least 1
*/
secondsStep: {type: "int", group: "Misc", defaultValue: DEFAULT_STEP},
/**
* Defines the value of the control.
*/
value: { type: "string", group: "Data", defaultValue: null},
/**
* Determines the format of the <code>value</code> property.
*/
valueFormat: {type: "string", group: "Data", defaultValue: null},
/**
* Allows to set a value of 24:00, used to indicate the end of the day.
* Works only with HH or H formats. Don't use it together with am/pm.
*/
support2400: {type: "boolean", group: "Misc", defaultValue: false},
/**
* Determines whether there is a shortcut navigation to current time.
*
* @since 1.98
*/
showCurrentTimeButton : {type : "boolean", group : "Behavior", defaultValue : false}
},
aggregations: {
/**
* Holds the inner AM/PM segmented button.
*/
_buttonAmPm: { type: "sap.m.SegmentedButton", multiple: false, visibility: "hidden" },
/**
* Holds the inner button for shortcut navigation to current time.
*/
_nowButton: { type: "sap.m.Button", multiple: false, visibility: "hidden" }
}
},
renderer: TimePickerInternalsRenderer
});
/**
* Initializes the control.
*
* @private
*/
TimePickerInternals.prototype.init = function () {
var oLocale = new Locale(Formatting.getLanguageTag()),
oLocaleData = LocaleData.getInstance(oLocale),
aPeriods = oLocaleData.getDayPeriods("abbreviated"),
sDefaultDisplayFormat = oLocaleData.getTimePattern("medium");
this._oResourceBundle = Library.getResourceBundleFor("sap.m");
this._sAM = aPeriods[0];
this._sPM = aPeriods[1];
this._kbdBuffer = "";
this.setDisplayFormat(sDefaultDisplayFormat);
this._setTimeValues();
this._sMinutes; //needed for the 2400 scenario to store the minutes and seconds when changing hour to 24 and back
this._sSeconds; //needed for the 2400 scenario to store the minutes and seconds when changing hour to 24 and back
this._clickAttached; // needed for focus capturing when click outside buttons
this._setAriaLabel(this._oResourceBundle.getText("TIMEPICKER_CLOCK_DIAL_LABEL"));
this._setAriaRoleDescription(this._oResourceBundle.getText("TIMEPICKER_INPUTS_ROLE_DESCRIPTION"));
};
/**
* Destroys the control.
*
* @private
*/
TimePickerInternals.prototype.exit = function () {
this._destroyControls();
this.destroyAggregation("_texts");
if (this._oNowButton) {
this._oNowButton.destroy();
this._oNowButton = null;
}
};
/**
* Sets the time <code>displayFormat</code>.
*
* @param {string} sFormat New display format
* @returns {this} <code>this</code> instance, used for chaining
* @public
*/
TimePickerInternals.prototype.setDisplayFormat = function (sFormat) {
this.setProperty("displayFormat", sFormat, true);
this._destroyControls();
this._createControls();
return this;
};
/**
* Sets the <code>localeId</code> property.
*
* @param {string} sLocaleId The ID of the Locale
* @returns {this} <code>this</code> instance, used for chaining
* @public
*/
TimePickerInternals.prototype.setLocaleId = function(sLocaleId) {
var oLocale,
aPeriods;
sLocaleId = this.validateProperty("localeId", sLocaleId);
this.setProperty("localeId", sLocaleId, true);
if (sLocaleId) {
oLocale = new Locale(sLocaleId);
aPeriods = LocaleData.getInstance(oLocale).getDayPeriods("abbreviated");
this._sAM = aPeriods[0];
this._sPM = aPeriods[1];
this._destroyControls();
this._createControls();
}
return this;
};
/**
* Sets <code>support2400</code> property.
*
* @param {boolean} bSupport2400 Whether the control supports setting of 24:00 value
* @returns {this} <code>this</code> instance, used for chaining
* @public
*/
TimePickerInternals.prototype.setSupport2400 = function (bSupport2400) {
this.setProperty("support2400", bSupport2400, true);
this._destroyControls();
this._createControls();
return this;
};
/**
* Sets the minutes clock step.
* @param {int} value The step used to generate values for the minutes clock
* @returns {this} <code>this</code> to allow method chaining
* @public
*/
TimePickerInternals.prototype.setMinutesStep = function(value) {
this.setProperty("minutesStep", value, true);
this._destroyControls();
this._createControls();
return this;
};
/**
* Sets the seconds clock step.
* @param {int} value The step used to generate values for the seconds clock
* @returns {this} <code>this</code> to allow method chaining
* @public
*/
TimePickerInternals.prototype.setSecondsStep = function(value) {
this.setProperty("secondsStep", value, true);
this._destroyControls();
this._createControls();
return this;
};
TimePickerInternals.prototype.setShowCurrentTimeButton = function(bShow) {
this._getCurrentTimeButton().setVisible(bShow);
return this.setProperty("showCurrentTimeButton", bShow);
};
/*
* PRIVATE API
*/
/**
* Destroys Contols of the picker.
* Must be overridden by controls that extend TimePickerInternals.
* @private
*/
TimePickerInternals.prototype._destroyControls = function() {};
/**
* Creates Contols of the picker.
* Must be overridden by controls that extend TimePickerInternals.
* @private
*/
TimePickerInternals.prototype._createControls = function() {};
/**
* Set what picker controls show.
*
* @param {object} oDate JavaScript date object
* @param {boolean} bHoursValueIs24 whether the hours value is 24 or not
* @private
*/
TimePickerInternals.prototype._setTimeValues = function(oDate, bHoursValueIs24) {};
/**
* @private
*/
TimePickerInternals.prototype._checkStyle = function (sPattern) {
return (sPattern === "short" || sPattern === "medium" || sPattern === "long" || sPattern === "full");
};
/**
* @private
*/
TimePickerInternals.prototype._getDisplayFormatPattern = function () {
var sPattern = this.getDisplayFormat();
if (this._checkStyle(sPattern)) {
sPattern = this._getLocaleBasedPattern(sPattern);
}
return sPattern;
};
/**
* @private
*/
TimePickerInternals.prototype._getValueFormatPattern = function () {
var sPattern = this._getBoundValueTypePattern() || this.getValueFormat() || "medium";
if (this._checkStyle(sPattern)) {
sPattern = this._getLocaleBasedPattern(sPattern);
}
return sPattern;
};
/**
* @private
*/
TimePickerInternals.prototype._getLocaleBasedPattern = function (sPlaceholder) {
return LocaleData.getInstance(
new Locale(Formatting.getLanguageTag())
).getTimePattern(sPlaceholder);
};
/**
* Returns the segmented button for the format.
* @returns {sap.m.SegmentedButton|null} Format segmented button
* @private
*/
TimePickerInternals.prototype._getFormatButton = function () {
return this.getAggregation("_buttonAmPm");
};
/**
* @private
*/
TimePickerInternals.prototype._parseValue = function (sValue) {
return this._getFormatter().parse(sValue);
};
/**
* @private
*/
TimePickerInternals.prototype._getFormatter = function () {
var sPattern = this._getBoundValueTypePattern(),
bRelative = false, // if true strings like "Tomorrow" are parsed fine
oBinding = this.getBinding("value"),
sCalendarType;
if (oBinding && oBinding.oType && oBinding.oType.oOutputFormat) {
bRelative = !!oBinding.oType.oOutputFormat.oFormatOptions.relative;
sCalendarType = oBinding.oType.oOutputFormat.oFormatOptions.calendarType;
}
if (!sPattern) {
// not databinding is used -> use given format
sPattern = this.getValueFormat() || "medium";
sCalendarType = CalendarType.Gregorian;
}
if (!sCalendarType) {
sCalendarType = Formatting.getCalendarType();
}
return this._getFormatterInstance(sPattern, bRelative, sCalendarType);
};
/**
* @private
*/
TimePickerInternals.prototype._getBoundValueTypePattern = function () {
var oBinding = this.getBinding("value"),
oBindingType = oBinding && oBinding.getType && oBinding.getType();
if (oBindingType instanceof SimpleDateType) {
return oBindingType.getOutputPattern();
}
if (oBindingType instanceof ODataType && oBindingType.oFormat) {
return oBindingType.oFormat.oFormatOptions.pattern;
}
return undefined;
};
/**
* @private
*/
TimePickerInternals.prototype._getFormatterInstance = function (sPattern, bRelative, sCalendarType, bDisplayFormat) {
var oFormat;
if (this._checkStyle(sPattern)) {
oFormat = this._getFormatInstance({style: sPattern, strictParsing: true, relative: bRelative, calendarType: sCalendarType});
} else {
oFormat = this._getFormatInstance({pattern: sPattern, strictParsing: true, relative: bRelative, calendarType: sCalendarType});
}
return oFormat;
};
/**
* @private
*/
TimePickerInternals.prototype._getFormatInstance = function (oArguments, bDisplayFormat) {
return DateFormat.getTimeInstance(oArguments);
};
/**
* @private
*/
TimePickerInternals.prototype._formatValue = function (oDate) {
if (oDate) {
return this._getFormatter().format(oDate);
}
return "";
};
/**
* Returns if the displayFormatPattern is HH or H (24 hours format with or without leading zero).
* @returns {boolean} Is the displayFormatPattern is HH or H (24 hours format with or without leading zero).
* @private
*/
TimePickerInternals.prototype._isFormatSupport24 = function () {
var sFormat = this._getDisplayFormatPattern();
return sFormat.indexOf("HH") !== -1 || sFormat.indexOf("H") !== -1;
};
TimePickerInternals.prototype._formatNumberToString = function (iNumber, bPrependZero, iMax, sReplacement) {
var sNumber;
if (bPrependZero && iNumber < 10) {
sNumber = "0" + iNumber;
} else if (iNumber === iMax && sReplacement !== "") {
sNumber = sReplacement;
} else {
sNumber = iNumber.toString();
}
return sNumber;
};
/**
* Sets the value for aria-label attribute.
* @param {string} sAriaLabel
* @return {this} this for chaining
* @private
*/
TimePickerInternals.prototype._setAriaLabel = function (sAriaLabel) {
this._sAriaLabel = sAriaLabel;
return this;
};
/**
* Returns the aria-roledescription value.
* @return {string} aria-roledescription
* @private
*/
TimePickerInternals.prototype._getAriaLabel = function () {
return this._sAriaLabel;
};
/**
* Sets the value for aria-roledescription attribute.
* @param {string} sAriaRoleDescription
* @return {this} this for chaining
* @private
*/
TimePickerInternals.prototype._setAriaRoleDescription = function (sAriaRoleDescription) {
this._sAriaRoleDescription = sAriaRoleDescription;
return this;
};
/**
* Returns the aria-roledescription value.
* @return {string} aria-roledescription
* @private
*/
TimePickerInternals.prototype._getAriaRoleDescription = function () {
return this._sAriaRoleDescription;
};
// Static Methods
/**
* Returns value with replaced zeros for the Hours.
*
* Example:
* 00:00:00 with displayFormat "HH:mm:ss" -> 24:00:00
* 00:00:00 with displayFormat "mm:HH:ss" -> 00:24:00
* 0:00:00 with displayFormat "H:mm:ss" -> 24:00:00
* 00:0:00 with displayFormat "mm:H:ss" -> 00:24:00
* @param {string} sValue Value to replace the zeroes in
* @param {int} iIndexOfHH index of the HH in the displayFormat
* @param {int} iIndexOfH index of the H in the displayFormat
* @private
*/
TimePickerInternals._replaceZeroHoursWith24 = function (sValue, iIndexOfHH, iIndexOfH) {
var iHoursDigits = 2,
sTrailingSpaces = ' ',
iSubStringIndex = iIndexOfHH,
bTrailingSpaces = sValue.charAt(iIndexOfH) === sTrailingSpaces,
iExtraIndex = bTrailingSpaces ? 1 : 0;
var oSignificantNumbers = /[1-9]/g;
if (iIndexOfH === -1) {
return sValue;
}
if (iIndexOfHH === -1) {
iHoursDigits = 1;
iSubStringIndex = iIndexOfH;
}
var sValueWithoutHours = sValue.substring(0, iSubStringIndex) + sValue.substring(iSubStringIndex + iExtraIndex + iHoursDigits);
if (oSignificantNumbers.test(sValueWithoutHours)) {
return sValue;
}
sValue = sValue.replace(/[0-9]/g, "0");
return sValue.substring(0, iSubStringIndex) + "24" + sValue.substring(iSubStringIndex + iExtraIndex + iHoursDigits);
};
/**
* Returns value with replaced zeros for the Hours.
*
* Example:
* 24:00:00 with displayFormat "HH:mm:ss" -> 00:00:00
* 00:24:00 with displayFormat "mm:HH:ss" -> 00:00:00
* 24:00:00 with displayFormat "H:mm:ss" -> 0:00:00
* 00:24:00 with displayFormat "mm:H:ss" -> 00:0:00
* @param {string} sValue Value to replace the 24 with zeroes in
* @param {int} iIndexOfHH index of the HH in the displayFormat
* @param {int} iIndexOfH index of the H in the displayFormat
* @private
*/
TimePickerInternals._replace24HoursWithZero = function (sValue, iIndexOfHH, iIndexOfH) {
var iHoursDigits = 2,
iSubStringIndex = iIndexOfHH;
if (iIndexOfHH === -1) {
iHoursDigits = 1;
iSubStringIndex = iIndexOfH;
}
return sValue.substr(0, iSubStringIndex) + strRepeat(0, iHoursDigits) + sValue.substr(iSubStringIndex + 2);
};
/**
* Return if provided value hours is equal to 24.
* @private
*/
TimePickerInternals._isHoursValue24 = function (sValue, iIndexOfHH, iIndexOfH) {
if (iIndexOfHH === -1 && iIndexOfH === -1) {
return false;
}
var iSubStringIndex = iIndexOfHH;
if (iIndexOfHH === -1) {
iSubStringIndex = iIndexOfH;
}
return sValue.substr(iSubStringIndex, 2) === "24";
};
/**
* Returns the button that navigates to the current time.
*
* @returns {sap.m.Button|null} button that displays seconds
* @private
*/
TimePickerInternals.prototype._getCurrentTimeButton = function() {
if (!this._oNowButton) {
this._oNowButton = new Button(this.getId() + "-now", {
icon: "sap-icon://present",
tooltip: this._oResourceBundle.getText("TIMEPICKER_TOOLTIP_NOW"),
type: ButtonType.Transparent,
visible: false,
press: function () {
this._setTimeValues(UI5Date.getInstance());
}.bind(this)
}).addStyleClass("sapMTPNow");
}
return this._oNowButton;
};
function strRepeat(sStr, iCount) {
var sResult = "";
for (var i = 0; i < iCount; i++) {
sResult += sStr;
}
return sResult;
}
return TimePickerInternals;
});