[IMP] mail: move code from components to models (ComposerTextInput)
+ Create ComposerTextInputView model + Replace uses of useRef with useRefToModel + Replace use of useUpdate with useUpdateToModel + Remove dead code (ComposerTextInput._isEmpty) Task-3001200. closes odoo/odoo#101707 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
@@ -84,7 +84,7 @@
|
||||
'o-has-current-partner-avatar': composerView.hasCurrentPartnerAvatar,
|
||||
'rounded-start-3': composerView.isCompact and composerView.hasCurrentPartnerAvatar,
|
||||
}"
|
||||
record="composerView"
|
||||
record="composerView.textInput"
|
||||
t-key="composerView.localId"
|
||||
/>
|
||||
<div class="o_Composer_buttons d-flex align-items-stretch align-self-stretch flex-shrink-0" t-att-class="{ 'o-composer-is-compact': composerView.isCompact, 'h-auto w-100 px-3': !composerView.isCompact, 'o-isDeviceSmall': messaging.device.isSmall, 'o-messaging-in-editing': composerView and composerView.messageViewInEditing, 'border-end': composerView.messageViewInEditing and !composerView.hasCurrentPartnerAvatar }">
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { useComponentToModel } from '@mail/component_hooks/use_component_to_model';
|
||||
import { useRefToModel } from '@mail/component_hooks/use_ref_to_model';
|
||||
import { useUpdate } from '@mail/component_hooks/use_update';
|
||||
import { useUpdateToModel } from '@mail/component_hooks/use_update_to_model';
|
||||
import { registerMessagingComponent } from '@mail/utils/messaging_component';
|
||||
|
||||
const { Component } = owl;
|
||||
@@ -13,70 +14,23 @@ export class ComposerTextInput extends Component {
|
||||
*/
|
||||
setup() {
|
||||
super.setup();
|
||||
useComponentToModel({ fieldName: 'component' });
|
||||
useRefToModel({ fieldName: 'mirroredTextareaRef', refName: 'mirroredTextarea' });
|
||||
useRefToModel({ fieldName: 'textareaRef', refName: 'textarea' });
|
||||
/**
|
||||
* Updates the composer text input content when composer is mounted
|
||||
* as textarea content can't be changed from the DOM.
|
||||
*/
|
||||
useUpdate({ func: () => this._update() });
|
||||
useUpdateToModel({ methodName: 'onComponentUpdate' });
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @returns {ComposerView}
|
||||
* @returns {ComposerTextInputView}
|
||||
*/
|
||||
get composerView() {
|
||||
get composerTextInputView() {
|
||||
return this.props.record;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines whether the textarea is empty or not.
|
||||
*
|
||||
* @private
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isEmpty() {
|
||||
return this.composerView.textareaRef.el.value === "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the content and height of a textarea
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_update() {
|
||||
if (!this.root.el) {
|
||||
return;
|
||||
}
|
||||
if (this.composerView.doFocus) {
|
||||
this.composerView.update({ doFocus: false });
|
||||
if (this.messaging.device.isSmall) {
|
||||
this.root.el.scrollIntoView();
|
||||
}
|
||||
this.composerView.textareaRef.el.focus();
|
||||
}
|
||||
if (this.composerView.hasToRestoreContent) {
|
||||
this.composerView.textareaRef.el.value = this.composerView.composer.textInputContent;
|
||||
if (this.composerView.isFocused) {
|
||||
this.composerView.textareaRef.el.setSelectionRange(
|
||||
this.composerView.composer.textInputCursorStart,
|
||||
this.composerView.composer.textInputCursorEnd,
|
||||
this.composerView.composer.textInputSelectionDirection,
|
||||
);
|
||||
}
|
||||
this.composerView.update({ hasToRestoreContent: false });
|
||||
}
|
||||
this.composerView.updateTextInputHeight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object.assign(ComposerTextInput, {
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="mail.ComposerTextInput" owl="1">
|
||||
<t t-if="composerView">
|
||||
<div class="o_ComposerTextInput position-relative bg-white" t-attf-class="{{ className }} {{ composerView.isCompact ? 'border border-end-0' : 'border-0' }}" t-att-class="{ 'border-start-0': composerView.isInChatWindow }" t-on-paste="composerView.onPasteTextInput" t-ref="root">
|
||||
<t t-if="composerView.composerSuggestionListView">
|
||||
<ComposerSuggestionListView record="composerView.composerSuggestionListView"/>
|
||||
<t t-if="composerTextInputView">
|
||||
<div class="o_ComposerTextInput position-relative bg-white" t-attf-class="{{ className }} {{ composerTextInputView.owner.isCompact ? 'border border-end-0' : 'border-0' }}" t-att-class="{ 'border-start-0': composerTextInputView.owner.isInChatWindow }" t-on-paste="composerTextInputView.owner.onPasteTextInput" t-ref="root">
|
||||
<t t-if="composerTextInputView.owner.composerSuggestionListView">
|
||||
<ComposerSuggestionListView record="composerTextInputView.owner.composerSuggestionListView"/>
|
||||
</t>
|
||||
<textarea class="o_ComposerTextInput_textarea o_ComposerTextInput_textareaStyle form-control px-3 border-0 shadow-none overflow-auto" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': composerView.isCompact, 'rounded-3': !composerView.isCompact }" t-esc="composerView.composer.textInputContent" t-att-placeholder="composerView.composer.placeholder" t-on-click="composerView.onClickTextarea" t-on-focusin="composerView.onFocusinTextarea" t-on-focusout="composerView.onFocusoutTextarea" t-on-keydown="composerView.onKeydownTextarea" t-on-keyup="composerView.onKeyupTextarea" t-on-input="composerView.onInputTextarea" t-ref="textarea"/>
|
||||
<textarea class="o_ComposerTextInput_textarea o_ComposerTextInput_textareaStyle form-control px-3 border-0 shadow-none overflow-auto" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': composerTextInputView.owner.isCompact, 'rounded-3': !composerTextInputView.owner.isCompact }" t-esc="composerTextInputView.owner.composer.textInputContent" t-att-placeholder="composerTextInputView.owner.composer.placeholder" t-on-click="composerTextInputView.owner.onClickTextarea" t-on-focusin="composerTextInputView.owner.onFocusinTextarea" t-on-focusout="composerTextInputView.owner.onFocusoutTextarea" t-on-keydown="composerTextInputView.owner.onKeydownTextarea" t-on-keyup="composerTextInputView.owner.onKeyupTextarea" t-on-input="composerTextInputView.owner.onInputTextarea" t-ref="textarea"/>
|
||||
<!--
|
||||
This is an invisible textarea used to compute the composer
|
||||
height based on the text content. We need it to downsize
|
||||
the textarea properly without flicker.
|
||||
-->
|
||||
<textarea class="o_ComposerTextInput_mirroredTextarea o_ComposerTextInput_textareaStyle position-absolute px-3 border-0 overflow-hidden opacity-0" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': composerView.isCompact, 'rounded-3': !composerView.isCompact }" t-esc="composerView.composer.textInputContent" t-ref="mirroredTextarea" disabled="1"/>
|
||||
<textarea class="o_ComposerTextInput_mirroredTextarea o_ComposerTextInput_textareaStyle position-absolute px-3 border-0 overflow-hidden opacity-0" t-att-class="{ 'o-composer-is-compact rounded-0 rounded-start-3': composerTextInputView.owner.isCompact, 'rounded-3': !composerTextInputView.owner.isCompact }" t-esc="composerTextInputView.owner.composer.textInputContent" t-ref="mirroredTextarea" disabled="1"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr, one } from '@mail/model/model_field';
|
||||
|
||||
registerModel({
|
||||
name: 'ComposerTextInputView',
|
||||
recordMethods: {
|
||||
onComponentUpdate() {
|
||||
if (!this.component.root.el) {
|
||||
return;
|
||||
}
|
||||
if (this.owner.doFocus) {
|
||||
this.owner.update({ doFocus: false });
|
||||
if (this.messaging.device.isSmall) {
|
||||
this.component.root.el.scrollIntoView();
|
||||
}
|
||||
this.textareaRef.el.focus();
|
||||
}
|
||||
if (this.owner.hasToRestoreContent) {
|
||||
this.textareaRef.el.value = this.owner.composer.textInputContent;
|
||||
if (this.owner.isFocused) {
|
||||
this.textareaRef.el.setSelectionRange(
|
||||
this.owner.composer.textInputCursorStart,
|
||||
this.owner.composer.textInputCursorEnd,
|
||||
this.owner.composer.textInputSelectionDirection,
|
||||
);
|
||||
}
|
||||
this.owner.update({ hasToRestoreContent: false });
|
||||
}
|
||||
this.owner.updateTextInputHeight();
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
component: attr(),
|
||||
/**
|
||||
* This is the invisible textarea used to compute the composer height
|
||||
* based on the text content. We need it to downsize the textarea
|
||||
* properly without flicker.
|
||||
*/
|
||||
mirroredTextareaRef: attr(),
|
||||
owner: one('ComposerView', {
|
||||
identifying: true,
|
||||
inverse: 'textInput',
|
||||
}),
|
||||
/**
|
||||
* Reference of the textarea. Useful to set height, selection and
|
||||
* content.
|
||||
*/
|
||||
textareaRef: attr(),
|
||||
},
|
||||
});
|
||||
@@ -284,10 +284,10 @@ registerModel({
|
||||
return;
|
||||
}
|
||||
this.saveStateInStore();
|
||||
if (this.textareaLastInputValue !== this.textareaRef.el.value) {
|
||||
if (this.textareaLastInputValue !== this.textInput.textareaRef.el.value) {
|
||||
this.handleCurrentPartnerIsTyping();
|
||||
}
|
||||
this.update({ textareaLastInputValue: this.textareaRef.el.value });
|
||||
this.update({ textareaLastInputValue: this.textInput.textareaRef.el.value });
|
||||
this.updateTextInputHeight();
|
||||
},
|
||||
/**
|
||||
@@ -626,10 +626,10 @@ registerModel({
|
||||
*/
|
||||
saveStateInStore() {
|
||||
this.composer.update({
|
||||
textInputContent: this.textareaRef.el.value,
|
||||
textInputCursorEnd: this.textareaRef.el.selectionEnd,
|
||||
textInputCursorStart: this.textareaRef.el.selectionStart,
|
||||
textInputSelectionDirection: this.textareaRef.el.selectionDirection,
|
||||
textInputContent: this.textInput.textareaRef.el.value,
|
||||
textInputCursorEnd: this.textInput.textareaRef.el.selectionEnd,
|
||||
textInputCursorStart: this.textInput.textareaRef.el.selectionStart,
|
||||
textInputSelectionDirection: this.textInput.textareaRef.el.selectionDirection,
|
||||
});
|
||||
},
|
||||
/**
|
||||
@@ -669,8 +669,8 @@ registerModel({
|
||||
* Updates the textarea height of text input.
|
||||
*/
|
||||
updateTextInputHeight() {
|
||||
this.mirroredTextareaRef.el.value = this.composer.textInputContent;
|
||||
this.textareaRef.el.style.height = this.mirroredTextareaRef.el.scrollHeight + 'px';
|
||||
this.textInput.mirroredTextareaRef.el.value = this.composer.textInputContent;
|
||||
this.textInput.textareaRef.el.style.height = this.textInput.mirroredTextareaRef.el.scrollHeight + 'px';
|
||||
},
|
||||
/**
|
||||
* Update a posted message when the message is ready.
|
||||
@@ -1302,12 +1302,6 @@ registerModel({
|
||||
identifying: true,
|
||||
inverse: 'composerViewInEditing',
|
||||
}),
|
||||
/**
|
||||
* This is the invisible textarea used to compute the composer height
|
||||
* based on the text content. We need it to downsize the textarea
|
||||
* properly without flicker.
|
||||
*/
|
||||
mirroredTextareaRef: attr(),
|
||||
/**
|
||||
* Determines the next function to execute after the current mention
|
||||
* RPC is done, if any.
|
||||
@@ -1426,10 +1420,10 @@ registerModel({
|
||||
return this.composer.textInputContent.substring(this.suggestionDelimiterPosition + 1, this.composer.textInputCursorStart);
|
||||
},
|
||||
}),
|
||||
/**
|
||||
* Reference of the textarea. Useful to set height, selection and content.
|
||||
*/
|
||||
textareaRef: attr(),
|
||||
textInput: one('ComposerTextInputView', {
|
||||
default: {},
|
||||
inverse: 'owner',
|
||||
}),
|
||||
/**
|
||||
* States the thread view on which this composer allows editing (if any).
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user