diff --git a/attachment_preview/__manifest__.py b/attachment_preview/__manifest__.py index 32827993..050b1668 100644 --- a/attachment_preview/__manifest__.py +++ b/attachment_preview/__manifest__.py @@ -4,21 +4,16 @@ { "name": "Preview attachments", "version": "12.0.1.0.2", - "author": "Therp BV," - "Onestein," - "Odoo Community Association (OCA)", + "author": "Therp BV," "Onestein," "Odoo Community Association (OCA)", "license": "AGPL-3", - "summary": 'Preview attachments supported by Viewer.js', + "summary": "Preview attachments supported by Viewer.js", "category": "Knowledge Management", - "depends": [ - 'web', - 'mail' - ], + "depends": ["web", "mail"], "data": [ "templates/assets.xml", ], "qweb": [ - 'static/src/xml/attachment_preview.xml', + "static/src/xml/attachment_preview.xml", ], "installable": True, } diff --git a/attachment_preview/models/ir_attachment.py b/attachment_preview/models/ir_attachment.py index 0b88b0e7..a24cb4cc 100644 --- a/attachment_preview/models/ir_attachment.py +++ b/attachment_preview/models/ir_attachment.py @@ -6,70 +6,71 @@ import logging import mimetypes import os.path -from odoo import models, api +from odoo import api, models _logger = logging.getLogger(__name__) class IrAttachment(models.Model): - _inherit = 'ir.attachment' + _inherit = "ir.attachment" @api.model - def get_binary_extension(self, model, ids, binary_field, - filename_field=None): + def get_binary_extension(self, model, ids, binary_field, filename_field=None): result = {} ids_to_browse = ids if isinstance(ids, collections.Iterable) else [ids] # First pass: load fields in bin_size mode to avoid loading big files # unnecessarily. if filename_field: - for this in self.env[model].with_context( - bin_size=True).browse(ids_to_browse): + for this in ( + self.env[model].with_context(bin_size=True).browse(ids_to_browse) + ): if not this.id: result[this.id] = False continue - extension = '' + extension = "" if this[filename_field]: - filename, extension = os.path.splitext( - this[filename_field]) + filename, extension = os.path.splitext(this[filename_field]) if this[binary_field] and extension: result[this.id] = extension - _logger.debug('Got extension %s from filename %s', - extension, this[filename_field]) + _logger.debug( + "Got extension %s from filename %s", + extension, + this[filename_field], + ) # Second pass for all attachments which have to be loaded fully # to get the extension from the content ids_to_browse = [_id for _id in ids_to_browse if _id not in result] - for this in self.env[model].with_context( - bin_size=True).browse(ids_to_browse): + for this in self.env[model].with_context(bin_size=True).browse(ids_to_browse): if not this[binary_field]: result[this.id] = False continue try: import magic - if model == self._name and binary_field == 'datas'\ - and this.store_fname: + + if model == self._name and binary_field == "datas" and this.store_fname: mimetype = magic.from_file( - this._full_path(this.store_fname), mime=True) - _logger.debug('Magic determined mimetype %s from file %s', - mimetype, this.store_fname) + this._full_path(this.store_fname), mime=True + ) + _logger.debug( + "Magic determined mimetype %s from file %s", + mimetype, + this.store_fname, + ) else: - mimetype = magic.from_buffer( - this[binary_field], mime=True) - _logger.debug('Magic determined mimetype %s from buffer', - mimetype) + mimetype = magic.from_buffer(this[binary_field], mime=True) + _logger.debug("Magic determined mimetype %s from buffer", mimetype) except ImportError: (mimetype, encoding) = mimetypes.guess_type( - 'data:;base64,' + this[binary_field], strict=False) - _logger.debug('Mimetypes guessed type %s from buffer', - mimetype) - extension = mimetypes.guess_extension( - mimetype.split(';')[0], strict=False) + "data:;base64," + this[binary_field], strict=False + ) + _logger.debug("Mimetypes guessed type %s from buffer", mimetype) + extension = mimetypes.guess_extension(mimetype.split(";")[0], strict=False) result[this.id] = extension for _id in result: - result[_id] = (result[_id] or '').lstrip('.').lower() + result[_id] = (result[_id] or "").lstrip(".").lower() return result if isinstance(ids, collections.Iterable) else result[ids] @api.model def get_attachment_extension(self, ids): - return self.get_binary_extension( - self._name, ids, 'datas', 'datas_fname') + return self.get_binary_extension(self._name, ids, "datas", "datas_fname") diff --git a/attachment_preview/static/src/js/attachment_preview.js b/attachment_preview/static/src/js/attachment_preview.js index 85413877..80340a6a 100644 --- a/attachment_preview/static/src/js/attachment_preview.js +++ b/attachment_preview/static/src/js/attachment_preview.js @@ -1,41 +1,69 @@ /* Copyright 2014 Therp BV () * License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). */ -odoo.define('attachment_preview', function (require) { - 'use strict'; +odoo.define("attachment_preview", function (require) { + "use strict"; - var core = require('web.core'); + var core = require("web.core"); var _t = core._t; var qweb = core.qweb; - var Chatter = require('mail.Chatter'); - var basic_fields = require('web.basic_fields'); - var FormRenderer = require('web.FormRenderer'); - var FormController = require('web.FormController'); - var Widget = require('web.Widget'); + var Chatter = require("mail.Chatter"); + var basic_fields = require("web.basic_fields"); + var FormRenderer = require("web.FormRenderer"); + var FormController = require("web.FormController"); + var Widget = require("web.Widget"); var AttachmentPreviewMixin = { canPreview: function (extension) { - return $.inArray( - extension, - ['odt', 'odp', 'ods', 'fodt', 'pdf', 'ott', 'fodp', 'otp', - 'fods', 'ots', - ]) > -1; + 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, ''); + 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); + 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}); + this.trigger_up("onAttachmentPreview", {url: url}); } else { window.open(url); } @@ -45,7 +73,7 @@ odoo.define('attachment_preview', function (require) { Chatter.include(AttachmentPreviewMixin); Chatter.include({ events: _.extend({}, Chatter.prototype.events, { - 'click .o_attachment_preview': '_onPreviewAttachment', + "click .o_attachment_preview": "_onPreviewAttachment", }), previewableAttachments: null, @@ -53,11 +81,13 @@ odoo.define('attachment_preview', function (require) { _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)); + this.getPreviewableAttachments().done( + function (atts) { + this.previewableAttachments = atts; + this.updatePreviewButtons(atts); + this.getParent().attachmentPreviewWidget.setAttachments(atts); + }.bind(this) + ); return res; }, @@ -65,7 +95,7 @@ odoo.define('attachment_preview', function (require) { update: function () { var res = this._super.apply(this, arguments); var self = this; - if (this.getParent().$el.hasClass('attachment_preview')) { + if (this.getParent().$el.hasClass("attachment_preview")) { this._fetchAttachments().done(function () { self._openAttachmentBox(); self.getPreviewableAttachments().done(function (atts) { @@ -82,21 +112,33 @@ odoo.define('attachment_preview', function (require) { 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'); + 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_extension) { - this.showPreview(attachment_id, attachment_url, attachment_extension, attachment_title, split_screen); + this.showPreview( + attachment_id, + attachment_url, + attachment_extension, + attachment_title, + split_screen + ); } else { this._rpc({ - model: 'ir.attachment', - method: 'get_attachment_extension', + model: "ir.attachment", + method: "get_attachment_extension", args: [attachment_id], }).then(function (extension) { - self.showPreview(attachment_id, attachment_url, extension, null, split_screen); + self.showPreview( + attachment_id, + attachment_url, + extension, + null, + split_screen + ); }); } }, @@ -105,56 +147,67 @@ odoo.define('attachment_preview', function (require) { var self = this; var deferred = $.Deferred(); - var $items = this.$el.find('.o_attachment_preview'); - var attachments = _.object($items.map(function () { - return parseInt($(this).attr('data-id'), 10); - }), $items.map(function () { - return { - url: $(this).attr('data-url'), - extension: $(this).attr('data-extension'), - title: $(this).attr('data-original-title'), - }; - })); + var $items = this.$el.find(".o_attachment_preview"); + var attachments = _.object( + $items.map(function () { + return parseInt($(this).attr("data-id"), 10); + }), + $items.map(function () { + return { + url: $(this).attr("data-url"), + extension: $(this).attr("data-extension"), + title: $(this).attr("data-original-title"), + }; + }) + ); this._rpc({ - model: 'ir.attachment', - method: 'get_attachment_extension', + 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, id) { - 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 + }).then( + function (extensions) { + var reviewableAttachments = _.map( + _.keys( + _.pick(extensions, function (extension, id) { + return self.canPreview(extension); + }) ), - }; - }); - deferred.resolve(reviewableAttachments); - }, function () { - deferred.reject(); - }); + 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 () { + this.$el.find(".o_attachment_preview").each(function () { var $this = $(this); - var id = $this.attr('data-id'); + var id = $this.attr("data-id"); var att = _.findWhere(previewableAttachments, {id: id}); if (att) { - $this.attr('data-extension', att.extension); + $this.attr("data-extension", att.extension); } else { $this.remove(); } @@ -165,7 +218,7 @@ odoo.define('attachment_preview', function (require) { basic_fields.FieldBinaryFile.include(AttachmentPreviewMixin); basic_fields.FieldBinaryFile.include({ events: _.extend({}, basic_fields.FieldBinaryFile.prototype.events, { - 'click .fa-search': '_onPreview', + "click .fa-search": "_onPreview", }), _renderReadonly: function () { @@ -183,23 +236,21 @@ odoo.define('attachment_preview', function (require) { _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); + 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, - ], + model: "ir.attachment", + method: "get_binary_extension", + args: [this.model, this.recordData.id, this.name, this.attrs.filename], }); }, @@ -207,13 +258,13 @@ odoo.define('attachment_preview', function (require) { this.showPreview( null, _.str.sprintf( - '/web/content?model=%s&field=%s&id=%d', + "/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), + $(event.currentTarget).attr("data-extension"), + _.str.sprintf(_t("Preview %s"), this.field.string), false ); event.stopPropagation(); @@ -221,22 +272,22 @@ odoo.define('attachment_preview', function (require) { }); var AttachmentPreviewWidget = Widget.extend({ - template: 'attachment_preview.AttachmentPreviewWidget', + 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', + "click .attachment_preview_close": "_onCloseClick", + "click .attachment_preview_previous": "_onPreviousClick", + "click .attachment_preview_next": "_onNextClick", + "click .attachment_preview_popout": "_onPopoutClick", }, start: function () { 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'); + 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; }, @@ -281,28 +332,32 @@ odoo.define('attachment_preview', function (require) { }, show: function () { - this.$el.removeClass('d-none'); - this.trigger('shown'); + this.$el.removeClass("d-none"); + this.trigger("shown"); }, hide: function () { - this.$el.addClass('d-none'); - this.trigger('hidden'); + this.$el.addClass("d-none"); + this.trigger("hidden"); }, updatePaginator: function () { - var value = _.str.sprintf('%s / %s', this.activeIndex + 1, this.attachments.length); + 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'); + this.$iframe.attr("src", "about:blank"); return; } var att = this.attachments[this.activeIndex]; - this.$iframe.attr('src', att.previewUrl); + this.$iframe.attr("src", att.previewUrl); }, setAttachments: function (attachments) { @@ -315,7 +370,7 @@ odoo.define('attachment_preview', function (require) { FormRenderer.include({ custom_events: _.extend({}, FormRenderer.prototype.custom_events, { - onAttachmentPreview: '_onAttachmentPreview', + onAttachmentPreview: "_onAttachmentPreview", }), attachmentPreviewWidget: null, @@ -323,7 +378,11 @@ odoo.define('attachment_preview', function (require) { init: function () { var res = this._super.apply(this, arguments); this.attachmentPreviewWidget = new AttachmentPreviewWidget(this); - this.attachmentPreviewWidget.on('hidden', this, this._attachmentPreviewWidgetHidden); + this.attachmentPreviewWidget.on( + "hidden", + this, + this._attachmentPreviewWidgetHidden + ); return res; }, @@ -335,11 +394,11 @@ odoo.define('attachment_preview', function (require) { }, _attachmentPreviewWidgetHidden: function () { - this.$el.removeClass('attachment_preview'); + this.$el.removeClass("attachment_preview"); }, showAttachmentPreviewWidget: function () { - this.$el.addClass('attachment_preview'); + this.$el.addClass("attachment_preview"); this.attachmentPreviewWidget.setAttachments( this.chatter.previewableAttachments @@ -357,7 +416,6 @@ odoo.define('attachment_preview', function (require) { }, }); - return { AttachmentPreviewMixin: AttachmentPreviewMixin, AttachmentPreviewWidget: AttachmentPreviewWidget, diff --git a/attachment_preview/static/src/js/viewerjs_tweaks.js b/attachment_preview/static/src/js/viewerjs_tweaks.js index cd8a0cdc..ad745646 100644 --- a/attachment_preview/static/src/js/viewerjs_tweaks.js +++ b/attachment_preview/static/src/js/viewerjs_tweaks.js @@ -7,8 +7,8 @@ window.Viewer = function (plugin, parameters) { if (!plugin) { // eslint-disable-next-line no-alert - alert('Unsupported file type'); + alert("Unsupported file type"); } return original_Viewer(plugin, parameters); }; -}(window.Viewer)); +})(window.Viewer); diff --git a/attachment_preview/static/src/scss/attachment_preview.scss b/attachment_preview/static/src/scss/attachment_preview.scss index 9c2bf904..354cabe8 100644 --- a/attachment_preview/static/src/scss/attachment_preview.scss +++ b/attachment_preview/static/src/scss/attachment_preview.scss @@ -44,7 +44,7 @@ padding: 4px; float: left; width: 100%; - background-color: #FFF; + background-color: #fff; border-left: 1px solid $gray-800; button { diff --git a/attachment_preview/static/src/xml/attachment_preview.xml b/attachment_preview/static/src/xml/attachment_preview.xml index da3f10f5..a505f885 100644 --- a/attachment_preview/static/src/xml/attachment_preview.xml +++ b/attachment_preview/static/src/xml/attachment_preview.xml @@ -1,19 +1,23 @@ - + - + - + @@ -21,15 +25,25 @@
- - - + + +
- + - +
- +