[FIX] web: better support for async field widgets

Most field widgets are synchronous, but some of them have to do extra
work before being ready (for example, the pad widget, or widget which
needs to lazy load JS/CSS files).  Because of that, the new views have
been well tested with synchronous widgets, but not completely with async
widgets.

Some code depended upon the fact that the widget was ready immediately
after being created.  This was incorrect, and is fixed in this commit,
by adding a new hook that is called in (basic) views after a widget is
ready (meaning, start and willstart are done)
This commit is contained in:
Géry Debongnie
2017-11-24 14:59:14 +01:00
parent fb6c9c2443
commit d6ff8c8351
3 changed files with 54 additions and 17 deletions
@@ -356,6 +356,17 @@ var BasicRenderer = AbstractRenderer.extend({
_hasContent: function () {
return this.state.count !== 0;
},
/**
* This function is called each time a field widget is created, when it is
* ready (after its willStart and Start methods are complete). This is the
* place where work having to do with $el should be done.
*
* @private
* @param {Widget} widget the field widget instance
* @param {Object} node the attrs coming from the arch
*/
_postProcessField: function (widget, node) {
},
/**
* Registers or updates the modifiers data associated to the given node.
* This method is quiet complex as it handles all the needs of the basic
@@ -524,6 +535,7 @@ var BasicRenderer = AbstractRenderer.extend({
));
},
}, modifiersOptions || {}));
self._postProcessField(widget, node);
});
return widget;
@@ -226,6 +226,17 @@ var FormRenderer = BasicRenderer.extend({
}
return idForLabel;
},
/**
* @override
* @private
*/
_postProcessField: function (widget, node) {
this._setIDForLabel(widget, this._getIDForLabel(node.attrs.name));
this._handleAttributes(widget.$el, node);
if (JSON.parse(node.attrs.default_focus || "0")) {
this.defaultFocusField = widget;
}
},
/**
* @private
* @param {Object} node
@@ -287,23 +298,6 @@ var FormRenderer = BasicRenderer.extend({
this._registerModifiers(node, this.state, $result);
return $result;
},
/**
* @override
* @private
* @param {string} node
* @param {Object} record
* @param {Object} [options]
* @returns {AbstractField}
*/
_renderFieldWidget: function (node, record, options, modifiersOptions) {
var widget = this._super.apply(this, arguments);
this._setIDForLabel(widget, this._getIDForLabel(node.attrs.name));
this._handleAttributes(widget.$el, node);
if (JSON.parse(node.attrs.default_focus || "0")) {
this.defaultFocusField = widget;
}
return widget;
},
/**
* @private
* @param {Object} node
@@ -167,6 +167,37 @@ QUnit.module('Views', {
form.destroy();
});
QUnit.test('attributes are transferred on async widgets', function (assert) {
assert.expect(1);
var def = $.Deferred();
var FieldChar = fieldRegistry.get('char');
fieldRegistry.add('asyncwidget', FieldChar.extend({
willStart: function () {
return def;
},
}));
createAsyncView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<group>' +
'<field name="foo" style="color: blue" widget="asyncwidget"/>' +
'</group>' +
'</form>',
res_id: 2,
}).then(function (form) {
assert.strictEqual(form.$('.o_field_widget[name=foo]').attr('style'), 'color: blue',
"should apply style attribute on fields");
form.destroy();
delete fieldRegistry.map.asyncwidget;
});
def.resolve();
});
QUnit.test('only necessary fields are fetched with correct context', function (assert) {
assert.expect(2);