flectra/addons/mail/static/src/js/document_viewer.js

353 lines
9.9 KiB
JavaScript

flectra.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_rotate': '_onRotate',
'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',
'keyup': '_onKeyUp',
'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 match = attachment.mimetype.match("(image|video|application/pdf)");
if (match) {
attachment.type = match[1];
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();
},
/**
* Get CSS transform property based on scale and angle
*
* @private
* @param {float} scale
* @param {float} angle
*/
_getTransform: function(scale, angle) {
return 'scale3d(' + scale + ', ' + scale + ', 1) rotate(' + angle + 'deg)'
},
/**
* Rotate image clockwise by provided angle
*
* @private
* @param {float} angle
*/
_rotate: function (angle) {
this._reset();
var new_angle = (this.angle || 0) + angle;
this.$('.o_viewer_img').css('transform', this._getTransform(this.scale, new_angle));
this.$('.o_viewer_img').css('max-width', new_angle % 180 !== 0 ? $(document).height() : '100%');
this.$('.o_viewer_img').css('max-height', new_angle % 180 !== 0 ? $(document).width() : '100%');
this.angle = new_angle;
},
/**
* Zoom in/out image by provided scale
*
* @private
* @param {integer} scale
*/
_zoom: function (scale) {
if (scale > 0.5) {
this.$('.o_viewer_img').css('transform', this._getTransform(scale, this.angle || 0));
this.scale = scale;
}
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {MouseEvent} e
*/
_onClose: function (e) {
e.preventDefault();
this.$el.modal('hide');
this.trigger_up('document_viewer_closed');
},
/**
* 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;
}
},
/**
* Close popup on ESCAPE keyup
*
* @private
* @param {KeyEvent} e
*/
_onKeyUp: function (e) {
switch (e.which) {
case $.ui.keyCode.ESCAPE:
e.preventDefault();
this._onClose(e);
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
*/
_onRotate: function (e) {
e.preventDefault();
this._rotate(90);
},
/**
* @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;
});