[IMP] web: remaining_days widget editable in edit mode
Before this commit: remaining_days widget is not editable and it just shows information based on value like, Today, Yesterday, Tommorrow etc, when we change mode to edit it should have date/datetime picker so that user can change value of the widget. After this commit: remaining_days widget will display date/datetime picker in edit mode and in readonly mode it will display delta between the value of the field and today, it will also support edition of date/datetime value in multi edit mode. task-2507961 closes odoo/odoo#70578 Signed-off-by: Simon Genin (ges@odoo) <ges@odoo.com>
This commit is contained in:
@@ -1068,10 +1068,83 @@ const RemainingDays = AbstractField.extend({
|
||||
description: _lt("Remaining Days"),
|
||||
supportedFieldTypes: ['date', 'datetime'],
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
// use the session timezone when formatting dates
|
||||
this.formatOptions.timezone = true;
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the associated <input/> element.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
getFocusableElement() {
|
||||
return this.datewidget && this.datewidget.$input || $();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @returns {string} the content of the input
|
||||
*/
|
||||
_getValue() {
|
||||
let value = this.datewidget.getValue();
|
||||
if (this.field.type === "datetime") {
|
||||
value = value && value.add(-this.getSession().getTZOffset(value), 'minutes');
|
||||
}
|
||||
return value;
|
||||
},
|
||||
/**
|
||||
* Instantiates a new DateWidget datepicker.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_makeDatePicker() {
|
||||
this.datepickerOptions = _.defaults({}, { defaultDate: this.value });
|
||||
if (this.field.type === "datetime" && this.value) {
|
||||
const offset = this.getSession().getTZOffset(this.value);
|
||||
const displayedValue = this.value.clone().add(offset, 'minutes');
|
||||
this.datepickerOptions.defaultDate = displayedValue;
|
||||
}
|
||||
if (this.field.type === "date") {
|
||||
return new datepicker.DateWidget(this, this.datepickerOptions);
|
||||
}
|
||||
return new datepicker.DateTimeWidget(this, this.datepickerOptions);
|
||||
},
|
||||
/**
|
||||
* Displays date/datetime picker in edit mode.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
async _renderEdit() {
|
||||
await this._super(...arguments);
|
||||
if (this.datewidget) {
|
||||
this.datewidget.destroy();
|
||||
}
|
||||
|
||||
this.datewidget = this._makeDatePicker();
|
||||
this.datewidget.on('datetime_changed', this, () => {
|
||||
const value = this._getValue();
|
||||
if ((!value && this.value) || (value && !this._isSameValue(value))) {
|
||||
this._setValue(value);
|
||||
}
|
||||
});
|
||||
|
||||
await this.datewidget.appendTo('<div>');
|
||||
this.$el.append(this.datewidget.$el);
|
||||
},
|
||||
|
||||
/**
|
||||
* Displays the delta (in days) between the value of the field and today. If
|
||||
* the delta is larger than 99 days, displays the date as usual (without
|
||||
@@ -1079,7 +1152,7 @@ const RemainingDays = AbstractField.extend({
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
_render() {
|
||||
_renderReadonly() {
|
||||
if (this.value === false) {
|
||||
this.$el.removeClass('font-weight-bold text-danger text-warning');
|
||||
return;
|
||||
|
||||
@@ -4958,8 +4958,93 @@ QUnit.module('basic_fields', {
|
||||
unpatchDate();
|
||||
});
|
||||
|
||||
QUnit.test('remaining_days widget on a date field in multi edit list view', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const unpatchDate = patchDate(2017, 9, 8, 15, 35, 11); // October 8 2017, 15:35:11
|
||||
this.data.partner.records = [
|
||||
{ id: 1, date: '2017-10-08' }, // today
|
||||
{ id: 2, date: '2017-10-09' }, // tomorrow
|
||||
{ id: 8, date: false },
|
||||
];
|
||||
|
||||
const list = await createView({
|
||||
View: ListView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<tree multi_edit="1"><field name="date" widget="remaining_days"/></tree>',
|
||||
translateParameters: { // Avoid issues due to localization formats
|
||||
date_format: '%m/%d/%Y',
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(list.$('.o_data_cell:nth(0)').text(), 'Today');
|
||||
assert.strictEqual(list.$('.o_data_cell:nth(1)').text(), 'Tomorrow');
|
||||
|
||||
// select two records and edit them
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_list_record_selector input'));
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(1) .o_list_record_selector input'));
|
||||
|
||||
await testUtils.dom.click(list.$('.o_data_row:first .o_data_cell'));
|
||||
assert.containsOnce(list, 'input.o_datepicker_input', 'should have date picker input');
|
||||
await testUtils.fields.editAndTrigger(list.$('.o_datepicker_input'), '10/10/2017', ['input', 'change', 'focusout']);
|
||||
|
||||
assert.containsOnce(document.body, '.modal');
|
||||
assert.strictEqual($('.modal .o_field_widget').text(), "In 2 days",
|
||||
"should have 'In 2 days' value to change");
|
||||
await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
|
||||
|
||||
assert.strictEqual(list.$('.o_data_row:first .o_data_cell').text(), "In 2 days",
|
||||
"should have 'In 2 days' as date field value");
|
||||
assert.strictEqual(list.$('.o_data_row:nth(1) .o_data_cell').text(), "In 2 days",
|
||||
"should have 'In 2 days' as date field value");
|
||||
|
||||
list.destroy();
|
||||
unpatchDate();
|
||||
});
|
||||
|
||||
QUnit.test('remaining_days widget, enter wrong value manually in multi edit list view', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const unpatchDate = patchDate(2017, 9, 8, 15, 35, 11); // October 8 2017, 15:35:11
|
||||
this.data.partner.records = [
|
||||
{ id: 1, date: '2017-10-08' }, // today
|
||||
{ id: 2, date: '2017-10-09' }, // tomorrow
|
||||
{ id: 8, date: false },
|
||||
];
|
||||
|
||||
const list = await createView({
|
||||
View: ListView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<tree multi_edit="1"><field name="date" widget="remaining_days"/></tree>',
|
||||
translateParameters: { // Avoid issues due to localization formats
|
||||
date_format: '%m/%d/%Y',
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(list.$('.o_data_cell:nth(0)').text(), 'Today');
|
||||
assert.strictEqual(list.$('.o_data_cell:nth(1)').text(), 'Tomorrow');
|
||||
|
||||
// select two records and edit them
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(0) .o_list_record_selector input'));
|
||||
await testUtils.dom.click(list.$('.o_data_row:eq(1) .o_list_record_selector input'));
|
||||
|
||||
await testUtils.dom.click(list.$('.o_data_row:first .o_data_cell'));
|
||||
assert.containsOnce(list, 'input.o_datepicker_input', 'should have date picker input');
|
||||
await testUtils.fields.editAndTrigger(list.$('.o_datepicker_input'), 'blabla', ['input', 'change']);
|
||||
await testUtils.dom.click(list.$el);
|
||||
|
||||
assert.containsNone(document.body, '.modal');
|
||||
assert.strictEqual(list.$('.o_data_cell:nth(0)').text(), 'Today');
|
||||
assert.strictEqual(list.$('.o_data_cell:nth(1)').text(), 'Tomorrow');
|
||||
|
||||
list.destroy();
|
||||
unpatchDate();
|
||||
});
|
||||
|
||||
QUnit.test('remaining_days widget on a date field in form view', async function (assert) {
|
||||
assert.expect(4);
|
||||
assert.expect(8);
|
||||
|
||||
const unpatchDate = patchDate(2017, 9, 8, 15, 35, 11); // October 8 2017, 15:35:11
|
||||
this.data.partner.records = [
|
||||
@@ -4977,11 +5062,64 @@ QUnit.module('basic_fields', {
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Today');
|
||||
assert.hasClass(form.$('.o_field_widget'), 'font-weight-bold text-warning');
|
||||
|
||||
// in edit mode, this widget should not be editable.
|
||||
// in edit mode, this widget should be editable.
|
||||
await testUtils.form.clickEdit(form);
|
||||
|
||||
assert.hasClass(form.$('.o_form_view'), 'o_form_editable');
|
||||
assert.containsOnce(form, 'div.o_field_widget[name=date]');
|
||||
assert.containsOnce(form, 'div.o_field_widget[name=date] .o_datepicker');
|
||||
|
||||
await testUtils.dom.openDatepicker(form.$('.o_datepicker'));
|
||||
assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 1,
|
||||
"datepicker should be opened");
|
||||
|
||||
await testUtils.dom.click($('.bootstrap-datetimepicker-widget .day[data-day="10/09/2017"]'));
|
||||
await testUtils.form.clickSave(form);
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Tomorrow');
|
||||
|
||||
await testUtils.form.clickEdit(form);
|
||||
await testUtils.dom.openDatepicker(form.$('.o_datepicker'));
|
||||
await testUtils.dom.click($('.bootstrap-datetimepicker-widget .day[data-day="10/07/2017"]'));
|
||||
await testUtils.form.clickSave(form);
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Yesterday');
|
||||
assert.hasClass(form.$('.o_field_widget'), 'text-danger');
|
||||
|
||||
form.destroy();
|
||||
unpatchDate();
|
||||
});
|
||||
|
||||
QUnit.test('remaining_days widget on a datetime field in form view', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const unpatchDate = patchDate(2017, 9, 8, 15, 35, 11); // October 8 2017, 15:35:11
|
||||
this.data.partner.records = [
|
||||
{ id: 1, datetime: '2017-10-08 10:00:00' }, // today
|
||||
];
|
||||
|
||||
const form = await createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form><field name="datetime" widget="remaining_days"/></form>',
|
||||
res_id: 1,
|
||||
});
|
||||
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Today');
|
||||
assert.hasClass(form.$('.o_field_widget'), 'text-warning');
|
||||
|
||||
// in edit mode, this widget should be editable.
|
||||
await testUtils.form.clickEdit(form);
|
||||
|
||||
assert.hasClass(form.$('.o_form_view'), 'o_form_editable');
|
||||
assert.containsOnce(form, 'div.o_field_widget[name=datetime] .o_datepicker');
|
||||
|
||||
await testUtils.dom.openDatepicker(form.$('.o_datepicker'));
|
||||
assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 1,
|
||||
"datepicker should be opened");
|
||||
|
||||
await testUtils.dom.click($('.bootstrap-datetimepicker-widget .day[data-day="10/09/2017"]'));
|
||||
await testUtils.dom.click($('a[data-action="close"]'));
|
||||
await testUtils.form.clickSave(form);
|
||||
assert.strictEqual(form.$('.o_field_widget').text(), 'Tomorrow');
|
||||
|
||||
form.destroy();
|
||||
unpatchDate();
|
||||
|
||||
Reference in New Issue
Block a user