Skip to content

Commit

Permalink
[FIX] web: don't loose focus when editing cell in list
Browse files Browse the repository at this point in the history
Have a list with readonly modifiers on at least one column.
Have the first record of the list be readonly as computed by the modifier
Create and edit a second record
Enter a value in the cell and hit TAB

Before this commit:
The focus on the targetted cell was lost and the rendering of the cell was in mode readonly
This was because the baseMode of the modifier dict was applied to one and only one node (== one column) and hence to *all* the records

After this commit:
The rendering and keyboard TAB navigation works as expected in the list editable
The baseMode concept has been sharpened and each cell now has one

OPW-1816569
OPW-1824979
closes #23809
closes #22859
closes #23436
  • Loading branch information
kebeclibre committed Mar 23, 2018
1 parent ef540eb commit 8df055b
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 7 deletions.
16 changes: 9 additions & 7 deletions addons/web/static/src/js/views/basic/basic_renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ var BasicRenderer = AbstractRenderer.extend({
// If the view is in edit mode and that a widget have to switch
// its "readonly" state, we have to re-render it completely
if ('readonly' in modifiers && element.widget) {
var mode = modifiers.readonly ? 'readonly' : modifiersData.baseMode;
var mode = modifiers.readonly ? 'readonly' : modifiersData.baseModeByRecord[record.id];
if (mode !== element.widget.mode) {
self._rerenderFieldWidget(element.widget, record, {
keepBaseMode: true,
Expand Down Expand Up @@ -416,16 +416,17 @@ var BasicRenderer = AbstractRenderer.extend({
* @param {Object} [options.callback] the callback to call on registration
* and on modifiers updates
* @param {boolean} [options.keepBaseMode=false] this function registers the
* 'baseMode' of the node; this is a field widget specific settings which
* 'baseMode' of the node on a per record basis;
* this is a field widget specific settings which
* represents the generic mode of the widget, regardless of its modifiers
* (the interesting case is the list view: all widgets are supposed to be
* in the baseMode 'readonly', except the ones that are in the line that
* is currently being edited).
* With option 'keepBaseMode' set to true, the current baseMode of the
* With option 'keepBaseMode' set to true, the baseMode of the record's
* node isn't overridden (this is particularily useful when a field widget
* is re-rendered because its readonly modifier changed, as in this case,
* we don't want to change its base mode).
* @param {string} [options.mode] the 'baseMode' of the node is set to this
* @param {string} [options.mode] the 'baseMode' of the record's node is set to this
* value (if not given, it is set to this.mode, the mode of the renderer)
* @returns {Object} for code efficiency, returns the last evaluated
* modifiers for the given node and record.
Expand All @@ -443,15 +444,16 @@ var BasicRenderer = AbstractRenderer.extend({
modifiers: modifiers,
evaluatedModifiers: {},
elementsByRecord: {},
baseModeByRecord : {},
};
if (!_.isEmpty(modifiers)) { // Register only if modifiers might change (TODO condition might be improved here)
this.allModifiersData.push(modifiersData);
}
}

// Compute node's base mode if necessary
if (!options.keepBaseMode) {
modifiersData.baseMode = options.mode || this.mode;
// Compute the record's base mode
if (!modifiersData.baseModeByRecord[record.id] || !options.keepBaseMode) {
modifiersData.baseModeByRecord[record.id] = options.mode || this.mode;
}

// Evaluate if necessary
Expand Down
59 changes: 59 additions & 0 deletions addons/web/static/tests/fields/relational_fields_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2260,6 +2260,65 @@ QUnit.module('relational_fields', {

QUnit.module('FieldOne2Many');

QUnit.test('one2many list editable with cell readonly modifier', function (assert) {
assert.expect(4);

this.data.partner.records[0].p = [2];
this.data.partner.records[1].turtles = [1,2];
var form = createView({
View: FormView,
model: 'partner',
data: this.data,
arch:'<form string="Partners">' +
'<field name="p">' +
'<tree editable="bottom">' +
'<field name="turtles" invisible="1"/>' +
'<field name="foo" attrs="{&quot;readonly&quot; : [(&quot;turtles&quot;, &quot;!=&quot;, [])] }"/>' +
'<field name="qux" attrs="{&quot;readonly&quot; : [(&quot;turtles&quot;, &quot;!=&quot;, [])] }"/>' +
'</tree>' +
'</field>' +
'</form>',
res_id: 1,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/partner/write') {
assert.deepEqual(args.args[1].p[1][2], {foo: 'ff', qux: 99},
'The right values should be written');
}
return this._super(route, args);
}
});

form.$buttons.find('.o_form_button_edit').click();
form.$('.o_field_x2many_list_row_add a').click();

var $targetInput = $('.o_selected_row .o_input[name=foo]');
assert.equal($targetInput[0], document.activeElement,
'The first input of the line should have the focus');

// Simulating hitting the 'f' key twice
$targetInput.val('f').trigger('input');
$targetInput.val($targetInput.val() + 'f').trigger('input');

assert.equal($targetInput[0], document.activeElement,
'The first input of the line should still have the focus');

// Simulating a TAB key
$targetInput.trigger($.Event('keydown', {which: 9, keyCode:9}));

var $secondTarget = $('.o_selected_row .o_input[name=qux]');

assert.equal($secondTarget[0], document.activeElement,
'The second input of the line should have the focus after the TAB press');


$secondTarget.val(9).trigger('input');
$secondTarget.val($secondTarget.val() + 9).trigger('input');

form.$buttons.find('.o_form_button_save').click();

form.destroy();
});

QUnit.test('one2many basic properties', function (assert) {
assert.expect(6);

Expand Down

0 comments on commit 8df055b

Please sign in to comment.