/* Copyright 2014 Therp BV () * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ odoo.define("attachment_preview", function(require) { "use strict"; var core = require("web.core"); var _t = core._t; var Chatter = require("mail.Chatter"); var basic_fields = require("web.basic_fields"); var FormRenderer = require("web.FormRenderer"); var Widget = require("web.Widget"); var active_attachment_id = 0; var active_attachment_index = 0; var first_click = true; var AttachmentPreviewMixin = { canPreview: function(extension) { return ( $.inArray(extension, [ "odt", "odp", "ods", "fodt", "pdf", "ott", "fodp", "otp", "fods", "ots", ]) > -1 ); }, getUrl: function( attachment_id, attachment_url, attachment_extension, attachment_title ) { var url = (window.location.origin || "") + "/attachment_preview/static/lib/ViewerJS/index.html" + "?type=" + encodeURIComponent(attachment_extension) + "&title=" + encodeURIComponent(attachment_title) + "#" + attachment_url.replace(window.location.origin, ""); return url; }, showPreview: function( attachment_id, attachment_url, attachment_extension, attachment_title, split_screen ) { var url = this.getUrl( attachment_id, attachment_url, attachment_extension, attachment_title ); if (split_screen) { this.trigger_up("onAttachmentPreview", {url: url}); } else { window.open(url); } }, }; Chatter.include(AttachmentPreviewMixin); Chatter.include({ events: _.extend({}, Chatter.prototype.events, { "click .o_attachment_preview": "_onPreviewAttachment", }), previewableAttachments: null, _openAttachmentBox: function() { var res = this._super.apply(this, arguments); this.getPreviewableAttachments().done( function(atts) { this.previewableAttachments = atts; this.updatePreviewButtons(atts); this.getParent().attachmentPreviewWidget.setAttachments(atts); }.bind(this) ); return res; }, update: function() { var res = this._super.apply(this, arguments); var self = this; if (this.getParent().$el.hasClass("attachment_preview")) { this._fetchAttachments().then(function() { self._openAttachmentBox(); self.getPreviewableAttachments().done(function(atts) { self.updatePreviewButtons(self.previewableAttachments); self.previewableAttachments = atts; self.getParent().attachmentPreviewWidget.setAttachments(atts); }); }); } return res; }, _onPreviewAttachment: function(event) { event.preventDefault(); var self = this, $target = $(event.currentTarget), split_screen = $target.attr("data-target") !== "new", attachment_id = parseInt($target.attr("data-id"), 10), attachment_url = $target.attr("data-url"), attachment_extension = $target.attr("data-extension"), attachment_title = $target.attr("data-original-title"); if (attachment_id !== active_attachment_id) { active_attachment_id = attachment_id; first_click = true; } if (attachment_extension) { this.showPreview( attachment_id, attachment_url, attachment_extension, attachment_title, split_screen ); } else { this._rpc({ model: "ir.attachment", method: "get_attachment_extension", args: [attachment_id], }).then(function(extension) { self.showPreview( attachment_id, attachment_url, extension, null, split_screen ); }); } }, getPreviewableAttachments: function() { var self = this; var deferred = $.Deferred(); var attachments = _.object( this.attachments.map(function(attachment) { return attachment.id; }), this.attachments.map(function(attachment) { return { url: attachment.url, extension: attachment.filename.split(".")[1], title: attachment.name, }; }) ); this._rpc({ model: "ir.attachment", method: "get_attachment_extension", args: [ _.map(_.keys(attachments), function(id) { return parseInt(id, 10); }), ], }).then( function(extensions) { var reviewableAttachments = _.map( _.keys( _.pick(extensions, function(extension) { return self.canPreview(extension); }) ), function(id) { return { id: id, url: attachments[id].url, extension: extensions[id], title: attachments[id].title, previewUrl: self.getUrl( id, attachments[id].url, extensions[id], id + " - " + attachments[id].title ), }; } ); deferred.resolve(reviewableAttachments); }, function() { deferred.reject(); } ); return deferred.promise(); }, updatePreviewButtons: function(previewableAttachments) { this.$el.find(".o_attachment_preview").each(function() { var $this = $(this); var id = $this.attr("data-id"); var att = _.findWhere(previewableAttachments, {id: id}); if (att) { $this.attr("data-extension", att.extension); } else { $this.remove(); } }); }, }); basic_fields.FieldBinaryFile.include(AttachmentPreviewMixin); basic_fields.FieldBinaryFile.include({ events: _.extend({}, basic_fields.FieldBinaryFile.prototype.events, { "click .fa-search": "_onPreview", }), _renderReadonly: function() { var self = this; this._super.apply(this, arguments); if (this.recordData.id) { this._getBinaryExtension().then(function(extension) { if (self.canPreview(extension)) { self._renderPreviewButton(extension); } }); } }, _renderPreviewButton: function(extension) { this.$previewBtn = $(""); this.$previewBtn.addClass("fa fa-search mr-2"); this.$previewBtn.attr("href", "javascript:void(0)"); this.$previewBtn.attr( "title", _.str.sprintf(_t("Preview %s"), this.field.string) ); this.$previewBtn.attr("data-extension", extension); this.$el.find(".fa-download").before(this.$previewBtn); }, _getBinaryExtension: function() { return this._rpc({ model: "ir.attachment", method: "get_binary_extension", args: [this.model, this.recordData.id, this.name, this.attrs.filename], }); }, _onPreview: function(event) { this.showPreview( null, _.str.sprintf( "/web/content?model=%s&field=%s&id=%d", this.model, this.name, this.recordData.id ), $(event.currentTarget).attr("data-extension"), _.str.sprintf(_t("Preview %s"), this.field.string), false ); event.stopPropagation(); }, }); var AttachmentPreviewWidget = Widget.extend({ template: "attachment_preview.AttachmentPreviewWidget", activeIndex: 0, attachments: null, events: { "click .attachment_preview_close": "_onCloseClick", "click .attachment_preview_previous": "_onPreviousClick", "click .attachment_preview_next": "_onNextClick", "click .attachment_preview_popout": "_onPopoutClick", }, start: function() { first_click = true; var res = this._super.apply(this, arguments); this.$overlay = this.$el.find(".attachment_preview_overlay"); this.$iframe = this.$el.find(".attachment_preview_iframe"); this.$current = this.$el.find(".attachment_preview_current"); return res; }, _onCloseClick: function() { this.hide(); }, _onPreviousClick: function() { this.previous(); }, _onNextClick: function() { this.next(); }, _onPopoutClick: function() { if (!this.attachments[this.activeIndex]) { return; } window.open(this.attachments[this.activeIndex].previewUrl); }, next: function() { var index = this.activeIndex + 1; if (index >= this.attachments.length) { index = 0; } this.activeIndex = index; this.updatePaginator(); this.loadPreview(); }, previous: function() { var index = this.activeIndex - 1; if (index < 0) { index = this.attachments.length - 1; } this.activeIndex = index; this.updatePaginator(); this.loadPreview(); }, show: function() { this.$el.removeClass("d-none"); this.trigger("shown"); }, hide: function() { first_click = true; this.$el.addClass("d-none"); this.trigger("hidden"); }, updatePaginator: function() { var value = _.str.sprintf( "%s / %s", this.activeIndex + 1, this.attachments.length ); this.$current.html(value); }, loadPreview: function() { if (this.attachments.length === 0) { this.$iframe.attr("src", "about:blank"); return; } if (first_click) { for (var i in this.attachments) { if (this.attachments[i].id === active_attachment_id.toString()) { active_attachment_index = i; first_click = false; } } } else { active_attachment_index = this.activeIndex; } var att = this.attachments[active_attachment_index]; this.$iframe.attr("src", att.previewUrl); }, setAttachments: function(attachments) { this.attachments = attachments; this.activeIndex = 0; this.updatePaginator(); this.loadPreview(); }, }); FormRenderer.include({ custom_events: _.extend({}, FormRenderer.prototype.custom_events, { onAttachmentPreview: "_onAttachmentPreview", }), attachmentPreviewWidget: null, init: function() { var res = this._super.apply(this, arguments); this.attachmentPreviewWidget = new AttachmentPreviewWidget(this); this.attachmentPreviewWidget.on( "hidden", this, this._attachmentPreviewWidgetHidden ); return res; }, start: function() { var self = this; return this._super.apply(this, arguments).then(function() { return self.attachmentPreviewWidget.insertAfter(self.$el); }); }, _attachmentPreviewWidgetHidden: function() { this.$el.removeClass("attachment_preview"); }, showAttachmentPreviewWidget: function() { this.$el.addClass("attachment_preview"); this.attachmentPreviewWidget.setAttachments( this.chatter.previewableAttachments ); this.attachmentPreviewWidget.show(); }, on_detach_callback: function() { this.attachmentPreviewWidget.hide(); return this._super.apply(this, arguments); }, _onAttachmentPreview: function() { this.showAttachmentPreviewWidget(); }, }); return { AttachmentPreviewMixin: AttachmentPreviewMixin, AttachmentPreviewWidget: AttachmentPreviewWidget, }; });