summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorMichael Mattiello (mcm) <mcm@odoo.com>2020-03-27 10:56:05 +0000
committerMichael Mattiello (mcm) <mcm@odoo.com>2020-03-31 07:11:01 +0000
commit9324282b0118e311382ee9a57cd10ef3f02d1dbb (patch)
treeb4663f82c2e837ba23f70b562b6dfd743b96167f /addons
parent91c7e574ed4a08a4d9998a7f5f481b99ae6154ee (diff)
[REF] web,*: add new field registry for components
* account This commit adds a new field registry for component fields. This field registry is used to only register the new field components and the other one should register the legacy fields. Those two registries will be used together while all legacy fields are not converted to owl component. As the legacy registry now throws an error when adding a component field the existing component fields (account.ShowGroupedList and account.ShowResequenceRenderer) are moved into the new registry. This commit also refactors some field managers (form renderer, list editable renderer, calendar popover) to use the new registry and thus support the component fields. task id: 2193996
Diffstat (limited to 'addons')
-rw-r--r--addons/account/static/src/js/account_resequence_field.js2
-rw-r--r--addons/account/static/src/js/grouped_view_widget.js2
-rw-r--r--addons/web/static/src/js/fields/field_registry.js11
-rw-r--r--addons/web/static/src/js/fields/field_registry_owl.js31
-rw-r--r--addons/web/static/src/js/views/basic/basic_view.js8
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_popover.js48
-rw-r--r--addons/web/static/src/js/views/form/form_renderer.js7
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js8
-rw-r--r--addons/web/static/tests/views/form_tests.js10
-rw-r--r--addons/web/views/webclient_templates.xml1
10 files changed, 115 insertions, 13 deletions
diff --git a/addons/account/static/src/js/account_resequence_field.js b/addons/account/static/src/js/account_resequence_field.js
index 0f918e9a297..57b57bfeac0 100644
--- a/addons/account/static/src/js/account_resequence_field.js
+++ b/addons/account/static/src/js/account_resequence_field.js
@@ -4,7 +4,7 @@ odoo.define('account.ShowResequenceRenderer', function (require) {
const { Component } = owl;
const { useState } = owl.hooks;
const AbstractFieldOwl = require('web.AbstractFieldOwl');
-const field_registry = require('web.field_registry');
+const field_registry = require('web.field_registry_owl');
class ChangeLine extends Component { }
ChangeLine.template = 'account.ResequenceChangeLine';
diff --git a/addons/account/static/src/js/grouped_view_widget.js b/addons/account/static/src/js/grouped_view_widget.js
index 3af2d0e1fe0..e1df30cf997 100644
--- a/addons/account/static/src/js/grouped_view_widget.js
+++ b/addons/account/static/src/js/grouped_view_widget.js
@@ -4,7 +4,7 @@ odoo.define('account.ShowGroupedList', function (require) {
const { Component } = owl;
const { useState } = owl.hooks;
const AbstractFieldOwl = require('web.AbstractFieldOwl');
-const field_registry = require('web.field_registry');
+const field_registry = require('web.field_registry_owl');
class ListItem extends Component { }
ListItem.template = 'account.GroupedItemTemplate';
diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js
index 49f1f678304..b8b3fe61452 100644
--- a/addons/web/static/src/js/fields/field_registry.js
+++ b/addons/web/static/src/js/fields/field_registry.js
@@ -3,7 +3,16 @@ odoo.define('web.field_registry', function (require) {
var Registry = require('web.Registry');
-return new Registry();
+var FieldRegistry = Registry.extend({
+ add: function (key, value, score) {
+ if (value.prototype instanceof owl.Component) {
+ throw new Error("This registry should not contain any Component. Use 'web.field_registry_owl' instead.");
+ }
+ return this._super(...arguments);
+ },
+});
+
+return new FieldRegistry();
});
odoo.define('web._field_registry', function (require) {
diff --git a/addons/web/static/src/js/fields/field_registry_owl.js b/addons/web/static/src/js/fields/field_registry_owl.js
new file mode 100644
index 00000000000..f5f7d900ef8
--- /dev/null
+++ b/addons/web/static/src/js/fields/field_registry_owl.js
@@ -0,0 +1,31 @@
+odoo.define('web.field_registry_owl', function (require) {
+ "use strict";
+
+ const Registry = require('web.Registry');
+
+ const FieldRegistry = Registry.extend({
+ add: function (key, value, score) {
+ if (!(value.prototype instanceof owl.Component)) {
+ throw new Error("This registry should only contain subclasses of Component");
+ }
+ return this._super(...arguments);
+ },
+ });
+
+ return new FieldRegistry();
+});
+
+odoo.define('web._field_registry_owl', function (require) {
+ "use strict";
+
+ /**
+ * This module registers field components (specifications of the AbstractField Component)
+ */
+
+ const basicFields = require('web.basic_fields_owl');
+ const registry = require('web.field_registry_owl');
+
+ // Basic fields
+ registry
+ .add('boolean', basicFields.FieldBoolean);
+});
diff --git a/addons/web/static/src/js/views/basic/basic_view.js b/addons/web/static/src/js/views/basic/basic_view.js
index 140c338d6f6..4d266657c71 100644
--- a/addons/web/static/src/js/views/basic/basic_view.js
+++ b/addons/web/static/src/js/views/basic/basic_view.js
@@ -15,6 +15,7 @@ var BasicController = require('web.BasicController');
var BasicModel = require('web.BasicModel');
var config = require('web.config');
var fieldRegistry = require('web.field_registry');
+var fieldRegistryOwl = require('web.field_registry_owl');
var pyUtils = require('web.py_utils');
var utils = require('web.utils');
@@ -78,7 +79,8 @@ var BasicView = AbstractView.extend({
_getFieldWidgetClass: function (viewType, field, attrs) {
var FieldWidget;
if (attrs.widget) {
- FieldWidget = fieldRegistry.getAny([viewType + "." + attrs.widget, attrs.widget]);
+ FieldWidget = fieldRegistryOwl.getAny([viewType + "." + attrs.widget, attrs.widget]) ||
+ fieldRegistry.getAny([viewType + "." + attrs.widget, attrs.widget]);
if (!FieldWidget) {
console.warn("Missing widget: ", attrs.widget, " for field", attrs.name, "of type", field.type);
}
@@ -87,7 +89,9 @@ var BasicView = AbstractView.extend({
// is not specified in the view
FieldWidget = fieldRegistry.get('kanban.many2many_tags');
}
- return FieldWidget || fieldRegistry.getAny([viewType + "." + field.type, field.type, "abstract"]);
+ return FieldWidget ||
+ fieldRegistryOwl.getAny([viewType + "." + field.type, field.type, "abstract"]) ||
+ fieldRegistry.getAny([viewType + "." + field.type, field.type, "abstract"]);
},
/**
* In some cases, we already have a preloaded record
diff --git a/addons/web/static/src/js/views/calendar/calendar_popover.js b/addons/web/static/src/js/views/calendar/calendar_popover.js
index d804f74e53e..9b4af4bb065 100644
--- a/addons/web/static/src/js/views/calendar/calendar_popover.js
+++ b/addons/web/static/src/js/views/calendar/calendar_popover.js
@@ -2,10 +2,13 @@ odoo.define('web.CalendarPopover', function (require) {
"use strict";
var fieldRegistry = require('web.field_registry');
+const fieldRegistryOwl = require('web.field_registry_owl');
+const FieldWrapper = require('web.FieldWrapper');
var StandaloneFieldManagerMixin = require('web.StandaloneFieldManagerMixin');
var Widget = require('web.Widget');
+const { WidgetAdapterMixin } = require('web.OwlCompatibility');
-var CalendarPopover = Widget.extend(StandaloneFieldManagerMixin, {
+var CalendarPopover = Widget.extend(WidgetAdapterMixin, StandaloneFieldManagerMixin, {
template: 'CalendarView.event.popover',
events: {
'click .o_cw_popover_edit': '_onClickPopoverEdit',
@@ -45,6 +48,25 @@ var CalendarPopover = Widget.extend(StandaloneFieldManagerMixin, {
});
return this._super.apply(this, arguments);
},
+ /**
+ * @override
+ */
+ destroy: function () {
+ this._super.apply(this, arguments);
+ WidgetAdapterMixin.destroy.call(this);
+ },
+ /**
+ * Called each time the widget is attached into the DOM.
+ */
+ on_attach_callback: function () {
+ WidgetAdapterMixin.on_attach_callback.call(this);
+ },
+ /**
+ * Called each time the widget is detached from the DOM.
+ */
+ on_detach_callback: function () {
+ WidgetAdapterMixin.on_detach_callback.call(this);
+ },
//--------------------------------------------------------------------------
// Public
@@ -129,8 +151,20 @@ var CalendarPopover = Widget.extend(StandaloneFieldManagerMixin, {
var record = self.model.get(recordID);
_.each(fieldsToGenerate, function (field) {
if (field.invisible) return;
- var FieldClass = fieldRegistry.getAny([field.widget, field.type]);
- var fieldWidget = new FieldClass(self, field.name, record, self.displayFields[field.name]);
+ let isLegacy = true;
+ let fieldWidget;
+ let FieldClass = fieldRegistryOwl.getAny([field.widget, field.type]);
+ if (FieldClass) {
+ isLegacy = false;
+ fieldWidget = new FieldWrapper(this, FieldClass, {
+ fieldName: field.name,
+ record,
+ options: self.displayFields[field.name],
+ });
+ } else {
+ FieldClass = fieldRegistry.getAny([field.widget, field.type]);
+ fieldWidget = new FieldClass(self, field.name, record, self.displayFields[field.name]);
+ }
self._registerWidget(recordID, field.name, fieldWidget);
var $field = $('<li>', {class: 'list-group-item flex-shrink-0 d-flex flex-wrap'});
@@ -139,7 +173,13 @@ var CalendarPopover = Widget.extend(StandaloneFieldManagerMixin, {
var $fieldContainer = $('<div>', {class: 'flex-grow-1'});
$fieldContainer.appendTo($field);
- defs.push(fieldWidget.appendTo($fieldContainer).then(function () {
+ let def;
+ if (isLegacy) {
+ def = fieldWidget.appendTo($fieldContainer);
+ } else {
+ def = fieldWidget.mount($fieldContainer[0]);
+ }
+ defs.push(def.then(function () {
self.$fieldsList.push($field);
}));
});
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 bcab9808773..a258d16a917 100644
--- a/addons/web/static/src/js/views/form/form_renderer.js
+++ b/addons/web/static/src/js/views/form/form_renderer.js
@@ -1065,6 +1065,13 @@ var FormRenderer = BasicRenderer.extend({
*/
_onNavigationMove: function (ev) {
ev.stopPropagation();
+ // We prevent the default behaviour and stop the propagation of the
+ // originalEvent when the originalEvent is a tab keydown to not let
+ // the browser do it. The action is done by this renderer.
+ if (ev.data.originalEvent && ['next', 'previous'].includes(ev.data.direction)) {
+ ev.data.originalEvent.preventDefault();
+ ev.data.originalEvent.stopPropagation();
+ }
var index;
let target = ev.data.target || ev.target;
if (target.__owl__) {
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 8b4db487ac4..8cd7f5a370d 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
@@ -15,6 +15,7 @@ var core = require('web.core');
var dom = require('web.dom');
var ListRenderer = require('web.ListRenderer');
var utils = require('web.utils');
+const { WidgetAdapterMixin } = require('web.OwlCompatibility');
var _t = core._t;
@@ -462,6 +463,9 @@ ListRenderer.include({
}
return Promise.all(defs).then(function () {
+ // mark Owl sub components as mounted
+ WidgetAdapterMixin.on_attach_callback.call(self);
+
// necessary to trigger resize on fieldtexts
core.bus.trigger('DOM_updated');
});
@@ -1553,6 +1557,10 @@ ListRenderer.include({
return;
}
ev.stopPropagation(); // stop the event, the action is done by this renderer
+ if (ev.data.originalEvent && ['next', 'previous'].includes(ev.data.direction)) {
+ ev.data.originalEvent.preventDefault();
+ ev.data.originalEvent.stopPropagation();
+ }
switch (ev.data.direction) {
case 'previous':
if (this.currentFieldIndex > 0) {
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index 9b5cad26e75..ee3c68534e3 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -4308,17 +4308,19 @@ QUnit.module('Views', {
// focus first input, trigger tab
form.$('input[name="foo"]').focus();
- form.$('input[name="foo"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
+ const tabKey = { keyCode: $.ui.keyCode.TAB, which: $.ui.keyCode.TAB };
+ await testUtils.dom.triggerEvent(form.$('input[name="foo"]'), 'keydown', tabKey);
assert.ok($.contains(form.$('div[name="bar"]')[0], document.activeElement),
"bar checkbox should be focused");
- form.$('div[name="bar"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
+ await testUtils.dom.triggerEvent(document.activeElement, 'keydown', tabKey);
assert.strictEqual(form.$('input[name="display_name"]')[0], document.activeElement,
"display_name should be focused");
// simulate shift+tab on active element
- $(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB, shiftKey: true}));
- $(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB, shiftKey: true}));
+ const shiftTabKey = Object.assign({}, tabKey, { shiftKey: true });
+ await testUtils.dom.triggerEvent(document.activeElement, 'keydown', shiftTabKey);
+ await testUtils.dom.triggerEvent(document.activeElement, 'keydown', shiftTabKey);
assert.strictEqual(document.activeElement, form.$('input[name="foo"]')[0],
"first input should be focused");
diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml
index 05c534f4056..4778e5a328c 100644
--- a/addons/web/views/webclient_templates.xml
+++ b/addons/web/views/webclient_templates.xml
@@ -293,6 +293,7 @@
<script type="text/javascript" src="/web/static/src/js/fields/abstract_field.js"></script>
<script type="text/javascript" src="/web/static/src/js/fields/basic_fields.js"></script>
<script type="text/javascript" src="/web/static/src/js/fields/field_registry.js"></script>
+ <script type="text/javascript" src="/web/static/src/js/fields/field_registry_owl.js"></script>
<script type="text/javascript" src="/web/static/src/js/views/basic/widget_registry.js"></script>
<script type="text/javascript" src="/web/static/src/js/fields/field_utils.js"></script>
<script type="text/javascript" src="/web/static/src/js/fields/relational_fields.js"></script>