diff options
Diffstat (limited to 'addons/web/static/src/js/components/datepicker.js')
| -rw-r--r-- | addons/web/static/src/js/components/datepicker.js | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/addons/web/static/src/js/components/datepicker.js b/addons/web/static/src/js/components/datepicker.js new file mode 100644 index 00000000..94ce7ece --- /dev/null +++ b/addons/web/static/src/js/components/datepicker.js @@ -0,0 +1,263 @@ +odoo.define('web.DatePickerOwl', function (require) { + "use strict"; + + const field_utils = require('web.field_utils'); + const time = require('web.time'); + const { useAutofocus } = require('web.custom_hooks'); + + const { Component, hooks } = owl; + const { useExternalListener, useRef, useState } = hooks; + + let datePickerId = 0; + + /** + * Date picker + * + * This component exposes the API of the tempusdominus datepicker library. + * As such, its template is a simple input that will open the TD datepicker + * when clicked on. The component will also synchronize any user-input value + * with the library widget and vice-vera. + * + * For further details regarding the implementation of the picker itself, please + * refer to the official tempusdominus documentation (note: all props given + * to this component will be passed as arguments to instantiate the picker widget). + * @extends Component + */ + class DatePicker extends Component { + constructor() { + super(...arguments); + + this.inputRef = useRef('input'); + this.state = useState({ warning: false }); + + this.datePickerId = `o_datepicker_${datePickerId++}`; + this.typeOfDate = 'date'; + + useAutofocus(); + useExternalListener(window, 'scroll', this._onWindowScroll); + } + + mounted() { + $(this.el).on('show.datetimepicker', this._onDateTimePickerShow.bind(this)); + $(this.el).on('hide.datetimepicker', this._onDateTimePickerHide.bind(this)); + $(this.el).on('error.datetimepicker', () => false); + + const pickerOptions = Object.assign({ format: this.defaultFormat }, this.props); + this._datetimepicker(pickerOptions); + this.inputRef.el.value = this._formatDate(this.props.date); + } + + willUnmount() { + this._datetimepicker('destroy'); + } + + willUpdateProps(nextProps) { + for (const prop in nextProps) { + this._datetimepicker(prop, nextProps[prop]); + } + if (nextProps.date) { + this.inputRef.el.value = this._formatDate(nextProps.date); + } + } + + //--------------------------------------------------------------------- + // Private + //--------------------------------------------------------------------- + + /** + * @returns {string} + */ + get defaultFormat() { + return time.getLangDateFormat(); + } + + //--------------------------------------------------------------------- + // Private + //--------------------------------------------------------------------- + + /** + * Handle bootstrap datetimepicker calls. + * @private + * @param {...any} args anything that will be passed to the datetimepicker function. + */ + _datetimepicker(...args) { + $(this.el).datetimepicker(...args); + } + + /** + * @private + * @param {moment} date + * @returns {string} + */ + _formatDate(date) { + try { + return field_utils.format[this.typeOfDate](date, null, { timezone: false }); + } catch (err) { + return false; + } + } + + /** + * @private + * @param {string|false} value + * @returns {moment} + */ + _parseInput(inputValue) { + try { + return field_utils.parse[this.typeOfDate](inputValue, null, { timezone: false }); + } catch (err) { + return false; + } + } + + //--------------------------------------------------------------------- + // Handlers + //--------------------------------------------------------------------- + + /** + * Reacts to the datetimepicker being hidden + * Used to unbind the scroll event from the datetimepicker + * @private + */ + _onDateTimePickerHide() { + const date = this._parseInput(this.inputRef.el.value); + this.state.warning = date.format('YYYY-MM-DD') > moment().format('YYYY-MM-DD'); + this.trigger('datetime-changed', { date }); + } + + /** + * Reacts to the datetimepicker being shown + * Could set/verify our widget value + * And subsequently update the datetimepicker + * @private + */ + _onDateTimePickerShow() { + this.inputRef.el.select(); + } + + /** + * @private + */ + _onInputClick() { + this._datetimepicker('toggle'); + } + + /** + * @private + */ + _onInputChange() { + const date = this._parseInput(this.inputRef.el.value); + if (date) { + this.state.warning = date.format('YYYY-MM-DD') > moment().format('YYYY-MM-DD'); + this.trigger('datetime-changed', { date }); + } else { + this.inputRef.el.value = this._formatDate(this.props.date); + } + } + + /** + * @private + */ + _onWindowScroll(ev) { + if (ev.target !== this.inputRef.el) { + this._datetimepicker('hide'); + } + } + } + + DatePicker.defaultProps = { + calendarWeeks: true, + icons: { + clear: 'fa fa-delete', + close: 'fa fa-check primary', + date: 'fa fa-calendar', + down: 'fa fa-chevron-down', + next: 'fa fa-chevron-right', + previous: 'fa fa-chevron-left', + time: 'fa fa-clock-o', + today: 'fa fa-calendar-check-o', + up: 'fa fa-chevron-up', + }, + get locale() {return moment.locale();}, + maxDate: moment({ y: 9999, M: 11, d: 31 }), + minDate: moment({ y: 1000 }), + useCurrent: false, + widgetParent: 'body', + }; + DatePicker.props = { + // Actual date value + date: moment, + // Other props + buttons: { + type: Object, + shape: { + showClear: Boolean, + showClose: Boolean, + showToday: Boolean, + }, + optional: 1, + }, + calendarWeeks: Boolean, + format: { type: String, optional: 1 }, + icons: { + type: Object, + shape: { + clear: String, + close: String, + date: String, + down: String, + next: String, + previous: String, + time: String, + today: String, + up: String, + }, + }, + keyBinds: { validate: kb => typeof kb === 'object' || kb === null, optional: 1 }, + locale: String, + maxDate: moment, + minDate: moment, + readonly: { type: Boolean, optional: 1 }, + useCurrent: Boolean, + widgetParent: String, + }; + DatePicker.template = 'web.DatePicker'; + + /** + * Date/time picker + * + * Similar to the DatePicker component, adding the handling of more specific + * time values: hour-minute-second. + * + * Once again, refer to the tempusdominus documentation for implementation + * details. + * @extends DatePicker + */ + class DateTimePicker extends DatePicker { + constructor() { + super(...arguments); + + this.typeOfDate = 'datetime'; + } + + /** + * @override + */ + get defaultFormat() { + return time.getLangDatetimeFormat(); + } + } + + DateTimePicker.defaultProps = Object.assign(Object.create(DatePicker.defaultProps), { + buttons: { + showClear: false, + showClose: true, + showToday: false, + }, + }); + + return { + DatePicker, + DateTimePicker, + }; +}); |
