summaryrefslogtreecommitdiff
path: root/addons/web/static
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static')
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js19
-rw-r--r--addons/web/static/src/js/fields/field_utils.js66
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js30
-rw-r--r--addons/web/static/tests/fields/field_utils_tests.js18
4 files changed, 123 insertions, 10 deletions
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index 8657e44c49b..252ef70894e 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -863,6 +863,25 @@ var FieldDate = InputField.extend({
this.datewidget.setValue(this.value);
this.$input = this.datewidget.$input;
},
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Confirm the value on hit enter and re-render
+ *
+ * @private
+ * @override
+ * @param {KeyboardEvent} ev
+ */
+ async _onKeydown(ev) {
+ this._super(...arguments);
+ if (ev.which === $.ui.keyCode.ENTER) {
+ await this._setValue(this.$input.val());
+ this._render();
+ }
+ },
});
var FieldDateTime = FieldDate.extend({
diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js
index 8f8b9bbb2ab..4ffceb93408 100644
--- a/addons/web/static/src/js/fields/field_utils.js
+++ b/addons/web/static/src/js/fields/field_utils.js
@@ -414,6 +414,42 @@ function formatSelection(value, field, options) {
////////////////////////////////////////////////////////////////////////////////
/**
+ * Smart date inputs are shortcuts to write dates quicker.
+ * These shortcuts should respect the format ^[+-]\d+[dmwy]?$
+ *
+ * e.g.
+ * "+1d" or "+1" will return now + 1 day
+ * "-2w" will return now - 2 weeks
+ * "+3m" will return now + 3 months
+ * "-4y" will return now + 4 years
+ *
+ * @param {string} value
+ * @returns {Moment|false} Moment date object
+ */
+function parseSmartDateInput(value) {
+ const units = {
+ d: 'days',
+ m: 'months',
+ w: 'weeks',
+ y: 'years',
+ };
+ const re = new RegExp(`^([+-])(\\d+)([${Object.keys(units).join('')}]?)$`);
+ const match = re.exec(value);
+ if (match) {
+ let date = moment();
+ const offset = parseInt(match[2], 10);
+ const unit = units[match[3] || 'd'];
+ if (match[1] === '+') {
+ date.add(offset, unit);
+ } else {
+ date.subtract(offset, unit);
+ }
+ return date;
+ }
+ return false;
+}
+
+/**
* Create an Date object
* The method toJSON return the formated value to send value server side
*
@@ -433,11 +469,16 @@ function parseDate(value, field, options) {
var datePattern = time.getLangDateFormat();
var datePatternWoZero = datePattern.replace('MM', 'M').replace('DD', 'D');
var date;
- if (options && options.isUTC) {
- value = value.padStart(10, "0"); // server may send "932-10-10" for "0932-10-10" on some OS
- date = moment.utc(value);
+ const smartDate = parseSmartDateInput(value);
+ if (smartDate) {
+ date = smartDate;
} else {
- date = moment.utc(value, [datePattern, datePatternWoZero, moment.ISO_8601]);
+ if (options && options.isUTC) {
+ value = value.padStart(10, "0"); // server may send "932-10-10" for "0932-10-10" on some OS
+ date = moment.utc(value);
+ } else {
+ date = moment.utc(value, [datePattern, datePatternWoZero, moment.ISO_8601]);
+ }
}
if (date.isValid()) {
if (date.year() === 0) {
@@ -475,13 +516,18 @@ function parseDateTime(value, field, options) {
var pattern1 = datePattern + ' ' + timePattern;
var pattern2 = datePatternWoZero + ' ' + timePatternWoZero;
var datetime;
- if (options && options.isUTC) {
- // phatomjs crash if we don't use this format
- datetime = moment.utc(value.replace(' ', 'T') + 'Z');
+ const smartDate = parseSmartDateInput(value);
+ if (smartDate) {
+ datetime = smartDate;
} else {
- datetime = moment.utc(value, [pattern1, pattern2, moment.ISO_8601]);
- if (options && options.timezone) {
- datetime.add(-session.getTZOffset(datetime), 'minutes');
+ if (options && options.isUTC) {
+ // phatomjs crash if we don't use this format
+ datetime = moment.utc(value.replace(' ', 'T') + 'Z');
+ } else {
+ datetime = moment.utc(value, [pattern1, pattern2, moment.ISO_8601]);
+ if (options && options.timezone) {
+ datetime.add(-session.getTZOffset(datetime), 'minutes');
+ }
}
}
if (datetime.isValid()) {
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js
index 504d69dff69..965a98e973b 100644
--- a/addons/web/static/tests/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_tests.js
@@ -3891,6 +3891,36 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test('date field: hit enter should update value', async function (assert) {
+ assert.expect(2);
+
+ const form = await createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners"><field name="date"/></form>',
+ res_id: 1,
+ translateParameters: { // Avoid issues due to localization formats
+ date_format: '%m/%d/%Y',
+ },
+ viewOptions: {
+ mode: 'edit',
+ },
+ });
+
+ const year = (new Date()).getFullYear();
+
+ await testUtils.fields.editInput(form.el.querySelector('input[name="date"]'), '01/08');
+ await testUtils.fields.triggerKeydown(form.el.querySelector('input[name="date"]'), 'enter');
+ assert.strictEqual(form.el.querySelector('input[name="date"]').value, '01/08/' + year);
+
+ await testUtils.fields.editInput(form.el.querySelector('input[name="date"]'), '08/01');
+ await testUtils.fields.triggerKeydown(form.el.querySelector('input[name="date"]'), 'enter');
+ assert.strictEqual(form.el.querySelector('input[name="date"]').value, '08/01/' + year);
+
+ form.destroy();
+ });
+
QUnit.module('FieldDatetime');
QUnit.test('datetime field in form view', async function (assert) {
diff --git a/addons/web/static/tests/fields/field_utils_tests.js b/addons/web/static/tests/fields/field_utils_tests.js
index f3ab43260ae..567390e336d 100644
--- a/addons/web/static/tests/fields/field_utils_tests.js
+++ b/addons/web/static/tests/fields/field_utils_tests.js
@@ -413,4 +413,22 @@ QUnit.test('parse datetime without separator', function (assert) {
core._t.database.parameters = originalParameters;
});
});
+
+QUnit.test('parse smart date input', function (assert) {
+ assert.expect(10);
+
+ const format = "DD MM YYYY";
+ assert.strictEqual(fieldUtils.parse.date("+1d").format(format), moment().add(1, 'days').format(format));
+ assert.strictEqual(fieldUtils.parse.datetime("+2w").format(format), moment().add(2, 'weeks').format(format));
+ assert.strictEqual(fieldUtils.parse.date("+3m").format(format), moment().add(3, 'months').format(format));
+ assert.strictEqual(fieldUtils.parse.datetime("+4y").format(format), moment().add(4, 'years').format(format));
+
+ assert.strictEqual(fieldUtils.parse.date("+5").format(format), moment().add(5, 'days').format(format));
+ assert.strictEqual(fieldUtils.parse.datetime("-5").format(format), moment().subtract(5, 'days').format(format));
+
+ assert.strictEqual(fieldUtils.parse.date("-4y").format(format), moment().subtract(4, 'years').format(format));
+ assert.strictEqual(fieldUtils.parse.datetime("-3m").format(format), moment().subtract(3, 'months').format(format));
+ assert.strictEqual(fieldUtils.parse.date("-2w").format(format), moment().subtract(2, 'weeks').format(format));
+ assert.strictEqual(fieldUtils.parse.datetime("-1d").format(format), moment().subtract(1, 'days').format(format));
+});
});