diff --git a/addons/mail/static/src/js/chatter.js b/addons/mail/static/src/js/chatter.js index c8496d62ef4ca..8c5c5d8ba836c 100644 --- a/addons/mail/static/src/js/chatter.js +++ b/addons/mail/static/src/js/chatter.js @@ -34,7 +34,15 @@ var Chatter = Widget.extend(chat_mixin, { }, supportedFieldTypes: ['one2many'], - // inherited + /** + * @override + * @param {widget} parent + * @param {Object} record + * @param {Object} mailFields + * @param {boolean} [mailFields.mail_activity=false] + * @param {boolean} [mailFields.mail_followers=false] + * @param {boolean} [mailFields.mail_thread=false] + */ init: function (parent, record, mailFields, options) { this._super.apply(this, arguments); this._setState(record); @@ -61,6 +69,9 @@ var Chatter = Widget.extend(chat_mixin, { this.postRefresh = nodeOptions.post_refresh || 'never'; } }, + /** + * @override + */ start: function () { this.$topbar = this.$('.o_chatter_topbar'); @@ -80,7 +91,15 @@ var Chatter = Widget.extend(chat_mixin, { return this._super.apply(this, arguments); }, - // public + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * @param {Object} record + * @param {integer} [record.res_id=undefined] + * @param {Object[]} [fieldNames=undefined] + */ update: function (record, fieldNames) { var self = this; @@ -120,7 +139,14 @@ var Chatter = Widget.extend(chat_mixin, { }); }, - // private + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + * @param {boolean} force + */ _closeComposer: function (force) { if (this.composer && (this.composer.is_empty() || force)) { this.$el.removeClass('o_chatter_composer_active'); @@ -129,6 +155,24 @@ var Chatter = Widget.extend(chat_mixin, { this.composer.clear_composer(); } }, + /** + * @private + */ + _disableChatter: function () { + this.$('.btn').prop('disabled', true); // disable buttons + }, + /** + * @private + */ + _enableChatter: function () { + this.$('.btn').prop('disabled', false); // enable buttons + }, + /** + * @private + * @param {Object} options + * @param {Object[]} [options.suggested_partners=[]] + * @param {boolean} [options.is_log=false] + */ _openComposer: function (options) { var self = this; var old_composer = this.composer; @@ -172,6 +216,11 @@ var Chatter = Widget.extend(chat_mixin, { self.$('.o_chatter_button_log_note').toggleClass('o_active', self.composer.options.is_log); }); }, + /** + * @private + * @param {Deferred} def + * @returns {Deferred} + */ _render: function (def) { // the rendering of the chatter is aynchronous: relational data of its fields needs to be // fetched (in some case, it might be synchronous as they hold an internal cache). @@ -196,9 +245,24 @@ var Chatter = Widget.extend(chat_mixin, { if (self.fields.thread) { self.fields.thread.$el.appendTo(self.$el); } - }).always($spinner.remove.bind($spinner)); + }).always(function () { + // disable widgets in creation mode, otherwise enable + self._switchEnableChatter(!self.creationMode); + $spinner.remove; + }); }, + /** + * @private + * @param {Object} record + * @param {integer} [record.res_id=false] + * @param {string} [record.model=false] + * @param {string} record.data.display_name + */ _setState: function (record) { + + this.wasCreationMode = !!this.creationMode; + this.creationMode = !record.res_id; + if (!this.record || this.record.res_id !== record.res_id) { this.context = { default_res_id: record.res_id || false, @@ -211,6 +275,20 @@ var Chatter = Widget.extend(chat_mixin, { this.record = record; this.record_name = record.data.display_name; }, + /** + * @private + * @param {boolean} [enable] use true to enable the buttons or false to disable them + */ + _switchEnableChatter: function (enable) { + if (_.isBoolean(enable)) { + enable ? this._enableChatter() : this._disableChatter(); + } else { + this.$('.btn').prop('disabled', !this.$('.btn').first().prop('disabled')); // toggle based on 1st btn + } + }, + /** + * @private + */ _updateMentionSuggestions: function () { if (!this.fields.followers) { return; @@ -243,7 +321,13 @@ var Chatter = Widget.extend(chat_mixin, { }); }, - // handlers + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @private + */ _onOpenComposerMessage: function () { var self = this; if (!this.suggested_partners_def) { @@ -275,9 +359,21 @@ var Chatter = Widget.extend(chat_mixin, { self._openComposer({ is_log: false, suggested_partners: suggested_partners }); }); }, + /** + * @private + */ _onOpenComposerNote: function () { this._openComposer({is_log: true}); }, + /** + * @private + * @param {OdooEvent} event + * @param {string} event.name='reload_mail_fields' + * @param {Object} event.data + * @param {boolean} [event.data.activity=false] + * @param {boolean} [event.data.followers=false] + * @param {boolean} [event.data.thread=false] + */ _onReloadMailFields: function (event) { var fieldNames = []; if (this.fields.activity && event.data.activity) { @@ -294,6 +390,9 @@ var Chatter = Widget.extend(chat_mixin, { keepChanges: true, }); }, + /** + * @private + */ _onScheduleActivity: function () { this.fields.activity.scheduleActivity(false); }, diff --git a/addons/mail/static/src/js/form_renderer.js b/addons/mail/static/src/js/form_renderer.js index 574075db9d64d..47a2b6b795ecc 100644 --- a/addons/mail/static/src/js/form_renderer.js +++ b/addons/mail/static/src/js/form_renderer.js @@ -44,39 +44,22 @@ FormRenderer.include({ /** * Overrides the function that renders the nodes to return the chatter's $el * for the 'oe_chatter' div node. - * Returns an empty div instead of the chatter's $el in create mode. * * @override * @private */ _renderNode: function (node) { if (node.tag === 'div' && node.attrs.class === 'oe_chatter') { - if (this.chatter) { - // Detach the chatter before updating the $el. - // This is important because if the view is now in create mode - // (edit mode with no res_id), the chatter will be removed from - // the DOM, and its handlers will be unbound. By detaching it - // beforehand, we ensure to keep its handlers alive so that if - // it is re-appended later, everything will still work properly - this.chatter.$el.detach(); - } - if (this.mode === 'edit' && !this.state.data.id) { - // there is no chatter in create mode - var $div = $('
Creating a new record...
", + date: moment(), + author_id: [session.partner_id, session.partner_display_name], + displayed_author: session.partner_display_name, + avatar_src: "/web/image/res.partner/" + session.partner_id + "/image_small", + attachment_ids: [], + customer_email_data: [], + tracking_value_ids: [], + }]; + }, + /** + * @private + * @param {integer[]} ids + * @param {Object} [options] + */ _fetchAndRenderThread: function (ids, options) { var self = this; options = options || {}; options.ids = ids; var fetch_def = this.dp.add(this._getMessages(options)); return fetch_def.then(function (raw_messages) { - self.thread.render(raw_messages, {display_load_more: raw_messages.length < ids.length}); + var isCreationMode = false; + if (!self.res_id) { + raw_messages = self._forgeCreationModeMessages(); + isCreationMode = true; + } + self.thread.render(raw_messages, { + display_load_more: raw_messages.length < ids.length, + isCreationMode: isCreationMode, + }); }); }, - // handlers + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + /** * When a new message arrives, fetch its data to render it * @param {Number} message_id : the identifier of the new message diff --git a/addons/mail/static/src/xml/chatter.xml b/addons/mail/static/src/xml/chatter.xml index d45bd3312037e..e36bff6e6f1d4 100644 --- a/addons/mail/static/src/xml/chatter.xml +++ b/addons/mail/static/src/xml/chatter.xml @@ -50,14 +50,14 @@ Chatter (mail_thread widget) buttons -->