summaryrefslogtreecommitdiff
path: root/addons/mail/static/src/js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/mail/static/src/js')
-rw-r--r--addons/mail/static/src/js/attachment_box.js91
-rw-r--r--addons/mail/static/src/js/chatter.js141
-rw-r--r--addons/mail/static/src/js/composers/chatter_composer.js3
-rw-r--r--addons/mail/static/src/js/discuss_mobile.js2
-rw-r--r--addons/mail/static/src/js/models/messages/abstract_message.js8
-rw-r--r--addons/mail/static/src/js/models/threads/document_thread.js8
-rw-r--r--addons/mail/static/src/js/thread_field.js6
-rw-r--r--addons/mail/static/src/js/thread_widget.js13
-rw-r--r--addons/mail/static/src/js/tools/debug_manager.js4
-rw-r--r--addons/mail/static/src/js/tour.js25
-rw-r--r--addons/mail/static/src/js/views/activity/activity_view.js2
11 files changed, 229 insertions, 74 deletions
diff --git a/addons/mail/static/src/js/attachment_box.js b/addons/mail/static/src/js/attachment_box.js
index b42e8aeca95..f58c64f26e7 100644
--- a/addons/mail/static/src/js/attachment_box.js
+++ b/addons/mail/static/src/js/attachment_box.js
@@ -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;
@@ -72,6 +69,19 @@ var AttachmentBox = Widget.extend({
//--------------------------------------------------------------------------
/**
+ * 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
* used to prevent the click from opening the document viewer.
@@ -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;
diff --git a/addons/mail/static/src/js/chatter.js b/addons/mail/static/src/js/chatter.js
index 000353d1219..da23521f65f 100644
--- a/addons/mail/static/src/js/chatter.js
+++ b/addons/mail/static/src/js/chatter.js
@@ -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 () {
@@ -322,6 +357,16 @@ var Chatter = Widget.extend({
},
/**
* @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
* @returns {Deferred}
*/
@@ -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
+ */
+ _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
*/
- _onOpenAttachments: function () {
- if (this.attachmentBoxOpened) {
+ _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));
}
},
/**
@@ -485,6 +566,12 @@ var Chatter = Widget.extend({
},
/**
* @private
+ */
+ _onReloadAttachmentBox: function () {
+ this._reloadAttachmentBox();
+ },
+ /**
+ * @private
* @param {OdooEvent} event
* @param {string} event.name
* @param {Object} event.data
diff --git a/addons/mail/static/src/js/composers/chatter_composer.js b/addons/mail/static/src/js/composers/chatter_composer.js
index cda91eab205..777467e6eb8 100644
--- a/addons/mail/static/src/js/composers/chatter_composer.js
+++ b/addons/mail/static/src/js/composers/chatter_composer.js
@@ -3,6 +3,7 @@ odoo.define('mail.composer.Chatter', function (require) {
var BasicComposer = require('mail.composer.Basic');
var mailUtils = require('mail.utils');
+var session = require('web.session');
var core = require('web.core');
var viewDialogs = require('web.view_dialogs');
@@ -195,7 +196,7 @@ var ChatterComposer = BasicComposer.extend({
message = _.extend(message, {
subtype: 'mail.mt_comment',
message_type: 'comment',
- context: self.context,
+ context: _.defaults({}, self.context, session.user_context),
});
// Subtype
diff --git a/addons/mail/static/src/js/discuss_mobile.js b/addons/mail/static/src/js/discuss_mobile.js
index 30136fee798..549e05b78fd 100644
--- a/addons/mail/static/src/js/discuss_mobile.js
+++ b/addons/mail/static/src/js/discuss_mobile.js
@@ -16,7 +16,7 @@ if (!config.device.isMobile) {
* Overrides Discuss module in mobile
*/
Discuss.include({
- template: 'mail.discuss_mobile',
+ contentTemplate: 'mail.discuss_mobile',
events: _.extend(Discuss.prototype.events, {
'click .o_mail_mobile_tab': '_onMobileTabClicked',
'click .o_mailbox_inbox_item': '_onMobileInboxButtonClicked',
diff --git a/addons/mail/static/src/js/models/messages/abstract_message.js b/addons/mail/static/src/js/models/messages/abstract_message.js
index f5cf55f0ef1..c1ae22b9708 100644
--- a/addons/mail/static/src/js/models/messages/abstract_message.js
+++ b/addons/mail/static/src/js/models/messages/abstract_message.js
@@ -336,6 +336,14 @@ var AbstractMessage = Class.extend({
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.
*
diff --git a/addons/mail/static/src/js/models/threads/document_thread.js b/addons/mail/static/src/js/models/threads/document_thread.js
index d902d69765c..6c15b39d25e 100644
--- a/addons/mail/static/src/js/models/threads/document_thread.js
+++ b/addons/mail/static/src/js/models/threads/document_thread.js
@@ -157,6 +157,14 @@ var DocumentThread = Thread.extend({
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
*
* Useful in order to handle message history of the document thread,
diff --git a/addons/mail/static/src/js/thread_field.js b/addons/mail/static/src/js/thread_field.js
index 5c85a2adb37..a3807802ad7 100644
--- a/addons/mail/static/src/js/thread_field.js
+++ b/addons/mail/static/src/js/thread_field.js
@@ -71,6 +71,12 @@ var ThreadField = AbstractField.extend({
//--------------------------------------------------------------------------
/**
+ * @param {integer[]} attachmentIDs
+ */
+ removeAttachments: function (attachmentIDs) {
+ this._documentThread.removeAttachmentsFromMessages(attachmentIDs);
+ },
+ /**
* @override
* @return {boolean}
*/
diff --git a/addons/mail/static/src/js/thread_widget.js b/addons/mail/static/src/js/thread_widget.js
index d812d403007..2e2b7e222c6 100644
--- a/addons/mail/static/src/js/thread_widget.js
+++ b/addons/mail/static/src/js/thread_widget.js
@@ -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',
@@ -411,6 +412,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
* @param {integer} [options.channelID]
diff --git a/addons/mail/static/src/js/tools/debug_manager.js b/addons/mail/static/src/js/tools/debug_manager.js
index 4c768e8bb2d..452a062806f 100644
--- a/addons/mail/static/src/js/tools/debug_manager.js
+++ b/addons/mail/static/src/js/tools/debug_manager.js
@@ -23,6 +23,10 @@ DebugManager.include({
views: [[false, 'list'], [false, 'form']],
type: 'ir.actions.act_window',
domain: [['res_id', '=', selectedIDs[0]], ['model', '=', this._controller.modelName]],
+ context: {
+ default_res_model: this._controller.modelName,
+ default_res_id: selectedIDs[0],
+ },
});
},
});
diff --git a/addons/mail/static/src/js/tour.js b/addons/mail/static/src/js/tour.js
index 6b7160f2aa6..c345f2cd8a4 100644
--- a/addons/mail/static/src/js/tour.js
+++ b/addons/mail/static/src/js/tour.js
@@ -7,33 +7,24 @@ var tour = require('web_tour.tour');
var _t = core._t;
tour.register('mail_tour', {
- url: "/web",
-}, [tour.STEPS.SHOW_APPS_MENU_ITEM, {
- trigger: '.o_app[data-menu-xmlid="mail.menu_root_discuss"]',
- content: _t('Want to <b>get in touch</b> with your contacts? <i>Discuss with them here.</i>'),
- position: 'right',
- edition: 'community',
-}, {
- trigger: '.o_app[data-menu-xmlid="mail.menu_root_discuss"]',
- content: _t('Want to <b>get in touch</b> with your contacts? <i>Discuss with them here.</i>'),
- position: 'bottom',
- edition: 'enterprise',
-}, {
- trigger: '.o_mail_discuss .o_mail_discuss_sidebar .o_add[data-type="public"]',
+ url: "/web#action=mail.discuss",
+}, [{
+ trigger: '.o_mail_discuss .o_mail_discuss_sidebar .o_add[data-type="multi_user_channel"]',
content: _t("<p>Channels make it easy to organize information across different topics and groups.</p> <p>Try to <b>create your first channel</b> (e.g. sales, marketing, product XYZ, after work party, etc).</p>"),
position: 'bottom',
}, {
- trigger: '.o_mail_discuss .o_mail_discuss_sidebar .o_mail_add_thread[data-type="public"]',
+ trigger: '.o_mail_discuss .o_mail_discuss_sidebar .o_mail_add_thread[data-type="multi_user_channel"]',
content: _t("<p>Create a channel here.</p>"),
position: 'right',
+ auto: true,
run: function (actions) {
var t = new Date().getTime();
actions.text("SomeChannel_" + t, this.$anchor.find("input"));
},
}, {
- trigger: ".ui-menu-item > a",
- auto: true,
- in_modal: false,
+ trigger: ".ui-autocomplete .ui-menu-item > a:contains(Private)",
+ content: _t("<p> Create a private channel.</p>"),
+ position: 'right',
}, {
trigger: '.o_mail_discuss .o_composer_text_field',
content: _t("<p><b>Write a message</b> to the members of the channel here.</p> <p>You can notify someone with <i>'@'</i> or link another channel with <i>'#'</i>. Start your message with <i>'/'</i> to get the list of possible commands.</p>"),
diff --git a/addons/mail/static/src/js/views/activity/activity_view.js b/addons/mail/static/src/js/views/activity/activity_view.js
index b2c707f9d2d..9f0cec6b761 100644
--- a/addons/mail/static/src/js/views/activity/activity_view.js
+++ b/addons/mail/static/src/js/views/activity/activity_view.js
@@ -13,7 +13,7 @@ var _lt = core._lt;
var ActivityView = AbstractView.extend({
accesskey: "a",
display_name: _lt('Activity'),
- icon: 'fa-th',
+ icon: 'fa-clock-o',
config: _.extend({}, AbstractView.prototype.config, {
Controller: ActivityController,
Model: ActivityModel,