diff --git a/addons/mail/static/src/components/attachment_box/attachment_box.js b/addons/mail/static/src/components/attachment_box/attachment_box.js index cca9928ad72..6e3803b85a9 100644 --- a/addons/mail/static/src/components/attachment_box/attachment_box.js +++ b/addons/mail/static/src/components/attachment_box/attachment_box.js @@ -13,7 +13,6 @@ export class AttachmentBox extends Component { setup() { super.setup(); useComponentToModel({ fieldName: 'component', modelName: 'AttachmentBoxView' }); - this._onDropZoneFilesDropped = this._onDropZoneFilesDropped.bind(this); } //-------------------------------------------------------------------------- @@ -27,20 +26,6 @@ export class AttachmentBox extends Component { return this.messaging && this.messaging.models['AttachmentBoxView'].get(this.props.localId); } - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - - /** - * @private - * @param {Object} detail - * @param {FileList} detail.files - */ - async _onDropZoneFilesDropped(detail) { - await this.attachmentBoxView.fileUploader.uploadFiles(detail.files); - this.attachmentBoxView.useDragVisibleDropZone.update({ isVisible: false }); - } - } Object.assign(AttachmentBox, { diff --git a/addons/mail/static/src/components/attachment_box/attachment_box.xml b/addons/mail/static/src/components/attachment_box/attachment_box.xml index d6a6cbb85b9..8bc18a0083e 100644 --- a/addons/mail/static/src/components/attachment_box/attachment_box.xml +++ b/addons/mail/static/src/components/attachment_box/attachment_box.xml @@ -16,7 +16,6 @@ diff --git a/addons/mail/static/src/components/chatter/chatter.xml b/addons/mail/static/src/components/chatter/chatter.xml index ae498380aec..f5e1a87ef41 100644 --- a/addons/mail/static/src/components/chatter/chatter.xml +++ b/addons/mail/static/src/components/chatter/chatter.xml @@ -33,7 +33,6 @@ diff --git a/addons/mail/static/src/components/composer/composer.js b/addons/mail/static/src/components/composer/composer.js index a45039cb10c..d04c91db924 100644 --- a/addons/mail/static/src/components/composer/composer.js +++ b/addons/mail/static/src/components/composer/composer.js @@ -15,7 +15,6 @@ export class Composer extends Component { super.setup(); useComponentToModel({ fieldName: 'component', modelName: 'ComposerView' }); useRefToModel({ fieldName: 'buttonEmojisRef', modelName: 'ComposerView', refName: 'buttonEmojis' }); - this._onDropZoneFilesDropped = this._onDropZoneFilesDropped.bind(this); } //-------------------------------------------------------------------------- @@ -29,22 +28,6 @@ export class Composer extends Component { return this.messaging && this.messaging.models['ComposerView'].get(this.props.localId); } - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - - /** - * Called when some files have been dropped in the dropzone. - * - * @private - * @param {Object} detail - * @param {FileList} detail.files - */ - async _onDropZoneFilesDropped(detail) { - await this.composerView.fileUploader.uploadFiles(detail.files); - this.composerView.useDragVisibleDropZone.update({ isVisible: false }); - } - } Object.assign(Composer, { diff --git a/addons/mail/static/src/components/composer/composer.xml b/addons/mail/static/src/components/composer/composer.xml index 9d8aaf462bc..da1e2815c09 100644 --- a/addons/mail/static/src/components/composer/composer.xml +++ b/addons/mail/static/src/components/composer/composer.xml @@ -21,7 +21,6 @@ diff --git a/addons/mail/static/src/components/discuss_mobile_mailbox_selection/discuss_mobile_mailbox_selection.xml b/addons/mail/static/src/components/discuss_mobile_mailbox_selection/discuss_mobile_mailbox_selection.xml index 10687a46660..6f1e0f40674 100644 --- a/addons/mail/static/src/components/discuss_mobile_mailbox_selection/discuss_mobile_mailbox_selection.xml +++ b/addons/mail/static/src/components/discuss_mobile_mailbox_selection/discuss_mobile_mailbox_selection.xml @@ -4,13 +4,7 @@
- +
diff --git a/addons/mail/static/src/components/discuss_mobile_mailbox_selection_item/discuss_mobile_mailbox_selection_item.js b/addons/mail/static/src/components/discuss_mobile_mailbox_selection_item/discuss_mobile_mailbox_selection_item.js new file mode 100644 index 00000000000..79bcf7640d6 --- /dev/null +++ b/addons/mail/static/src/components/discuss_mobile_mailbox_selection_item/discuss_mobile_mailbox_selection_item.js @@ -0,0 +1,37 @@ +/** @odoo-module **/ + +import { registerMessagingComponent } from '@mail/utils/messaging_component'; + +const { Component } = owl; + +export class DiscussMobileMailboxSelectionItem extends Component { + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * @returns {DiscussView} + */ + get discussView() { + return this.messaging && this.messaging.models['DiscussView'].get(this.props.discussViewLocalId); + } + + /** + * @returns {Thread} + */ + get mailbox() { + return this.messaging && this.messaging.models['Thread'].get(this.props.mailboxLocalId); + } + +} + +Object.assign(DiscussMobileMailboxSelectionItem, { + props: { + discussViewLocalId: String, + mailboxLocalId: String, + }, + template: 'mail.DiscussMobileMailboxSelectionItem', +}); + +registerMessagingComponent(DiscussMobileMailboxSelectionItem); diff --git a/addons/mail/static/src/components/discuss_mobile_mailbox_selection_item/discuss_mobile_mailbox_selection_item.xml b/addons/mail/static/src/components/discuss_mobile_mailbox_selection_item/discuss_mobile_mailbox_selection_item.xml new file mode 100644 index 00000000000..4824d58bd50 --- /dev/null +++ b/addons/mail/static/src/components/discuss_mobile_mailbox_selection_item/discuss_mobile_mailbox_selection_item.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/addons/mail/static/src/components/drop_zone/drop_zone.js b/addons/mail/static/src/components/drop_zone/drop_zone.js index 306afe11f28..d88fb486076 100644 --- a/addons/mail/static/src/components/drop_zone/drop_zone.js +++ b/addons/mail/static/src/components/drop_zone/drop_zone.js @@ -2,29 +2,10 @@ import { registerMessagingComponent } from '@mail/utils/messaging_component'; -const { Component, useState } = owl; +const { Component } = owl; export class DropZone extends Component { - /** - * @override - */ - setup() { - super.setup(); - this.state = useState({ - /** - * Determine whether the user is dragging files over the dropzone. - * Useful to provide visual feedback in that case. - */ - isDraggingInside: false, - }); - /** - * Counts how many drag enter/leave happened on self and children. This - * ensures the drop effect stays active when dragging over a child. - */ - this._dragCount = 0; - } - //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- @@ -46,94 +27,6 @@ export class DropZone extends Component { return Boolean(this.root.el && this.root.el.contains(node)); } - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * Making sure that dragging content is external files. - * Ignoring other content dragging like text. - * - * @private - * @param {DataTransfer} dataTransfer - * @returns {boolean} - */ - _isDragSourceExternalFile(dataTransfer) { - const dragDataType = dataTransfer.types; - if (dragDataType.constructor === window.DOMStringList) { - return dragDataType.contains('Files'); - } - if (dragDataType.constructor === Array) { - return dragDataType.includes('Files'); - } - return false; - } - - //-------------------------------------------------------------------------- - // Handlers - //-------------------------------------------------------------------------- - - /** - * Shows a visual drop effect when dragging inside the dropzone. - * - * @private - * @param {DragEvent} ev - */ - _onDragenter(ev) { - ev.preventDefault(); - if (this._dragCount === 0) { - this.state.isDraggingInside = true; - } - this._dragCount++; - } - - /** - * Hides the visual drop effect when dragging outside the dropzone. - * - * @private - * @param {DragEvent} ev - */ - _onDragleave(ev) { - this._dragCount--; - if (this._dragCount === 0) { - this.state.isDraggingInside = false; - } - } - - /** - * Prevents default (from the template) in order to receive the drop event. - * The drop effect cursor works only when set on dragover. - * - * @private - * @param {DragEvent} ev - */ - _onDragover(ev) { - ev.preventDefault(); - ev.dataTransfer.dropEffect = 'copy'; - } - - /** - * 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, - * such as uploading them. - * - * @private - * @param {DragEvent} ev - */ - _onDrop(ev) { - ev.preventDefault(); - if (this._isDragSourceExternalFile(ev.dataTransfer)) { - if (this.props.onDropzoneFilesDropped) { - this.props.onDropzoneFilesDropped({ - files: ev.dataTransfer.files, - }); - } - } - this.state.isDraggingInside = false; - } - } Object.assign(DropZone, { diff --git a/addons/mail/static/src/components/drop_zone/drop_zone.xml b/addons/mail/static/src/components/drop_zone/drop_zone.xml index d1c4f7dd3a8..c4a246391fc 100644 --- a/addons/mail/static/src/components/drop_zone/drop_zone.xml +++ b/addons/mail/static/src/components/drop_zone/drop_zone.xml @@ -2,7 +2,7 @@ -
+

Drag Files Here

diff --git a/addons/mail/static/src/components/message_action_list/message_action_list.js b/addons/mail/static/src/components/message_action_list/message_action_list.js index f02e11768c8..be8c6c34603 100644 --- a/addons/mail/static/src/components/message_action_list/message_action_list.js +++ b/addons/mail/static/src/components/message_action_list/message_action_list.js @@ -13,7 +13,6 @@ export class MessageActionList extends Component { setup() { super.setup(); useRefToModel({ fieldName: 'actionReactionRef', modelName: 'MessageActionList', refName: 'actionReaction' }); - this.ADD_A_REACTION = this.env._t("Add a Reaction"); } /** diff --git a/addons/mail/static/src/components/message_action_list/message_action_list.xml b/addons/mail/static/src/components/message_action_list/message_action_list.xml index 5432e69fbaa..96dfb5722b5 100644 --- a/addons/mail/static/src/components/message_action_list/message_action_list.xml +++ b/addons/mail/static/src/components/message_action_list/message_action_list.xml @@ -3,7 +3,7 @@
- + diff --git a/addons/mail/static/src/models/drop_zone_view.js b/addons/mail/static/src/models/drop_zone_view.js index e36171be3a7..8f4d2e2da01 100644 --- a/addons/mail/static/src/models/drop_zone_view.js +++ b/addons/mail/static/src/models/drop_zone_view.js @@ -1,11 +1,95 @@ /** @odoo-module **/ import { registerModel } from '@mail/model/model_core'; -import { one } from '@mail/model/model_field'; +import { attr, one } from '@mail/model/model_field'; +import { decrement, increment } from '@mail/model/model_field_command'; registerModel({ name: 'DropZoneView', identifyingFields: [['attachmentBoxViewOwner', 'composerViewOwner']], + recordMethods: { + /** + * Shows a visual drop effect when dragging inside the dropzone. + * + * @param {DragEvent} ev + */ + onDragenter(ev) { + if (!this.exists()) { + return; + } + ev.preventDefault(); + if (this.dragCount === 0) { + this.update({ isDraggingInside: true }); + } + this.update({ dragCount: increment() }); + }, + /** + * Hides the visual drop effect when dragging outside the dropzone. + * + * @param {DragEvent} ev + */ + onDragleave(ev) { + if (!this.exists()) { + return; + } + this.update({ dragCount: decrement() }); + if (this.dragCount === 0) { + this.update({ isDraggingInside: false }); + } + }, + /** + * Prevents default (from the template) in order to receive the drop event. + * The drop effect cursor works only when set on dragover. + * + * @param {DragEvent} ev + */ + onDragover(ev) { + ev.preventDefault(); + ev.dataTransfer.dropEffect = 'copy'; + }, + /** + * 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, + * such as uploading them. + * + * @param {DragEvent} ev + */ + async onDrop(ev) { + if (!this.exists()) { + return; + } + ev.preventDefault(); + this.update({ isDraggingInside: false }); + if (this._isDragSourceExternalFile(ev.dataTransfer)) { + if (this.attachmentBoxViewOwner) { + await this.attachmentBoxViewOwner.fileUploader.uploadFiles(ev.dataTransfer.files); + } + if (this.composerViewOwner) { + await this.composerViewOwner.fileUploader.uploadFiles(ev.dataTransfer.files); + } + } + }, + /** + * Making sure that dragging content is external files. + * Ignoring other content dragging like text. + * + * @private + * @param {DataTransfer} dataTransfer + * @returns {boolean} + */ + _isDragSourceExternalFile(dataTransfer) { + const dragDataType = dataTransfer.types; + if (dragDataType.constructor === window.DOMStringList) { + return dragDataType.contains('Files'); + } + if (dragDataType.constructor === Array) { + return dragDataType.includes('Files'); + } + return false; + }, + }, fields: { attachmentBoxViewOwner: one('AttachmentBoxView', { inverse: 'dropZoneView', @@ -15,5 +99,19 @@ registerModel({ inverse: 'dropZoneView', readonly: true, }), + /** + * Counts how many drag enter/leave happened on self and children. This + * ensures the drop effect stays active when dragging over a child. + */ + dragCount: attr({ + default: 0, + }), + /** + * Determines whether the user is dragging files over the dropzone. + * Useful to provide visual feedback in that case. + */ + isDraggingInside: attr({ + default: false, + }), }, }); diff --git a/addons/mail/static/src/models/message_action_list.js b/addons/mail/static/src/models/message_action_list.js index 61abef25228..63123dfb729 100644 --- a/addons/mail/static/src/models/message_action_list.js +++ b/addons/mail/static/src/models/message_action_list.js @@ -72,6 +72,13 @@ registerModel({ onClickToggleStar(ev) { this.message.toggleStar(); }, + /** + * @private + * @returns {string} + */ + _computeAddReactionText() { + return this.env._t("Add a Reaction"); + }, /** * @private * @returns {boolean} @@ -103,6 +110,9 @@ registerModel({ * States the reference to the reaction action in the component. */ actionReactionRef: attr(), + addReactionText: attr({ + compute: '_computeAddReactionText', + }), deleteConfirmDialog: one('Dialog', { inverse: 'messageActionListOwnerAsDeleteConfirm', isCausal: true, diff --git a/addons/mail/static/src/models/message_list_view.js b/addons/mail/static/src/models/message_list_view.js index 7505ec19c2e..c6fc1e566bd 100644 --- a/addons/mail/static/src/models/message_list_view.js +++ b/addons/mail/static/src/models/message_list_view.js @@ -2,6 +2,7 @@ import { registerModel } from '@mail/model/model_core'; import { attr, one } from '@mail/model/model_field'; +import { clear } from '@mail/model/model_field_command'; registerModel({ name: 'MessageListView', @@ -16,6 +17,16 @@ registerModel({ } return this.component.root.el; }, + /** + * @private + * @returns {boolean|FieldCommand} + */ + _computeHasScrollAdjust() { + if (this.threadViewOwner.threadViewer.chatter) { + return this.threadViewOwner.threadViewer.chatter.hasMessageListScrollAdjust; + } + return clear(); + }, /*** * @private * @returns {boolean} @@ -38,6 +49,10 @@ registerModel({ * States the OWL component of this message list view */ component: attr(), + hasScrollAdjust: attr({ + compute: '_computeHasScrollAdjust', + default: true, + }), /** * States whether the message list scroll position is at the end of * the message list. Depending of the message list order, this could be diff --git a/addons/mail/static/src/models/messaging_menu.js b/addons/mail/static/src/models/messaging_menu.js index 5f9c0751fd7..a838d4d755d 100644 --- a/addons/mail/static/src/models/messaging_menu.js +++ b/addons/mail/static/src/models/messaging_menu.js @@ -122,6 +122,7 @@ registerModel({ activeTabId: attr({ default: 'all', }), + component: attr(), /** * States the counter of this messaging menu. The counter is an integer * value to give to the current user an estimate of how many things diff --git a/addons/mail/static/src/models/use_drag_visible_drop_zone.js b/addons/mail/static/src/models/use_drag_visible_drop_zone.js index b89d6ef0a7c..7b48ad29118 100644 --- a/addons/mail/static/src/models/use_drag_visible_drop_zone.js +++ b/addons/mail/static/src/models/use_drag_visible_drop_zone.js @@ -11,7 +11,7 @@ registerModel({ _created() { document.addEventListener('dragenter', this._onDragenterListener, true); document.addEventListener('dragleave', this._onDragleaveListener, true); - document.addEventListener('drop', this._onDropListener, true); + document.addEventListener('drop', this._onDropListener); // Thoses Events prevent the browser to open or download the file if // it's dropped outside of the dropzone @@ -21,7 +21,7 @@ registerModel({ _willDelete() { document.removeEventListener('dragenter', this._onDragenterListener, true); document.removeEventListener('dragleave', this._onDragleaveListener, true); - document.removeEventListener('drop', this._onDropListener, true); + document.removeEventListener('drop', this._onDropListener); window.removeEventListener('dragover', ev => ev.preventDefault()); window.removeEventListener('drop', ev => ev.preventDefault()); diff --git a/addons/mail/static/tests/qunit_mobile_suite_tests/components/discuss_mobile_mailbox_selection_tests.js b/addons/mail/static/tests/qunit_mobile_suite_tests/components/discuss_mobile_mailbox_selection_tests.js index 9197595eed3..d1dcdb860e2 100644 --- a/addons/mail/static/tests/qunit_mobile_suite_tests/components/discuss_mobile_mailbox_selection_tests.js +++ b/addons/mail/static/tests/qunit_mobile_suite_tests/components/discuss_mobile_mailbox_selection_tests.js @@ -48,13 +48,13 @@ QUnit.test('select another mailbox', async function (assert) { ); assert.containsOnce( document.body, - `.o_DiscussMobileMailboxSelection_button[ + `.o_DiscussMobileMailboxSelectionItem[ data-mailbox-local-id="${messaging.starred.localId}" ]`, "should have a button to open starred mailbox" ); - await click(`.o_DiscussMobileMailboxSelection_button[ + await click(`.o_DiscussMobileMailboxSelectionItem[ data-mailbox-local-id="${messaging.starred.localId}"] `); assert.containsOnce( @@ -106,7 +106,7 @@ QUnit.test('auto-select "Inbox" when discuss had channel as active thread', asyn "'mailbox' tab should be selected after click on mailbox tab" ); assert.hasClass( - document.querySelector(`.o_DiscussMobileMailboxSelection_button[data-mailbox-local-id="${ + document.querySelector(`.o_DiscussMobileMailboxSelectionItem[data-mailbox-local-id="${ messaging.inbox.localId }"]`), 'o-active',