Интеграция Owl в odoo

Odoo определяет необходимые инструменты для переходного этапа, на котором будут сосуществовать легаси виджеты Odoo и компоненты Owl. Есть два возможных сценария:

  1. Компонент Owl должен создавать экземпляры легаси виджетов
  2. Легаси виджет должен создавать экземпляры компонентов Owl

Сценарий 1. Компонент Owl должен создавать экземпляры легаси виджетов

ComponentAdapter это компонент Owl, предназначенный для использования в качестве универсального адаптера для компонентов Owl, которые встраивают устаревшие виджеты Odoo (или динамически как компоненты Owl, так и легаси виджеты Odoo), например::

    Owl Component
            |
    ComponentAdapter (Owl компонент)
            |
Legacy Widget(ы) (или Owl компоненты)

Адаптер принимает класс component/widget в качестве пропса Component и аргументы (кроме первого аргумента parent) для инициализации его в качестве пропса. Например:

<ComponentAdapter Component="LegacyWidget" params="params"/>

Буде транслирован в следующее:

const LegacyWidget = this.props.Component;
const legacyWidget = new LegacyWidget(this, this.props.params);

Если для инициализации устаревшего виджета задано более одного аргумента (в дополнение к parent), то порядок аргументов (для инициализации суб виджета) должен быть определен. Есть две альтернативы. Можно либо (1) указать пропс widgetArgs, соответствующий массиву аргументов, в противном случае (2) должен быть определен субкласс ComponentAdapter. Этот субкласс должен переопределять средство получения widgetArgs для преобразования аргументов, полученных в качестве пропсов, в массив аргументов для вызова init. Например :

(1)

<ComponentAdapter Component="LegacyWidget" firstArg="a" secondArg="b" widgetsArgs="[a, b]"/>

(2)

class SpecificAdapter extends ComponentAdapter {
    get widgetArgs() {
        return [this.props.firstArg, this.props.secondArg];
    }
}
<SpecificAdapter Component="LegacyWidget" firstArg="a" secondArg="b"/>

Если легаси виджет должен обновляться при изменении пропса, необходимо определить субкласс ComponentAdapter, чтобы переопределить updateWidget и renderWidget. Функция updateWidget принимает nextProps в качестве аргумента и должна обновлять внутреннее состояние виджета (функция может быть асинхронной и возвращать объект Promise). Однако, чтобы гарантировать, то что DOM обновляется сразу, он не должен выполнять ре-рендеринг. Эту роль берет на себя функция renderWidget, которая будет вызвана непосредственно перед исправлением DOM и которая, таким образом, должна быть синхронной. Например:

class SpecificAdapter extends ComponentAdapter {
   updateWidget(nextProps) {
       return this.widget.updateState(nextProps);
   }
   renderWidget() {
       return this.widget.render();
   }
}

Сценарий 2. Легаси виджет должен создавать экземпляры компонентов Owl


WidgetAdapterMixin и ComponentWrapper предназначены для совместного использования, когда легаси виджету Odoo необходимо создать экземпляр компонентов Owl. В этом случае иерархия виджетов/компонентов будет выглядеть следующим образом:

Легаси Виджет + WidgetAdapterMixin
                |
    ComponentWrapper (Owl компонент)
                |
        Owl компонент

В этом случае родительский легаси виджет должен использовать WidgetAdapterMixin, который гарантирует, то что хуки Owl (mounted, willUnmount, destroy...) правильно вызываются для субкомпонент. Более того, он должен создавать экземпляр ComponentWrapper и предоставьте ему класс компонентов Owl для использования вместе с его пропсами. Этот враппер гарантирует, что компонент Owl будет корректно обновлен (с помощью willUpdateProps), как это было бы, если бы он был встроен в иерархию Owl. Более того, этот враппер автоматически перенаправляет все события, инициируемые компонентом Owl (или его потомками), на легаси пользовательские события (trigger_up) на родительском легаси виджете. Пример:

class MyComponent extends Component {}
MyComponent.template = xml`<div>Owl компонент со значением <t t-esc="props.value"/></div>`;
const MyWidget = Widget.extend(WidgetAdapterMixin, {
    start() {
        this.component = new ComponentWrapper(this, MyComponent, {value: 44});
        return this.component.mount(this.el);
    },
    update() {
        return this.component.update({value: 45});
    },
});