[IMP] mail: adds delete and upload to chatter
This commit adds the ability to upload and delete attachments from the chatter. Task: #1911277 closes odoo/odoo#29702
This commit is contained in:
@@ -13,46 +13,43 @@ var AttachmentBox = Widget.extend({
|
||||
events: {
|
||||
"click .o_attachment_download": "_onAttachmentDownload",
|
||||
"click .o_attachment_view": "_onAttachmentView",
|
||||
"click .o_attachment_delete_cross": "_onDeleteAttachment",
|
||||
"click .o_upload_attachments_button": "_onUploadAttachments",
|
||||
"change .o_chatter_attachment_form .o_form_binary_form": "_onAddAttachment",
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @param {string} record.model
|
||||
* @param {Number} record.res_id
|
||||
* @param {Object[]} attachments
|
||||
*/
|
||||
init: function (parent, record) {
|
||||
init: function (parent, record, attachments) {
|
||||
this._super.apply(this, arguments);
|
||||
this.fileuploadId = _.uniqueId('oe_fileupload');
|
||||
$(window).on(this.fileuploadId, this._onUploaded.bind(this));
|
||||
this.currentResID = record.res_id;
|
||||
this.currentResModel = record.model;
|
||||
this.attachmentIDs = {};
|
||||
this.attachmentIDs = attachments;
|
||||
this.imageList = {};
|
||||
this.otherList = {};
|
||||
|
||||
_.each(attachments, function (attachment) {
|
||||
// required for compatibility with the chatter templates.
|
||||
attachment.url = '/web/content/' + attachment.id + '?download=true';
|
||||
attachment.filename = attachment.datas_fname || 'unnamed';
|
||||
});
|
||||
var sortedAttachments = _.partition(attachments, function (att) {
|
||||
return att.mimetype && att.mimetype.split('/')[0] === 'image';
|
||||
});
|
||||
this.imageList = sortedAttachments[0];
|
||||
this.otherList = sortedAttachments[1];
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
willStart: function () {
|
||||
var self = this;
|
||||
var domain = [
|
||||
['res_id', '=', this.currentResID],
|
||||
['res_model', '=', this.currentResModel],
|
||||
];
|
||||
return $.when(this._super.apply(this, arguments), this._rpc({
|
||||
model: 'ir.attachment',
|
||||
method: 'search_read',
|
||||
domain: domain,
|
||||
}).then(function (result) {
|
||||
self.attachmentIDs = result;
|
||||
_.each(result, function (attachment) {
|
||||
attachment.url = '/web/content/' + attachment.id + '?download=true';
|
||||
// required for compatibility with the chatter templates.
|
||||
attachment.filename = attachment.datas_fname || 'unnamed';
|
||||
});
|
||||
var sortedAttachments = _.partition(result, function (att) {
|
||||
return att.mimetype && att.mimetype.split('/')[0] === 'image';
|
||||
});
|
||||
self.imageList = sortedAttachments[0];
|
||||
self.otherList = sortedAttachments[1];
|
||||
}));
|
||||
destroy: function () {
|
||||
$(window).off(this.fileuploadId);
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -60,8 +57,8 @@ var AttachmentBox = Widget.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {Object} record
|
||||
*/
|
||||
* @param {Object} record
|
||||
*/
|
||||
update: function (record) {
|
||||
this.currentResID = record.res_id;
|
||||
this.currentResModel = record.model;
|
||||
@@ -71,6 +68,19 @@ var AttachmentBox = Widget.extend({
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method triggered when user click on 'add attachment' and select a file
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onAddAttachment: function (ev) {
|
||||
var $input = $(ev.currentTarget).find('input.o_input_file');
|
||||
if ($input.val() !== '') {
|
||||
var $binaryForm = this.$('form.o_form_binary_form');
|
||||
$binaryForm.submit();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
@@ -92,6 +102,33 @@ var AttachmentBox = Widget.extend({
|
||||
attachmentViewer.appendTo($('body'));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Opens File Explorer dialog if all fields are valid and record is saved
|
||||
*
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onUploadAttachments: function (ev) {
|
||||
this.$('input.o_input_file').click();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onDeleteAttachment: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var $target = $(ev.currentTarget);
|
||||
this.trigger_up('delete_attachment', {
|
||||
attachmentId: $target.data('id'),
|
||||
attachmentName: $target.data('name')
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onUploaded: function() {
|
||||
this.trigger_up('reload_attachment_box');
|
||||
},
|
||||
});
|
||||
|
||||
return AttachmentBox;
|
||||
|
||||
@@ -4,6 +4,7 @@ odoo.define('mail.Chatter', function (require) {
|
||||
var Activity = require('mail.Activity');
|
||||
var AttachmentBox = require('mail.AttachmentBox');
|
||||
var ChatterComposer = require('mail.composer.Chatter');
|
||||
var Dialog = require('web.Dialog');
|
||||
var Followers = require('mail.Followers');
|
||||
var ThreadField = require('mail.ThreadField');
|
||||
var mailUtils = require('mail.utils');
|
||||
@@ -13,25 +14,28 @@ var config = require('web.config');
|
||||
var core = require('web.core');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var _t = core._t;
|
||||
var QWeb = core.qweb;
|
||||
|
||||
// The purpose of this widget is to display the chatter area below the form view
|
||||
//
|
||||
// It instanciates the optional mail_thread, mail_activity and mail_followers widgets.
|
||||
// It instantiates the optional mail_thread, mail_activity and mail_followers widgets.
|
||||
// It Ensures that those widgets are appended at the right place, and allows them to communicate
|
||||
// with each other.
|
||||
// It synchronizes the rendering of those widgets (as they may be asynchronous), to limitate
|
||||
// It synchronizes the rendering of those widgets (as they may be asynchronous), to mitigate
|
||||
// the flickering when switching between records
|
||||
var Chatter = Widget.extend({
|
||||
template: 'mail.Chatter',
|
||||
custom_events: {
|
||||
delete_attachment: '_onDeleteAttachment',
|
||||
discard_record_changes: '_onDiscardRecordChanges',
|
||||
reload_attachment_box: '_onReloadAttachmentBox',
|
||||
reload_mail_fields: '_onReloadMailFields',
|
||||
},
|
||||
events: {
|
||||
'click .o_chatter_button_new_message': '_onOpenComposerMessage',
|
||||
'click .o_chatter_button_log_note': '_onOpenComposerNote',
|
||||
'click .o_chatter_button_attachment': '_onOpenAttachments',
|
||||
'click .o_chatter_button_attachment': '_onClickAttachmentButton',
|
||||
'click .o_chatter_button_schedule_activity': '_onScheduleActivity',
|
||||
},
|
||||
supportedFieldTypes: ['one2many'],
|
||||
@@ -52,15 +56,19 @@ var Chatter = Widget.extend({
|
||||
this._super.apply(this, arguments);
|
||||
this._setState(record);
|
||||
|
||||
this._dp = new concurrency.DropPrevious();
|
||||
this.attachments = {};
|
||||
this.fields = {};
|
||||
|
||||
this._areAttachmentsLoaded = false;
|
||||
this._disableAttachmentBox = !!options.disable_attachment_box;
|
||||
this._dp = new concurrency.DropPrevious();
|
||||
this._isAttachmentBoxOpen = false;
|
||||
// mention: get the prefetched partners and use them as mention suggestions
|
||||
// if there is a follower widget, the followers will be added to the
|
||||
// suggestions as well once fetched
|
||||
this._mentionPartnerSuggestions = this.call('mail_service', 'getMentionPartnerSuggestions');
|
||||
this._mentionSuggestions = this._mentionPartnerSuggestions;
|
||||
|
||||
this.fields = {};
|
||||
if (mailFields.mail_activity) {
|
||||
this.fields.activity = new Activity(this, mailFields.mail_activity, record, options);
|
||||
}
|
||||
@@ -74,16 +82,17 @@ var Chatter = Widget.extend({
|
||||
this.hasLogButton = options.display_log_button || nodeOptions.display_log_button;
|
||||
this.postRefresh = nodeOptions.post_refresh || 'never';
|
||||
}
|
||||
this.attachmentBoxOpened = false;
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
start: function () {
|
||||
this._$topbar = this.$('.o_chatter_topbar');
|
||||
this.$('.o_topbar_right_area').append(QWeb.render('mail.chatter.Attachment.Button', {
|
||||
count: this.record.data.message_attachment_count || 0,
|
||||
}));
|
||||
if(!this._disableAttachmentBox) {
|
||||
this.$('.o_topbar_right_area').append(QWeb.render('mail.chatter.Attachment.Button', {
|
||||
count: this.record.data.message_attachment_count || 0,
|
||||
}));
|
||||
}
|
||||
// render and append the buttons
|
||||
this._$topbar.prepend(QWeb.render('mail.chatter.Buttons', {
|
||||
newMessageButton: !!this.fields.thread,
|
||||
@@ -115,6 +124,8 @@ var Chatter = Widget.extend({
|
||||
if (this.record.res_id !== record.res_id) {
|
||||
this._closeComposer(true);
|
||||
this._closeAttachments();
|
||||
this._areAttachmentsLoaded = false;
|
||||
this.attachments = {};
|
||||
}
|
||||
|
||||
// update the state
|
||||
@@ -155,13 +166,12 @@ var Chatter = Widget.extend({
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {boolean} force
|
||||
*/
|
||||
_closeAttachments: function () {
|
||||
if (this.fields.attachments) {
|
||||
this.$('.o_chatter_button_attachment').removeClass('o_active_attach');
|
||||
this.fields.attachments.destroy();
|
||||
this.attachmentBoxOpened = false;
|
||||
this._isAttachmentBoxOpen = false;
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -231,22 +241,46 @@ var Chatter = Widget.extend({
|
||||
_enableComposer: function () {
|
||||
this.$(".o_composer_button_send").prop('disabled', false);
|
||||
},
|
||||
/*
|
||||
* @private
|
||||
* @return {Deferred}
|
||||
*/
|
||||
_fetchAttachments: function () {
|
||||
var self = this;
|
||||
var domain = [
|
||||
['res_id', '=', this.record.res_id],
|
||||
['res_model', '=', this.record.model],
|
||||
];
|
||||
return this._rpc({
|
||||
model: 'ir.attachment',
|
||||
method: 'search_read',
|
||||
domain: domain,
|
||||
fields: ['id', 'name', 'datas_fname', 'mimetype'],
|
||||
}).then(function (result) {
|
||||
self._areAttachmentsLoaded = true;
|
||||
self.attachments = result;
|
||||
});
|
||||
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_openAttachments: function () {
|
||||
var self = this;
|
||||
this.fields.attachments = new AttachmentBox(this, this.record);
|
||||
|
||||
_openAttachmentBox: function () {
|
||||
if (this.fields.attachments) {
|
||||
this._closeAttachments();
|
||||
}
|
||||
this.fields.attachments = new AttachmentBox(this, this.record, this.attachments);
|
||||
var $anchor = this.$('.o_chatter_topbar');
|
||||
if (this._composer) {
|
||||
$anchor = this.$('.o_thread_composer');
|
||||
var $anchor = this.$('.o_thread_composer');
|
||||
} else {
|
||||
var $anchor = this.$('.o_chatter_topbar');
|
||||
}
|
||||
this.fields.attachments.insertAfter($anchor).then(function () {
|
||||
self.$el.addClass('o_chatter_composer_active');
|
||||
self.$('.o_chatter_button_attachment').addClass('o_active_attach');
|
||||
});
|
||||
this.attachmentBoxOpened = true;
|
||||
this.fields.attachments.insertAfter($anchor);
|
||||
this.$el.addClass('o_chatter_composer_active');
|
||||
this.$('.o_chatter_button_attachment').addClass('o_active_attach');
|
||||
|
||||
this._isAttachmentBoxOpen = true;
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -286,6 +320,7 @@ var Chatter = Widget.extend({
|
||||
if (self._reloadAfterPost(messageData)) {
|
||||
self.trigger_up('reload');
|
||||
} else if (messageData.attachment_ids.length) {
|
||||
self._reloadAttachmentBox();
|
||||
self.trigger_up('reload', {fieldNames: ['message_attachment_count']});
|
||||
}
|
||||
}).fail(function () {
|
||||
@@ -320,6 +355,16 @@ var Chatter = Widget.extend({
|
||||
messageData.partner_ids.length
|
||||
);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_reloadAttachmentBox: function () {
|
||||
this._areAttachmentsLoaded = false;
|
||||
if (this._isAttachmentBoxOpen) {
|
||||
this._fetchAttachments().then(this._openAttachmentBox.bind(this));
|
||||
}
|
||||
this.trigger_up('reload', { fieldNames: ['message_attachment_count'] });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {Deferred} def
|
||||
@@ -344,7 +389,11 @@ var Chatter = Widget.extend({
|
||||
self.fields.activity.$el.appendTo(self.$el);
|
||||
}
|
||||
if (self.fields.followers) {
|
||||
self.fields.followers.$el.insertBefore(self.$('.o_chatter_button_attachment'));
|
||||
if (self._disableAttachmentBox) {
|
||||
self.fields.followers.$el.appendTo(self.$('.o_topbar_right_area'));
|
||||
} else {
|
||||
self.fields.followers.$el.insertBefore(self.$('.o_chatter_button_attachment'));
|
||||
}
|
||||
}
|
||||
if (self.fields.thread) {
|
||||
self.fields.thread.$el.appendTo(self.$el);
|
||||
@@ -383,8 +432,7 @@ var Chatter = Widget.extend({
|
||||
*/
|
||||
_updateAttachmentCounter: function () {
|
||||
var count = this.record.data.message_attachment_count || 0;
|
||||
this.$('.o_chatter_attachment_button_count').html(' ('+ count +')');
|
||||
this.$('.o_chatter_button_attachment').toggleClass('o_hidden', !count);
|
||||
this.$('.o_chatter_attachment_button_count').html(count);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
@@ -427,12 +475,45 @@ var Chatter = Widget.extend({
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} ev
|
||||
* @param {integer} ev.data.attachmentId
|
||||
* @param {String} ev.data.attachmentName
|
||||
*/
|
||||
_onOpenAttachments: function () {
|
||||
if (this.attachmentBoxOpened) {
|
||||
_onDeleteAttachment: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var self = this;
|
||||
var options = {
|
||||
confirm_callback: function () {
|
||||
self._rpc({
|
||||
model: 'ir.attachment',
|
||||
method: 'unlink',
|
||||
args: [parseInt(ev.data.attachmentId, 10)],
|
||||
})
|
||||
.then(function () {
|
||||
self._reloadAttachmentBox();
|
||||
self.fields.thread.removeAttachments([ev.data.attachmentId]);
|
||||
self.trigger_up('reload');
|
||||
});
|
||||
}
|
||||
};
|
||||
var promptText = _.str.sprintf(_t("Do you really want to delete %s?"), _.escape(ev.data.attachmentName));
|
||||
Dialog.confirm(this, promptText, options);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onClickAttachmentButton: function () {
|
||||
if(this._disableAttachmentBox) {
|
||||
return;
|
||||
}
|
||||
if (this._isAttachmentBoxOpen) {
|
||||
this._closeAttachments();
|
||||
} else {
|
||||
this._openAttachments();
|
||||
var def;
|
||||
if (!this._areAttachmentsLoaded) {
|
||||
def = this._fetchAttachments();
|
||||
}
|
||||
$.when(def).then(this._openAttachmentBox.bind(this));
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -483,6 +564,12 @@ var Chatter = Widget.extend({
|
||||
_onOpenComposerNote: function () {
|
||||
this._openComposer({ isLog: true });
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onReloadAttachmentBox: function () {
|
||||
this._reloadAttachmentBox();
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {OdooEvent} event
|
||||
|
||||
@@ -335,6 +335,14 @@ var AbstractMessage = Class.extend({
|
||||
needsModeration: function () {
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* @params {integer[]} attachmentIDs
|
||||
*/
|
||||
removeAttachments: function (attachmentIDs) {
|
||||
this._attachmentIDs = _.reject(this._attachmentIDs, function (attachment) {
|
||||
return _.contains(attachmentIDs, attachment.id);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* State whether this message should redirect to the author
|
||||
* when clicking on the author of this message.
|
||||
|
||||
@@ -156,6 +156,14 @@ var DocumentThread = Thread.extend({
|
||||
isLinkedToDocument: function () {
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* @param {integer[]} attachmentIDs
|
||||
*/
|
||||
removeAttachmentsFromMessages: function (attachmentIDs) {
|
||||
_.each(this.getMessages(), function (message) {
|
||||
message.removeAttachments(attachmentIDs);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Set list of message IDs of this document thread
|
||||
*
|
||||
|
||||
@@ -70,6 +70,12 @@ var ThreadField = AbstractField.extend({
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {integer[]} attachmentIDs
|
||||
*/
|
||||
removeAttachments: function (attachmentIDs) {
|
||||
this._documentThread.removeAttachmentsFromMessages(attachmentIDs);
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
* @return {boolean}
|
||||
|
||||
@@ -34,6 +34,7 @@ var ThreadWidget = Widget.extend({
|
||||
'click .o_thread_show_more': '_onClickShowMore',
|
||||
'click .o_attachment_download': '_onAttachmentDownload',
|
||||
'click .o_attachment_view': '_onAttachmentView',
|
||||
'click .o_attachment_delete_cross': '_onDeleteAttachment',
|
||||
'click .o_thread_message_needaction': '_onClickMessageNeedaction',
|
||||
'click .o_thread_message_star': '_onClickMessageStar',
|
||||
'click .o_thread_message_reply': '_onClickMessageReply',
|
||||
@@ -410,6 +411,18 @@ var ThreadWidget = Widget.extend({
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
_onDeleteAttachment: function (ev) {
|
||||
ev.stopPropagation();
|
||||
var $target = $(ev.currentTarget);
|
||||
this.trigger_up('delete_attachment', {
|
||||
attachmentId: $target.data('id'),
|
||||
attachmentName: $target.data('name')
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} options
|
||||
|
||||
@@ -1,25 +1,36 @@
|
||||
.oe_chatter {
|
||||
|
||||
.btn.o_active_attach {
|
||||
color: #875A7B;
|
||||
height: 300px;
|
||||
}
|
||||
.o_chatter_attachment {
|
||||
padding: 3px;
|
||||
.o_mail_chatter_attachments {
|
||||
min-height: 50px;
|
||||
|
||||
.o_border_dashed {
|
||||
position: relative;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 30px;
|
||||
border-bottom: 1px dashed gray('300');
|
||||
text-align: center;
|
||||
.o_chatter_attachment {
|
||||
padding: 3px;
|
||||
|
||||
.o_attach_title {
|
||||
input.o_input_file {
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.o_border_dashed {
|
||||
position: relative;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
border-bottom: 1px dashed gray('300');
|
||||
text-align: center;
|
||||
|
||||
.o_attach_title {
|
||||
position: relative;
|
||||
top: 10px;
|
||||
margin: 0 auto;
|
||||
padding: 0 10px;
|
||||
font-weight: bold;
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
width: 100%;
|
||||
padding-top: 0!important;
|
||||
|
||||
.o_attachment_delete_cross {
|
||||
@include o-position-absolute($right: 6px, $top:7px);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.o_spinner {
|
||||
text-align: center;
|
||||
font-size: large;
|
||||
@@ -21,9 +26,16 @@
|
||||
position: relative;
|
||||
float: right;
|
||||
flex: 1 1 auto;
|
||||
|
||||
.o_chatter_button_attachment {
|
||||
height: 2.3em;
|
||||
height: $o-statusbar-height - 2px;
|
||||
float: right;
|
||||
padding: 0px;
|
||||
margin-right: 25px;
|
||||
|
||||
.fa-paperclip, .o_chatter_attachment_button_count {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.o_followers {
|
||||
height: $o-statusbar-height + 1;
|
||||
|
||||
@@ -434,6 +434,10 @@ $o-mail-attachment-margin: 5px;
|
||||
font-size: $font-size-sm;
|
||||
}
|
||||
|
||||
.o_attachment_delete_cross {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.o_attachment_download {
|
||||
@include o-position-absolute($right: 7px, $bottom:7px);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,16 @@
|
||||
<t t-call="mail.Attachment"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_chatter_attachment_form">
|
||||
<t t-call="HiddenInputFile">
|
||||
<t t-set="fileupload_id" t-value="widget.fileuploadId"/>
|
||||
<t t-set="fileupload_action" t-translation="off">/web/binary/upload_attachment</t>
|
||||
<t t-set="multi_upload" t-value="true"/>
|
||||
<input type="hidden" name="model" t-att-value="widget.currentResModel"/>
|
||||
<input type="hidden" name="id" t-att-value="widget.currentResID"/>
|
||||
<center><span class="btn btn-link o_upload_attachments_button"><span class="fa fa-plus-square"/> Add Attachments</span></center>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -96,11 +106,11 @@
|
||||
</t>
|
||||
|
||||
<t t-name="mail.chatter.Attachment.Button">
|
||||
<button t-attf-class="btn btn-sm btn-link o_chatter_button_attachment #{!count and 'o_hidden' or ''}" title="View all the attachments of the current record">
|
||||
<button class="btn btn-link o_chatter_button_attachment" title="View all the attachments of the current record">
|
||||
<span>
|
||||
<i class="fa fa-paperclip"/>
|
||||
<span class="o_chatter_attachment_button_count">
|
||||
<t t-esc="' ('+count+')'"/>
|
||||
<t t-esc="count"/>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@@ -523,6 +523,7 @@
|
||||
<div class="o_image_box">
|
||||
<div class="o_attachment_image" t-attf-style="background-image:url('/web/image/#{attachment.id}/160x160/?crop=true')"/>
|
||||
<div t-attf-class="o_image_overlay o_attachment_view" t-att-data-id="attachment.id">
|
||||
<span class="fa fa-times o_attachment_delete_cross" t-att-title="'Delete ' + attachment.name" t-att-data-id="attachment.id" t-att-data-name="attachment.name"/>
|
||||
<span class="o_attachment_title text-white"><t t-esc="attachment.name"/></span>
|
||||
<a class="o_attachment_download" t-att-href='attachment.url'>
|
||||
<i t-attf-class="fa fa-download text-white" t-att-title="'Download ' + attachment.name" role="img" aria-label="Download"></i>
|
||||
@@ -546,6 +547,7 @@
|
||||
<t t-set="type" t-value="attachment.mimetype and attachment.mimetype.split('/').shift()"/>
|
||||
<div t-attf-class="o_attachment #{ editable ? 'o_attachment_editable' : '' } #{attachment.upload ? 'o_attachment_uploading' : ''}" t-att-title="attachment.name">
|
||||
<div class="o_attachment_wrap">
|
||||
<span t-if="!editable" class="fa fa-times o_attachment_delete_cross" t-att-title="'Delete ' + attachment.name" t-att-data-id="attachment.id" t-att-data-name="attachment.name"/>
|
||||
<t t-set="has_preview" t-value="type == 'image' or type == 'video' or attachment.mimetype == 'application/pdf'"/>
|
||||
<t t-set="ext" t-value="attachment.filename.split('.').pop()"/>
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ QUnit.test('Activity Done keep feedback on blur', function (assert) {
|
||||
});
|
||||
|
||||
QUnit.test('attachmentBox basic rendering', function (assert) {
|
||||
assert.expect(11);
|
||||
assert.expect(19);
|
||||
this.data.partner.records.push({
|
||||
id: 7,
|
||||
display_name: "attachment_test",
|
||||
@@ -334,6 +334,19 @@ QUnit.test('attachmentBox basic rendering', function (assert) {
|
||||
assert.containsOnce(form, '.o_attachment_image', "there should be an image preview");
|
||||
assert.containsOnce(form, '.o_attachments_previews', "there should be a list of previews");
|
||||
assert.containsOnce(form, '.o_attachments_list', "there should be a list of non previewable attachments");
|
||||
assert.containsOnce(form, '.o_upload_attachments_button', "there should be an 'Add Attachments' button");
|
||||
assert.containsOnce(form, '.o_form_binary_form', "there should be a binary form");
|
||||
|
||||
assert.containsOnce(form, 'input[name="model"]', "there should be an model input");
|
||||
var $modelInput = form.$('input[name="model"]');
|
||||
assert.hasAttrValue($modelInput, 'value', 'partner');
|
||||
assert.hasAttrValue($modelInput, 'type', 'hidden');
|
||||
|
||||
assert.containsOnce(form, 'input[name="model"]', "there should be an id input");
|
||||
var $resIdInput = form.$('input[name="id"]');
|
||||
assert.hasAttrValue($resIdInput, 'value', '7');
|
||||
assert.hasAttrValue($resIdInput, 'type', 'hidden');
|
||||
|
||||
assert.strictEqual(form.$('.o_attachment_title').text(), 'name1',
|
||||
"the image name should be correct");
|
||||
// since there are two elements "Download name2"; one "name" and the other "txt" as text content, the following test
|
||||
|
||||
Reference in New Issue
Block a user