[IMP] mail: Add a preview popup for attachments
Purpose ======= The goal is that when you click on an attachment, you should get a preview of it and then you get the possibility to download it.
This commit is contained in:
committed by
Yannick Tivisse
parent
fa432175e9
commit
46699c5214
@@ -135,6 +135,7 @@
|
||||
<script type="text/javascript" src="/bus/static/src/js/bus.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/chat_window.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/thread.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/document_viewer.js"></script>
|
||||
<script type="text/javascript" src="/im_livechat/static/src/js/im_livechat.js"></script>
|
||||
<t t-call="web.less_helpers"/>
|
||||
<link rel="stylesheet" href="/im_livechat/static/src/less/im_livechat_bootstrap.less"/>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base64
|
||||
import json
|
||||
import logging
|
||||
import psycopg2
|
||||
import werkzeug
|
||||
|
||||
@@ -2,6 +2,7 @@ odoo.define('mail.composer', function (require) {
|
||||
"use strict";
|
||||
|
||||
var chat_mixin = require('mail.chat_mixin');
|
||||
var DocumentViewer = require('mail.DocumentViewer');
|
||||
var utils = require('mail.utils');
|
||||
|
||||
var core = require('web.core');
|
||||
@@ -354,6 +355,8 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
"click .o_composer_button_send": "send_message",
|
||||
"click .o_composer_button_add_attachment": "on_click_add_attachment",
|
||||
"click .o_attachment_delete": "on_attachment_delete",
|
||||
"click .o_attachment_download": "_onAttachmentDownload",
|
||||
"click .o_attachment_view": "_onAttachmentView",
|
||||
},
|
||||
// RPCs done to fetch the mention suggestions are throttled with the following value
|
||||
MENTION_THROTTLE: 200,
|
||||
@@ -758,6 +761,29 @@ var BasicComposer = Widget.extend(chat_mixin, {
|
||||
focus: function () {
|
||||
this.$input.focus();
|
||||
},
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onAttachmentDownload: function (event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onAttachmentView: function (event) {
|
||||
var activeAttachmentID = $(event.currentTarget).data('id');
|
||||
var attachments = this.get('attachment_ids');
|
||||
if (activeAttachmentID) {
|
||||
var attachmentViewer = new DocumentViewer(this, attachments, activeAttachmentID);
|
||||
attachmentViewer.appendTo($('body'));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
var ExtendedComposer = BasicComposer.extend({
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
odoo.define('mail.DocumentViewer', function (require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var SCROLL_ZOOM_STEP = 0.1;
|
||||
var ZOOM_STEP = 0.5;
|
||||
|
||||
var DocumentViewer = Widget.extend({
|
||||
template: "DocumentViewer",
|
||||
events: {
|
||||
'click .o_download_btn': '_onDownload',
|
||||
'click .o_viewer_img': '_onImageClicked',
|
||||
'click .o_viewer_video': '_onVideoClicked',
|
||||
'click .move_next': '_onNext',
|
||||
'click .move_previous': '_onPrevious',
|
||||
'click .o_zoom_in': '_onZoomIn',
|
||||
'click .o_zoom_out': '_onZoomOut',
|
||||
'click .o_close_btn, .o_viewer_img_wrapper': '_onClose',
|
||||
'click .o_print_btn': '_onPrint',
|
||||
'DOMMouseScroll .o_viewer_content': '_onScroll', // Firefox
|
||||
'mousewheel .o_viewer_content': '_onScroll', // Chrome, Safari, IE
|
||||
'keydown': '_onKeydown',
|
||||
'mousedown .o_viewer_img': '_onStartDrag',
|
||||
'mousemove .o_viewer_content': '_onDrag',
|
||||
'mouseup .o_viewer_content': '_onEndDrag'
|
||||
},
|
||||
/**
|
||||
* The documentViewer takes an array of objects describing attachments in
|
||||
* argument, and the ID of an active attachment (the one to display first).
|
||||
* Documents that are not of type image or video are filtered out.
|
||||
*
|
||||
* @override
|
||||
* @param {Array[Object]} attachments list of attachments
|
||||
* @param {integer} activeAttachmentID
|
||||
*/
|
||||
init: function (parent, attachments, activeAttachmentID) {
|
||||
this._super.apply(this, arguments);
|
||||
this.attachment = _.filter(attachments, function (attachment) {
|
||||
var type = attachment.mimetype.split('/').shift();
|
||||
if (type === 'image' || type === 'video') {
|
||||
attachment.type = type;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
this.activeAttachment = _.findWhere(attachments, {id: activeAttachmentID});
|
||||
this._reset();
|
||||
},
|
||||
/**
|
||||
* Open a modal displaying the active attachment
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this.$el.modal('show');
|
||||
this.$el.on('hidden.bs.modal', _.bind(this._onDestroy, this));
|
||||
this.$('.o_viewer_img').load(_.bind(this._onImageLoaded, this));
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_next: function () {
|
||||
var index = _.findIndex(this.attachment, this.activeAttachment);
|
||||
index = (index + 1) % this.attachment.length;
|
||||
this.activeAttachment = this.attachment[index];
|
||||
this._updateContent();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_previous: function () {
|
||||
var index = _.findIndex(this.attachment, this.activeAttachment);
|
||||
index = index === 0 ? this.attachment.length - 1 : index - 1;
|
||||
this.activeAttachment = this.attachment[index];
|
||||
this._updateContent();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_reset: function () {
|
||||
this.scale = 1;
|
||||
this.dragStartX = this.dragstopX = 0;
|
||||
this.dragStartY = this.dragstopY = 0;
|
||||
},
|
||||
/**
|
||||
* Render the active attachment
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_updateContent: function () {
|
||||
this.$('.o_viewer_content').html(QWeb.render('DocumentViewer.Content', {
|
||||
widget: this
|
||||
}));
|
||||
this.$('.o_viewer_img').load(_.bind(this._onImageLoaded, this));
|
||||
this._reset();
|
||||
},
|
||||
/**
|
||||
* Zoom in/out image by provided scale
|
||||
*
|
||||
* @private
|
||||
* @param {integer} scale
|
||||
*/
|
||||
_zoom: function (scale) {
|
||||
if (scale > 0.5) {
|
||||
this.$('.o_viewer_img').css('transform', 'scale3d(' + scale + ', ' + scale + ', 1)');
|
||||
this.scale = scale;
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onClose: function (e) {
|
||||
e.preventDefault();
|
||||
this.$el.modal('hide');
|
||||
},
|
||||
/**
|
||||
* When popup close complete destroyed modal even DOM footprint too
|
||||
* @private
|
||||
*/
|
||||
_onDestroy: function () {
|
||||
if (this.isDestroyed()) {
|
||||
return;
|
||||
}
|
||||
this.$el.modal('hide');
|
||||
this.$el.remove();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onDownload: function (e) {
|
||||
e.preventDefault();
|
||||
window.location = '/web/content/' + this.activeAttachment.id + '?download=true';
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onDrag: function (e) {
|
||||
e.preventDefault();
|
||||
if (this.enableDrag) {
|
||||
var $image = this.$('.o_viewer_img');
|
||||
var $zoomer = this.$('.o_viewer_zoomer');
|
||||
var top = $image.prop('offsetHeight') * this.scale > $zoomer.height() ? e.clientY - this.dragStartY : 0;
|
||||
var left = $image.prop('offsetWidth') * this.scale > $zoomer.width() ? e.clientX - this.dragStartX : 0;
|
||||
$zoomer.css("transform", "translate3d("+ left +"px, " + top + "px, 0)");
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onEndDrag: function (e) {
|
||||
e.preventDefault();
|
||||
if (this.enableDrag) {
|
||||
this.enableDrag = false;
|
||||
this.dragstopX = e.clientX - this.dragStartX;
|
||||
this.dragstopY = e.clientY - this.dragStartY;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* On click of image do not close modal so stop event propagation
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onImageClicked: function (e) {
|
||||
e.stopPropagation();
|
||||
},
|
||||
/**
|
||||
* Remove loading indicator when image loaded
|
||||
* @private
|
||||
*/
|
||||
_onImageLoaded: function () {
|
||||
this.$('.o_loading_img').hide();
|
||||
},
|
||||
/**
|
||||
* Move next previous attachment on keyboard right left key
|
||||
*
|
||||
* @private
|
||||
* @param {KeyEvent} e
|
||||
*/
|
||||
_onKeydown: function (e){
|
||||
switch (e.which) {
|
||||
case $.ui.keyCode.RIGHT:
|
||||
e.preventDefault();
|
||||
this._next();
|
||||
break;
|
||||
case $.ui.keyCode.LEFT:
|
||||
e.preventDefault();
|
||||
this._previous();
|
||||
break;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onNext: function (e) {
|
||||
e.preventDefault();
|
||||
this._next();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onPrevious: function (e) {
|
||||
e.preventDefault();
|
||||
this._previous();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onPrint: function (e) {
|
||||
e.preventDefault();
|
||||
var src = this.$('.o_viewer_img').prop('src');
|
||||
var script = QWeb.render('PrintImage', {
|
||||
src: src
|
||||
});
|
||||
var printWindow = window.open('about:blank', "_new");
|
||||
printWindow.document.open();
|
||||
printWindow.document.write(script);
|
||||
printWindow.document.close();
|
||||
},
|
||||
/**
|
||||
* Zoom image on scroll
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onScroll: function (e) {
|
||||
var scale;
|
||||
if (e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) {
|
||||
scale = this.scale + SCROLL_ZOOM_STEP;
|
||||
this._zoom(scale);
|
||||
} else {
|
||||
scale = this.scale - SCROLL_ZOOM_STEP;
|
||||
this._zoom(scale);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onStartDrag: function (e) {
|
||||
e.preventDefault();
|
||||
this.enableDrag = true;
|
||||
this.dragStartX = e.clientX - (this.dragstopX || 0);
|
||||
this.dragStartY = e.clientY - (this.dragstopY || 0);
|
||||
},
|
||||
/**
|
||||
* On click of video do not close modal so stop event propagation
|
||||
* and provide play/pause the video instead of quitting it
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onVideoClicked: function (e) {
|
||||
e.stopPropagation();
|
||||
var videoElement = e.target;
|
||||
if (videoElement.paused) {
|
||||
videoElement.play();
|
||||
} else {
|
||||
videoElement.pause();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onZoomIn: function (e) {
|
||||
e.preventDefault();
|
||||
var scale = this.scale + ZOOM_STEP;
|
||||
this._zoom(scale);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} e
|
||||
*/
|
||||
_onZoomOut: function (e) {
|
||||
e.preventDefault();
|
||||
var scale = this.scale - ZOOM_STEP;
|
||||
this._zoom(scale);
|
||||
},
|
||||
});
|
||||
return DocumentViewer;
|
||||
});
|
||||
@@ -2,6 +2,7 @@ odoo.define('mail.ChatThread', function (require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var DocumentViewer = require('mail.DocumentViewer');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
@@ -30,6 +31,8 @@ var Thread = Widget.extend({
|
||||
"click img": "on_click_redirect",
|
||||
"click strong": "on_click_redirect",
|
||||
"click .o_thread_show_more": "on_click_show_more",
|
||||
"click .o_attachment_download": "_onAttachmentDownload",
|
||||
"click .o_attachment_view": "_onAttachmentView",
|
||||
"click .o_thread_message_needaction": function (event) {
|
||||
var message_id = $(event.currentTarget).data('message-id');
|
||||
this.trigger("mark_as_read", message_id);
|
||||
@@ -110,6 +113,8 @@ var Thread = Widget.extend({
|
||||
ORDER: ORDER,
|
||||
}));
|
||||
|
||||
this.attachments = _.uniq(_.flatten(_.map(messages, 'attachment_ids')));
|
||||
|
||||
_.each(msgs, function(msg) {
|
||||
var $msg = self.$('.o_thread_message[data-message-id="'+ msg.id +'"]');
|
||||
$msg.find('.o_mail_timestamp').data('date', msg.date);
|
||||
@@ -300,6 +305,29 @@ var Thread = Widget.extend({
|
||||
destroy: function () {
|
||||
clearInterval(this.update_timestamps_interval);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onAttachmentDownload: function (event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
_onAttachmentView: function (event) {
|
||||
var activeAttachmentID = $(event.currentTarget).data('id');
|
||||
if (activeAttachmentID) {
|
||||
var attachmentViewer = new DocumentViewer(this, this.attachments, activeAttachmentID);
|
||||
attachmentViewer.appendTo($('body'));
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Thread.ORDER = ORDER;
|
||||
|
||||
@@ -238,36 +238,60 @@
|
||||
100% { background: @odoo-brand-optional }
|
||||
}
|
||||
|
||||
@o-mail-attachment-image-size: 60px;
|
||||
@o-mail-attachment-image-size: 100px;
|
||||
.o_attachment {
|
||||
position: relative;
|
||||
width: 2*@o-mail-attachment-image-size;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
height: @o-mail-attachment-image-size;
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.o_image {
|
||||
.o-position-absolute(@top: 0, @left: @o-mail-attachment-image-size/2);
|
||||
width: @o-mail-attachment-image-size;
|
||||
height: @o-mail-attachment-image-size;
|
||||
width: @o-mail-attachment-image-size;
|
||||
margin: 5px;
|
||||
.o_image_box {
|
||||
position: relative;
|
||||
img {
|
||||
width: @o-mail-attachment-image-size;
|
||||
height: @o-mail-attachment-image-size;
|
||||
}
|
||||
.o_image_overlay{
|
||||
display: none;
|
||||
}
|
||||
&:hover .o_image_overlay {
|
||||
display: block;
|
||||
.o-position-absolute(@top: 0, @left: 0, @right:0, @bottom:0);
|
||||
z-index: 20;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
.o_attachment_download {
|
||||
.o-position-absolute(@left: 10px, @bottom:5px);
|
||||
}
|
||||
.o_attachment_play {
|
||||
.o-position-absolute(@top: 50%, @left: 50%);
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.o_overlay_download {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
i {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_attachment_name {
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
margin-top: @o-mail-attachment-image-size;
|
||||
overflow: hidden;
|
||||
.caption {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
color: @odoo-main-text-color;
|
||||
overflow: hidden;
|
||||
padding: 5px;
|
||||
a {
|
||||
color: @odoo-main-text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.o_attachment_progress_bar {
|
||||
display: none;
|
||||
}
|
||||
.o_attachment_delete {
|
||||
.o-position-absolute(@top: 0, @right: 0);
|
||||
.o-position-absolute(@top: -10px, @right: -8px);
|
||||
color: @odoo-main-text-color;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
@@ -289,9 +313,76 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .o_attachment_delete {
|
||||
opacity: 1;
|
||||
.o-transition(opacity, 0.2s, linear);
|
||||
}
|
||||
}
|
||||
|
||||
.o_modal_fullscreen {
|
||||
.o_viewer_content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
.o_viewer-header {
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
padding: 10px 10px 0;
|
||||
background-color: rgba(0, 0, 0, 0.45);
|
||||
cursor: auto;
|
||||
.o_image_caption {
|
||||
color: #FFFFFF;
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
.o_loading_img {
|
||||
.o-position-absolute(@top: 50%);
|
||||
width: 25px;
|
||||
right: 50%;
|
||||
z-index: 1;
|
||||
}
|
||||
.o_viewer_img_wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
.o_viewer_zoomer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.o-flex-display();
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
img, video {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
transition: 0.3s cubic-bezier(0, 0, 0.49, 1.6) 0s, opacity 0.15s;
|
||||
}
|
||||
.o_viewer_video {
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.o_viewer_toolbar {
|
||||
.o-position-absolute(@left: 50%);
|
||||
bottom: 15px;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 8px 10px 0px 10px;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
.arrow {
|
||||
.o-position-absolute(@top: 50%);
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.arrow-left {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.arrow-right {
|
||||
right: 0;
|
||||
}
|
||||
i.fa {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,6 @@
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.o_mail_body_long {
|
||||
|
||||
@@ -18,6 +18,87 @@
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="DocumentViewer.Content">
|
||||
<div class="o_viewer_content">
|
||||
<div class="o_viewer-header">
|
||||
<h2 class="o_image_caption"><t t-esc="widget.activeAttachment.name"/></h2>
|
||||
<ul class="list-inline pull-right">
|
||||
<li t-if="widget.activeAttachment.type == 'image'">
|
||||
<a class="o_print_btn" href="#">
|
||||
<i class="fa fa-2x fa-print"/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="o_close_btn" href="#">
|
||||
<i class="fa fa-2x fa-times"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="o_viewer_img_wrapper">
|
||||
<div class="o_viewer_zoomer">
|
||||
<div t-if="widget.activeAttachment.type == 'image'" class="o_loading_img">
|
||||
<i class="fa fa-spinner fa-spin fa-3x fa-fw" aria-hidden="true"/>
|
||||
</div>
|
||||
<img t-if="widget.activeAttachment.type == 'image'" class="o_viewer_img" t-attf-src="/web/image/#{widget.activeAttachment.id}?unique=1"/>
|
||||
<video t-if="widget.activeAttachment.type == 'video'" class="o_viewer_video" controls="controls">
|
||||
<source t-attf-src="/web/image/#{widget.activeAttachment.id}" t-att-data-type="widget.activeAttachment.mimetype"/>
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
<div t-if="widget.activeAttachment.type == 'image'" class="o_viewer_toolbar">
|
||||
<ul class="list-inline">
|
||||
<li>
|
||||
<a class="o_zoom_out" href="#">
|
||||
<i class="fa fa-2x fa-search-minus"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="o_zoom_in" href="#">
|
||||
<i class="fa fa-2x fa-search-plus"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="o_download_btn" href="#">
|
||||
<i class="fa fa-2x fa-download"/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="DocumentViewer">
|
||||
<div class="modal o_modal_fullscreen" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<t t-call="DocumentViewer.Content"/>
|
||||
<a class="arrow arrow-left move_previous" href="#">
|
||||
<span class="fa fa-3x fa-chevron-left"/>
|
||||
</a>
|
||||
<a class="arrow arrow-right move_next" href="#">
|
||||
<span class="fa fa-3x fa-chevron-right"/>
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="PrintImage">
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function onload_img() {
|
||||
setTimeout('print_img()', 10);
|
||||
}
|
||||
function print_img() {
|
||||
window.print();
|
||||
window.close();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload='onload_img()'>
|
||||
<img t-att-src='src' />
|
||||
</body>
|
||||
</html>
|
||||
</t>
|
||||
|
||||
<!-- When a channel is empty-->
|
||||
<div t-name="mail.EmptyChannel" class="o_mail_no_content">
|
||||
<t t-if="options.channel_id==='channel_inbox'">
|
||||
@@ -175,10 +256,47 @@
|
||||
</t>
|
||||
|
||||
<t t-name="mail.Attachment">
|
||||
<t t-set="type" t-value="attachment.mimetype.split('/').shift()"/>
|
||||
<div t-attf-class="o_attachment #{attachment.upload ? 'o_attachment_uploading' : ''}" t-att-title="attachment.name">
|
||||
<a class="o_image" t-att-href='attachment.url' target="_blank" t-att-data-mimetype="attachment.mimetype" t-attf-data-src="/web/image/#{attachment.id}/100x80">
|
||||
<span class='o_attachment_name'><t t-esc='attachment.name'/></span>
|
||||
</a>
|
||||
<t t-if="type == 'image'">
|
||||
<div class="o_image_box">
|
||||
<img t-attf-src="/web/image/#{attachment.id}/200x200/?crop=True"/>
|
||||
<div t-attf-class="o_image_overlay o_attachment_view" t-att-data-id="attachment.id">
|
||||
<a class="o_attachment_download" t-att-href='attachment.url' target="_blank">
|
||||
<i t-attf-class="fa fa-2x fa-arrow-circle-o-down" title="Download this attachment" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-elif="type == 'video'">
|
||||
<div class="o_image_box o_image_preview">
|
||||
<img class="o_image" t-att-data-mimetype="attachment.mimetype"/>
|
||||
<div t-attf-class="o_image_overlay o_attachment_view" t-att-data-id="attachment.id">
|
||||
<a class="o_attachment_play">
|
||||
<i t-attf-class="fa fa-2x fa-play-circle" title="Play this video" aria-hidden="true"></i>
|
||||
</a>
|
||||
<a class="o_attachment_download" t-att-href='attachment.url' target="_blank">
|
||||
<i t-attf-class="fa fa-2x fa-arrow-circle-o-down" title="Download this attachment" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="o_image_box">
|
||||
<img class="o_image" t-att-data-mimetype="attachment.mimetype"/>
|
||||
<div t-attf-class="o_image_overlay">
|
||||
<a class="o_overlay_download" t-att-href='attachment.url' target="_blank"/>
|
||||
<a class="o_attachment_download" t-att-href='attachment.url' target="_blank">
|
||||
<i t-attf-class="fa fa-2x fa-arrow-circle-o-down" title="Download this attachment" aria-hidden="true"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<div class="caption">
|
||||
<a t-att-href='attachment.url' target="_blank">
|
||||
<t t-esc='attachment.name'/>
|
||||
</a>
|
||||
</div>
|
||||
<t t-if="editable">
|
||||
<div class="o_attachment_delete">
|
||||
<i class='fa fa-times-circle' title="Delete this attachment" t-att-data-id="attachment.id"/>
|
||||
|
||||
@@ -494,6 +494,92 @@ QUnit.test('chatter: post, receive and star messages', function (assert) {
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test('chatter: Attachment viewer', function (assert) {
|
||||
assert.expect(5);
|
||||
this.data.partner.records[0].message_ids = [1];
|
||||
var messages = [{
|
||||
attachment_ids: [{
|
||||
filename: 'image1.jpg',
|
||||
id:1,
|
||||
mimetype: 'image/jpeg',
|
||||
name: 'Test Image 1',
|
||||
url: '/web/content/1?download=true'
|
||||
},{
|
||||
filename: 'image2.jpg',
|
||||
id:2,
|
||||
mimetype: 'image/jpeg',
|
||||
name: 'Test Image 2',
|
||||
url: '/web/content/2?download=true'
|
||||
},{
|
||||
filename: 'image3.jpg',
|
||||
id:3,
|
||||
mimetype: 'image/jpeg',
|
||||
name: 'Test Image 3',
|
||||
url: '/web/content/3?download=true'
|
||||
}],
|
||||
author_id: ["1", "John Doe"],
|
||||
body: "Attachement viewer test",
|
||||
date: moment("2016-12-20 09:35:40"),
|
||||
displayed_author: "John Doe",
|
||||
id: 1,
|
||||
is_note: false,
|
||||
is_starred: false,
|
||||
model: 'partner',
|
||||
res_id: 2,
|
||||
}];
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<sheet>' +
|
||||
'<field name="foo"/>' +
|
||||
'</sheet>' +
|
||||
'<div class="oe_chatter">' +
|
||||
'<field name="message_ids" widget="mail_thread" options="{\'display_log_button\': True}"/>' +
|
||||
'</div>' +
|
||||
'</form>',
|
||||
res_id: 2,
|
||||
mockRPC: function (route) {
|
||||
if(_.str.contains(route, '/mail/attachment/preview/')){
|
||||
var canvas = document.createElement('canvas');
|
||||
return $.when(canvas.toDataURL());
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
intercepts: {
|
||||
get_messages: function (event) {
|
||||
event.stopPropagation();
|
||||
var requested_msgs = _.filter(messages, function (msg) {
|
||||
return _.contains(event.data.options.ids, msg.id);
|
||||
});
|
||||
event.data.callback($.when(requested_msgs));
|
||||
},
|
||||
get_bus: function (event) {
|
||||
event.stopPropagation();
|
||||
event.data.callback(new Bus());
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.strictEqual(form.$('.o_thread_message .o_attachment').length, 3,
|
||||
"there should be three attachment on message");
|
||||
assert.strictEqual(form.$('.o_thread_message .o_attachment .caption a').first().attr('href'), '/web/content/1?download=true',
|
||||
"image caption should have correct download link");
|
||||
// click on first image attachement
|
||||
form.$('.o_thread_message .o_attachment .o_image_box .o_image_overlay').first().click();
|
||||
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[src*="/web/image/1?unique=1"]').length, 1,
|
||||
"Modal popup should open with first image src");
|
||||
// click on next button
|
||||
$('.modal .arrow.arrow-right.move_next span').click();
|
||||
assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[src*="/web/image/2?unique=1"]').length, 1,
|
||||
"Modal popup should have now second image src");
|
||||
assert.strictEqual($('.o_modal_fullscreen .o_viewer_toolbar .o_download_btn').length, 1,
|
||||
"Modal popup should have download button");
|
||||
// close attachment popup
|
||||
$('.o_modal_fullscreen .o_viewer-header .o_close_btn').click();
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('form activity widget: schedule next activity', function (assert) {
|
||||
assert.expect(5);
|
||||
this.data.partner.records[0].activity_ids = [1];
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<script type="text/javascript" src="/mail/static/src/js/client_action.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/chat_window.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/extended_chat_window.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/document_viewer.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/composer.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/chat_manager.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/chatter.js"></script>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
background-image: url('/web/static/src/img/mimetypes/unknown.png');
|
||||
background-size: contain;
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
height: 100px;
|
||||
display: inline-block;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/bus/static/src/js/bus.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/chat_window.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/document_viewer.js"></script>
|
||||
<script type="text/javascript" src="/mail/static/src/js/thread.js"></script>
|
||||
<script type="text/javascript" src="/im_livechat/static/src/js/im_livechat.js"></script>
|
||||
<link rel="stylesheet" href="/mail/static/src/less/chat_window.less"></link>
|
||||
|
||||
Reference in New Issue
Block a user