diff --git a/addons/mail/static/src/components/attachment_viewer/attachment_viewer.js b/addons/mail/static/src/components/attachment_viewer/attachment_viewer.js index 48ae6cf0ae2..067881a7ac8 100644 --- a/addons/mail/static/src/components/attachment_viewer/attachment_viewer.js +++ b/addons/mail/static/src/components/attachment_viewer/attachment_viewer.js @@ -114,7 +114,7 @@ export class AttachmentViewer extends Component { * @private */ _close() { - this.attachmentViewer.close(); + this.attachmentViewer.delete(); } /** @@ -163,14 +163,10 @@ export class AttachmentViewer extends Component { * @private */ _next() { - const attachmentViewer = this.attachmentViewer; - const index = attachmentViewer.attachments.findIndex(attachment => - attachment === attachmentViewer.attachment - ); - const nextIndex = (index + 1) % attachmentViewer.attachments.length; - attachmentViewer.update({ - attachment: link(attachmentViewer.attachments[nextIndex]), - }); + if (!this.attachmentViewer.dialogOwner || !this.attachmentViewer.dialogOwner.attachmentListOwnerAsAttachmentView) { + return; + } + this.attachmentViewer.dialogOwner.attachmentListOwnerAsAttachmentView.selectNextAttachment(); } /** @@ -179,16 +175,10 @@ export class AttachmentViewer extends Component { * @private */ _previous() { - const attachmentViewer = this.attachmentViewer; - const index = attachmentViewer.attachments.findIndex(attachment => - attachment === attachmentViewer.attachment - ); - const nextIndex = index === 0 - ? attachmentViewer.attachments.length - 1 - : index - 1; - attachmentViewer.update({ - attachment: link(attachmentViewer.attachments[nextIndex]), - }); + if (!this.attachmentViewer.dialogOwner || !this.attachmentViewer.dialogOwner.attachmentListOwnerAsAttachmentView) { + return; + } + this.attachmentViewer.dialogOwner.attachmentListOwnerAsAttachmentView.selectPreviousAttachment(); } /** diff --git a/addons/mail/static/src/models/attachment_card/attachment_card.js b/addons/mail/static/src/models/attachment_card/attachment_card.js index 4846282a490..4563eca1dc5 100644 --- a/addons/mail/static/src/models/attachment_card/attachment_card.js +++ b/addons/mail/static/src/models/attachment_card/attachment_card.js @@ -2,7 +2,7 @@ import { registerModel } from '@mail/model/model_core'; import { attr, one } from '@mail/model/model_field'; -import { insert, insertAndReplace, replace } from '@mail/model/model_field_command'; +import { insertAndReplace, replace } from '@mail/model/model_field_command'; registerModel({ name: 'AttachmentCard', @@ -15,13 +15,9 @@ registerModel({ if (!this.attachment || !this.attachment.isViewable) { return; } - this.messaging.dialogManager.update({ - dialogs: insert({ - attachmentViewer: insertAndReplace({ - attachment: replace(this.attachment), - attachmentList: replace(this.attachmentList), - }), - }), + this.attachmentList.update({ + attachmentListViewDialog: insertAndReplace(), + selectedAttachment: replace(this.attachment), }); }, /** diff --git a/addons/mail/static/src/models/attachment_image/attachment_image.js b/addons/mail/static/src/models/attachment_image/attachment_image.js index 2a4f1d373fa..329c4577cdd 100644 --- a/addons/mail/static/src/models/attachment_image/attachment_image.js +++ b/addons/mail/static/src/models/attachment_image/attachment_image.js @@ -2,7 +2,7 @@ import { registerModel } from '@mail/model/model_core'; import { attr, one } from '@mail/model/model_field'; -import { clear, insert, insertAndReplace, replace } from '@mail/model/model_field_command'; +import { clear, insertAndReplace, replace } from '@mail/model/model_field_command'; registerModel({ name: 'AttachmentImage', @@ -15,13 +15,9 @@ registerModel({ if (!this.attachment || !this.attachment.isViewable) { return; } - this.messaging.dialogManager.update({ - dialogs: insert({ - attachmentViewer: insertAndReplace({ - attachment: replace(this.attachment), - attachmentList: replace(this.attachmentList), - }), - }), + this.attachmentList.update({ + attachmentListViewDialog: insertAndReplace(), + selectedAttachment: replace(this.attachment), }); }, /** diff --git a/addons/mail/static/src/models/attachment_list/attachment_list.js b/addons/mail/static/src/models/attachment_list/attachment_list.js index 44d2b7c5ef0..23b93cdf275 100644 --- a/addons/mail/static/src/models/attachment_list/attachment_list.js +++ b/addons/mail/static/src/models/attachment_list/attachment_list.js @@ -8,6 +8,22 @@ registerModel({ name: 'AttachmentList', identifyingFields: [['composerView', 'messageView', 'attachmentBoxViewOwner']], recordMethods: { + /** + * Select the next attachment. + */ + selectNextAttachment() { + const index = this.attachments.findIndex(attachment => attachment === this.selectedAttachment); + const nextIndex = index === this.attachments.length - 1 ? 0 : index + 1; + this.update({ selectedAttachment: replace(this.attachments[nextIndex]) }); + }, + /** + * Select the previous attachment. + */ + selectPreviousAttachment() { + const index = this.attachments.findIndex(attachment => attachment === this.selectedAttachment); + const prevIndex = index === 0 ? this.attachments.length - 1 : index - 1; + this.update({ selectedAttachment: replace(this.attachments[prevIndex]) }); + }, _computeAttachmentImages() { return insertAndReplace(this.imageAttachments.map(attachment => { return { @@ -80,6 +96,10 @@ registerModel({ inverse: 'attachmentList', isCausal: true, }), + attachmentListViewDialog: one('Dialog', { + inverse: 'attachmentListOwnerAsAttachmentView', + isCausal: true, + }), /** * States the attachments to be displayed by this attachment list. */ @@ -116,6 +136,7 @@ registerModel({ nonImageAttachments: many('Attachment', { compute: '_computeNonImageAttachments', }), + selectedAttachment: one('Attachment'), /** * States the attachments that can be viewed inside the browser. */ diff --git a/addons/mail/static/src/models/attachment_viewer/attachment_viewer.js b/addons/mail/static/src/models/attachment_viewer/attachment_viewer.js index 12d84fae5d9..da956f57ca8 100644 --- a/addons/mail/static/src/models/attachment_viewer/attachment_viewer.js +++ b/addons/mail/static/src/models/attachment_viewer/attachment_viewer.js @@ -5,17 +5,8 @@ import { attr, many, one } from '@mail/model/model_field'; registerModel({ name: 'AttachmentViewer', - identifyingFields: ['attachmentList'], + identifyingFields: ['dialogOwner'], recordMethods: { - /** - * Close the attachment viewer by closing its linked dialog. - */ - close() { - const dialog = this.messaging.models['Dialog'].find(dialog => dialog.record === this); - if (dialog) { - dialog.delete(); - } - }, /** * Returns whether the given html element is inside this attachment viewer. * @@ -47,9 +38,11 @@ registerModel({ angle: attr({ default: 0, }), - attachment: one('Attachment'), + attachment: one('Attachment', { + related: 'attachmentList.selectedAttachment', + }), attachmentList: one('AttachmentList', { - readonly: true, + related: 'dialogOwner.attachmentListOwnerAsAttachmentView', required: true, }), attachments: many('Attachment', { @@ -62,7 +55,7 @@ registerModel({ /** * Determines the dialog displaying this attachment viewer. */ - dialog: one('Dialog', { + dialogOwner: one('Dialog', { inverse: 'attachmentViewer', isCausal: true, readonly: true, diff --git a/addons/mail/static/src/models/dialog/dialog.js b/addons/mail/static/src/models/dialog/dialog.js index f214a740b0e..8671b6afa70 100644 --- a/addons/mail/static/src/models/dialog/dialog.js +++ b/addons/mail/static/src/models/dialog/dialog.js @@ -2,11 +2,14 @@ import { registerModel } from '@mail/model/model_core'; import { attr, one } from '@mail/model/model_field'; -import { clear, replace } from '@mail/model/model_field_command'; +import { clear, insertAndReplace, replace } from '@mail/model/model_field_command'; registerModel({ name: 'Dialog', - identifyingFields: ['manager', ['attachmentViewer', 'followerSubtypeList']], + identifyingFields: [[ + 'attachmentListOwnerAsAttachmentView', + 'followerOwnerAsSubtypeList', + ]], recordMethods: { /** * @param {Element} element @@ -15,6 +18,40 @@ registerModel({ hasElementInContent(element) { return Boolean(this.record && this.record.containsElement(element)); }, + /** + * @private + * @returns {FieldCommand} + */ + _computeAttachmentViewer() { + if (this.attachmentListOwnerAsAttachmentView) { + return insertAndReplace(); + } + return clear(); + }, + /** + * @private + * @returns {string|FieldCommand} + */ + _computeComponentName() { + if (this.attachmentViewer) { + return 'AttachmentViewer'; + } + if (this.followerSubtypeList) { + return 'FollowerSubtypeList'; + } + return clear(); + }, + /** + * @private + * @returns {FieldCommand} + */ + _computeFollowerSubtypeList() { + if (this.followerOwnerAsSubtypeList) { + return insertAndReplace(); + } + return clear(); + }, + /** /** * @private * @returns {boolean} @@ -29,6 +66,16 @@ registerModel({ } return true; }, + /** + * @private + * @returns {FieldCommand} + */ + _computeManager() { + if (this.messaging.dialogManager) { + return replace(this.messaging.dialogManager); + } + return clear(); + }, /** * @private * @returns {FieldCommand} @@ -41,36 +88,36 @@ registerModel({ return replace(this.followerSubtypeList); } }, - _computeComponentName() { - if (this.attachmentViewer) { - return 'AttachmentViewer'; - } - if (this.followerSubtypeList) { - return 'FollowerSubtypeList'; - } - return clear(); - }, }, fields: { - attachmentViewer: one('AttachmentViewer', { - isCausal: true, - inverse: 'dialog', + attachmentListOwnerAsAttachmentView: one('AttachmentList', { + inverse: 'attachmentListViewDialog', readonly: true, }), + attachmentViewer: one('AttachmentViewer', { + compute: '_computeAttachmentViewer', + inverse: 'dialogOwner', + isCausal: true, + }), componentName: attr({ compute: '_computeComponentName', required: true, }), - followerSubtypeList: one('FollowerSubtypeList', { - isCausal: true, - inverse: 'dialog', + followerOwnerAsSubtypeList: one('Follower', { + inverse: 'followerSubtypeListDialog', readonly: true, }), + followerSubtypeList: one('FollowerSubtypeList', { + compute: '_computeFollowerSubtypeList', + inverse: 'dialogOwner', + isCausal: true, + }), isCloseable: attr({ compute: '_computeIsCloseable', default: true, }), manager: one('DialogManager', { + compute: '_computeManager', inverse: 'dialogs', readonly: true, }), diff --git a/addons/mail/static/src/models/follower/follower.js b/addons/mail/static/src/models/follower/follower.js index 29067cb8dbb..ab8e3738c7f 100644 --- a/addons/mail/static/src/models/follower/follower.js +++ b/addons/mail/static/src/models/follower/follower.js @@ -2,7 +2,7 @@ import { registerModel } from '@mail/model/model_core'; import { attr, many, one } from '@mail/model/model_field'; -import { clear, insert, insertAndReplace, link, replace, unlink, unlinkAll } from '@mail/model/model_field_command'; +import { clear, insert, insertAndReplace, link, unlink, unlinkAll } from '@mail/model/model_field_command'; registerModel({ name: 'Follower', @@ -47,7 +47,7 @@ registerModel({ * Close subtypes dialog */ closeSubtypes() { - this.update({ subtypeList: clear() }); + this.update({ followerSubtypeListDialog: clear() }); }, /** * Opens the most appropriate view that is a profile for this follower. @@ -98,13 +98,7 @@ registerModel({ this.update({ selectedSubtypes: unlink(subtype) }); } } - this.messaging.dialogManager.update({ - dialogs: insert({ - followerSubtypeList: insertAndReplace({ - follower: replace(this), - }), - }), - }); + this.update({ followerSubtypeListDialog: insertAndReplace() }); }, /** * @param {FollowerSubtype} subtype @@ -145,6 +139,10 @@ registerModel({ followedThread: one('Thread', { inverse: 'followers', }), + followerSubtypeListDialog: one('Dialog', { + inverse: 'followerOwnerAsSubtypeList', + isCausal: true, + }), id: attr({ readonly: true, required: true, @@ -159,10 +157,6 @@ registerModel({ required: true, }), selectedSubtypes: many('FollowerSubtype'), - subtypeList: many('FollowerSubtypeList', { - inverse: 'follower', - isCausal: true, - }), subtypes: many('FollowerSubtype'), }, }); diff --git a/addons/mail/static/src/models/follower_subtype_list/follower_subtype_list.js b/addons/mail/static/src/models/follower_subtype_list/follower_subtype_list.js index db463571359..6cf9fcda3e0 100644 --- a/addons/mail/static/src/models/follower_subtype_list/follower_subtype_list.js +++ b/addons/mail/static/src/models/follower_subtype_list/follower_subtype_list.js @@ -2,10 +2,11 @@ import { registerModel } from '@mail/model/model_core'; import { attr, one } from '@mail/model/model_field'; +import { replace } from '@mail/model/model_field_command'; registerModel({ name: 'FollowerSubtypeList', - identifyingFields: ['follower'], + identifyingFields: ['dialogOwner'], recordMethods: { /** * Returns whether the given html element is inside this follower subtype list. @@ -25,14 +26,13 @@ registerModel({ /** * States the dialog displaying this follower subtype list. */ - dialog: one('Dialog', { + dialogOwner: one('Dialog', { inverse: 'followerSubtypeList', isCausal: true, readonly: true, }), follower: one('Follower', { - inverse: 'subtypeList', - readonly: true, + related: 'dialogOwner.followerOwnerAsSubtypeList', required: true, }), },