[FIX] web: Listview editable

(backport of enterprise version)

Fix various problems with list view editable :
* Click outside which should discard/save the line in edition
* Warnings which should not appear when line is being discarded/saved
* JS test

+ JS code refactoring
This commit is contained in:
qsm-odoo
2015-09-08 14:14:31 +02:00
parent 4932bb13f3
commit 3f7d350fe2
3 changed files with 75 additions and 78 deletions
@@ -14,7 +14,6 @@ var utils = require('web.utils');
var ViewManager = require('web.ViewManager');
var formats = require('web.formats');
var _t = core._t;
var QWeb = core.qweb;
var COMMANDS = common.commands;
@@ -854,7 +853,7 @@ var FieldX2Many = AbstractManyField.extend({
var view = this.get_active_view();
if (view && view.type === "list" && view.controller.__focus) {
var def = $.Deferred();
view.controller._on_blur_one2many(true).always(function () {
view.controller._on_blur_one2many().always(function () {
def.resolve();
});
return def;
@@ -904,7 +903,6 @@ var X2ManyViewManager = ViewManager.extend({
this.set_cp_bus(this.control_panel.get_bus());
this._super(parent, dataset, views, flags);
this.registry = core.view_registry.extend(x2many_views);
this.__ignore_blur = false;
},
start: function() {
this.control_panel.prependTo(this.$el);
@@ -1004,12 +1002,6 @@ var X2ManyList = ListView.List.extend({
'class': 'oe_form_field_x2many_list_row_add'
}).append(
$('<a>', {href: '#'}).text(_t("Add an item"))
.mousedown(function () {
// FIXME: needs to be an official API somehow
if (self.view.editor.is_editing()) {
self.view.__ignore_blur = true;
}
})
.click(function (e) {
e.preventDefault();
e.stopPropagation();
@@ -1018,7 +1010,7 @@ var X2ManyList = ListView.List.extend({
clearTimeout(self.view.editor.form.__blur_timeout);
self.view.editor.form.__blur_timeout = false;
}
self.view.ensure_saved().done(function () {
self.view.save_edition().done(function () {
self.view.do_add_record();
});
}));
@@ -1045,23 +1037,17 @@ var One2ManyListView = X2ManyListView.extend({
this.on('save:before cancel:before', this, this.proxy('_before_unedit'));
/* detect if the user try to exit the one2many widget */
var self = this;
this._mousedown_blur_line = function (event) {
if (self.__focus) {
self.__ignore_blur = true;
if ($(event.target).closest("button, *:not(.oe_form_field_x2many_list_row_add) > a").length ||
(!$(event.target).closest(self.editor.$el[0]).length && !$(event.target).closest(self.$el[0]).length)) {
self.__ignore_blur = false;
}
}
};
$(document).on('mousedown', this._mousedown_blur_line);
core.bus.on('click', this, this._on_click_outside);
this.dataset.on('dataset_changed', this, function () {
self._dataset_changed = true;
this._dataset_changed = true;
});
this.dataset.x2m.on('load_record', this, function () {
self._dataset_changed = false;
this._dataset_changed = false;
});
this.on('warning', this, function(e) { // In case of a one2many, we do not want any warning which comes from the editor
e.stop_propagation();
});
},
do_add_record: function () {
@@ -1121,11 +1107,12 @@ var One2ManyListView = X2ManyListView.extend({
}
var parent_form = this.x2m.view;
var self = this;
this.ensure_saved().then(function () {
if (parent_form)
this.save_edition().then(function () {
if (parent_form) {
return parent_form.save();
else
} else {
return $.when();
}
}).done(function () {
var ds = self.x2m.dataset;
var changed_records = _.find(ds.cache, function(record) {
@@ -1133,7 +1120,7 @@ var One2ManyListView = X2ManyListView.extend({
});
if (!self.x2m.options.reload_on_button && !changed_records) {
self.handle_button(name, id, callback);
}else {
} else {
self.handle_button(name, id, function(){
self.x2m.view.reload();
});
@@ -1149,9 +1136,12 @@ var One2ManyListView = X2ManyListView.extend({
reload_content: function () {
var self = this;
if (self.__focus) {
self._on_blur_one2many(true);
self._on_blur_one2many();
return this._super().then(function () {
self.start_edition(self.records.get(self.editor.form.datarecord.id));
var record_being_edited = self.records.get(self.editor.form.datarecord.id);
if (record_being_edited) {
self.start_edition(record_being_edited);
}
});
}
return this._super();
@@ -1161,31 +1151,52 @@ var One2ManyListView = X2ManyListView.extend({
this._dataset_changed = false;
this.__focus = true;
},
_on_blur_one2many: function (force) {
var self = this;
var def = $.when();
if (this.__ignore_blur && !force) {
this.__ignore_blur = false;
_on_click_outside: function(e) {
if(this.__ignore_blur || !this.editor.is_editing()) {
return;
}
var $target = $(e.target);
// If click on a button, a ui-autocomplete dropdown or modal-backdrop, it is not considered as a click outside
var click_outside = ($target.closest('.ui-autocomplete,.btn,.modal-backdrop').length === 0);
// Check if click inside the current list editable
var $o2m = $target.closest(".oe_list_editable");
if($o2m.length && $o2m[0] === this.el) {
click_outside = false;
}
// Check if click inside a modal which is on top of the current list editable
var $modal = $target.closest(".modal");
if($modal.length) {
var $currentModal = this.$el.closest(".modal");
if($currentModal.length === 0 || $currentModal[0] !== $modal[0]) {
click_outside = false;
}
}
if (click_outside) {
this._on_blur_one2many();
}
},
_on_blur_one2many: function() {
if(this.__ignore_blur) {
return $.when();
}
this.__ignore_blur = true;
this.__focus = false;
this.dataset.x2m.internal_dataset_changed = false;
if (this.editor.form.is_dirty()) {
def = this.ensure_saved();
} else if (this.editor.record) {
def = this.cancel_edition();
}
def.then(function () {
var self = this;
return this.save_edition().done(function () {
if (self._dataset_changed) {
self.dataset.trigger('dataset_changed');
}
});
return def;
}).always(function() {
self.__ignore_blur = false;
});
},
_after_edit: function () {
this.editor.form.on('blurred', this, this._on_blur_one2many);
@@ -1215,10 +1226,6 @@ var One2ManyListView = X2ManyListView.extend({
return this._super(record);
},
destroy: function () {
this._super();
$(document).off('mousedown', this._mousedown_blur_line);
}
});
var One2ManyGroups = ListView.Groups.extend({
@@ -1656,7 +1663,6 @@ var FieldMany2ManyCheckBoxes = AbstractManyField.extend(common.ReinitializeField
}
});
core.form_widget_registry
.add('many2one', FieldMany2One)
.add('many2many', FieldMany2Many)
@@ -1673,3 +1679,4 @@ return {
};
});
@@ -47,11 +47,6 @@ var Editor = Widget.extend({
$buttons: $(),
$pager: $(),
});
// FIXME
// this.on('warning', this, function(e) {
// e.stop_propagation();
// });
},
start: function () {
var self = this;
@@ -115,7 +110,7 @@ var Editor = Widget.extend({
if(result.created && !self.record.id) {
self.record.id = result.result;
}
return self.cancel();
return self.record;
});
},
cancel: function (force) {
@@ -305,24 +300,13 @@ ListView.include(/** @lends instance.web.ListView# */{
},
do_button_action: function (name, id, callback) {
var self = this;
this.ensure_saved().done(function (data) {
this.save_edition().done(function (data) {
if(!id && data.created) {
id = data.record.get('id');
}
self.handle_button(name, id, callback);
});
},
/**
* Ensures the editable list is saved (saves any pending edition if
* needed, or tries to)
*
* Returns a deferred to the end of the saving.
*
* @returns {$.Deferred}
*/
ensure_saved: function () {
return this.save_edition();
},
/**
* Builds a record with the provided id (``false`` for a creation),
* setting all columns with ``false`` value so code which relies on
@@ -358,10 +342,8 @@ ListView.include(/** @lends instance.web.ListView# */{
this.records.add(record, {at: (this.prepends_on_create())? 0 : null});
}
return this.ensure_saved().then(function() {
return this.save_edition().then(function() {
return $.when.apply($, self.editor.form.render_value_defs);
}, function() {
return self.cancel_edition();
}).then(function () {
var $recordRow = self.groups.get_row_for(record);
var cells = self.get_cells_for($recordRow);
@@ -406,7 +388,7 @@ ListView.include(/** @lends instance.web.ListView# */{
}
});
}, function() {
return $.Deferred().resolve(); // Here the cancel edition failed so the start_edition is considered as done and succeeded
return $.Deferred().resolve(); // Here the save/cancel edition failed so the start_edition is considered as done and succeeded
});
},
get_cells_for: function ($row) {
@@ -478,13 +460,18 @@ ListView.include(/** @lends instance.web.ListView# */{
// onwrite callback could be altering & reloading the
// record which has *just* been saved, so first perform all
// onwrites then do a final reload of the record
return self.handle_onwrite(record)
return self.cancel_edition(true)
.then(function() {
return self.handle_onwrite(record);
})
.then(function () {
return self.reload_record(record);
})
.then(function () {
return {created: created, record: record};
});
}, function() {
return self.cancel_edition();
});
});
});
+8 -5
View File
@@ -62,8 +62,7 @@ odoo.define_section('editor', ['web.ListEditor'], function (test, mock) {
return e.appendTo($fix)
.done(function () {
ok(!e.is_editing(), "should not be editing");
ok(e.form instanceof FormView,
"should use default form type");
ok(e.form instanceof FormView, "should use default form type");
});
});
@@ -93,7 +92,9 @@ odoo.define_section('editor', ['web.ListEditor'], function (test, mock) {
.then(function (form) {
assert.ok(e.is_editing(), "should be editing");
assert.equal(counter, 3, "should have configured all fields");
return e.save();
return e.save().then(function() {
return e.cancel();
});
})
.done(function (record) {
assert.ok(!e.is_editing(), "should have stopped editing");
@@ -133,7 +134,7 @@ odoo.define_section('editor', ['web.ListEditor'], function (test, mock) {
assert.expect(2);
var warnings = 0;
var e = new ListEditor({
dataset: new data.DataSetSearch(null, 'test.model'),
prepends_on_create: function () { return false; },
@@ -157,7 +158,9 @@ odoo.define_section('editor', ['web.ListEditor'], function (test, mock) {
});
})
.then(function (form) {
return e.save();
return e.save().then(function() {
return e.cancel();
});
})
.done(function () { assert.ok(false, "cancel should not succeed"); })
.fail(function () {