From d6ff8c8351a5e7db0cccfc80f64706ac90f033df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Fri, 24 Nov 2017 13:21:11 +0100 Subject: [PATCH] [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) --- .../src/js/views/basic/basic_renderer.js | 12 +++++++ .../static/src/js/views/form/form_renderer.js | 28 +++++++---------- addons/web/static/tests/views/form_tests.js | 31 +++++++++++++++++++ 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js index 543ce01191e..21fabbc2274 100644 --- a/addons/web/static/src/js/views/basic/basic_renderer.js +++ b/addons/web/static/src/js/views/basic/basic_renderer.js @@ -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; diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 32bcc5ed914..c356b6c761a 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -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 diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index bb4c1e45cbb..22a39bd319d 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -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: '
' + + '' + + '' + + '' + + '
', + 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);