[FIX] web: several minor issues with editable list
- correctly update the pager when a record is added or removed - destroy the widgets of the removed row when the user clicks on 'Cancel' when creating a new record - ensure that the list always contains 4 rows (before this rev., in list views with less than 4 records, if the user created a new record, then clicked on 'Discard', there were only 3 rows left - properly destroy field widgets when removed from the DOM Note that the change of parent.parentID to parent.static is not a bug fix, but it's better to use the key that indicates the type of list element, instead of implying it from other attributes.
This commit is contained in:
committed by
Géry Debongnie
parent
a5ca63c83b
commit
130c47bc0a
@@ -768,7 +768,7 @@ var BasicModel = AbstractModel.extend({
|
||||
removeLine: function (elementID) {
|
||||
var record = this.localData[elementID];
|
||||
var parent = this.localData[record.parentID];
|
||||
if (parent.parentID) {
|
||||
if (parent.static) {
|
||||
// x2Many case: the new record has been stored in _changes, as a
|
||||
// command so we remove the command(s) related to that record
|
||||
parent._changes = _.filter(parent._changes, function (change) {
|
||||
@@ -777,6 +777,7 @@ var BasicModel = AbstractModel.extend({
|
||||
} else {
|
||||
// main list view case: the new record is in data
|
||||
parent.data = _.without(parent.data, elementID);
|
||||
parent.count--;
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -273,18 +273,18 @@ var BasicRenderer = AbstractRenderer.extend({
|
||||
* from internal referencing.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} record
|
||||
* @param {string} recordID id of the local resource
|
||||
* @param {AbstractField} widget
|
||||
* @returns {integer} the index of the removed widget
|
||||
*/
|
||||
_destroyFieldWidget: function (record, widget) {
|
||||
var recordWidgets = this.allFieldWidgets[record.id];
|
||||
_destroyFieldWidget: function (recordID, widget) {
|
||||
var recordWidgets = this.allFieldWidgets[recordID];
|
||||
var index = recordWidgets.indexOf(widget);
|
||||
if (index >= 0) {
|
||||
recordWidgets.splice(index, 1);
|
||||
}
|
||||
this._unregisterModifiersElement(widget.__node, record, widget);
|
||||
widget.$el.destroy();
|
||||
this._unregisterModifiersElement(widget.__node, recordID, widget);
|
||||
widget.destroy();
|
||||
return index;
|
||||
},
|
||||
/**
|
||||
@@ -541,7 +541,7 @@ var BasicRenderer = AbstractRenderer.extend({
|
||||
widget.$el.replaceWith(newWidget.$el);
|
||||
|
||||
// Destroy the old widget and position the new one at the old one's
|
||||
var oldIndex = this._destroyFieldWidget(record, widget);
|
||||
var oldIndex = this._destroyFieldWidget(record.id, widget);
|
||||
var recordWidgets = this.allFieldWidgets[record.id];
|
||||
recordWidgets.splice(oldIndex, 0, newWidget);
|
||||
recordWidgets.pop();
|
||||
@@ -553,13 +553,13 @@ var BasicRenderer = AbstractRenderer.extend({
|
||||
* node and record.
|
||||
*
|
||||
* @param {Object} node
|
||||
* @param {Object} record
|
||||
* @param {string} recordID id of the local resource
|
||||
* @param {jQuery|AbstractField} element
|
||||
*/
|
||||
_unregisterModifiersElement: function (node, record, element) {
|
||||
_unregisterModifiersElement: function (node, recordID, element) {
|
||||
var modifiersData = this._getModifiersData(node);
|
||||
if (modifiersData) {
|
||||
var elements = modifiersData.elementsByRecord[record.id];
|
||||
var elements = modifiersData.elementsByRecord[recordID];
|
||||
var index = _.findIndex(elements, function (oldElement) {
|
||||
return oldElement.widget === element
|
||||
|| oldElement.$el[0] === element[0];
|
||||
|
||||
@@ -182,6 +182,7 @@ var ListController = BasicController.extend({
|
||||
if ((recordID || this.handle) !== this.handle) {
|
||||
var state = this.model.get(this.handle);
|
||||
this.renderer.removeLine(state, recordID);
|
||||
this._updatePager();
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -202,6 +203,7 @@ var ListController = BasicController.extend({
|
||||
var state = self.model.get(self.handle);
|
||||
self.renderer.updateState(state, {});
|
||||
self.renderer.editRecord(recordID);
|
||||
self._updatePager();
|
||||
}).always(this._enableButtons.bind(this));
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -133,6 +133,7 @@ ListRenderer.include({
|
||||
* @param {string} recordID
|
||||
*/
|
||||
removeLine: function (state, recordID) {
|
||||
var self = this;
|
||||
var rowIndex = _.findIndex(this.state.data, {id: recordID});
|
||||
this.state = state;
|
||||
if (rowIndex === -1) {
|
||||
@@ -141,8 +142,20 @@ ListRenderer.include({
|
||||
if (rowIndex === this.currentRow) {
|
||||
this.currentRow = null;
|
||||
}
|
||||
|
||||
// remove the row
|
||||
var $row = this.$('.o_data_row:nth(' + rowIndex + ')');
|
||||
$row.remove();
|
||||
if (this.state.count >= 4) {
|
||||
$row.remove();
|
||||
} else {
|
||||
$row.replaceWith(this._renderEmptyRow());
|
||||
}
|
||||
|
||||
// destroy the removed row's widgets
|
||||
var widgetsToDestroy = this.allFieldWidgets[recordID].slice();
|
||||
_.each(widgetsToDestroy, function (widget) {
|
||||
self._destroyFieldWidget(recordID, widget);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Updates the already rendered row associated to the given recordID so that
|
||||
@@ -221,7 +234,7 @@ ListRenderer.include({
|
||||
// destroyed. This is not the case for simple buttons so we have to
|
||||
// do it here.
|
||||
if ($td.hasClass('o_list_button')) {
|
||||
self._unregisterModifiersElement(node, record, $td.children());
|
||||
self._unregisterModifiersElement(node, recordID, $td.children());
|
||||
}
|
||||
|
||||
// For edit mode we only replace the content of the cell with its
|
||||
@@ -231,14 +244,14 @@ ListRenderer.include({
|
||||
if (editMode) {
|
||||
$td.empty().append($newTd.contents());
|
||||
} else {
|
||||
self._unregisterModifiersElement(node, record, $td);
|
||||
self._unregisterModifiersElement(node, recordID, $td);
|
||||
$td.replaceWith($newTd);
|
||||
}
|
||||
});
|
||||
delete this.defs;
|
||||
|
||||
// Destroy old field widgets
|
||||
_.each(oldWidgets, this._destroyFieldWidget.bind(this, record));
|
||||
_.each(oldWidgets, this._destroyFieldWidget.bind(this, recordID));
|
||||
|
||||
// Toggle selected class here so that style is applied at the end
|
||||
$row.toggleClass('o_selected_row', editMode);
|
||||
|
||||
@@ -2,6 +2,7 @@ odoo.define('web.list_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
var config = require('web.config');
|
||||
var basicFields = require('web.basic_fields');
|
||||
var FormView = require('web.FormView');
|
||||
var ListView = require('web.ListView');
|
||||
var testUtils = require('web.test_utils');
|
||||
@@ -388,6 +389,54 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('editable list: add a line and discard', function (assert) {
|
||||
assert.expect(11);
|
||||
|
||||
var oldDestroy = basicFields.FieldChar.prototype.destroy;
|
||||
basicFields.FieldChar.prototype.destroy = function () {
|
||||
assert.step('destroy');
|
||||
oldDestroy.apply(this, arguments);
|
||||
};
|
||||
|
||||
var list = createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree editable="bottom"><field name="foo"/><field name="bar"/></tree>',
|
||||
domain: [['foo', '=', 'yop']],
|
||||
});
|
||||
|
||||
assert.strictEqual(list.$('tbody tr').length, 4,
|
||||
"list should contain 4 rows");
|
||||
assert.strictEqual(list.$('.o_data_row').length, 1,
|
||||
"list should contain one record (and thus 3 empty rows)");
|
||||
assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-1',
|
||||
"pager should be correct");
|
||||
|
||||
list.$buttons.find('.o_list_button_add').click();
|
||||
|
||||
assert.strictEqual(list.$('tbody tr').length, 4,
|
||||
"list should still contain 4 rows");
|
||||
assert.strictEqual(list.$('.o_data_row').length, 2,
|
||||
"list should contain two record (and thus 2 empty rows)");
|
||||
assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-2',
|
||||
"pager should be correct");
|
||||
|
||||
list.$buttons.find('.o_list_button_discard').click();
|
||||
|
||||
assert.strictEqual(list.$('tbody tr').length, 4,
|
||||
"list should still contain 4 rows");
|
||||
assert.strictEqual(list.$('.o_data_row').length, 1,
|
||||
"list should contain one record (and thus 3 empty rows)");
|
||||
assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-1',
|
||||
"pager should be correct");
|
||||
assert.verifySteps(['destroy'],
|
||||
"should have destroyed the widget of the removed line");
|
||||
|
||||
basicFields.FieldChar.prototype.destroy = oldDestroy;
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('field changes are triggered correctly', function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user