[FIX] web: pressing enter in list editable create new line
The editable list view (and the x2manys) have been reimplemented, but the user experience was not totally (this is an understatement) polished. With this commit, we reintroduce a good functionality: pressing enter on the last line of the list creates a new line. Also, this commit removes a 'debug: true', leftover by someone with a trigram starting by F and ending by WI.
This commit is contained in:
@@ -18,6 +18,7 @@ var qweb = core.qweb;
|
||||
|
||||
var ListController = BasicController.extend({
|
||||
custom_events: _.extend({}, BasicController.prototype.custom_events, {
|
||||
add_record: '_onAddRecord',
|
||||
button_clicked: '_onButtonClicked',
|
||||
change_mode: '_onChangeMode',
|
||||
selection_changed: '_onSelectionChanged',
|
||||
@@ -149,6 +150,28 @@ var ListController = BasicController.extend({
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add a record to the list
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_addRecord: function () {
|
||||
var self = this;
|
||||
this.model.addDefaultRecord(this.handle, {position: this.editable}).then(function (recordID) {
|
||||
self._toggleNoContentHelper(false);
|
||||
var state = self.model.get(self.handle);
|
||||
self.renderer.updateState(state);
|
||||
self.renderer.editRecord(recordID);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Archive the current selection
|
||||
*
|
||||
* @private
|
||||
* @param {string[]} ids
|
||||
* @param {boolean} archive
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_archive: function (ids, archive) {
|
||||
if (ids.length === 0) {
|
||||
return $.when();
|
||||
@@ -204,9 +227,20 @@ var ListController = BasicController.extend({
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Add a record to the list
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onAddRecord: function (event) {
|
||||
event.stopPropagation();
|
||||
this._addRecord();
|
||||
},
|
||||
/**
|
||||
* Handles a click on a button by performing its action.
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onButtonClicked: function (event) {
|
||||
@@ -218,6 +252,7 @@ var ListController = BasicController.extend({
|
||||
* edit, and vice versa. In that case, we need to make sure that the buttons
|
||||
* displayed in the control panel are correct.
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onChangeMode: function (event) {
|
||||
@@ -228,6 +263,7 @@ var ListController = BasicController.extend({
|
||||
* can switch to the form view with no active res_id, so it is in 'create'
|
||||
* mode, or we can edit inline.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onCreateRecord: function (event) {
|
||||
@@ -236,33 +272,36 @@ var ListController = BasicController.extend({
|
||||
// list editable renderer and would unselect the newly created row
|
||||
event.stopPropagation();
|
||||
|
||||
var self = this;
|
||||
if (this.editable) {
|
||||
this.model.addDefaultRecord(this.handle).then(function (recordID) {
|
||||
self._toggleNoContentHelper(false);
|
||||
var state = self.model.get(self.handle);
|
||||
self.renderer.updateState(state);
|
||||
self.renderer.editRecord(recordID);
|
||||
});
|
||||
this._addRecord();
|
||||
} else {
|
||||
this.trigger_up('switch_view', {view_type: 'form', res_id: undefined});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Called when the 'delete' action is clicked on in the side bar.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onDeleteSelectedRecords: function () {
|
||||
this._deleteRecords(this.selectedRecords);
|
||||
},
|
||||
/**
|
||||
* Handler called when the user clicked on the 'Discard' button.
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onDiscard: function () {
|
||||
_onDiscard: function (event) {
|
||||
event.stopPropagation();
|
||||
this.model.discardChanges(this.handle);
|
||||
this._updateButtons('readonly');
|
||||
this.update(this.handle, {reload: false});
|
||||
},
|
||||
/**
|
||||
* Opens the Export Dialog
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onExportData: function () {
|
||||
var record = this.model.get(this.handle);
|
||||
@@ -274,6 +313,7 @@ var ListController = BasicController.extend({
|
||||
* This should be moved in basic controller, and shared between basic views.
|
||||
*
|
||||
* @override
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onFieldChanged: function (event) {
|
||||
@@ -287,6 +327,7 @@ var ListController = BasicController.extend({
|
||||
* row, which is done when clicking on 'Save' (anywhere outside the row
|
||||
* actually), so this function should only switch back to readonly mode
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onSave: function (event) {
|
||||
@@ -300,6 +341,7 @@ var ListController = BasicController.extend({
|
||||
* When the current selection changes (by clicking on the checkboxes on the
|
||||
* left), we need to display (or hide) the 'sidebar'.
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onSelectionChanged: function (event) {
|
||||
@@ -309,6 +351,7 @@ var ListController = BasicController.extend({
|
||||
/**
|
||||
* Called when clicking on 'Archive' or 'Unarchive' in the sidebar.
|
||||
*
|
||||
* @private
|
||||
* @param {boolean} archive
|
||||
*/
|
||||
_onToggleArchiveState: function (archive) {
|
||||
@@ -319,6 +362,7 @@ var ListController = BasicController.extend({
|
||||
* tell the model to sort itself properly, to update the pager and to
|
||||
* rerender the view.
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onToggleColumnOrder: function (event) {
|
||||
@@ -335,6 +379,7 @@ var ListController = BasicController.extend({
|
||||
* This method just transfer the request to the model, then update the
|
||||
* renderer.
|
||||
*
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
*/
|
||||
_onToggleGroup: function (event) {
|
||||
|
||||
@@ -271,6 +271,15 @@ ListRenderer.include({
|
||||
}
|
||||
return $rows;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
* @returns {Deferred} this deferred is resolved immediately
|
||||
*/
|
||||
_renderView: function () {
|
||||
this.currentRow = null;
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
/**
|
||||
* This is one of the trickiest method in the editable renderer. It has to
|
||||
* do a lot of stuff: it has to determine which cell should be selected (if
|
||||
@@ -563,6 +572,9 @@ ListRenderer.include({
|
||||
_onMoveNextLine: function () {
|
||||
if (this.currentRow < this.state.data.length - 1) {
|
||||
this._selectCell(this.currentRow + 1, 0);
|
||||
} else {
|
||||
this._unselectRow();
|
||||
this.trigger_up('add_record');
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -3394,7 +3394,6 @@ QUnit.module('Views', {
|
||||
}
|
||||
return this._super(route, args);
|
||||
},
|
||||
debug: true,
|
||||
});
|
||||
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
|
||||
@@ -1302,7 +1302,6 @@ QUnit.module('Views', {
|
||||
arch: '<tree editable="bottom"><field name="foo"/><field name="bar"/></tree>',
|
||||
});
|
||||
|
||||
|
||||
assert.strictEqual(list.$('tr.o_data_row').length, 4,
|
||||
"should have 4 records");
|
||||
list.$buttons.find('.o_list_button_add').click();
|
||||
@@ -1528,6 +1527,40 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('pressing enter on last line of editable list view', function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
var list = createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree editable="bottom"><field name="foo"/></tree>',
|
||||
mockRPC: function (route, args) {
|
||||
assert.step(route);
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
// click on 3rd line
|
||||
list.$('td:contains(gnap)').click();
|
||||
assert.ok(list.$('tr.o_data_row:eq(2)').hasClass('o_selected_row'),
|
||||
"3rd row should be selected");
|
||||
|
||||
// press enter in input
|
||||
list.$('tr.o_selected_row input').trigger({type: 'keydown', which: 13}); // enter
|
||||
assert.ok(list.$('tr.o_data_row:eq(3)').hasClass('o_selected_row'),
|
||||
"4rd row should be selected");
|
||||
assert.notOk(list.$('tr.o_data_row:eq(2)').hasClass('o_selected_row'),
|
||||
"3rd row should no longer be selected");
|
||||
|
||||
// press enter on last row
|
||||
list.$('tr.o_selected_row input').trigger({type: 'keydown', which: 13}); // enter
|
||||
assert.strictEqual(list.$('tr.o_data_row').length, 5, "should have created a 5th row");
|
||||
|
||||
assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/foo/default_get']);
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user