/** * Class of the date input control */ Ext.define("Terrasoft.controls.DateEdit", { extend: "Terrasoft.BaseEdit", alternateClassName: "Terrasoft.DateEdit", mixins: { rightIcon: "Terrasoft.RightIcon" }, /** * Parameter indicating whether the right icon is used * @type {Boolean} * @override * @protected */ enableRightIcon: true, /** * Classes of CSS styles for the right icon * @protected * @property {String[]} rightIconClasses */ rightIconClasses: ["ts-date-edit-right-icon"], /** * Link to the DatePicker control * @private * @type {Terrasoft.DatePicker} */ datePicker: null, /** * The value of the control * @protected * @type {Date} */ value: null, /** * Date format * @type {String} */ format: Terrasoft.Resources.CultureSettings.dateFormat, /** * The expansion of the data set for a template. * @protected * @override * @return {Object} */ getTplData: function () { var tplData = this.callParent(arguments); tplData.value = Ext.Date.format(this.value, this.format); var wrapClass = tplData.wrapClass; wrapClass.push("date-edit"); return tplData; }, /** * Creates the {@link Terrasoft.DatePicker} element * and sets the {@link #datePicker datePicker} parameter to the link. * @private */ createDatePicker: function () { var datePicker = this.datePicker = Ext.create("Terrasoft.DatePicker", { renderTo: Ext.getBody(), parentEl: this.wrapEl, date: this.value }); datePicker.on("dateSelected", this.onDateSelected, this); datePicker.on("currentDateSelected", this.onDateSelected, this); }, /** * Tries to parse string to date by format. * @private * @param {String} value String date. * @param {String} format String format to parse. * @param {Boolean} strict Strict parsing. * @return {Date|Null} Return Date or null if cannot parse. */ tryParseDate: function (value, format, strict) { try { return Terrasoft.parseDate(value, format, strict); } catch (e) { console.warn(e && e.message); return null; } }, /** * Initializing DOM events. * @protected * @override */ initDomEvents: function () { this.callParent(arguments); /** * @event click * Right click event */ this.on("rightIconClick", this.onButtonClick, this); var document = Ext.getDoc(); /** * @event mousedown * Mouse click event in the document area. */ document.on("mousedown", this.onMouseDownCollapse, this); }, /** * Hides the calendar if the click occurred outside the control or calendar. * @protected * @param {Event} e mousedown event */ onMouseDownCollapse: function (e) { var isInDateEditWrap = e.within(this.getWrapEl()); var datePicker = this.datePicker; var isInDatePickerWrap = datePicker === null || e.within(datePicker.getWrapEl()); if (!isInDateEditWrap && !isInDatePickerWrap) { datePicker.setVisible(false); } }, /** * Handler for the button click. * @protected */ onButtonClick: function () { if (this.readonly) { return; } var datePicker = this.datePicker; if (!datePicker) { this.createDatePicker(); } else { var date = this.value; if (date) { datePicker.setDisplayedDate(date); datePicker.setDate(date); } if (datePicker.visible) { datePicker.setVisible(false); } else { var wrapEl = this.getWrapEl(); datePicker.show(wrapEl); } } }, /** * Subscribe to the event model and, if necessary, subscribe to changes bindable property * control type Property. * @protected * @override * @param {Object} binding An object that describes the parameters of the binding properties of the control * to the model. * @param {String} property Name of the property to bind the control. * @param {Terrasoft.data.modules.BaseViewModel} model The data model which is linked to the control. */ subscribeForPropertyChangeEvent: function (binding, property, model) { var changeEvent = binding.config.changeEvent; if (changeEvent === "change") { var modelProperty = binding.modelItem; var onControlPropertyChange = function (value) { var modelValue = model.get(modelProperty); var columnType = model.getColumnDataType(modelProperty); var newDate = value ? new Date(value) : new Date(); if (!value) { newDate = value; } else if (columnType === Terrasoft.DataValueType.DATE_TIME && Ext.isDate(modelValue)) { newDate.setHours(modelValue.getHours(), modelValue.getMinutes(), modelValue.getSeconds(), modelValue.getMilliseconds()); } model.set(modelProperty, newDate); }; this.on(changeEvent, onControlPropertyChange); var dependentProperties = [modelProperty]; // The handler for changing one property in the model var handler = function (viewModel, value) { if (value === "") { value = "invalid value"; } else if (value === null) { value = ""; } this.setControlPropertyValue(binding, value, model); }; this.toggleSubscriptionForModelEvents(model, null, dependentProperties, handler, this); } else { this.callParent(arguments); } }, /** * Key event handler. Pressing the key displays the calendar. * @protected * @override * @param {Ext.EventObjectImpl} e event object */ onKeyDown: function (e) { if (!this.enabled) { return; } this.callParent(arguments); var key = e.getKey(); var datePicker = this.datePicker; if (key === e.DOWN) { if (!datePicker) { this.createDatePicker(); } else { datePicker.show(this.getWrapEl()); } } else if (key === e.TAB && datePicker) { this.datePicker.setVisible(false); } }, /** * The handler of the event of getting focus by control. * When you get the focus, the text inside the control is highlighted. * @protected * @override */ onFocus: function () { this.callParent(); var el = this.getEl(); if (el && el.dom && el.dom.value) { el.dom.select(); } }, /** * Handler for the date selection event. * Hides the calendar, set the value of the control equal to the selected date, * sets focus to the element. * @protected */ onDateSelected: function () { var datePicker = this.datePicker; if (this.enabled) { this.setValue(datePicker.getDate()); } datePicker.setVisible(false); var el = this.getEl(); el.focus(); }, /** * The method compares the value date and the value of the control, * if they are not caused by the event "change" and set the new value. * This method takes a string or object Date. * @protected * @override * @param {String|Date} date The date or a string representation. * @return {Boolean} Returns true - if the value has changed, otherwise - false. */ changeValue: function (date) { var newValue = this.getCorrectValue(date); var isChanged = this.isChanged(newValue); if (isChanged) { this.value = newValue; this.fireEvent("change", newValue, this); } return isChanged; }, /** * Returns the result of parse parameter date. * @param {Date|String} date The date or a string representation. * @return {Date|Null|String} Returns date, null or "". */ getCorrectValue: function (date) { var newValue = null; if (Ext.isDate(date)) { newValue = date; } if (Ext.isString(date)) { var currentValue = this.value; if (date === "") { newValue = null; } else { newValue = this.parseDate(date) || ""; } if (Ext.isDate(currentValue) && Ext.isDate(newValue)) { newValue.setHours(currentValue.getHours(), currentValue.getMinutes(), currentValue.getSeconds(), currentValue.getMilliseconds()); } } return newValue; }, /** * Returns the result of the comparison parameter newValue, to the value of the control. * @param {Date|String} newValue The date or a string representation. * @return {Boolean} Returns true - if the value has changed, otherwise - false. */ isChanged: function (newValue) { var isChanged; var currentValue = this.value; if (Ext.isDate(currentValue) && Ext.isDate(newValue)) { isChanged = !Ext.Date.isEqual(currentValue, newValue); } else { isChanged = newValue !== currentValue; } return isChanged; }, /** * Returns the formatted value of the control (date string). * @return {String} */ getFormattedValue: function () { return Terrasoft.utils.string.getTypedStringValue(this.value, Terrasoft.DataValueType.DATE); }, /** * Destroys the control and clears the event handlers. * If the {@link Terrasoft.DatePicker datePicker} element is created, it destroys it, and clears the handlers associated with it. * @override */ onDestroy: function () { var datePicker = this.datePicker; if (datePicker !== null) { datePicker.un("dateSelected", this.onDateSelected, this); datePicker.un("currentDateSelected", this.onDateSelected, this); datePicker.destroy(); } this.callParent(arguments); }, /** * Sets the value of the control, checks its value for correctness. * If the item is displayed and its value is changed, set a new value to the dom element. * @param {String / Date} date If a string is passed, it converts it to a Date object. * @return {Boolean} Returns a sign that the value has changed */ setValue: function (date) { var isChanged = this.changeValue(date); if (this.rendered) { var el = this.getEl(); el.dom.value = this.getFormattedValue(); } return isChanged; }, /** * If the focus is lost, it sets the value of the control if it changes. * @method onBlur * @override * @inheritdoc Terrasoft.baseedit#onBlur */ onBlur: function () { if (!this.enabled || !this.rendered) { return; } var value = this.getTypedValue(); this.setValue(value); this.focused = false; this.fireEvent("blur", this); this.fireEvent("focusChanged", this); }, /** * Pressing the "ENTER" key sets the value of the control if it has changed. * @method onEnterKeyPressed * @override * @inheritdoc Terrasoft.baseedit#onEnterKeyPressed */ onEnterKeyPressed: function () { var value = this.getTypedValue(); var isChanged = this.setValue(value); this.fireEvent("enterkeypressed", this); if (!isChanged) { this.fireEvent("editenterkeypressed", this); } }, /** * Converts string to date. * If you pass a string of 6 or 8 digits. * Converts it into a Date object based on the current * date format "Terrasoft.Resources.CultureSettings.dateFormat" culture. * Prevents the efЁfect of "rollover" of a Date object in JavaScript, ie, takes into * account the existence of the date. * For example, the date of leap years and the possible number of days in the month, * if the conversion can not be transferred to a string returns null. * @method parseDate * @param {String} value The string date. * @return {Date|Null} The conversion results. */ parseDate: function (value) { var clearFormat = this.getDateFormat(value); var result = this.tryParseDate(value, clearFormat, true) || this.tryParseDate(value, this.format, true); return result; }, /** * Analyzes the length of the string passed and returns the appropriate format to convert a string to a Date object. * Allows for setting the current culture specified in Terrasoft.Resources.CultureSettings. * If the format string is longer than 6 characters will return the format with full representation * of the year (4 digits) * otherwise a brief presentation format (2 digits). * @method getDateFormat * @param {String} value The format of the date string. * @return {String} string The date format. */ getDateFormat: function (value) { var regex = /^(\d{6}||\d{8})$/; var format = this.format; if (regex.test(value)) { var dot = new RegExp("\\.", "g"); var clearFormat = format.replace(dot, ""); var clearValue = value.replace(dot, ""); var length = clearValue.length; var isShortDate = length <= 6; if (isShortDate) { return clearFormat.replace("Y", "y"); } return clearFormat.replace("y", "Y"); } return format; }, /** * @inheritdoc Terrasoft.controls.component#isEventWithin. * @override */ isEventWithin: function (event) { var isWithin = this.callParent(arguments); if (!isWithin && this.datePicker) { isWithin = this.datePicker.isEventWithin(event); } return isWithin; } });