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; /** * This widget is deprecated, and should instead use AttachmentViewer component. * @see `mail/static/src/components/attachment_viewer/attachment_viewer.js` * TODO: remove this widget when it's not longer used * * @deprecated */ 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_zoom_reset': '_onZoomReset', '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} 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.type === 'url' ? attachment.url.match("(youtu|.png|.jpg|.gif)") : attachment.mimetype.match("(image|video|application/pdf|text)"); if (match) { attachment.fileType = match[1]; if (match[1].match("(.png|.jpg|.gif)")) { attachment.fileType = 'image'; } if (match[1] === 'youtu') { var youtube_array = attachment.url.split('/'); var youtube_token = youtube_array[youtube_array.length-1]; if (youtube_token.indexOf('watch') !== -1) { youtube_token = youtube_token.split('v=')[1]; var amp = youtube_token.indexOf('&') if (amp !== -1){ youtube_token = youtube_token.substring(0, amp); } } attachment.youtube = youtube_token; } return true; } }); this.activeAttachment = _.findWhere(attachments, {id: activeAttachmentID}); this.modelName = 'ir.attachment'; 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').on("load", _.bind(this._onImageLoaded, this)); this.$('[data-toggle="tooltip"]').tooltip({delay: 0}); return this._super.apply(this, arguments); }, /** * @override */ destroy: function () { if (this.isDestroyed()) { return; } this.$el.modal('hide'); this.$el.remove(); 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').on("load", _.bind(this._onImageLoaded, this)); this.$('[data-toggle="tooltip"]').tooltip({delay: 0}); 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; } this.$('.o_zoom_reset').add('.o_zoom_out').toggleClass('disabled', scale === 1); }, //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- /** * @private * @param {MouseEvent} e */ _onClose: function (e) { e.preventDefault(); this.destroy(); }, /** * When popup close complete destroyed modal even DOM footprint too * * @private */ _onDestroy: function () { this.destroy(); }, /** * @private * @param {MouseEvent} e */ _onDownload: function (e) { e.preventDefault(); window.location = '/web/content/' + this.modelName + '/' + this.activeAttachment.id + '/' + 'datas' + '?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)"); $image.css('cursor', 'move'); } }, /** * @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; this.$('.o_viewer_img').css('cursor', ''); } }, /** * 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); }, /** * @private * @param {MouseEvent} e */ _onZoomReset: function (e) { e.preventDefault(); this.$('.o_viewer_zoomer').css("transform", ""); this._zoom(1); }, }); return DocumentViewer; });