[IMP] mail: introduce view models (step 9)

This commit introduces models that define records being 1:1 map with components,
as a step to move further to having essentially all business code in models.

Having code in models is desirable to have very maintainable code, thanks to
robust and declarative code with an ORM-like architecture.

Task-2831082

closes odoo/odoo#91698

Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
Alexandre Kühn
2022-05-18 23:54:39 +02:00
parent 4439532138
commit 8e2625c8ee
7 changed files with 30 additions and 46 deletions
@@ -3,7 +3,7 @@
import { useComponentToModel } from '@mail/component_hooks/use_component_to_model';
import { registerMessagingComponent } from '@mail/utils/messaging_component';
const { Component, onMounted, onWillUnmount, useEffect } = owl;
const { Component, onMounted, onWillUnmount } = owl;
export class AutocompleteInput extends Component {
@@ -15,12 +15,6 @@ export class AutocompleteInput extends Component {
useComponentToModel({ fieldName: 'component' });
onMounted(() => this._mounted());
onWillUnmount(() => this._willUnmount());
useEffect(() => {
if (this.props.inputRef) {
this.props.inputRef.el = this.root.el;
return () => this.props.inputRef.el = null;
}
})
}
_mounted() {
@@ -178,10 +172,6 @@ Object.assign(AutocompleteInput, {
type: Function,
optional: true,
},
inputRef: {
type: { el: Object },
optional: true,
},
},
template: 'mail.AutocompleteInput',
});
@@ -46,8 +46,12 @@ export class ChatWindow extends Component {
}
if (this.chatWindow.isDoFocus) {
this.chatWindow.update({ isDoFocus: false });
if (this._inputRef.el) {
this._inputRef.el.focus();
if (
this.chatWindow.newMessageAutocompleteInputView &&
this.chatWindow.newMessageAutocompleteInputView.component &&
this.chatWindow.newMessageAutocompleteInputView.component.root.el
) {
this.chatWindow.newMessageAutocompleteInputView.component.root.el.focus();
}
}
}
@@ -17,7 +17,6 @@
className="'o_ChatWindow_header flex-grow-0 flex-shrink-0'"
chatWindow="chatWindow"
record="chatWindow.chatWindowHeaderView"
onClicked="chatWindow.onClickHeader"
/>
<t t-if="chatWindow.channelMemberListView">
<ChannelMemberList record="chatWindow.channelMemberListView" className="'bg-white'"/>
@@ -41,7 +40,6 @@
record="chatWindow.newMessageAutocompleteInputView"
select="chatWindow.onAutocompleteSelect"
source="chatWindow.onAutocompleteSource"
inputRef="_inputRef"
/>
</div>
</t>
@@ -1,7 +1,6 @@
/** @odoo-module **/
import { registerMessagingComponent } from '@mail/utils/messaging_component';
import { isEventHandled } from '@mail/utils/utils';
const { Component } = owl;
@@ -25,40 +24,12 @@ export class ChatWindowHeader extends Component {
return this.props.record;
}
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {MouseEvent} ev
*/
_onClick(ev) {
if (
isEventHandled(ev, 'ChatWindow.onClickCommand') ||
isEventHandled(ev, 'ChatWindowHeader.ClickShiftNext') ||
isEventHandled(ev, 'ChatWindowHeader.ClickShiftPrev') ||
isEventHandled(ev, 'ChatWindow.onClickHideMemberList') ||
isEventHandled(ev, 'ChatWindow.onClickShowMemberList')
) {
return;
}
const chatWindow = this.chatWindow;
if (this.props.onClicked) {
this.props.onClicked({ chatWindow });
}
}
}
Object.assign(ChatWindowHeader, {
props: {
chatWindow: Object,
record: Object,
onClicked: {
type: Function,
optional: true,
},
},
template: 'mail.ChatWindowHeader',
});
@@ -3,7 +3,7 @@
<t t-name="mail.ChatWindowHeader" owl="1">
<t t-if="chatWindowHeaderView and chatWindow">
<div class="o_ChatWindowHeader d-flex align-items-center text-white" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'o_cursor_pointer': !messaging.device.isSmall }" t-attf-class="{{ className }}" t-on-click="_onClick" t-ref="root">
<div class="o_ChatWindowHeader d-flex align-items-center text-white" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall, 'o_cursor_pointer': !messaging.device.isSmall }" t-attf-class="{{ className }}" t-on-click="chatWindowHeaderView.onClick" t-ref="root">
<t t-if="chatWindow.hasCloseAsBackButton">
<div class="o_ChatWindowHeader_command o_ChatWindowHeader_commandBack o_ChatWindowHeader_commandClose o_cursor_pointer d-flex align-items-center h-100 px-3 py-0 mr-2" t-att-class="{ 'o-isDeviceSmall': messaging.device.isSmall }" t-on-click="chatWindow.onClickClose" title="Close conversation">
<i class="fa fa-arrow-left"/>
@@ -7,7 +7,6 @@
className="'o_ChatWindowHiddenMenuItem_chatWindowHeader opacity-100-hover'"
record="chatWindowHeaderView"
chatWindow="chatWindowHeaderView.chatWindowOwner"
onClicked="chatWindowHeaderView.chatWindowOwner.onClickFromChatWindowHiddenMenu"
/>
</li>
</t>
@@ -2,10 +2,32 @@
import { registerModel } from '@mail/model/model_core';
import { one } from '@mail/model/model_field';
import { isEventHandled } from '@mail/utils/utils';
registerModel({
name: 'ChatWindowHeaderView',
identifyingFields: ['chatWindowOwner'],
recordMethods: {
/**
* @param {MouseEvent} ev
*/
onClick(ev) {
if (
isEventHandled(ev, 'ChatWindow.onClickCommand') ||
isEventHandled(ev, 'ChatWindowHeader.ClickShiftNext') ||
isEventHandled(ev, 'ChatWindowHeader.ClickShiftPrev') ||
isEventHandled(ev, 'ChatWindow.onClickHideMemberList') ||
isEventHandled(ev, 'ChatWindow.onClickShowMemberList')
) {
return;
}
if (!this.chatWindowOwner.isVisible) {
this.chatWindowOwner.onClickFromChatWindowHiddenMenu(ev);
} else {
this.chatWindowOwner.onClickHeader(ev);
}
},
},
fields: {
chatWindowOwner: one('ChatWindow', {
inverse: 'chatWindowHeaderView',