[IMP] mail: improve attachment_viewer
This commit improves the expendability of the attachment_viewer model and component by making it less dependent on attachment_list. This is required by the refactoring in wowl of the documents app(s). TaskId-2898342 closes odoo/odoo#94930 Related: odoo/enterprise#28976 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
@@ -93,13 +93,13 @@ export class AttachmentViewer extends Component {
|
||||
* @private
|
||||
*/
|
||||
_handleImageLoad() {
|
||||
if (!this.attachmentViewer.exists() || !this.attachmentViewer.attachment) {
|
||||
if (!this.attachmentViewer.exists() || !this.attachmentViewer.attachmentViewerViewable) {
|
||||
return;
|
||||
}
|
||||
const refs = this._getRefs();
|
||||
const image = refs[`image_${this.attachmentViewer.attachment.id}`];
|
||||
const image = refs[`image_${this.attachmentViewer.attachmentViewerViewable.localId}`];
|
||||
if (
|
||||
this.attachmentViewer.attachment.isImage &&
|
||||
this.attachmentViewer.attachmentViewerViewable.isImage &&
|
||||
(!image || !image.complete)
|
||||
) {
|
||||
this.attachmentViewer.update({ isImageLoading: true });
|
||||
@@ -142,7 +142,7 @@ export class AttachmentViewer extends Component {
|
||||
_updateZoomerStyle() {
|
||||
const attachmentViewer = this.attachmentViewer;
|
||||
const refs = this._getRefs();
|
||||
const image = refs[`image_${this.attachmentViewer.attachment.id}`];
|
||||
const image = refs[`image_${this.attachmentViewer.attachmentViewerViewable.localId}`];
|
||||
const tx = image.offsetWidth * attachmentViewer.scale > this._zoomerRef.el.offsetWidth
|
||||
? this._translate.x + this._translate.dx
|
||||
: 0;
|
||||
|
||||
@@ -5,24 +5,24 @@
|
||||
<t t-if="attachmentViewer">
|
||||
<div class="o_AttachmentViewer flex-column align-items-center d-flex w-100 h-100" t-attf-class="{{ className }}" t-on-click="attachmentViewer.onClick" t-on-keydown="_onKeydown" tabindex="0" t-ref="root">
|
||||
<div class="o_AttachmentViewer_header d-flex w-100 bg-black-75 text-400" t-on-click="attachmentViewer.onClickHeader">
|
||||
<t t-if="attachmentViewer.attachment.isViewable">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isViewable">
|
||||
<div class="o_AttachmentViewer_headerItem o_AttachmentViewer_icon d-flex align-items-center ms-4 me-2">
|
||||
<t t-if="attachmentViewer.attachment.isImage">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isImage">
|
||||
<i class="fa fa-picture-o" role="img" title="Image"/>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachment.isPdf">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isPdf">
|
||||
<i class="fa fa-file-text" role="img" title="PDF file"/>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachment.isText">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isText">
|
||||
<i class="fa fa-file-text" role="img" title="Text file"/>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachment.isVideo">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isVideo">
|
||||
<i class="fa fa-video-camera" role="img" title="Video"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<div class="o_AttachmentViewer_headerItem o_AttachmentViewer_name d-flex align-items-center mx-2">
|
||||
<span class="o_AttachmentViewer_nameText text-truncate" t-esc="attachmentViewer.attachment.displayName"/>
|
||||
<span class="o_AttachmentViewer_nameText text-truncate" t-esc="attachmentViewer.attachmentViewerViewable.displayName"/>
|
||||
</div>
|
||||
<div class="flex-grow-1"/>
|
||||
<div class="o_AttachmentViewer_buttonDownload o_AttachmentViewer_headerItem o_AttachmentViewer_headerItemButton d-flex align-items-center px-3 o_cursor_pointer" t-on-click="attachmentViewer.onClickDownload" role="button" title="Download">
|
||||
@@ -35,33 +35,33 @@
|
||||
<i class="fa fa-fw fa-times" role="img"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_AttachmentViewer_main position-absolute top-0 bottom-0 start-0 end-0 align-items-center justify-content-center d-flex" t-att-class="{ 'o_with_img overflow-hidden': attachmentViewer.attachment.isImage }" t-on-mousemove="_onMousemoveView">
|
||||
<t t-if="attachmentViewer.attachment.isImage">
|
||||
<div class="o_AttachmentViewer_main position-absolute top-0 bottom-0 start-0 end-0 align-items-center justify-content-center d-flex" t-att-class="{ 'o_with_img overflow-hidden': attachmentViewer.attachmentViewerViewable.isImage }" t-on-mousemove="_onMousemoveView">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isImage">
|
||||
<div class="o_AttachmentViewer_zoomer position-absolute align-items-center justify-content-center d-flex w-100 h-100" t-ref="zoomer">
|
||||
<t t-if="attachmentViewer.isImageLoading">
|
||||
<div class="o_AttachmentViewer_loading position-absolute">
|
||||
<i class="fa fa-3x fa-circle-o-notch fa-fw fa-spin text-white" role="img" title="Loading"/>
|
||||
</div>
|
||||
</t>
|
||||
<img class="o_AttachmentViewer_view o_AttachmentViewer_viewImage mw-100 mh-100 bg-black" t-on-click="attachmentViewer.onClickImage" t-on-mousedown="_onMousedownImage" t-on-wheel="_onWheelImage" t-on-load="attachmentViewer.onLoadImage" t-att-src="attachmentViewer.imageUrl" t-att-style="attachmentViewer.imageStyle" draggable="false" alt="Viewer" t-key="'image_' + attachmentViewer.attachment.id" t-ref="image_{{ attachmentViewer.attachment.id }}"/>
|
||||
<img class="o_AttachmentViewer_view o_AttachmentViewer_viewImage mw-100 mh-100 bg-black" t-on-click="attachmentViewer.onClickImage" t-on-mousedown="_onMousedownImage" t-on-wheel="_onWheelImage" t-on-load="attachmentViewer.onLoadImage" t-att-src="attachmentViewer.attachmentViewerViewable.imageUrl" t-att-style="attachmentViewer.imageStyle" draggable="false" alt="Viewer" t-key="'image_' + attachmentViewer.attachmentViewerViewable.localId" t-ref="image_{{ attachmentViewer.attachmentViewerViewable.localId }}"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachment.isPdf">
|
||||
<iframe class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_viewPdf w-75 h-100 bg-black border-0" t-ref="iframeViewerPdf" t-att-class="{ 'w-100': messaging.device.isSmall }" t-att-src="attachmentViewer.attachment.defaultSource"/>
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isPdf">
|
||||
<iframe class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_viewPdf w-75 h-100 bg-black border-0" t-ref="iframeViewerPdf" t-att-class="{ 'w-100': messaging.device.isSmall }" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachment.isText">
|
||||
<iframe class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_text w-75 h-100 bg-white border-0" t-att-src="attachmentViewer.attachment.defaultSource"/>
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isText">
|
||||
<iframe class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_text w-75 h-100 bg-white border-0" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachment.isUrlYoutube">
|
||||
<iframe allow="autoplay; encrypted-media" class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_youtube w-75 h-100 bg-black border-0" t-att-src="attachmentViewer.attachment.defaultSource" height="315" width="560"/>
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isUrlYoutube">
|
||||
<iframe allow="autoplay; encrypted-media" class="o_AttachmentViewer_view o_AttachmentViewer_viewIframe o_AttachmentViewer_youtube w-75 h-100 bg-black border-0" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource" height="315" width="560"/>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachment.isVideo">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isVideo">
|
||||
<video class="o_AttachmentViewer_view o_AttachmentViewer_viewVideo w-75 h-75 bg-black" t-att-class="{ 'w-100 h-100': messaging.device.isSmall }" t-on-click="attachmentViewer.onClickVideo" controls="controls">
|
||||
<source t-att-data-type="attachmentViewer.attachment.mimetype" t-att-src="attachmentViewer.attachment.defaultSource"/>
|
||||
<source t-att-data-type="attachmentViewer.attachmentViewerViewable.mimetype" t-att-src="attachmentViewer.attachmentViewerViewable.defaultSource"/>
|
||||
</video>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="attachmentViewer.attachment.isImage">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewable.isImage">
|
||||
<div class="o_AttachmentViewer_toolbar position-absolute bottom-0 d-flex" role="toolbar">
|
||||
<div class="o_AttachmentViewer_toolbarButton btn btn-dark p-3 rounded-0" t-on-click="_onClickZoomIn" title="Zoom In (+)" role="button">
|
||||
<i class="fa fa-fw fa-plus" role="img"/>
|
||||
@@ -83,7 +83,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="attachmentViewer.attachments.length > 1">
|
||||
<t t-if="attachmentViewer.attachmentViewerViewables.length > 1">
|
||||
<div class="o_AttachmentViewer_buttonNavigation o_AttachmentViewer_buttonNavigationPrevious o_AttachmentViewer_buttonNavigationPreviousIcon btn btn-dark position-absolute top-0 bottom-0 start-0 align-items-center justify-content-center d-flex my-auto ms-3 rounded-circle" t-on-click="attachmentViewer.onClickPrevious" title="Previous (Left-Arrow)" role="button">
|
||||
<span class="fa fa-chevron-left" role="img"/>
|
||||
</div>
|
||||
|
||||
@@ -300,6 +300,10 @@ registerModel({
|
||||
attachmentLists: many('AttachmentList', {
|
||||
inverse: 'attachments',
|
||||
}),
|
||||
attachmentViewerViewable: one('AttachmentViewerViewable', {
|
||||
inverse: 'attachmentOwner',
|
||||
isCausal: true,
|
||||
}),
|
||||
checksum: attr(),
|
||||
/**
|
||||
* States on which composer this attachment is currently being created.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { registerModel } from '@mail/model/model_core';
|
||||
import { attr, many, one } from '@mail/model/model_field';
|
||||
import { clear, insertAndReplace, replace } from '@mail/model/model_field_command';
|
||||
|
||||
registerModel({
|
||||
name: 'AttachmentViewer',
|
||||
@@ -59,7 +60,7 @@ registerModel({
|
||||
*/
|
||||
onClickDownload(ev) {
|
||||
ev.stopPropagation();
|
||||
this.attachment.download();
|
||||
this.attachmentViewerViewable.download();
|
||||
},
|
||||
/**
|
||||
* Called when clicking on the header. Stop propagation of event to prevent
|
||||
@@ -181,17 +182,27 @@ registerModel({
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @returns {string}
|
||||
*/
|
||||
_computeImageUrl() {
|
||||
if (!this.attachment) {
|
||||
return;
|
||||
_computeAttachmentViewerViewable() {
|
||||
if (this.attachmentList) {
|
||||
return insertAndReplace({
|
||||
attachmentOwner: replace(this.attachmentList.selectedAttachment),
|
||||
});
|
||||
}
|
||||
if (!this.attachment.accessToken && this.attachment.originThread && this.attachment.originThread.model === 'mail.channel') {
|
||||
return `/mail/channel/${this.attachment.originThread.id}/image/${this.attachment.id}`;
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeAttachmentViewerViewables() {
|
||||
if (this.attachmentList) {
|
||||
return insertAndReplace(
|
||||
this.attachmentList.viewableAttachments.map((attachment) => {
|
||||
return { attachmentOwner: replace(attachment) };
|
||||
})
|
||||
);
|
||||
}
|
||||
const accessToken = this.attachment.accessToken ? `?access_token=${this.attachment.accessToken}` : '';
|
||||
return `/web/image/${this.attachment.id}${accessToken}`;
|
||||
return clear();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -221,15 +232,14 @@ registerModel({
|
||||
angle: attr({
|
||||
default: 0,
|
||||
}),
|
||||
attachment: one('Attachment', {
|
||||
related: 'attachmentList.selectedAttachment',
|
||||
}),
|
||||
attachmentList: one('AttachmentList', {
|
||||
related: 'dialogOwner.attachmentListOwnerAsAttachmentView',
|
||||
required: true,
|
||||
}),
|
||||
attachments: many('Attachment', {
|
||||
related: 'attachmentList.viewableAttachments',
|
||||
attachmentViewerViewable: one("AttachmentViewerViewable", {
|
||||
compute: "_computeAttachmentViewerViewable",
|
||||
}),
|
||||
attachmentViewerViewables: many("AttachmentViewerViewable", {
|
||||
compute: "_computeAttachmentViewerViewables",
|
||||
}),
|
||||
/**
|
||||
* States the OWL component of this attachment viewer.
|
||||
@@ -249,13 +259,6 @@ registerModel({
|
||||
imageStyle: attr({
|
||||
compute: '_computeImageStyle',
|
||||
}),
|
||||
/**
|
||||
* Determines the source URL to use for the image.
|
||||
*/
|
||||
imageUrl: attr({
|
||||
compute: '_computeImageUrl',
|
||||
readonly: true,
|
||||
}),
|
||||
/**
|
||||
* Determine whether the user is currently dragging the image.
|
||||
* This is useful to determine whether a click outside of the image
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registerModel } from "@mail/model/model_core";
|
||||
import { attr, one } from "@mail/model/model_field";
|
||||
|
||||
/**
|
||||
* Intermediary model to facilitate adding support for additional
|
||||
* models to the AttachmentViewer.
|
||||
*/
|
||||
|
||||
registerModel({
|
||||
name: "AttachmentViewerViewable",
|
||||
identifyingFields: [["attachmentOwner"]],
|
||||
recordMethods: {
|
||||
download() {
|
||||
return this.attachmentOwner.download();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeAccessToken() {
|
||||
return this.attachmentOwner.accessToken;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeDefaultSource() {
|
||||
return this.attachmentOwner.defaultSource;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeDisplayName() {
|
||||
return this.attachmentOwner.displayName;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeImageUrl() {
|
||||
if (
|
||||
!this.attachmentOwner.accessToken &&
|
||||
this.attachmentOwner.originThread &&
|
||||
this.attachmentOwner.originThread.model === "mail.channel"
|
||||
) {
|
||||
return `/mail/channel/${this.attachmentOwner.originThread.id}/image/${this.attachmentOwner.id}`;
|
||||
}
|
||||
const accessToken = this.attachmentOwner.accessToken
|
||||
? `?access_token=${this.attachmentOwner.accessToken}`
|
||||
: "";
|
||||
return `/web/image/${this.attachmentOwner.id}${accessToken}`;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeIsImage() {
|
||||
return this.attachmentOwner.isImage;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeIsPdf() {
|
||||
return this.attachmentOwner.isPdf;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeIsText() {
|
||||
return this.attachmentOwner.isText;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeIsUrlYoutube() {
|
||||
return this.attachmentOwner.isUrlYoutube;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeIsVideo() {
|
||||
return this.attachmentOwner.isVideo;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeIsViewable() {
|
||||
return this.attachmentOwner.isViewable;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_computeMimetype() {
|
||||
return this.attachmentOwner.mimetype;
|
||||
},
|
||||
},
|
||||
fields: {
|
||||
attachmentOwner: one("Attachment", {
|
||||
inverse: 'attachmentViewerViewable',
|
||||
readonly: true,
|
||||
}),
|
||||
accessToken: attr({
|
||||
compute: "_computeAccessToken",
|
||||
}),
|
||||
defaultSource: attr({
|
||||
compute: "_computeDefaultSource",
|
||||
}),
|
||||
displayName: attr({
|
||||
compute: "_computeDisplayName",
|
||||
}),
|
||||
imageUrl: attr({
|
||||
compute: "_computeImageUrl",
|
||||
}),
|
||||
isImage: attr({
|
||||
compute: "_computeIsImage",
|
||||
}),
|
||||
isPdf: attr({
|
||||
compute: "_computeIsPdf",
|
||||
}),
|
||||
isText: attr({
|
||||
compute: "_computeIsText",
|
||||
}),
|
||||
isUrlYoutube: attr({
|
||||
compute: "_computeIsUrlYoutube",
|
||||
}),
|
||||
isVideo: attr({
|
||||
compute: "_computeIsVideo",
|
||||
}),
|
||||
isViewable: attr({
|
||||
compute: "_computeIsViewable",
|
||||
}),
|
||||
mimetype: attr({
|
||||
compute: "_computeMimetype",
|
||||
}),
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user