[IMP] mail,snailmail,web: remove t-on on component

Preparation work to use OWL v2 in discuss code.

Task-2694200

closes odoo/odoo#80024

Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Alexandre Kühn
2021-12-01 14:07:57 +00:00
parent aa07f93ef7
commit 30d7766eea
50 changed files with 235 additions and 122 deletions
@@ -26,6 +26,7 @@ export class Activity extends Component {
* Useful to programmatically prompts the browser file uploader.
*/
this._fileUploaderRef = useRef('fileUploader');
this._onAttachmentCreated = this._onAttachmentCreated.bind(this);
}
//--------------------------------------------------------------------------
@@ -105,12 +106,11 @@ export class Activity extends Component {
/**
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {mail.attachment} ev.detail.attachment
* @param {Object} detail
* @param {mail.attachment} detail.attachment
*/
_onAttachmentCreated(ev) {
this.activity.markAsDone({ attachments: [ev.detail.attachment] });
_onAttachmentCreated(detail) {
this.activity.markAsDone({ attachments: [detail.attachment] });
}
/**
@@ -132,7 +132,7 @@
<FileUploader
t-if="activity.thread"
threadLocalId="activity.thread.localId"
t-on-o-attachment-created="_onAttachmentCreated"
onAttachmentCreated="_onAttachmentCreated"
t-ref="fileUploader"
/>
</t>
@@ -23,6 +23,7 @@ export class AttachmentBox extends Component {
this._fileUploaderRef = useRef('fileUploader');
useComponentToModel({ fieldName: 'component', modelName: 'mail.attachment_box_view', propNameAsRecordLocalId: 'attachmentBoxViewLocalId' });
useRefToModel({ fieldName: 'fileUploaderRef', modelName: 'mail.attachment_box_view', propNameAsRecordLocalId: 'attachmentBoxViewLocalId', refName: 'fileUploader' });
this._onDropZoneFilesDropped = this._onDropZoneFilesDropped.bind(this);
}
//--------------------------------------------------------------------------
@@ -42,13 +43,11 @@ export class AttachmentBox extends Component {
/**
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {FileList} ev.detail.files
* @param {Object} detail
* @param {FileList} detail.files
*/
async _onDropZoneFilesDropped(ev) {
ev.stopPropagation();
await this._fileUploaderRef.comp.uploadFiles(ev.detail.files);
async _onDropZoneFilesDropped(detail) {
await this._fileUploaderRef.comp.uploadFiles(detail.files);
this.isDropZoneVisible.value = false;
}
@@ -15,7 +15,7 @@
<t t-if="isDropZoneVisible.value">
<DropZone
className="'o_AttachmentBox_dropZone'"
t-on-o-dropzone-files-dropped="_onDropZoneFilesDropped"
onDropzoneFilesDropped="_onDropZoneFilesDropped"
t-ref="dropzone"
/>
</t>
@@ -23,7 +23,7 @@
<AttachmentList
className="'o_attachmentBox_attachmentList'"
attachmentListLocalId="attachmentBoxView.chatter.attachmentList.localId"
t-on-o-attachment-removed="attachmentBoxView.onAttachmentRemoved"
onAttachmentRemoved="attachmentBoxView.onAttachmentRemoved"
/>
</t>
<button class="o_AttachmentBox_buttonAdd btn btn-link" type="button" t-on-click="attachmentBoxView.onClickAddAttachment">
@@ -33,7 +33,7 @@
</div>
<FileUploader
threadLocalId="attachmentBoxView.chatter.thread.localId"
t-on-o-attachment-created="attachmentBoxView.onAttachmentCreated"
onAttachmentCreated="attachmentBoxView.onAttachmentCreated"
t-ref="fileUploader"
/>
</t>
@@ -30,6 +30,10 @@ export class AttachmentCard extends Component {
Object.assign(AttachmentCard, {
props: {
attachmentCardLocalId: String,
onAttachmentRemoved: {
type: Function,
optional: true,
},
},
template: 'mail.AttachmentCard',
});
@@ -60,7 +60,8 @@
<t t-if="attachmentCard.hasDeleteConfirmDialog">
<AttachmentDeleteConfirmDialog
attachmentLocalId="attachmentCard.attachment.localId"
t-on-dialog-closed="attachmentCard.onDeleteConfirmDialogClosed"
onAttachmentRemoved="props.onAttachmentRemoved"
onClosed="attachmentCard.onDeleteConfirmDialogClosed"
/>
</t>
</div>
@@ -54,7 +54,11 @@ export class AttachmentDeleteConfirmDialog extends Component {
async _onClickOk() {
await this.attachment.remove();
this.root.comp._close();
this.trigger('o-attachment-removed', { attachmentLocalId: this.props.attachmentLocalId });
if (this.props.onAttachmentRemoved) {
this.props.onAttachmentRemoved({
attachmentLocalId: this.props.attachmentLocalId,
})
}
}
}
@@ -63,6 +67,14 @@ Object.assign(AttachmentDeleteConfirmDialog, {
components: { Dialog },
props: {
attachmentLocalId: String,
onAttachmentRemoved: {
type: Function,
optional: true,
},
onClosed: {
type: Function,
optional: true,
}
},
template: 'mail.AttachmentDeleteConfirmDialog',
});
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.AttachmentDeleteConfirmDialog" owl="1">
<Dialog contentClass="'o_AttachmentDeleteConfirmDialog'" title="getTitle()" size="'medium'" t-ref="root">
<Dialog contentClass="'o_AttachmentDeleteConfirmDialog'" title="getTitle()" size="'medium'" onClosed="props.onClosed" t-ref="root">
<p class="o_AttachmentDeleteConfirmDialog_mainText" t-esc="getBody()"/>
<t t-set-slot="buttons">
<button class="o_AttachmentDeleteConfirmDialog_confirmButton btn btn-primary" t-on-click="_onClickOk">Ok</button>
@@ -30,6 +30,10 @@ export class AttachmentImage extends Component {
Object.assign(AttachmentImage, {
props: {
attachmentImageLocalId: String,
onAttachmentRemoved: {
type: Function,
optional: true,
},
},
template: 'mail.AttachmentImage',
});
@@ -35,7 +35,8 @@
<t t-if="attachmentImage.hasDeleteConfirmDialog">
<AttachmentDeleteConfirmDialog
attachmentLocalId="attachmentImage.attachment.localId"
t-on-dialog-closed="attachmentImage.onDeleteConfirmDialogClosed"
onAttachmentRemoved="props.onAttachmentRemoved"
onClosed="attachmentImage.onDeleteConfirmDialogClosed"
/>
</t>
</div>
@@ -18,6 +18,10 @@ export class AttachmentList extends Component {
Object.assign(AttachmentList, {
props: {
attachmentListLocalId: String,
onAttachmentRemoved: {
type: Function,
optional: true,
},
},
template: 'mail.AttachmentList',
});
@@ -6,12 +6,12 @@
<t t-if="attachmentList">
<div class="o_AttachmentList_partialList o_AttachmentList_partialListImages">
<t t-foreach="attachmentList.attachmentImages" t-as="attachmentImage" t-key="attachmentImage.localId">
<AttachmentImage className="'o_AttachmentList_attachment'" attachmentImageLocalId="attachmentImage.localId"/>
<AttachmentImage className="'o_AttachmentList_attachment'" attachmentImageLocalId="attachmentImage.localId" onAttachmentRemoved="props.onAttachmentRemoved"/>
</t>
</div>
<div class="o_AttachmentList_partialList o_AttachmentList_partialListNonImages">
<t t-foreach="attachmentList.attachmentCards" t-as="attachmentCard" t-key="attachmentCard.localId">
<AttachmentCard className="'o_AttachmentList_attachment'" attachmentCardLocalId="attachmentCard.localId"/>
<AttachmentCard className="'o_AttachmentList_attachment'" attachmentCardLocalId="attachmentCard.localId" onAttachmentRemoved="props.onAttachmentRemoved"/>
</t>
</div>
</t>
@@ -124,7 +124,9 @@ export class AutocompleteInput extends Component {
* @param {MouseEvent} ev
*/
_onBlur(ev) {
this.trigger('o-hide');
if (this.props.onHide) {
this.props.onHide();
}
}
/**
@@ -133,7 +135,9 @@ export class AutocompleteInput extends Component {
*/
_onKeydown(ev) {
if (ev.key === 'Escape') {
this.trigger('o-hide');
if (this.props.onHide) {
this.props.onHide();
}
}
}
@@ -156,6 +160,14 @@ Object.assign(AutocompleteInput, {
},
isFocusOnMount: Boolean,
isHtml: Boolean,
onFocusin: {
type: Function,
optional: true,
},
onHide: {
type: Function,
optional: true,
},
placeholder: String,
select: {
type: Function,
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.AutocompleteInput" owl="1">
<input class="o_AutocompleteInput" t-attf-class="{{ className }}" t-on-blur="_onBlur" t-on-keydown="_onKeydown" t-att-placeholder="props.placeholder" t-ref="root"/>
<input class="o_AutocompleteInput" t-attf-class="{{ className }}" t-on-blur="_onBlur" t-on-focusin="props.onFocusin" t-on-keydown="_onKeydown" t-att-placeholder="props.placeholder" t-ref="root"/>
</t>
</templates>
@@ -34,6 +34,8 @@ export class ChatWindow extends Component {
// the following are passed as props to children
this._onAutocompleteSelect = this._onAutocompleteSelect.bind(this);
this._onAutocompleteSource = this._onAutocompleteSource.bind(this);
this._onClickedHeader = this._onClickedHeader.bind(this);
this._onFocusinThread = this._onFocusinThread.bind(this);
}
//--------------------------------------------------------------------------
@@ -179,10 +181,8 @@ export class ChatWindow extends Component {
* window.
*
* @private
* @param {CustomEvent} ev
*/
_onClickedHeader(ev) {
ev.stopPropagation();
_onClickedHeader() {
if (this.messaging.device.isMobile) {
return;
}
@@ -199,10 +199,8 @@ export class ChatWindow extends Component {
* Called when an element in the thread becomes focused.
*
* @private
* @param {FocusEvent} ev
*/
_onFocusinThread(ev) {
ev.stopPropagation();
_onFocusinThread() {
if (!this.chatWindow) {
// prevent crash on destroy
return;
@@ -17,7 +17,7 @@
chatWindowLocalId="chatWindow.localId"
hasCloseAsBackButton="props.hasCloseAsBackButton"
isExpandable="props.isExpandable"
t-on-o-clicked="_onClickedHeader"
onClicked="_onClickedHeader"
t-ref="header"
/>
<t t-if="chatWindow.thread and chatWindow.thread.hasMemberListFeature and chatWindow.isMemberListOpened">
@@ -32,7 +32,7 @@
hasComposerCurrentPartnerAvatar="false"
hasComposerSendButton="messaging.device.isMobile"
threadViewLocalId="chatWindow.threadView.localId"
t-on-focusin="_onFocusinThread"
onFocusin="_onFocusinThread"
t-ref="thread"
/>
</t>
@@ -46,7 +46,7 @@
placeholder="newMessageFormInputPlaceholder"
select="_onAutocompleteSelect"
source="_onAutocompleteSource"
t-on-focusin="chatWindow.onFocusInNewMessageFormInput"
onFocusin="chatWindow.onFocusInNewMessageFormInput"
t-ref="input"
/>
</div>
@@ -60,7 +60,9 @@ export class ChatWindowHeader extends Component {
return;
}
const chatWindow = this.chatWindow;
this.trigger('o-clicked', { chatWindow });
if (this.props.onClicked) {
this.props.onClicked({ chatWindow });
}
}
/**
@@ -137,6 +139,10 @@ Object.assign(ChatWindowHeader, {
chatWindowLocalId: String,
hasCloseAsBackButton: Boolean,
isExpandable: Boolean,
onClicked: {
type: Function,
optional: true,
},
},
template: 'mail.ChatWindowHeader',
});
@@ -13,6 +13,7 @@ export class ChatWindowHiddenMenu extends Component {
setup() {
super.setup();
this._onClickCaptureGlobal = this._onClickCaptureGlobal.bind(this);
this._onClickedChatWindow = this._onClickedChatWindow.bind(this);
/**
* Reference of the dropup list. Useful to auto-set max height based on
* browser screen height.
@@ -109,12 +110,11 @@ export class ChatWindowHiddenMenu extends Component {
/**
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {mail.chat_window} ev.detail.chatWindow
* @param {Object} detail
* @param {mail.chat_window} detail.chatWindow
*/
_onClickedChatWindow(ev) {
const chatWindow = ev.detail.chatWindow;
_onClickedChatWindow(detail) {
const chatWindow = detail.chatWindow;
chatWindow.makeActive();
this.messaging.chatWindowManager.closeHiddenMenu();
}
@@ -15,7 +15,7 @@
<ChatWindowHeader
className="'o_ChatWindowHiddenMenu_chatWindowHeader'"
chatWindowLocalId="chatWindow.localId"
t-on-o-clicked="_onClickedChatWindow"
onClicked="_onClickedChatWindow"
/>
</li>
</t>
@@ -36,6 +36,10 @@ export class Composer extends Component {
this._onClickCaptureGlobal = this._onClickCaptureGlobal.bind(this);
onMounted(() => this._mounted());
onWillUnmount(() => this._willUnmount());
this._onDropZoneFilesDropped = this._onDropZoneFilesDropped.bind(this);
this._onComposerTextInputSendShortcut = this._onComposerTextInputSendShortcut.bind(this);
this._onPasteTextInput = this._onPasteTextInput.bind(this);
this._onEmojiSelection = this._onEmojiSelection.bind(this);
}
_mounted() {
@@ -228,28 +232,24 @@ export class Composer extends Component {
* Called when some files have been dropped in the dropzone.
*
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {FileList} ev.detail.files
* @param {Object} detail
* @param {FileList} detail.files
*/
async _onDropZoneFilesDropped(ev) {
ev.stopPropagation();
await this._fileUploaderRef.comp.uploadFiles(ev.detail.files);
async _onDropZoneFilesDropped(detail) {
await this._fileUploaderRef.comp.uploadFiles(detail.files);
this.isDropZoneVisible.value = false;
}
/**
* Handles `o-emoji-selection` event from the emoji popover.
* Handles `onEmojiSelection` callback from the emoji popover.
*
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {string} ev.detail.unicode
* @param {Object} detail
* @param {string} detail.unicode
*/
_onEmojiSelection(ev) {
ev.stopPropagation();
_onEmojiSelection(detail) {
this._textInputRef.comp.saveStateInStore();
this.composerView.insertIntoTextInput(ev.detail.unicode);
this.composerView.insertIntoTextInput(detail.unicode);
if (!this.messaging.device.isMobileDevice) {
this.composerView.update({ doFocus: true });
}
@@ -20,7 +20,7 @@
<t t-if="isDropZoneVisible.value">
<DropZone
className="'o_Composer_dropZone'"
t-on-o-dropzone-files-dropped="_onDropZoneFilesDropped"
onDropzoneFilesDropped="_onDropZoneFilesDropped"
t-ref="dropzone"
/>
</t>
@@ -85,8 +85,8 @@
hasMentionSuggestionsBelowPosition="props.hasMentionSuggestionsBelowPosition"
isCompact="props.isCompact"
sendShortcuts="props.textInputSendShortcuts"
t-on-o-composer-text-input-send-shortcut="_onComposerTextInputSendShortcut"
t-on-paste="_onPasteTextInput"
onComposerTextInputSendShortcut="_onComposerTextInputSendShortcut"
onPaste="_onPasteTextInput"
t-key="composerView.localId"
t-ref="textInput"
/>
@@ -100,7 +100,7 @@
<div class="o_Composer_toolButtonSeparator"/>
</t>
<div class="o_Composer_primaryToolButtons" t-att-class="{ 'o-composer-is-compact': props.isCompact }">
<Popover position="'top'" t-on-o-emoji-selection="_onEmojiSelection">
<Popover position="'top'">
<!-- TODO FIXME o-open not possible to code due to https://github.com/odoo/owl/issues/693 -->
<button class="o_Composer_button o_Composer_buttonEmojis o_Composer_toolButton btn btn-light"
t-att-class="{
@@ -112,7 +112,7 @@
<i class="fa fa-smile-o"/>
</button>
<t t-set="opened">
<EmojisPopover t-ref="emojisPopover"/>
<EmojisPopover t-ref="emojisPopover" onEmojiSelection="_onEmojiSelection"/>
</t>
</Popover>
<button class="o_Composer_button o_Composer_buttonAttachment o_Composer_toolButton btn btn-light fa fa-paperclip" t-att-class="{ 'o-mobile': messaging.device.isMobile }" title="Add attachment" type="button" t-on-click="_onClickAddAttachment"/>
@@ -272,7 +272,9 @@ export class ComposerTextInput extends Component {
!ev.metaKey &&
!ev.shiftKey
) {
this.trigger('o-composer-text-input-send-shortcut');
if (this.props.onComposerTextInputSendShortcut) {
this.props.onComposerTextInputSendShortcut();
}
ev.preventDefault();
return;
}
@@ -283,7 +285,9 @@ export class ComposerTextInput extends Component {
!ev.metaKey &&
!ev.shiftKey
) {
this.trigger('o-composer-text-input-send-shortcut');
if (this.props.onComposerTextInputSendShortcut) {
this.props.onComposerTextInputSendShortcut();
}
ev.preventDefault();
return;
}
@@ -294,7 +298,9 @@ export class ComposerTextInput extends Component {
ev.metaKey &&
!ev.shiftKey
) {
this.trigger('o-composer-text-input-send-shortcut');
if (this.props.onComposerTextInputSendShortcut) {
this.props.onComposerTextInputSendShortcut();
}
ev.preventDefault();
return;
}
@@ -400,6 +406,14 @@ Object.assign(ComposerTextInput, {
composerViewLocalId: String,
hasMentionSuggestionsBelowPosition: Boolean,
isCompact: Boolean,
onComposerTextInputSendShortcut: {
type: Function,
optional: true,
},
onPaste: {
type: Function,
optional: true,
},
/**
* Keyboard shortcuts from text input to send message.
*/
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.ComposerTextInput" owl="1">
<div class="o_ComposerTextInput" t-attf-class="{{ className }}" t-ref="root">
<div class="o_ComposerTextInput" t-attf-class="{{ className }}" t-on-paste="props.onPaste" t-ref="root">
<t t-if="composerView">
<t t-if="composerView.hasSuggestions">
<ComposerSuggestionList
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="mail.DeleteMessageConfirmDialog" owl="1">
<Dialog contentClass="'o_DeleteMessageConfirmDialog ' + className" title="title" t-on-dialog-closed="messageActionList and messageActionList.onDeleteConfirmDialogClosed" t-ref="root">
<Dialog contentClass="'o_DeleteMessageConfirmDialog ' + className" title="title" onClosed="messageActionList and messageActionList.onDeleteConfirmDialogClosed" t-ref="root">
<t t-if="messageActionList">
<p>Are you sure you want to delete this message?</p>
<blockquote class="o_DeleteMessageConfirmDialog_blockquote">
@@ -10,7 +10,7 @@
<small t-if="!messageActionList.message.originThread or messageActionList.message.originThread.model !== 'mail.channel'">Pay attention: The followers of this document who were notified by email will still be able to read the content of this message and reply to it.</small>
<t t-set-slot="buttons">
<button class="btn btn-primary" t-on-click="messageActionList.onClickConfirmDelete">Delete</button>
<button class="btn btn-secondary" t-on-click="dialogRef.comp._close()">Cancel</button>
<button class="btn btn-secondary" t-on-click="root.comp._close()">Cancel</button>
</t>
</t>
</Dialog>
@@ -20,6 +20,8 @@ export class Discuss extends Component {
this._onMobileAddItemHeaderInputSource = this._onMobileAddItemHeaderInputSource.bind(this);
useUpdate({ func: () => this._update() });
onWillUnmount(() => this._willUnmount());
this._onHideMobileAddItemHeader = this._onHideMobileAddItemHeader.bind(this);
this._onSelectMobileNavbarTab = this._onSelectMobileNavbarTab.bind(this);
}
_update() {
@@ -132,10 +134,8 @@ export class Discuss extends Component {
/**
* @private
* @param {CustomEvent} ev
*/
_onHideMobileAddItemHeader(ev) {
ev.stopPropagation();
_onHideMobileAddItemHeader() {
this.discuss.clearIsAddingItem();
}
@@ -171,16 +171,14 @@ export class Discuss extends Component {
/**
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {string} ev.detail.tabId
* @param {Object} detail
* @param {string} detail.tabId
*/
_onSelectMobileNavbarTab(ev) {
ev.stopPropagation();
if (this.discuss.activeMobileNavbarTabId === ev.detail.tabId) {
_onSelectMobileNavbarTab(detail) {
if (this.discuss.activeMobileNavbarTabId === detail.tabId) {
return;
}
this.discuss.update({ activeMobileNavbarTabId: ev.detail.tabId });
this.discuss.update({ activeMobileNavbarTabId: detail.tabId });
if (
this.discuss.activeMobileNavbarTabId === 'mailbox' &&
(!this.discuss.thread || this.discuss.thread.model !== 'mailbox')
@@ -39,7 +39,7 @@
placeholder="discuss.isAddingChannel ? addChannelInputPlaceholder : addChatInputPlaceholder"
select="_onMobileAddItemHeaderInputSelect"
source="_onMobileAddItemHeaderInputSource"
t-on-o-hide="_onHideMobileAddItemHeader"
onHide="_onHideMobileAddItemHeader"
/>
</div>
</t>
@@ -81,7 +81,7 @@
className="'o_Discuss_mobileNavbar'"
activeTabId="discuss.activeMobileNavbarTabId"
tabs="mobileNavbarTabs()"
t-on-o-select-mobile-messaging-navbar-tab="_onSelectMobileNavbarTab"
onSelectMobileMessagingNavbarTab="_onSelectMobileNavbarTab"
/>
</t>
</t>
@@ -35,7 +35,7 @@
placeholder="category.newItemPlaceholderText"
select="category.onAddItemAutocompleteSelect"
source="category.onAddItemAutocompleteSource"
t-on-o-hide="category.onHideAddingItem"
onHide="category.onHideAddingItem"
/>
</div>
</t>
@@ -106,7 +106,7 @@ export class DropZone extends Component {
}
/**
* Triggers the `o-dropzone-files-dropped` event when new files are dropped
* Trigger callback 'props.onDropzoneFilesDropped' with event when new files are dropped
* on the dropzone, and then removes the visual drop effect.
*
* The parents should handle this event to process the files as they wish,
@@ -118,9 +118,11 @@ export class DropZone extends Component {
_onDrop(ev) {
ev.preventDefault();
if (this._isDragSourceExternalFile(ev.dataTransfer)) {
this.trigger('o-dropzone-files-dropped', {
files: ev.dataTransfer.files,
});
if (this.props.onDropzoneFilesDropped) {
this.props.onDropzoneFilesDropped({
files: ev.dataTransfer.files,
});
}
}
this.state.isDraggingInside = false;
}
@@ -128,7 +130,12 @@ export class DropZone extends Component {
}
Object.assign(DropZone, {
props: {},
props: {
onDropzoneFilesDropped: {
type: Function,
optional: true,
},
},
template: 'mail.DropZone',
});
@@ -56,15 +56,22 @@ export class EmojisPopover extends Component {
*/
_onClickEmoji(ev) {
this.close();
this.trigger('o-emoji-selection', {
unicode: ev.currentTarget.dataset.unicode,
});
if (this.props.onEmojiSelection) {
this.props.onEmojiSelection({
unicode: ev.currentTarget.dataset.unicode,
});
}
}
}
Object.assign(EmojisPopover, {
props: {},
props: {
onEmojiSelection: {
type: Function,
optional: true,
},
},
template: 'mail.EmojisPopover',
});
@@ -154,7 +154,9 @@ export class FileUploader extends Component {
originThread: (!composer && thread) ? replace(thread) : undefined,
...attachmentData,
});
this.trigger('o-attachment-created', { attachment });
if (this.props.onAttachmentCreated) {
this.props.onAttachmentCreated({ attachment });
}
}
/**
@@ -177,6 +179,10 @@ Object.assign(FileUploader, {
type: String,
optional: true,
},
onAttachmentCreated: {
type: Function,
optional: true,
},
threadLocalId: {
type: String,
optional: true,
@@ -53,6 +53,10 @@ export class Follower extends Component {
Object.assign(Follower, {
props: {
followerLocalId: String,
onClick: {
type: Function,
optional: true,
},
},
template: 'mail.Follower',
});
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.Follower" owl="1">
<div class="o_Follower" t-attf-class="{{ className }}" t-ref="root">
<div class="o_Follower" t-attf-class="{{ className }}" t-on-click="props.onClick" t-ref="root">
<t t-if="follower">
<a class="o_Follower_details d-flex" t-att-class="{ 'o-inactive': !follower.isActive }" href="#" t-on-click="_onClickDetails">
<img class="o_Follower_avatar" t-att-src="follower.partner.avatarUrl" alt="Avatar"/>
@@ -22,6 +22,7 @@ export class FollowerListMenu extends Component {
this._onClickCaptureGlobal = this._onClickCaptureGlobal.bind(this);
onMounted(() => this._mounted());
onWillUnmount(() => this._willUnmount());
this._onClickFollower = this._onClickFollower.bind(this);
}
_mounted() {
@@ -22,7 +22,7 @@
<Follower
className="'o_FollowerMenu_follower dropdown-item'"
followerLocalId="follower.localId"
t-on-click="_onClickFollower"
onClick="_onClickFollower"
/>
</t>
</t>
@@ -3,9 +3,9 @@
<t t-name="mail.MessageActionList" owl="1">
<div class="o_MessageActionList d-flex" t-attf-class="{{ className }}" t-on-click="messageActionList and messageActionList.onClick" t-ref="root">
<t t-if="messageActionList">
<Popover t-if="messageActionList.message.hasReactionIcon" class="o_MessageActionList_action o_MessageActionList_actionReaction p-2 fa fa-lg fa-smile-o" position="'top'" titleAttribute="ADD_A_REACTION" t-on-o-emoji-selection="messageActionList.onEmojiSelection" t-on-o-popover-closed="messageActionList.onReactionPopoverClosed" t-on-o-popover-opened="messageActionList.onReactionPopoverOpened" t-ref="reactionPopover">
<Popover t-if="messageActionList.message.hasReactionIcon" class="o_MessageActionList_action o_MessageActionList_actionReaction p-2 fa fa-lg fa-smile-o" position="'top'" titleAttribute="ADD_A_REACTION" onClosed="messageActionList.onReactionPopoverClosed" onOpened="messageActionList.onReactionPopoverOpened" t-ref="reactionPopover">
<t t-set="opened">
<EmojisPopover/>
<EmojisPopover onEmojiSelection="messageActionList.onEmojiSelection"/>
</t>
</Popover>
<span t-if="messageActionList.message.canStarBeToggled" class="o_MessageActionList_action o_MessageActionList_actionStar p-2" t-att-class="{
@@ -23,6 +23,8 @@ export class MessagingMenu extends Component {
this._onMobileNewMessageInputSelect = this._onMobileNewMessageInputSelect.bind(this);
this._onMobileNewMessageInputSource = this._onMobileNewMessageInputSource.bind(this);
this._onClickCaptureGlobal = this._onClickCaptureGlobal.bind(this);
this._onHideMobileNewMessage = this._onHideMobileNewMessage.bind(this);
this._onSelectMobileNavbarTab = this._onSelectMobileNavbarTab.bind(this);
// for now, the legacy env is needed for internal functions such as
// `useModels` to work
this.env = owl.Component.env;
@@ -133,10 +135,8 @@ export class MessagingMenu extends Component {
/**
* @private
* @param {CustomEvent} ev
*/
_onHideMobileNewMessage(ev) {
ev.stopPropagation();
_onHideMobileNewMessage() {
this.messagingMenu.toggleMobileNewMessage();
}
@@ -177,13 +177,11 @@ export class MessagingMenu extends Component {
/**
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {string} ev.detail.tabId
* @param {Object} detail
* @param {string} detail.tabId
*/
_onSelectMobileNavbarTab(ev) {
ev.stopPropagation();
this.messagingMenu.update({ activeTabId: ev.detail.tabId });
_onSelectMobileNavbarTab(detail) {
this.messagingMenu.update({ activeTabId: detail.tabId });
}
}
@@ -45,7 +45,7 @@
placeholder="mobileNewMessageInputPlaceholder"
select="_onMobileNewMessageInputSelect"
source="_onMobileNewMessageInputSource"
t-on-o-hide="_onHideMobileNewMessage"
onHide="_onHideMobileNewMessage"
/>
</t>
</div>
@@ -59,7 +59,7 @@
className="'o_MessagingMenu_mobileNavbar'"
activeTabId="messagingMenu.activeTabId"
tabs="tabs"
t-on-o-select-mobile-messaging-navbar-tab="_onSelectMobileNavbarTab"
onSelectMobileMessagingNavbarTab="_onSelectMobileNavbarTab"
/>
</t>
</t>
@@ -15,9 +15,11 @@ export class MobileMessagingNavbar extends Component {
* @param {MouseEvent} ev
*/
_onClick(ev) {
this.trigger('o-select-mobile-messaging-navbar-tab', {
tabId: ev.currentTarget.dataset.tabId,
});
if (this.props.onSelectMobileMessagingNavbarTab) {
this.props.onSelectMobileMessagingNavbarTab({
tabId: ev.currentTarget.dataset.tabId,
});
}
}
}
@@ -28,6 +30,10 @@ Object.assign(MobileMessagingNavbar, {
},
props: {
activeTabId: String,
onSelectMobileMessagingNavbarTab: {
type: Function,
optional: true,
},
tabs: {
type: Array,
element: {
@@ -51,7 +51,7 @@
<!-- Dialogs -->
<t t-if="messaging.userSetting.rtcConfigurationMenu.isOpen">
<Dialog size="'small'" title="'Settings'" t-on-dialog-closed="rtcCallViewer.onRtcSettingsDialogClosed">
<Dialog size="'small'" title="'Settings'" onClosed="rtcCallViewer.onRtcSettingsDialogClosed">
<RtcConfigurationMenu/>
<t t-set-slot="buttons">
<!-- Explicit No buttons -->
@@ -59,7 +59,7 @@
</Dialog>
</t>
<t t-if="rtcCallViewer and rtcCallViewer.rtcLayoutMenu">
<Dialog size="'small'" title="'Change Layout'" t-on-dialog-closed="rtcCallViewer.onLayoutSettingsDialogClosed">
<Dialog size="'small'" title="'Change Layout'" onClosed="rtcCallViewer.onLayoutSettingsDialogClosed">
<RtcLayoutMenu localId="rtcCallViewer.rtcLayoutMenu.localId"/>
<t t-set-slot="buttons">
<!-- Explicit No buttons -->
@@ -128,6 +128,10 @@ Object.assign(ThreadView, {
type: Boolean,
optional: true,
},
onFocusin: {
type: Function,
optional: true,
},
showComposerAttachmentsExtensions: Boolean,
showComposerAttachmentsFilenames: Boolean,
threadViewLocalId: String,
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="mail.ThreadView" owl="1">
<div class="o_ThreadView" t-att-class="threadView and threadView.extraClass" t-attf-class="{{ className }}" t-att-data-correspondent-id="threadView and threadView.thread and threadView.thread.correspondent and threadView.thread.correspondent.id" t-att-data-thread-local-id="threadView and threadView.thread and threadView.thread.localId" t-ref="root">
<div class="o_ThreadView" t-att-class="threadView and threadView.extraClass" t-attf-class="{{ className }}" t-att-data-correspondent-id="threadView and threadView.thread and threadView.thread.correspondent and threadView.thread.correspondent.id" t-att-data-thread-local-id="threadView and threadView.thread and threadView.thread.localId" t-on-focusin="props.onFocusin" t-ref="root">
<t t-if="threadView">
<t t-if="threadView.topbar">
<ThreadViewTopbar className="'border-bottom'" localId="threadView.topbar.localId"/>
@@ -182,11 +182,7 @@ registerModel({
await this.open();
}
},
/**
* @param {CustomEvent} ev
*/
onHideAddingItem(ev) {
ev.stopPropagation();
onHideAddingItem() {
this.update({ isAddingItem: false });
},
/**
@@ -103,15 +103,14 @@ registerModel({
this.update({ showDeleteConfirm: false });
},
/**
* Handles `o-emoji-selection` event from the emoji popover.
* Handles `onEmojiSelection` calback from the emoji popover.
*
* @private
* @param {CustomEvent} ev
* @param {Object} ev.detail
* @param {string} ev.detail.unicode
* @param {Object} detail
* @param {string} detail.unicode
*/
onEmojiSelection(ev) {
this.message.addReaction(ev.detail.unicode);
onEmojiSelection(detail) {
this.message.addReaction(detail.unicode);
},
/**
* @private
@@ -12,6 +12,7 @@ patch(Message.prototype, 'snailmail/static/src/components/message/message.js', {
*/
setup() {
this._super();
this._onDialogClosedSnailmailError = this._onDialogClosedSnailmailError.bind(this);
this.snailmailState = useState({
// Determine if the error dialog is displayed.
hasDialog: false,
@@ -18,7 +18,7 @@
<xpath expr="//*[@name='rootCondition']" position="inside">
<t t-if="snailmailState.hasDialog">
<SnailmailErrorDialog messageLocalId="messageView.message.localId" t-on-dialog-closed="_onDialogClosedSnailmailError"/>
<SnailmailErrorDialog messageLocalId="messageView.message.localId" onClosed="_onDialogClosedSnailmailError"/>
</t>
</xpath>
@@ -78,6 +78,10 @@ Object.assign(SnailmailErrorDialog, {
components: { Dialog },
props: {
messageLocalId: String,
onClosed: {
type: Function,
optional: true,
},
},
template: 'snailmail.SnailmailErrorDialog',
});
@@ -2,7 +2,7 @@
<templates xml:space="preserve">
<t t-name="snailmail.SnailmailErrorDialog" owl="1">
<Dialog contentClass="'o_SnailmailErrorDialog'" title="title" size="'medium'" t-ref="root">
<Dialog contentClass="'o_SnailmailErrorDialog'" title="title" size="'medium'" onClosed="props.onClosed" t-ref="root">
<t t-if="message and notification">
<t t-if="notification.failure_type === 'sn_credit'">
<p class="o_SnailmailErrorDialog_contentCredit">
@@ -105,6 +105,9 @@ odoo.define('web.OwlDialog', function (require) {
* @private
*/
_close() {
if (this.props.onClosed) {
this.props.onClosed();
}
this.trigger('dialog-closed');
}
@@ -149,6 +152,12 @@ odoo.define('web.OwlDialog', function (require) {
}
}
_onDialogClosed() {
if (this.props.onClosed) {
this.props.onClosed();
}
}
/**
* @private
*/
@@ -248,6 +257,7 @@ odoo.define('web.OwlDialog', function (require) {
backdrop: { validate: b => ['static', true, false].includes(b) },
contentClass: { type: String, optional: 1 },
fullscreen: { type: Boolean, optional: 1 },
onClosed: { type: Function, optional: 1 },
renderFooter: Boolean,
renderHeader: Boolean,
size: { validate: s => ['extra-large', 'large', 'medium', 'small'].includes(s) },
@@ -81,6 +81,9 @@ odoo.define('web.Popover', function (require) {
_close() {
this.state.displayed = false;
if (this.props.onClosed) {
this.props.onClosed();
}
this.trigger('o-popover-closed');
}
@@ -173,8 +176,14 @@ odoo.define('web.Popover', function (require) {
_onClick(ev) {
this.state.displayed = !this.state.displayed;
if (this.state.displayed) {
if (this.props.onOpened) {
this.props.onOpened();
}
this.trigger('o-popover-opened');
} else {
if (this.props.onClosed) {
this.props.onClosed();
}
this.trigger('o-popover-closed');
}
}
@@ -319,6 +328,14 @@ odoo.define('web.Popover', function (require) {
position: 'bottom',
};
Popover.props = {
onClosed: {
type: Function,
optional: true,
},
onOpened: {
type: Function,
optional: true,
},
popoverClass: {
type: String,
optional: true,
+1 -1
View File
@@ -242,7 +242,7 @@
<t t-name="web.OwlDialog" owl="1">
<Portal target="'body'">
<div class="o_dialog" t-on-focus="_onFocus" t-on-click="_onClick">
<div class="o_dialog" t-on-focus="_onFocus" t-on-click="_onClick" t-on-dialog-closed="_onDialogClosed">
<div role="dialog" class="modal"
tabindex="-1"
t-att-class="{ o_technical_modal: props.technical, o_modal_full: props.fullscreen }"