UNPKG

@openui5/sap.m

Version:

OpenUI5 UI Library sap.m

772 lines (606 loc) 23.1 kB
/*! * 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. */ //Provides control sap.m.DateTimePicker. sap.ui.define([ 'jquery.sap.global', './InputBase', './DatePicker', 'sap/ui/model/type/Date', 'sap/ui/unified/DateRange', './library', 'sap/ui/core/Control', 'sap/ui/Device', 'sap/ui/core/format/DateFormat', 'sap/ui/core/LocaleData', './DateTimePickerRenderer', './TimePickerSliders', "sap/ui/events/KeyCodes", "sap/ui/core/IconPool" ], function( jQuery, InputBase, DatePicker, Date1, DateRange, library, Control, Device, DateFormat, LocaleData, DateTimePickerRenderer, TimePickerSliders, KeyCodes, IconPool ) { "use strict"; // shortcut for sap.m.PlacementType var PlacementType = library.PlacementType; // From sap.ui.Device.media.RANGESETS.SAP_STANDARD - "Phone": For screens smaller than 600 pixels. var STANDART_PHONE_RANGESET = "Phone"; /** * Constructor for a new <code>DateTimePicker</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 * Enables the users to select date and time values in a combined input. * * <h3>Overview</h3> * * The <code>DateTimePicker</code> control consists of two parts: the input field and the * date/time picker. * * <b>Note:</b> The {@link sap.ui.unified.Calendar} is used internally only if the * <code>DateTimePicker</code> is opened (not used for the initial rendering). If * the <code>sap.ui.unified</code> library is not loaded before the * <code>DateTimePicker</code> is opened, it will be loaded upon opening. This * could lead to a waiting time when the <code>DateTimePicker</code> is opened for * the first time. To prevent this, apps using the <code>DateTimePicker</code> * should also load the <code>sap.ui.unified</code> library. * * <h3>Usage</h3> * * Use this control if you need a combined date and time input control. * * Don't use it if you want to use either a date or a time value. In this case, * use the {@link sap.m.DatePicker} or the {@link sap.m.TimePicker} controls * instead. * * The user can enter a date by: * <ul> <li>Using the calendar or a time selector that opens in a popup</li> * <li>Typing it in directly in the input field</li></ul> * * On app level, there are two options to provide a date for the * <code>DateTimePicker</code> - as a string to the <code>value</code> property * or as a JavaScript Date object to the <code>dateValue</code> property (only one * of these properties should be used at a time): * * <ul><li>Use the <code>value</code> property if you want to bind the * <code>DateTimePicker</code> to a model using the * <code>sap.ui.model.type.DateTime</code></li> * <li>Use the <code>value</code> property if the date is provided as a string from * the backend or inside the app (for example, as ABAP type DATS field)</li> * <li>Use the <code>dateValue</code> property if the date is already provided as a * JavaScript Date object or you want to work with a JavaScript Date object. * Use <code>dateValue</code> as a helper property to easily obtain the day, month, year, * hours, minutes and seconds of the chosen date and time. Although possible to bind it, * the recommendation is not to do it. * When binding is needed, use <code>value</code> property instead</li></ul> * * <h3>Formatting</h3> * * All formatting and parsing of dates from and to strings is done using the * {@link sap.ui.core.format.DateFormat}. If a date is entered by typing it into * the input field, it must fit to the used date format and locale. * * Supported format options are pattern-based on Unicode LDML Date Format notation. * See {@link http://unicode.org/reports/tr35/#Date_Field_Symbol_Table} * * For example, if the <code>valueFormat</code> is "yyyy-MM-dd-HH-mm-ss", the * <code>displayFormat</code> is "MMM d, y, HH:mm:ss", and the used locale is * English, a valid value string is "2015-07-30-10-30-15", which leads to an output * of "Jul 30, 2015, 10:30:15". * * If no placeholder is set to the <code>DateTimePicker</code>, the used * <code>displayFormat</code> is displayed as a placeholder. If another placeholder * is needed, it must be set. * * <b>Note:</b> If the string does NOT match the <code>displayFormat</code> * (from user input) or the <code>valueFormat</code> (on app level), the * {@link sap.ui.core.format.DateFormat} makes an attempt to parse it based on the * locale settings. For more information, see the respective documentation in the * API Reference. * * <h3>Responsive behavior</h3> * * The <code>DateTimePicker</code> is responsive and fully adapts to all devices. * For larger screens, such as tablet or desktop, it opens as a popover. For * mobile devices, it opens in full screen. * * @extends sap.m.DatePicker * @version 1.60.39 * * @constructor * @public * @since 1.38.0 * @alias sap.m.DateTimePicker * @see {@link fiori:https://experience.sap.com/fiori-design-web/datetime-picker/ Date/Time Picker} * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel */ var DateTimePicker = DatePicker.extend("sap.m.DateTimePicker", /** @lends sap.m.DateTimePicker.prototype */ { metadata : { library : "sap.m", properties: { /** * Sets the minutes slider step. If the step is less than 1, it will be automatically converted back to 1. * The minutes slider is populated only by multiples of the step. * @since 1.56 */ minutesStep: {type: "int", group: "Misc", defaultValue: 1 }, /** * Sets the seconds slider step. If the step is less than 1, it will be automatically converted back to 1. * The seconds slider is populated only by multiples of the step. * @since 1.56 */ secondsStep: {type: "int", group: "Misc", defaultValue: 1 } }, aggregations: { /** * Internal aggregation that contains the inner _picker pop-up. */ _popup: { type: "sap.m.ResponsivePopover", multiple: false, visibility: "hidden" } }, designtime: "sap/m/designtime/DateTimePicker.designtime" }}); var PopupContent = Control.extend("sap.m.internal.DateTimePickerPopup", { metadata: { aggregations: { _switcher : {type: "sap.ui.core.Control", multiple: false, visibility: "hidden"}, calendar : {type: "sap.ui.core.Control", multiple: false}, timeSliders: {type: "sap.ui.core.Control", multiple: false} } }, renderer: function(oRm, oPopup) { oRm.write("<div"); oRm.writeControlData(oPopup); oRm.addClass("sapMDateTimePopupCont"); oRm.addClass("sapMTimePickerDropDown"); oRm.writeClasses(); oRm.write(">"); var oSwitcher = oPopup.getAggregation("_switcher"); if (oSwitcher) { oRm.write("<div"); oRm.addClass("sapMTimePickerSwitch"); oRm.writeClasses(); oRm.write(">"); oRm.renderControl(oSwitcher); oRm.write("</div>"); } var oCalendar = oPopup.getCalendar(); if (oCalendar) { oRm.renderControl(oCalendar); } oRm.write("<div"); oRm.addClass("sapMTimePickerSep"); oRm.writeClasses(); oRm.write(">"); oRm.write("</div>"); var oSliders = oPopup.getTimeSliders(); if (oSliders) { oRm.renderControl(oSliders); } oRm.write("</div>"); }, init: function() { }, onBeforeRendering: function() { var oSwitcher = this.getAggregation("_switcher"); if (!oSwitcher) { var oResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m"); var sDateText = oResourceBundle.getText("DATETIMEPICKER_DATE"); var sTimeText = oResourceBundle.getText("DATETIMEPICKER_TIME"); oSwitcher = new sap.m.SegmentedButton(this.getId() + "-Switch", { selectedKey: "Cal", items: [ new sap.m.SegmentedButtonItem(this.getId() + "-Switch-Cal", {key: "Cal", text: sDateText}), new sap.m.SegmentedButtonItem(this.getId() + "-Switch-Sli", {key: "Sli", text: sTimeText}) ] }); oSwitcher.attachSelect(this._handleSelect, this); this.setAggregation("_switcher", oSwitcher, true); } if (Device.system.phone || jQuery('html').hasClass("sapUiMedia-Std-Phone")) { oSwitcher.setVisible(true); oSwitcher.setSelectedKey("Cal"); } else { oSwitcher.setVisible(false); } }, onAfterRendering: function() { if (Device.system.phone || jQuery('html').hasClass("sapUiMedia-Std-Phone")) { var oSwitcher = this.getAggregation("_switcher"); var sKey = oSwitcher.getSelectedKey(); this._switchVisibility(sKey); } }, _handleSelect: function(oEvent) { this._switchVisibility(oEvent.getParameter("key")); }, _switchVisibility: function(sKey) { var oCalendar = this.getCalendar(); var oSliders = this.getTimeSliders(); if (!oCalendar || !oSliders) { return; } if (sKey == "Cal") { oCalendar.$().css("display", ""); oSliders.$().css("display", "none"); } else { oCalendar.$().css("display", "none"); oSliders.$().css("display", ""); oSliders._updateSlidersValues(); oSliders._onOrientationChanged(); oSliders.openFirstSlider(); } }, switchToTime: function() { var oSwitcher = this.getAggregation("_switcher"); if (oSwitcher && oSwitcher.getVisible()) { oSwitcher.setSelectedKey("Sli"); this._switchVisibility("Sli"); } }, getSpecialDates: function() { return this._oDateTimePicker.getSpecialDates(); } }); DateTimePicker.prototype.init = function() { DatePicker.prototype.init.apply(this, arguments); this._bOnlyCalendar = false; }; /** * Apply the correct icon to the used Date control * @protected */ DateTimePicker.prototype.getIconSrc = function () { return IconPool.getIconURI("date-time"); }; DateTimePicker.prototype.exit = function(){ DatePicker.prototype.exit.apply(this, arguments); if (this._oSliders) { this._oSliders.destroy(); delete this._oSliders; } this._oPopupContent = undefined; // is destroyed via popup aggregation - just remove reference Device.media.detachHandler(this._handleWindowResize, this); }; DateTimePicker.prototype.setDisplayFormat = function(sDisplayFormat) { DatePicker.prototype.setDisplayFormat.apply(this, arguments); if (this._oSliders) { this._oSliders.setDisplayFormat(_getTimePattern.call(this)); } return this; }; DateTimePicker.prototype.setMinutesStep = function(iMinutesStep) { this.setProperty('minutesStep', iMinutesStep, true); if (this._oSliders) { this._oSliders.setMinutesStep(iMinutesStep); } return this; }; DateTimePicker.prototype.setMinDate = function (oDate) { DatePicker.prototype.setMinDate.call(this, oDate); if (oDate) { //make sure the time part is as the original one this._oMinDate.setHours(oDate.getHours(), oDate.getMinutes(), oDate.getSeconds()); } return this; }; DateTimePicker.prototype.setMaxDate = function (oDate) { DatePicker.prototype.setMaxDate.call(this, oDate); if (oDate) { //make sure the time part is as the original one this._oMaxDate.setHours(oDate.getHours(), oDate.getMinutes(), oDate.getSeconds()); } return this; }; DateTimePicker.prototype.setSecondsStep = function(iSecondsStep) { this.setProperty('secondsStep', iSecondsStep, true); if (this._oSliders) { this._oSliders.setSecondsStep(iSecondsStep); } return this; }; DateTimePicker.prototype._getFormatInstance = function(oArguments, bDisplayFormat){ var oMyArguments = jQuery.extend({}, oArguments); // check for mixed styles var iSlashIndex = -1; if (oMyArguments.style) { iSlashIndex = oMyArguments.style.indexOf("/"); } if (bDisplayFormat) { // also create a date formatter as fallback for parsing var oDateArguments = jQuery.extend({}, oMyArguments); if (iSlashIndex > 0) { oDateArguments.style = oDateArguments.style.substr(0, iSlashIndex); } this._oDisplayFormatDate = DateFormat.getInstance(oDateArguments); } return DateFormat.getDateTimeInstance(oMyArguments); }; DateTimePicker.prototype._checkStyle = function(sPattern){ if (DatePicker.prototype._checkStyle.apply(this, arguments)) { // it's a simple style return true; } else if (sPattern.indexOf("/") > 0) { // could be a mixed style var aStyles = ["short", "medium", "long", "full"]; var bStyle = false; for (var i = 0; i < aStyles.length; i++) { var sStyle1 = aStyles[i]; for (var j = 0; j < aStyles.length; j++) { var sStyle2 = aStyles[j]; if (sPattern == sStyle1 + "/" + sStyle2) { bStyle = true; break; } } if (bStyle) { break; } } return bStyle; } // is something else return false; }; DateTimePicker.prototype._parseValue = function(sValue, bDisplayFormat) { var oDate = DatePicker.prototype._parseValue.apply(this, arguments); if (bDisplayFormat && !oDate) { // maybe only a date is entered oDate = this._oDisplayFormatDate.parse(sValue); if (oDate) { // use time of existing date or current time var oOldDate = this.getDateValue(); if (!oOldDate) { oOldDate = new Date(); } oDate.setHours(oOldDate.getHours()); oDate.setMinutes(oOldDate.getMinutes()); oDate.setSeconds(oOldDate.getSeconds()); oDate.setMilliseconds(oOldDate.getMilliseconds()); } } return oDate; }; DateTimePicker.prototype._getLocaleBasedPattern = function(sPlaceholder) { var oLocaleData = LocaleData.getInstance( sap.ui.getCore().getConfiguration().getFormatSettings().getFormatLocale() ), iSlashIndex = sPlaceholder.indexOf("/"); if (iSlashIndex > 0) { return oLocaleData.getCombinedDateTimePattern(sPlaceholder.substr(0, iSlashIndex), sPlaceholder.substr(iSlashIndex + 1)); } else { return oLocaleData.getCombinedDateTimePattern(sPlaceholder, sPlaceholder); } }; DateTimePicker.prototype._createPopup = function(){ if (!this._oPopup) { var oResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.m"); var sOKButtonText = oResourceBundle.getText("TIMEPICKER_SET"); var sCancelButtonText = oResourceBundle.getText("TIMEPICKER_CANCEL"); this._oPopupContent = new PopupContent(this.getId() + "-PC"); this._oPopupContent._oDateTimePicker = this; this._oPopup = new sap.m.ResponsivePopover(this.getId() + "-RP", { showCloseButton: false, showHeader: false, placement: PlacementType.VerticalPreferedBottom, beginButton: new sap.m.Button(this.getId() + "-OK", { text: sOKButtonText, press: jQuery.proxy(_handleOkPress, this) }), endButton: new sap.m.Button(this.getId() + "-Cancel", { text: sCancelButtonText, press: jQuery.proxy(_handleCancelPress, this) }), content: this._oPopupContent }); this._oPopup.addStyleClass("sapMDateTimePopup"); var oPopover = this._oPopup.getAggregation("_popup"); // hide arrow in case of popover as dialog does not have an arrow if (oPopover.setShowArrow) { oPopover.setShowArrow(false); } this._oPopup.attachAfterOpen(_handleAfterOpen, this); this._oPopup.attachAfterClose(_handleAfterClose, this); if (Device.system.desktop) { this._oPopoverKeydownEventDelegate = { onkeydown: function(oEvent) { var oKC = KeyCodes, iKC = oEvent.which || oEvent.keyCode, bAlt = oEvent.altKey; // Popover should be closed when Alt+Arrow key or F4 is pressed if ((bAlt && (iKC === oKC.ARROW_UP || iKC === oKC.ARROW_DOWN)) || iKC === oKC.F4) { _handleOkPress.call(this, oEvent); //focus the input this.focus(); oEvent.preventDefault(); } } }; this._oPopup.addEventDelegate(this._oPopoverKeydownEventDelegate, this); } // define a parent-child relationship between the control's and the _picker pop-up this.setAggregation("_popup", this._oPopup, true); } }; DateTimePicker.prototype._openPopup = function(){ if (!this._oPopup) { return; } this.addStyleClass(InputBase.ICON_PRESSED_CSS_CLASS); this._storeInputSelection(this._$input.get(0)); var oPopover = this._oPopup.getAggregation("_popup"); oPopover.oPopup.setAutoCloseAreas([this.getDomRef()]); this._oPopup.openBy(this); var oSliders = this._oPopup.getContent()[0] && this._oPopup.getContent()[0].getTimeSliders(); if (oSliders) {//Sliders values need to be updated after a popup is (especially sliders) is really visible setTimeout(oSliders._updateSlidersValues.bind(oSliders), 0); } }; DateTimePicker.prototype._createPopupContent = function(){ var bNoCalendar = !this._oCalendar; DatePicker.prototype._createPopupContent.apply(this, arguments); if (bNoCalendar) { this._oPopupContent.setCalendar(this._oCalendar); this._oCalendar.attachSelect(_selectDate, this); var that = this, oHideMonthPicker = this._oCalendar._hideMonthPicker, oHideYearPicker = this._oCalendar._hideYearPicker; this._oCalendar._hideMonthPicker = function (bSkipFocus) { oHideMonthPicker.apply(this, arguments); if (!bSkipFocus) { that._selectFocusedDateValue(new DateRange().setStartDate(this._getFocusedDate().toLocalJSDate())); } }; this._oCalendar._hideYearPicker = function (bSkipFocus) { oHideYearPicker.apply(this, arguments); if (!bSkipFocus) { that._selectFocusedDateValue(new DateRange().setStartDate(this._getFocusedDate().toLocalJSDate())); } }; } if (!this._oSliders) { this._oSliders = new TimePickerSliders(this.getId() + "-Sliders", { minutesStep: this.getMinutesStep(), secondsStep: this.getSecondsStep(), displayFormat: _getTimePattern.call(this), localeId: this.getLocaleId() })._setShouldOpenSliderAfterRendering(true); this._oPopupContent.setTimeSliders(this._oSliders); } }; DateTimePicker.prototype._selectFocusedDateValue = function (oDateRange) { var oCalendar = this._oCalendar; oCalendar.removeAllSelectedDates(); oCalendar.addSelectedDate(oDateRange); return this; }; DateTimePicker.prototype._fillDateRange = function(){ var oDate = this.getDateValue(); if (oDate) { oDate = new Date(oDate.getTime()); } else { oDate = this._getInitialFocusedDateValue(); var iMaxTimeMillis = this._oMaxDate.getTime() + 86400000 /* one day in milliseconds */; if (oDate.getTime() < this._oMinDate.getTime() || oDate.getTime() > iMaxTimeMillis) { oDate = this._oMinDate; } } this._oCalendar.focusDate(oDate); if (!this._oDateRange.getStartDate() || this._oDateRange.getStartDate().getTime() != oDate.getTime()) { this._oDateRange.setStartDate(oDate); } this._oSliders._setTimeValues(oDate); }; DateTimePicker.prototype._getSelectedDate = function(){ var oDate = DatePicker.prototype._getSelectedDate.apply(this, arguments); if (oDate) { var oDateTime = this._oSliders.getTimeValues(); var sPattern = this._oSliders._getDisplayFormatPattern(); if (sPattern.search("h") >= 0 || sPattern.search("H") >= 0) { oDate.setHours(oDateTime.getHours()); } if (sPattern.search("m") >= 0) { oDate.setMinutes(oDateTime.getMinutes()); } if (sPattern.search("s") >= 0) { oDate.setSeconds(oDateTime.getSeconds()); } if (oDate.getTime() < this._oMinDate.getTime()) { oDate = new Date(this._oMinDate.getTime()); }else if (oDate.getTime() > this._oMaxDate.getTime()){ oDate = new Date(this._oMaxDate.getTime()); } } return oDate; }; DateTimePicker.prototype._getInitialFocusedDateValue = function () { return this.getInitialFocusedDateValue() || new Date(); }; DateTimePicker.prototype.getLocaleId = function(){ return sap.ui.getCore().getConfiguration().getFormatSettings().getFormatLocale().toString(); }; /** * @see sap.ui.core.Control#getAccessibilityInfo * @returns {Object} Current accessibility state of the control * @protected */ DateTimePicker.prototype.getAccessibilityInfo = function() { var oInfo = DatePicker.prototype.getAccessibilityInfo.apply(this, arguments); oInfo.type = sap.ui.getCore().getLibraryResourceBundle("sap.m").getText("ACC_CTR_TYPE_DATETIMEINPUT"); return oInfo; }; function _handleOkPress(oEvent){ this._selectDate(); } function _handleCancelPress(oEvent){ this.onsaphide(oEvent); this._oCalendar.removeAllSelectedDates(); this._oCalendar.addSelectedDate(new DateRange().setStartDate(this._getInitialFocusedDateValue())); } /** * @private */ DateTimePicker.prototype._handleWindowResize = function(mParams) { var oSwitcher = this.getAggregation("_popup").getContent()[0].getAggregation("_switcher"), oCalendar = this.getAggregation("_popup").getContent()[0].getCalendar(), oSliders = this.getAggregation("_popup").getContent()[0].getTimeSliders(); if (mParams.name === STANDART_PHONE_RANGESET) { oSwitcher.setVisible(true); // Getting "sap.m.internal.DateTimePickerPopup" instance in order to call "_switchVisibility(sKey)" method this.getAggregation("_popup").getContent()[0]._switchVisibility(oSwitcher.getSelectedKey()); } else { oSwitcher.setVisible(false); oSliders.$().css("display", ""); oCalendar.$().css("display", ""); } }; function _handleAfterOpen(oEvent){ this.$("inner").attr("aria-expanded", true); this._oCalendar.focus(); this._oSliders._onOrientationChanged(); Device.media.attachHandler(this._handleWindowResize, this); } function _handleAfterClose(){ this.removeStyleClass(InputBase.ICON_PRESSED_CSS_CLASS); this.$("inner").attr("aria-expanded", false); this._restoreInputSelection(this._$input.get(0)); Device.media.detachHandler(this._handleWindowResize, this); } function _getTimePattern(){ var sDisplayFormat = this.getDisplayFormat(); var sTimePattern; var oBinding = this.getBinding("value"); if (oBinding && oBinding.oType && (oBinding.oType instanceof Date1)) { sDisplayFormat = oBinding.oType.getOutputPattern(); } else if (oBinding && oBinding.oType && oBinding.oType.oFormat) { sDisplayFormat = oBinding.oType.oFormat.oFormatOptions.pattern; } else { sDisplayFormat = this.getDisplayFormat(); } if (!sDisplayFormat) { sDisplayFormat = "medium"; } var iSlashIndex = sDisplayFormat.indexOf("/"); if (iSlashIndex > 0 && this._checkStyle(sDisplayFormat)) { sDisplayFormat = sDisplayFormat.substr(iSlashIndex + 1); } if (sDisplayFormat == "short" || sDisplayFormat == "medium" || sDisplayFormat == "long" || sDisplayFormat == "full") { var oLocale = sap.ui.getCore().getConfiguration().getFormatSettings().getFormatLocale(); var oLocaleData = LocaleData.getInstance(oLocale); sTimePattern = oLocaleData.getTimePattern(sDisplayFormat); } else { sTimePattern = sDisplayFormat; } return sTimePattern; } function _selectDate(oEvent) { this._oPopupContent.switchToTime(); } return DateTimePicker; });