summaryrefslogtreecommitdiff
path: root/addons/web/static/src/js/widgets/date_picker.js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/src/js/widgets/date_picker.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web/static/src/js/widgets/date_picker.js')
-rw-r--r--addons/web/static/src/js/widgets/date_picker.js358
1 files changed, 358 insertions, 0 deletions
diff --git a/addons/web/static/src/js/widgets/date_picker.js b/addons/web/static/src/js/widgets/date_picker.js
new file mode 100644
index 00000000..fdbd1f7d
--- /dev/null
+++ b/addons/web/static/src/js/widgets/date_picker.js
@@ -0,0 +1,358 @@
+odoo.define('web.datepicker', function (require) {
+"use strict";
+
+var core = require('web.core');
+var field_utils = require('web.field_utils');
+var time = require('web.time');
+var Widget = require('web.Widget');
+
+var _t = core._t;
+
+var DateWidget = Widget.extend({
+ template: "web.datepicker",
+ type_of_date: "date",
+ events: {
+ 'error.datetimepicker': 'errorDatetime',
+ 'change .o_datepicker_input': 'changeDatetime',
+ 'click input': '_onInputClicked',
+ 'input input': '_onInput',
+ 'keydown': '_onKeydown',
+ 'show.datetimepicker': '_onDateTimePickerShow',
+ 'hide.datetimepicker': '_onDateTimePickerHide',
+ },
+ /**
+ * @override
+ */
+ init: function (parent, options) {
+ this._super.apply(this, arguments);
+
+ this.name = parent.name;
+ this.options = _.extend({
+ locale: moment.locale(),
+ format : this.type_of_date === 'datetime' ? time.getLangDatetimeFormat() : time.getLangDateFormat(),
+ minDate: moment({ y: 1000 }),
+ maxDate: moment({ y: 9999, M: 11, d: 31 }),
+ useCurrent: false,
+ icons: {
+ time: 'fa fa-clock-o',
+ date: 'fa fa-calendar',
+ up: 'fa fa-chevron-up',
+ down: 'fa fa-chevron-down',
+ previous: 'fa fa-chevron-left',
+ next: 'fa fa-chevron-right',
+ today: 'fa fa-calendar-check-o',
+ clear: 'fa fa-trash',
+ close: 'fa fa-check primary',
+ },
+ calendarWeeks: true,
+ buttons: {
+ showToday: false,
+ showClear: false,
+ showClose: false,
+ },
+ widgetParent: 'body',
+ keyBinds: null,
+ }, options || {});
+
+ this.__libInput = 0;
+ // tempusdominus doesn't offer any elegant way to check whether the
+ // datepicker is open or not, so we have to listen to hide/show events
+ // and manually keep track of the 'open' state
+ this.__isOpen = false;
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ this.$input = this.$('input.o_datepicker_input');
+ this.__libInput++;
+ this.$el.datetimepicker(this.options);
+ this.__libInput--;
+ this._setReadonly(false);
+ },
+ /**
+ * @override
+ */
+ destroy: function () {
+ if (this._onScroll) {
+ window.removeEventListener('wheel', this._onScroll, true);
+ }
+ this.__libInput++;
+ this.$el.datetimepicker('destroy');
+ this.__libInput--;
+ this._super.apply(this, arguments);
+ },
+
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+
+ /**
+ * set datetime value
+ */
+ changeDatetime: function () {
+ if (this.__libInput > 0) {
+ if (this.options.warn_future) {
+ this._warnFuture(this.getValue());
+ }
+ this.trigger("datetime_changed");
+ return;
+ }
+ var oldValue = this.getValue();
+ if (this.isValid()) {
+ this._setValueFromUi();
+ var newValue = this.getValue();
+ var hasChanged = !oldValue !== !newValue;
+ if (oldValue && newValue) {
+ var formattedOldValue = oldValue.format(time.getLangDatetimeFormat());
+ var formattedNewValue = newValue.format(time.getLangDatetimeFormat());
+ if (formattedNewValue !== formattedOldValue) {
+ hasChanged = true;
+ }
+ }
+ if (hasChanged) {
+ if (this.options.warn_future) {
+ this._warnFuture(newValue);
+ }
+ this.trigger("datetime_changed");
+ }
+ } else {
+ var formattedValue = oldValue ? this._formatClient(oldValue) : null;
+ this.$input.val(formattedValue);
+ }
+ },
+ /**
+ * Library clears the wrong date format so just ignore error
+ */
+ errorDatetime: function (e) {
+ return false;
+ },
+ /**
+ * Focuses the datepicker input. This function must be called in order to
+ * prevent 'input' events triggered by the lib to bubble up, and to cause
+ * unwanted effects (like triggering 'field_changed' events)
+ */
+ focus: function () {
+ this.__libInput++;
+ this.$input.focus();
+ this.__libInput--;
+ },
+ /**
+ * @returns {Moment|false}
+ */
+ getValue: function () {
+ var value = this.get('value');
+ return value && value.clone();
+ },
+ /**
+ * @returns {boolean}
+ */
+ isValid: function () {
+ var value = this.$input.val();
+ if (value === "") {
+ return true;
+ } else {
+ try {
+ this._parseClient(value);
+ return true;
+ } catch (e) {
+ return false;
+ }
+ }
+ },
+ /**
+ * @returns {Moment|false} value
+ */
+ maxDate: function (date) {
+ this.__libInput++;
+ this.$el.datetimepicker('maxDate', date || null);
+ this.__libInput--;
+ },
+ /**
+ * @returns {Moment|false} value
+ */
+ minDate: function (date) {
+ this.__libInput++;
+ this.$el.datetimepicker('minDate', date || null);
+ this.__libInput--;
+ },
+ /**
+ * @param {Moment|false} value
+ */
+ setValue: function (value) {
+ this.set({'value': value});
+ var formatted_value = value ? this._formatClient(value) : null;
+ this.$input.val(formatted_value);
+ this._setLibInputValue(value);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * add a warning to communicate that a date in the future has been set
+ *
+ * @private
+ * @param {Moment} currentDate
+ */
+ _warnFuture: function (currentDate) {
+ if (!this.$warning) {
+ this.$warning = $('<span>', {
+ class: 'fa fa-exclamation-triangle o_tz_warning o_datepicker_warning',
+ });
+ var title = _t("This date is in the future. Make sure this is what you expect.");
+ this.$warning.attr('title', title);
+ this.$input.after(this.$warning);
+ }
+ // Get rid of time and TZ crap for comparison
+ if (currentDate && currentDate.format('YYYY-MM-DD') > moment().format('YYYY-MM-DD')) {
+ this.$warning.show();
+ } else {
+ this.$warning.hide();
+ }
+ },
+
+ /**
+ * @private
+ * @param {Moment} v
+ * @returns {string}
+ */
+ _formatClient: function (v) {
+ return field_utils.format[this.type_of_date](v, null, {timezone: false});
+ },
+ /**
+ * @private
+ * @param {string|false} v
+ * @returns {Moment}
+ */
+ _parseClient: function (v) {
+ return field_utils.parse[this.type_of_date](v, null, {timezone: false});
+ },
+ /**
+ * @private
+ * @param {Moment|false} value
+ */
+ _setLibInputValue: function (value) {
+ this.__libInput++;
+ this.$el.datetimepicker('date', value || null);
+ this.__libInput--;
+ },
+ /**
+ * @private
+ * @param {boolean} readonly
+ */
+ _setReadonly: function (readonly) {
+ this.readonly = readonly;
+ this.$input.prop('readonly', this.readonly);
+ },
+ /**
+ * set the value from the input value
+ *
+ * @private
+ */
+ _setValueFromUi: function () {
+ var value = this.$input.val() || false;
+ this.setValue(this._parseClient(value));
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Reacts to the datetimepicker being hidden
+ * Used to unbind the scroll event from the datetimepicker
+ *
+ * @private
+ */
+ _onDateTimePickerHide: function () {
+ this.__isOpen = false;
+ this.changeDatetime();
+ if (this._onScroll) {
+ window.removeEventListener('wheel', this._onScroll, true);
+ }
+ this.changeDatetime();
+ },
+ /**
+ * Reacts to the datetimepicker being shown
+ * Could set/verify our widget value
+ * And subsequently update the datetimepicker
+ *
+ * @private
+ */
+ _onDateTimePickerShow: function () {
+ this.__isOpen = true;
+ if (this.$input.val().length !== 0 && this.isValid()) {
+ this.$input.select();
+ }
+ var self = this;
+ this._onScroll = function (ev) {
+ if (ev.target !== self.$input.get(0)) {
+ self.__libInput++;
+ self.$el.datetimepicker('hide');
+ self.__libInput--;
+ }
+ };
+ window.addEventListener('wheel', this._onScroll, true);
+ },
+ /**
+ * @private
+ * @param {KeyEvent} ev
+ */
+ _onKeydown: function (ev) {
+ if (ev.which === $.ui.keyCode.ESCAPE) {
+ if (this.__isOpen) {
+ // we don't want any other effects than closing the datepicker,
+ // like leaving the edition of a row in editable list view
+ ev.stopImmediatePropagation();
+ this.__libInput++;
+ this.$el.datetimepicker('hide');
+ this.__libInput--;
+ this.focus();
+ }
+ }
+ },
+ /**
+ * Prevents 'input' events triggered by the library to bubble up, as they
+ * might have unwanted effects (like triggering 'field_changed' events in
+ * the context of field widgets)
+ *
+ * @private
+ * @param {Event} ev
+ */
+ _onInput: function (ev) {
+ if (this.__libInput > 0) {
+ ev.stopImmediatePropagation();
+ }
+ },
+ /**
+ * @private
+ */
+ _onInputClicked: function () {
+ this.__libInput++;
+ this.$el.datetimepicker('toggle');
+ this.__libInput--;
+ this.focus();
+ },
+});
+
+var DateTimeWidget = DateWidget.extend({
+ type_of_date: "datetime",
+ init: function (parent, options) {
+ this._super(parent, _.extend({
+ buttons: {
+ showToday: false,
+ showClear: false,
+ showClose: true,
+ },
+ }, options || {}));
+ },
+});
+
+return {
+ DateWidget: DateWidget,
+ DateTimeWidget: DateTimeWidget,
+};
+
+});