diff options
| author | Vincent Schippefilt <vsc@odoo.com> | 2018-09-03 16:20:06 +0200 |
|---|---|---|
| committer | Vincent Schippefilt <vsc@odoo.com> | 2018-09-25 16:49:22 +0200 |
| commit | e343f5f5f95607b91a61fed167a6f11f0eeaeaa8 (patch) | |
| tree | d9cc4b8ff39fedc17db36c7f1ed3fbc1fea2ec5f /addons/web/static/src/js/views | |
| parent | 3dcf20284df9fb411a7093537ccd645a34543b20 (diff) | |
[IMP] web: x2many adds a new line by tabbing on a not dirty line
Before this change, when the focus was on the first field on a x2many
field, and the user pressed TAB, the line would be discarded and the
focus moved to the next field (at the level of the x2many) in the form.
This was an issue because if the first field was required, the focus
could not be moved out of the field with TAB so the user had to discard
the line manually (with ESC) before moving to the next field
This change works with 2 changes:
1. detecting if a line is dirty (has been modified by the user) and at
the end of the line, decide to either
- discard the line and move the next field, if the line is not dirty
- commit the line and add a new line, if the line is dirty
2. allow users to use TAB through required field inside x2many so they
can easilly go to the end of the line.
Task id : 1872248
Diffstat (limited to 'addons/web/static/src/js/views')
3 files changed, 31 insertions, 12 deletions
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index fbb4b0b122c..9dd7c4d1141 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -594,6 +594,7 @@ var BasicModel = AbstractModel.extend({ getDomain: element.getDomain, getFieldNames: element.getFieldNames, id: element.id, + isDirty: element.isDirty, limit: element.limit, model: element.model, offset: element.offset, @@ -648,6 +649,7 @@ var BasicModel = AbstractModel.extend({ getFieldNames: element.getFieldNames, groupedBy: element.groupedBy, id: element.id, + isDirty: element.isDirty, isOpen: element.isOpen, limit: element.limit, model: element.model, @@ -3490,6 +3492,7 @@ var BasicModel = AbstractModel.extend({ dataPoint.getContext = this._getContext.bind(this, dataPoint); dataPoint.getDomain = this._getDomain.bind(this, dataPoint); dataPoint.getFieldNames = this._getFieldNames.bind(this, dataPoint); + dataPoint.isDirty = this.isDirty.bind(this, dataPoint.id); this.localData[dataPoint.id] = dataPoint; diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index 40736b1b508..3691903c079 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -27,6 +27,7 @@ var ListController = BasicController.extend({ selection_changed: '_onSelectionChanged', toggle_column_order: '_onToggleColumnOrder', toggle_group: '_onToggleGroup', + navigation_move: '_onNavigationMove', }), /** * @constructor diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js index 9cfd6f0cd61..c423ddd3f02 100644 --- a/addons/web/static/src/js/views/list/list_editable_renderer.js +++ b/addons/web/static/src/js/views/list/list_editable_renderer.js @@ -813,6 +813,10 @@ ListRenderer.include({ _onFooterClick: function () { this.unselectRow(); }, + /** + * @param {KeyDownEvent} e + * @private + */ _onKeyDownAddRecord: function(e) { switch(e.keyCode) { case $.ui.keyCode.ENTER: @@ -823,25 +827,25 @@ ListRenderer.include({ } }, /** - * It will returns the first visible widget that is editable + * It will returns the last visible widget that is editable * * @private - * @returns {Class} Widget returns first widget + * @returns {Class} Widget returns last widget */ - _getFirstWidget: function () { + _getLastWidget: function () { var record = this.state.data[this.currentRow]; var recordWidgets = this.allFieldWidgets[record.id]; - var firstWidget = _.find(recordWidgets, function (widget) { - var isFirst = + var lastWidget = _.chain(recordWidgets).filter(function (widget) { + var isLast = widget.$el.is(':visible') && ( widget.$('input').length > 0 || widget.tagName === 'input' || widget.$('textarea').length > 0 || widget.tagName === 'textarea' ) && !widget.$el.hasClass('o_readonly_modifier'); - return isFirst; - }); - return firstWidget; + return isLast; + }).last().value(); + return lastWidget; }, /** @@ -872,11 +876,22 @@ ListRenderer.include({ break; case 'next': // When navigating with the keyboard, we want to get out of the list editable if the - // first field is left empty. + // entire line is left unmodified and we are on the next line. var column = this.columns[this.currentFieldIndex]; - var firstWidget = this._getFirstWidget(); - if (column.attrs.name === firstWidget.name && !firstWidget.$input.val()) { - this.trigger_up('activate_next_widget'); + var lastWidget = this._getLastWidget(); + if (column.attrs.name === lastWidget.name) { + if (this.currentRow + 1 < this.state.data.length) { + this._selectCell(this.currentRow+1, 0, {wrap:false}) + .fail(this._moveToNextLine.bind(this)); + } else { + var currentRowData = this.state.data[this.currentRow]; + if (currentRowData.isDirty(currentRowData.id)) { + this._moveToNextLine(); + } + else { + this.trigger_up('activate_next_widget'); + } + } } else { if (this.currentFieldIndex + 1 < this.columns.length) { this._selectCell(this.currentRow, this.currentFieldIndex + 1, {wrap: false}) |
