/*!
* UI development toolkit for HTML5 (OpenUI5)
* (c) Copyright 2009-2018 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
// Provides control sap.m.DateTimeField.
sap.ui.define([
'sap/ui/model/type/Date',
'sap/ui/model/odata/type/ODataType',
'./InputBase',
'sap/ui/core/LocaleData',
'sap/ui/core/library',
'sap/ui/core/format/DateFormat',
'./DateTimeFieldRenderer',
"sap/base/util/deepEqual",
"sap/base/Log",
"sap/ui/thirdparty/jquery",
// jQuery Plugin "cursorPos"
"sap/ui/dom/jquery/cursorPos"
], function(
SimpleDateType,
ODataType,
InputBase,
LocaleData,
coreLibrary,
DateFormat,
DateTimeFieldRenderer,
deepEqual,
Log,
jQuery
) {
"use strict";
// shortcut for sap.ui.core.CalendarType
var CalendarType = coreLibrary.CalendarType;
/**
* Constructor for a new sap.m.DateTimeField
.
*
* @param {string} [sId] ID for the new control, generated automatically if no ID is given
* @param {object} [mSettings] Initial settings for the new control
*
* @class
* The sap.m.DateTimeField
control provides a basic functionality for date/time input controls.
*
* To be extended by date and time picker controls. For internal use only.
* @abstract
*
* @extends sap.m.InputBase
*
* @author SAP SE
* @version 1.60.23
*
* @constructor
* @public
* @since 1.50.0
* @alias sap.m.DateTimeField
* @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
*/
var DateTimeField = InputBase.extend("sap.m.DateTimeField", /** @lends sap.m.DateTimeField.prototype */ {
metadata: {
"abstract" : true,
library: "sap.m",
properties: {
/**
* Determines the format, displayed in the input field.
*/
displayFormat: {type: "string", group: "Appearance", defaultValue: null},
/**
* Determines the format of the value property.
*/
valueFormat: {type: "string", group: "Data", defaultValue: null},
/**
* Holds a reference to a JavaScript Date Object. The value
(string)
* property will be set according to it. Alternatively, if the value
* and valueFormat
pair properties are supplied instead,
* the dateValue
will be instantiated according to the parsed
* value
.
* Use dateValue
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 value
property instead.
*/
dateValue: {type: "object", group: "Data", defaultValue: null},
/**
* Holds a reference to a JavaScript Date Object to define the initially focused
* date/time when the picker popup is opened.
*
* Notes:
*
* - Setting this property does not change the
value
property.
* - Depending on the context this property is used in ({@link sap.m.TimePicker},
* {@link sap.m.DatePicker} or {@link sap.m.DateTimePicker}), it takes into account only the time part, only
* the date part or both parts of the JavaScript Date Object.
*
* @since 1.54
*/
initialFocusedDateValue: {type: "object", group: "Data", defaultValue: null}
}
}
});
DateTimeField.prototype.setValue = function (sValue) {
sValue = this.validateProperty("value", sValue); // to convert null and undefined to ""
var sOldValue = this.getValue();
if (sValue === sOldValue) {
return this;
} else {
this._lastValue = sValue;
}
// set the property in any case but check validity on output
this.setProperty("value", sValue);
this._bValid = true;
// convert to date object
var oDate;
if (sValue) {
oDate = this._parseValue(sValue);
if (!oDate || oDate.getTime() < this._oMinDate.getTime() || oDate.getTime() > this._oMaxDate.getTime()) {
this._bValid = false;
Log.warning("Value can not be converted to a valid date", this);
}
}
this.setProperty("dateValue", oDate);
// do not call InputBase.setValue because the displayed value and the output value might have different pattern
if (this.getDomRef()) {
// convert to output
var sOutputValue;
if (oDate) {
sOutputValue = this._formatValue(oDate);
} else {
sOutputValue = sValue;
}
if (this._$input.val() !== sOutputValue) {
this._$input.val(sOutputValue);
this._curpos = this._$input.cursorPos();
}
}
return this;
};
DateTimeField.prototype.setDateValue = function (oDate) {
if (this._isValidDate(oDate)) {
throw new Error("Date must be a JavaScript date object; " + this);
}
if (deepEqual(this.getDateValue(), oDate)) {
return this;
}
oDate = this._dateValidation(oDate);
// convert date object to value
var sValue = this._formatValue(oDate, true);
if (sValue !== this.getValue()) {
this._lastValue = sValue;
}
// set the property in any case but check validity on output
this.setProperty("value", sValue);
if (this.getDomRef()) {
// convert to output
var sOutputValue = this._formatValue(oDate);
if (this._$input.val() !== sOutputValue) {
this._$input.val(sOutputValue);
this._curpos = this._$input.cursorPos();
}
}
return this;
};
DateTimeField.prototype.setValueFormat = function (sValueFormat) {
// if valueFormat changes the value must be parsed again
this.setProperty("valueFormat", sValueFormat, true); // no rerendering
var sValue = this.getValue();
if (sValue) {
this._handleDateValidation(this._parseValue(sValue));
}
return this;
};
DateTimeField.prototype.setDisplayFormat = function (sDisplayFormat) {
this.setProperty("displayFormat", sDisplayFormat, true); // no rerendering
this.updateDomValue(this._formatValue(this.getDateValue()));
this._updateDomPlaceholder(this._getPlaceholder());
return this;
};
DateTimeField.prototype.getDisplayFormatType = function () {
return null;
};
DateTimeField.prototype._dateValidation = function (oDate) {
this._bValid = true;
this.setProperty("dateValue", oDate);
return oDate;
};
DateTimeField.prototype._handleDateValidation = function (oDate) {
this._bValid = true;
this.setProperty("dateValue", oDate);
};
DateTimeField.prototype._getPlaceholder = function() {
var sPlaceholder = this.getPlaceholder();
if (!sPlaceholder) {
sPlaceholder = this._getDisplayFormatPattern();
if (!sPlaceholder) {
sPlaceholder = this._getDefaultDisplayStyle();
}
if (this._checkStyle(sPlaceholder)) {
sPlaceholder = this._getLocaleBasedPattern(sPlaceholder);
}
}
return sPlaceholder;
};
DateTimeField.prototype._getLocaleBasedPattern = function (sPlaceholder) {
return LocaleData.getInstance(
sap.ui.getCore().getConfiguration().getFormatSettings().getFormatLocale()
).getDatePattern(sPlaceholder);
};
DateTimeField.prototype._parseValue = function (sValue, bDisplayFormat) {
return this._getFormatter(bDisplayFormat).parse(sValue);
};
DateTimeField.prototype._formatValue = function (oDate, bValueFormat) {
if (oDate) {
return this._getFormatter(!bValueFormat).format(oDate);
}
return "";
};
DateTimeField.prototype._getDefaultDisplayStyle = function () {
return "medium";
};
DateTimeField.prototype._getDefaultValueStyle = function () {
return "short";
};
DateTimeField.prototype._getFormatter = function (bDisplayFormat) {
var sPattern = this._getBoundValueTypePattern(),
bRelative = false, // if true strings like "Tomorrow" are parsed fine
oFormat,
oBinding = this.getBinding("value"),
sCalendarType;
if (oBinding && oBinding.oType && oBinding.oType.oOutputFormat) {
bRelative = !!oBinding.oType.oOutputFormat.oFormatOptions.relative;
sCalendarType = oBinding.oType.oOutputFormat.oFormatOptions.calendarType;
}
/* eslint-disable no-lonely-if */
if (!sPattern) {
// not databinding is used -> use given format
if (bDisplayFormat) {
sPattern = ( this.getDisplayFormat() || this._getDefaultDisplayStyle() );
sCalendarType = this.getDisplayFormatType();
} else {
sPattern = ( this.getValueFormat() || this._getDefaultValueStyle() );
sCalendarType = CalendarType.Gregorian;
}
}
if (!sCalendarType) {
sCalendarType = sap.ui.getCore().getConfiguration().getCalendarType();
}
if (bDisplayFormat) {
if (sPattern === this._sUsedDisplayPattern && sCalendarType === this._sUsedDisplayCalendarType) {
oFormat = this._oDisplayFormat;
}
} else {
if (sPattern === this._sUsedValuePattern && sCalendarType === this._sUsedValueCalendarType) {
oFormat = this._oValueFormat;
}
}
if (oFormat) {
return oFormat;
}
return this._getFormatterInstance(oFormat, sPattern, bRelative, sCalendarType, bDisplayFormat);
};
DateTimeField.prototype._getFormatterInstance = function (oFormat, sPattern, bRelative, sCalendarType, bDisplayFormat) {
if (this._checkStyle(sPattern)) {
oFormat = this._getFormatInstance({style: sPattern, strictParsing: true, relative: bRelative, calendarType: sCalendarType}, bDisplayFormat);
} else {
oFormat = this._getFormatInstance({pattern: sPattern, strictParsing: true, relative: bRelative, calendarType: sCalendarType}, bDisplayFormat);
}
if (bDisplayFormat) {
this._sUsedDisplayPattern = sPattern;
this._sUsedDisplayCalendarType = sCalendarType;
this._oDisplayFormat = oFormat;
} else {
this._sUsedValuePattern = sPattern;
this._sUsedValueCalendarType = sCalendarType;
this._oValueFormat = oFormat;
}
return oFormat;
};
DateTimeField.prototype._getFormatInstance = function (oArguments, bDisplayFormat) {
return DateFormat.getInstance(oArguments);
};
DateTimeField.prototype._checkStyle = function (sPattern) {
return (sPattern === "short" || sPattern === "medium" || sPattern === "long" || sPattern === "full");
};
DateTimeField.prototype._getDisplayFormatPattern = function () {
var sPattern = this._getBoundValueTypePattern();
if (sPattern) {
return sPattern;
}
sPattern = this.getDisplayFormat();
if (this._checkStyle(sPattern)) {
sPattern = this._getLocaleBasedPattern(sPattern);
}
return sPattern;
};
DateTimeField.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;
};
// Cross frame check for a date should be performed here otherwise setDateValue would fail in OPA tests
// because Date object in the test is different than the Date object in the application (due to the iframe).
// We can use jQuery.type or this method:
// function isValidDate (date) {
// return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
//}
DateTimeField.prototype._isValidDate = function (oDate) {
return oDate && jQuery.type(oDate) !== "date";
};
/**
* Updates the placeholder of the input element with a given valye
* @param {string} sValue the new value
* @private
* @returns void
*/
DateTimeField.prototype._updateDomPlaceholder = function (sValue) {
if (this.getDomRef()) {
this._$input.attr("placeholder", sValue);
}
};
return DateTimeField;
});