diff --git a/attachment_preview/README.rst b/attachment_preview/README.rst index 197d487f..28f8ea5c 100644 --- a/attachment_preview/README.rst +++ b/attachment_preview/README.rst @@ -29,6 +29,10 @@ This addon allows to preview attachments supported by http://viewerjs.org. Currently, that's most Libreoffice files and PDFs. +.. image:: /attachment_preview/static/description/screenshot-split.png + :alt: Screenshot of split form view + :width: 100% + **Table of contents** .. contents:: @@ -46,7 +50,13 @@ Usage ===== The module adds a little print preview icon right of download links for -attachments or binary fields. +attachments or binary fields. When a preview is opened from the attachments +menu it's shown next to the form view. From this screen you can navigate +through the attachments using the arrow buttons. Using the pop-out button +next to the navigational buttons you can open the preview in a separate window. + +.. image:: /attachment_preview/static/description/screenshot-paginator.png + :alt: Screenshot navigator Bug Tracker =========== diff --git a/attachment_preview/__manifest__.py b/attachment_preview/__manifest__.py index ee02c750..77da9c13 100644 --- a/attachment_preview/__manifest__.py +++ b/attachment_preview/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Preview attachments", - "version": "11.0.1.2.1", + "version": "11.0.1.3.0", "author": "Therp BV," "Onestein," "Odoo Community Association (OCA)", diff --git a/attachment_preview/readme/DESCRIPTION.rst b/attachment_preview/readme/DESCRIPTION.rst index f1b31ab8..aadfd944 100644 --- a/attachment_preview/readme/DESCRIPTION.rst +++ b/attachment_preview/readme/DESCRIPTION.rst @@ -1,3 +1,7 @@ This addon allows to preview attachments supported by http://viewerjs.org. Currently, that's most Libreoffice files and PDFs. + +.. image:: /attachment_preview/static/description/screenshot-split.png + :alt: Screenshot of split form view + :width: 100% diff --git a/attachment_preview/readme/USAGE.rst b/attachment_preview/readme/USAGE.rst index e1783956..941a680c 100644 --- a/attachment_preview/readme/USAGE.rst +++ b/attachment_preview/readme/USAGE.rst @@ -1,2 +1,8 @@ The module adds a little print preview icon right of download links for -attachments or binary fields. +attachments or binary fields. When a preview is opened from the attachments +menu it's shown next to the form view. From this screen you can navigate +through the attachments using the arrow buttons. Using the pop-out button +next to the navigational buttons you can open the preview in a separate window. + +.. image:: /attachment_preview/static/description/screenshot-paginator.png + :alt: Screenshot navigator diff --git a/attachment_preview/static/description/screenshot-paginator.png b/attachment_preview/static/description/screenshot-paginator.png new file mode 100644 index 00000000..02910c83 Binary files /dev/null and b/attachment_preview/static/description/screenshot-paginator.png differ diff --git a/attachment_preview/static/description/screenshot-split.png b/attachment_preview/static/description/screenshot-split.png new file mode 100644 index 00000000..257952bf Binary files /dev/null and b/attachment_preview/static/description/screenshot-split.png differ diff --git a/attachment_preview/static/src/css/attachment_preview.css b/attachment_preview/static/src/css/attachment_preview.css deleted file mode 100644 index d94ff0e0..00000000 --- a/attachment_preview/static/src/css/attachment_preview.css +++ /dev/null @@ -1,15 +0,0 @@ -.o_cp_sidebar li .o_sidebar_preview_attachment { - position: absolute; - top: 5px; - right: 26px; - background-color: #FFF; -} - -.o_cp_sidebar .open .dropdown-menu > li > a { - padding-right: 46px; -} - -.o_form_uri .fa-search { - padding-left: 5px; - padding-right: 5px; -} diff --git a/attachment_preview/static/src/js/attachment_preview.js b/attachment_preview/static/src/js/attachment_preview.js index fee97da2..3f1f6604 100644 --- a/attachment_preview/static/src/js/attachment_preview.js +++ b/attachment_preview/static/src/js/attachment_preview.js @@ -6,8 +6,12 @@ odoo.define('attachment_preview', function(require) { var core = require('web.core'); var _t = core._t; + var qweb = core.qweb; var Sidebar = require('web.Sidebar'); 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) { @@ -18,68 +22,126 @@ odoo.define('attachment_preview', function(require) { 'fods', 'ots' ]) > -1; }, - showPreview: function(attachment_id, attachment_url, attachment_extension, attachment_title) { + + 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, ''); - window.open(url); - } + 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); + } + }, }; Sidebar.include(AttachmentPreviewMixin); Sidebar.include({ + events: _.extend({}, Sidebar.prototype.events, { + 'click .o_sidebar_preview_attachment': '_onPreviewAttachment' + }), + + previewableAttachments: null, + _redraw: function () { this._super.apply(this, arguments); - this.$('.o_sidebar_preview_attachment') - .click(this._onPreviewAttachment.bind(this)); - this.updatePreviewButtons(); + this.getPreviewableAttachments().done(function(atts) { + this.previewableAttachments = atts; + this.updatePreviewButtons(atts); + this.trigger_up('setPreviewableAttachments', {attachments: atts}); + }.bind(this)); }, + _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_extension) { - this.showPreview(attachment_id, attachment_url, attachment_extension, attachment_title); + 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); + self.showPreview(attachment_id, attachment_url, extension, null, split_screen); }); } }, - updatePreviewButtons: function() { + + getPreviewableAttachments: function() { var self = this; - return this._rpc({ + var deferred = $.Deferred(); + + var $items = this.$el.find('.o_sidebar_preview_attachment'); + 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', args: [ - this.$el.find('.o_sidebar_preview_attachment').map(function() { - return parseInt($(this).attr('data-id'), 10); - }).get() + _.map(_.keys(attachments), function(id) { + return parseInt(id, 10); + }) ] }).then(function(extensions) { - _(extensions).each(function(extension, id) { - var $element = self.$el.find('span.o_sidebar_preview_attachment[data-id="' + id + '"]'); - if (self.canPreview(extension)) { - $element.attr('data-extension', extension); - } else { - $element.remove(); + 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'] + ) } }); + deferred.resolve(reviewableAttachments); + }, function() { + deferred.reject(); }); + return deferred.promise(); }, + updatePreviewButtons: function(previewableAttachments) { + this.$el.find('.o_sidebar_preview_attachment').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); @@ -87,6 +149,7 @@ odoo.define('attachment_preview', function(require) { events: _.extend({}, basic_fields.FieldBinaryFile.prototype.events, { 'click .fa-search': '_onPreview' }), + _renderReadonly: function () { var self = this; this._super.apply(this, arguments); @@ -96,6 +159,7 @@ odoo.define('attachment_preview', function(require) { } }); }, + _renderPreviewButton: function(extension) { this.$previewBtn = $(""); this.$previewBtn.addClass('fa fa-search'); @@ -103,6 +167,7 @@ odoo.define('attachment_preview', function(require) { this.$previewBtn.attr('data-extension', extension); this.$el.find('.fa-download').after(this.$previewBtn); }, + _getBinaryExtension: function () { return this._rpc({ model: 'ir.attachment', @@ -115,6 +180,7 @@ odoo.define('attachment_preview', function(require) { ] }); }, + _onPreview: function(event) { this.showPreview( null, @@ -125,12 +191,158 @@ odoo.define('attachment_preview', function(require) { this.recordData.id ), $(event.currentTarget).attr('data-extension'), - _.str.sprintf(_t('Preview %s'), this.field.string) + _.str.sprintf(_t('Preview %s'), this.field.string), + false + ); + } + }); + + 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 () { + 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('hidden'); + this.trigger('shown'); + }, + + hide: function () { + this.$el.addClass('hidden'); + 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; + } + + var att = this.attachments[this.activeIndex]; + this.$iframe.attr('src', att.previewUrl); + }, + + setAttachments: function(attachments) { + this.attachments = attachments; + this.activeIndex = 0; + this.updatePaginator(); + this.loadPreview(); + } + }); + + FormRenderer.include({ + 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 () { + this._super.apply(this, arguments); + this.attachmentPreviewWidget.insertAfter(this.$el); + }, + + _attachmentPreviewWidgetHidden: function() { + this.$el.removeClass('attachment_preview'); + }, + + showAttachmentPreviewWidget: function () { + this.$el.addClass('attachment_preview'); + this.attachmentPreviewWidget.setAttachments( + this.getParent().sidebar.previewableAttachments + ); + this.attachmentPreviewWidget.show(); + }, + + on_detach_callback: function () { + this.attachmentPreviewWidget.hide(); + return this._super.apply(this, arguments); + } + + }); + + FormController.include({ + custom_events: _.extend({}, FormController.prototype.custom_events, { + onAttachmentPreview: '_onAttachmentPreview', + setPreviewableAttachments: '_setPreviewableAttachments' + }), + + _onAttachmentPreview: function (event) { + this.renderer.showAttachmentPreviewWidget(); + }, + + _setPreviewableAttachments: function(event) { + this.renderer.attachmentPreviewWidget.setAttachments( + event.data.attachments ); } }); return { - AttachmentPreviewMixin: AttachmentPreviewMixin + AttachmentPreviewMixin: AttachmentPreviewMixin, + AttachmentPreviewWidget: AttachmentPreviewWidget }; }); diff --git a/attachment_preview/static/src/less/attachment_preview.less b/attachment_preview/static/src/less/attachment_preview.less new file mode 100644 index 00000000..17c42ac1 --- /dev/null +++ b/attachment_preview/static/src/less/attachment_preview.less @@ -0,0 +1,56 @@ +.o_cp_sidebar { + li .o_sidebar_preview_attachment { + position: absolute; + top: 5px; + right: 26px; + background-color: #FFF; + + &.o_sidebar_preview_attachment_new_tab { + right: 43px; + } + } + + .open .dropdown-menu > li > a { + padding-right: 60px; + } +} + +.o_form_uri .fa-search { + padding-left: 5px; + padding-right: 5px; +} + +/* Preview widget */ + +.o_form_view.attachment_preview { + width: 60%; + float: left; +} + +.o_form_view + .attachment_preview_widget { + width: 40%; + height: 100%; + float: right; + position: relative; + + > .attachment_preview_iframe { + width: 100%; + height: calc(~"100% - 30px"); + float: left; + } + + .attachment_preview_buttons { + padding: 4px; + float: left; + width: 100%; + background-color: #FFF; + border-left: 1px solid @gray-lighter-dark; + + button { + min-width: 25px; + min-height: 25px; + padding-top: 2px; + padding-bottom: 2px; + } + } +} diff --git a/attachment_preview/static/src/xml/attachment_preview.xml b/attachment_preview/static/src/xml/attachment_preview.xml index e110f52c..fd2a9665 100644 --- a/attachment_preview/static/src/xml/attachment_preview.xml +++ b/attachment_preview/static/src/xml/attachment_preview.xml @@ -7,6 +7,29 @@ t-att-data-id="item.id" t-att-data-url="item.url" t-attf-title="Preview #{item.name}"/> + + + + + + diff --git a/attachment_preview/templates/assets.xml b/attachment_preview/templates/assets.xml index 1b94f3e9..8caf8f95 100644 --- a/attachment_preview/templates/assets.xml +++ b/attachment_preview/templates/assets.xml @@ -3,7 +3,7 @@