summaryrefslogtreecommitdiff
path: root/addons/mail/static/src
diff options
context:
space:
mode:
authorVincent Schippefilt <vsc@odoo.com>2019-03-06 14:02:19 +0100
committerAaron Bohy <aab@odoo.com>2019-03-06 20:07:17 +0100
commit1ae64793fa489b2c1d07408cd9671bc7126f78fa (patch)
tree23d908222f4e705b908dd23ef3823c26daf3baf0 /addons/mail/static/src
parentaa900d976f6fbb10f3940639b4d918d31a7556ca (diff)
[REF] mail: adapt code after jQuery update
Part of task 1896658 Co-authored-by: Aaron Bohy <aab@odoo.com> Co-authored-by: Christophe Matthieu <chm@odoo.com> Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com> Co-authored-by: David Monjoie <dmo@odoo.com> Co-authored-by: Martin Geubelle <mge@odoo.com> Co-authored-by: svs-odoo <svs@odoo.com> Co-authored-by: Vincent Schippefilt <vsc@odoo.com>
Diffstat (limited to 'addons/mail/static/src')
-rw-r--r--addons/mail/static/src/js/activity.js22
-rw-r--r--addons/mail/static/src/js/chatter.js53
-rw-r--r--addons/mail/static/src/js/composers/basic_composer.js55
-rw-r--r--addons/mail/static/src/js/composers/chatter_composer.js256
-rw-r--r--addons/mail/static/src/js/composers/extended_composer.js2
-rw-r--r--addons/mail/static/src/js/composers/mention_manager.js2
-rw-r--r--addons/mail/static/src/js/discuss.js27
-rw-r--r--addons/mail/static/src/js/discuss_mobile.js4
-rw-r--r--addons/mail/static/src/js/document_viewer.js4
-rw-r--r--addons/mail/static/src/js/followers.js38
-rw-r--r--addons/mail/static/src/js/form_renderer.js12
-rw-r--r--addons/mail/static/src/js/many2many_tags_email.js58
-rw-r--r--addons/mail/static/src/js/models/messages/message.js2
-rw-r--r--addons/mail/static/src/js/models/threads/abstract_thread.js14
-rw-r--r--addons/mail/static/src/js/models/threads/channel.js32
-rw-r--r--addons/mail/static/src/js/models/threads/document_thread.js14
-rw-r--r--addons/mail/static/src/js/models/threads/livechat.js2
-rw-r--r--addons/mail/static/src/js/models/threads/mailbox.js6
-rw-r--r--addons/mail/static/src/js/models/threads/mixins/thread_typing_mixin.js4
-rw-r--r--addons/mail/static/src/js/models/threads/multi_user_channel.js2
-rw-r--r--addons/mail/static/src/js/models/threads/searchable_thread.js4
-rw-r--r--addons/mail/static/src/js/models/threads/thread.js22
-rw-r--r--addons/mail/static/src/js/models/threads/two_user_channel.js2
-rw-r--r--addons/mail/static/src/js/services/mail_document_thread_manager.js2
-rw-r--r--addons/mail/static/src/js/services/mail_manager.js152
-rw-r--r--addons/mail/static/src/js/services/mail_notification_manager.js29
-rw-r--r--addons/mail/static/src/js/services/mail_status_manager.js2
-rw-r--r--addons/mail/static/src/js/services/mail_window_manager.js27
-rw-r--r--addons/mail/static/src/js/systray/systray_activity_menu.js2
-rw-r--r--addons/mail/static/src/js/systray/systray_messaging_menu.js4
-rw-r--r--addons/mail/static/src/js/thread_field.js14
-rw-r--r--addons/mail/static/src/js/thread_widget.js10
-rw-r--r--addons/mail/static/src/js/thread_windows/abstract_thread_window.js2
-rw-r--r--addons/mail/static/src/js/thread_windows/thread_window.js4
-rw-r--r--addons/mail/static/src/js/views/activity/activity_model.js6
-rw-r--r--addons/mail/static/src/js/views/activity/activity_renderer.js33
36 files changed, 487 insertions, 437 deletions
diff --git a/addons/mail/static/src/js/activity.js b/addons/mail/static/src/js/activity.js
index 68ff4b0b86f..607f1b8c553 100644
--- a/addons/mail/static/src/js/activity.js
+++ b/addons/mail/static/src/js/activity.js
@@ -25,11 +25,11 @@ var _t = core._t;
*
* @param {Widget} self a widget instance that can perform RPCs
* @param {Array} ids the ids of activities to read
- * @return {Deferred<Array>} resolved with the activities
+ * @return {Promise<Array>} resolved with the activities
*/
function _readActivities(self, ids) {
if (!ids.length) {
- return $.when([]);
+ return Promise.resolve([]);
}
var context = self.getSession().user_context;
if (self.record && !_.isEmpty(self.record.getContext())) {
@@ -64,7 +64,7 @@ BasicModel.include({
* @private
* @param {Object} record - an element from the localData
* @param {string} fieldName
- * @return {Deferred<Array>} resolved with the activities
+ * @return {Promise<Array>} resolved with the activities
*/
_fetchSpecialActivity: function (record, fieldName) {
var localID = (record._changes && fieldName in record._changes) ?
@@ -144,7 +144,7 @@ var BasicActivity = AbstractField.extend({
/**
* @param {integer} previousActivityTypeID
- * @return {$.Promise}
+ * @return {Promise}
*/
scheduleActivity: function () {
var callback = this._reload.bind(this, { activity: true, thread: true });
@@ -213,7 +213,7 @@ var BasicActivity = AbstractField.extend({
* @param {integer} id
* @param {integer} previousActivityTypeID
* @param {function} callback
- * @return {$.Deferred}
+ * @return {Promise}
*/
_openActivityForm: function (id, callback) {
var action = {
@@ -237,7 +237,7 @@ var BasicActivity = AbstractField.extend({
* @param {integer} activityID
* @param {string} feedback
* @param {integer[]} attachmentIds
- * @return {$.Promise}
+ * @return {Promise}
*/
_sendActivityFeedback: function (activityID, feedback, attachmentIds) {
return this._rpc({
@@ -303,7 +303,7 @@ var BasicActivity = AbstractField.extend({
/**
* @private
* @param {MouseEvent} ev
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_onEditActivity: function (ev) {
ev.preventDefault();
@@ -449,7 +449,7 @@ var BasicActivity = AbstractField.extend({
/**
* @private
* @param {MouseEvent} ev
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
_onPreviewMailTemplate: function (ev) {
ev.stopPropagation();
@@ -477,7 +477,7 @@ var BasicActivity = AbstractField.extend({
/**
* @private
* @param {MouseEvent} ev
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_onSendMailTemplate: function (ev) {
ev.stopPropagation();
@@ -493,7 +493,7 @@ var BasicActivity = AbstractField.extend({
/**
* @private
* @param {MouseEvent} ev
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
_onScheduleActivity: function (ev) {
ev.preventDefault();
@@ -504,7 +504,7 @@ var BasicActivity = AbstractField.extend({
* @private
* @param {MouseEvent} ev
* @param {Object} options
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_onUnlinkActivity: function (ev, options) {
ev.preventDefault();
diff --git a/addons/mail/static/src/js/chatter.js b/addons/mail/static/src/js/chatter.js
index 72971fbeee9..397ae2c8a16 100644
--- a/addons/mail/static/src/js/chatter.js
+++ b/addons/mail/static/src/js/chatter.js
@@ -103,7 +103,7 @@ var Chatter = Widget.extend({
}));
// start and append the widgets
var fieldDefs = _.invoke(this.fields, 'appendTo', $('<div>'));
- var def = this._dp.add($.when.apply($, fieldDefs));
+ var def = this._dp.add(Promise.all(fieldDefs));
this._render(def).then(this._updateMentionSuggestions.bind(this));
return this._super.apply(this, arguments);
@@ -153,7 +153,7 @@ var Chatter = Widget.extend({
fieldsToReset = this.fields;
}
var fieldDefs = _.invoke(fieldsToReset, 'reset', record);
- var def = this._dp.add($.when.apply($, fieldDefs));
+ var def = this._dp.add(Promise.all(fieldDefs));
this._render(def).then(function () {
self.$el.height('auto');
self._updateMentionSuggestions();
@@ -203,17 +203,18 @@ var Chatter = Widget.extend({
* Discard changes on the record.
*
* @private
- * @returns {$.Deferred} resolved if successfully discarding changes on
+ * @returns {Promise} resolved if successfully discarding changes on
* the record, rejected otherwise
*/
_discardChanges: function () {
- var def = $.Deferred();
- this.trigger_up('discard_changes', {
- recordID: this.record.id,
- onSuccess: def.resolve.bind(def),
- onFailure: def.reject.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('discard_changes', {
+ recordID: self.record.id,
+ onSuccess: resolve,
+ onFailure: reject,
+ });
});
- return def;
},
/**
* Discard changes on the record if the message will reload the record
@@ -221,14 +222,14 @@ var Chatter = Widget.extend({
*
* @private
* @param {Object} messageData
- * @return {$.Deferred} resolved if no reload or proceed to discard the
+ * @return {Promise} resolved if no reload or proceed to discard the
* changes on the record, rejected otherwise
*/
_discardOnReload: function (messageData) {
if (this._reloadAfterPost(messageData)) {
return this._discardChanges();
}
- return $.when();
+ return Promise.resolve();
},
/**
* @private
@@ -323,7 +324,7 @@ var Chatter = Widget.extend({
self._reloadAttachmentBox();
self.trigger_up('reload', {fieldNames: ['message_attachment_count'], keepChanges: true});
}
- }).fail(function () {
+ }).guardedCatch(function () {
self._enableComposer();
});
});
@@ -375,9 +376,9 @@ var Chatter = Widget.extend({
_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).
- // this function takes a deferred as argument, which is resolved once all fields have
+ // this function takes a promise as argument, which is resolved once all fields have
// fetched their data
- // this function appends the fields where they should be once the given deferred is resolved
+ // this function appends the fields where they should be once the given promise is resolved
// and if it takes more than 500ms, displays a spinner to indicate that it is loading
var self = this;
@@ -385,6 +386,11 @@ var Chatter = Widget.extend({
concurrency.rejectAfter(concurrency.delay(500), def).then(function () {
$spinner.appendTo(self.$el);
});
+ var always = function () {
+ // disable widgets in create mode, otherwise enable
+ self._isCreateMode ? self._disableChatter() : self._enableChatter();
+ $spinner.remove();
+ };
return def.then(function () {
if (self.fields.activity) {
@@ -400,11 +406,7 @@ var Chatter = Widget.extend({
if (self.fields.thread) {
self.fields.thread.$el.appendTo(self.$el);
}
- }).always(function () {
- // disable widgets in create mode, otherwise enable
- self._isCreateMode ? self._disableChatter() : self._enableChatter();
- $spinner.remove();
- });
+ }).then(always).guardedCatch(always);
},
/**
* @private
@@ -517,7 +519,7 @@ var Chatter = Widget.extend({
if (!this._areAttachmentsLoaded) {
def = this._fetchAttachments();
}
- $.when(def).then(this._openAttachmentBox.bind(this));
+ Promise.resolve(def).then(this._openAttachmentBox.bind(this));
}
},
/**
@@ -534,10 +536,10 @@ var Chatter = Widget.extend({
_onOpenComposerMessage: function () {
var self = this;
if (!this.suggested_partners_def) {
- this.suggested_partners_def = $.Deferred();
- var method = 'message_get_suggested_recipients';
- var args = [[this.context.default_res_id], this.context];
- this._rpc({model: this.record.model, method: method, args: args})
+ this.suggested_partners_def = new Promise(function (resolve, reject) {
+ var method = 'message_get_suggested_recipients';
+ var args = [[self.context.default_res_id], self.context];
+ self._rpc({model: self.record.model, method: method, args: args})
.then(function (result) {
if (!self.suggested_partners_def) {
return; // widget has been reset (e.g. we just switched to another record)
@@ -555,8 +557,9 @@ var Chatter = Widget.extend({
reason: recipient[2],
});
});
- self.suggested_partners_def.resolve(suggested_partners);
+ resolve(suggested_partners);
});
+ });
}
this.suggested_partners_def.then(function (suggested_partners) {
self._openComposer({ isLog: false, suggested_partners: suggested_partners });
diff --git a/addons/mail/static/src/js/composers/basic_composer.js b/addons/mail/static/src/js/composers/basic_composer.js
index 9def912612c..72936152ae5 100644
--- a/addons/mail/static/src/js/composers/basic_composer.js
+++ b/addons/mail/static/src/js/composers/basic_composer.js
@@ -128,7 +128,7 @@ var BasicComposer = Widget.extend({
.on('update_typing_partners', this, this._onUpdateTypingPartners);
// Mention
- this._mentionManager.prependTo(this.$('.o_composer'));
+ var prependPromise = this._mentionManager.prependTo(this.$('.o_composer'));
// Drag-Drop files
// Allowing body to detect dragenter and dragleave for display
@@ -137,7 +137,7 @@ var BasicComposer = Widget.extend({
$body.on('dragleave.' + this._dropZoneNS, this._onBodyFileDragLeave.bind(this));
$body.on("dragover." + this._dropZoneNS, this._onBodyFileDragover.bind(this));
$body.on("drop." + this._dropZoneNS, this._onBodyFileDrop.bind(this));
- return this._super();
+ return Promise.all([this._super(), prependPromise]);
},
destroy: function () {
$("body").off('dragleave.' + this._dropZoneNS);
@@ -236,7 +236,7 @@ var BasicComposer = Widget.extend({
* displayed to the user. If none of them match, then it will fetch for more
* partner suggestions (@see _mentionFetchPartners).
*
- * @param {$.Deferred<Object[]>} prefetchedPartners list of list of
+ * @param {Promise<Object[]>} prefetchedPartners list of list of
* prefetched partners.
*/
mentionSetPrefetchedPartners: function (prefetchedPartners) {
@@ -299,20 +299,21 @@ var BasicComposer = Widget.extend({
/**
* @private
* @param {string} search
- * @returns {$.Deferred<Object[]>}
+ * @returns {Promise<Object[]>}
*/
_mentionGetCannedResponses: function (search) {
var self = this;
- var def = $.Deferred();
- clearTimeout(this._cannedTimeout);
- this._cannedTimeout = setTimeout(function () {
- var cannedResponses = self.call('mail_service', 'getCannedResponses');
- var matches = fuzzy.filter(utils.unaccent(search), _.pluck(cannedResponses, 'source'));
- var indexes = _.pluck(matches.slice(0, self.options.mentionFetchLimit), 'index');
- def.resolve(_.map(indexes, function (index) {
- return cannedResponses[index];
- }));
- }, 500);
+ var def = new Promise(function (resolve, reject) {
+ clearTimeout(self._cannedTimeout);
+ self._cannedTimeout = setTimeout(function () {
+ var cannedResponses = self.call('mail_service', 'getCannedResponses');
+ var matches = fuzzy.filter(utils.unaccent(search), _.pluck(cannedResponses, 'source'));
+ var indexes = _.pluck(matches.slice(0, self.options.mentionFetchLimit), 'index');
+ resolve(_.map(indexes, function (index) {
+ return cannedResponses[index];
+ }));
+ }, 500);
+ });
return def;
},
/**
@@ -346,7 +347,7 @@ var BasicComposer = Widget.extend({
*/
_mentionFetchPartners: function (search) {
var self = this;
- return $.when(this._mentionPrefetchedPartners).then(function (prefetchedPartners) {
+ return Promise.resolve(this._mentionPrefetchedPartners).then(function (prefetchedPartners) {
// filter prefetched partners with the given search string
var suggestions = [];
var limit = self.options.mentionFetchLimit;
@@ -371,7 +372,7 @@ var BasicComposer = Widget.extend({
{ limit: limit, search: search }
);
}
- return $.when(suggestions).then(function (suggestions) {
+ return Promise.resolve(suggestions).then(function (suggestions) {
//add im_status on suggestions
_.each(suggestions, function (suggestionsSet) {
_.each(suggestionsSet, function (suggestion) {
@@ -387,27 +388,27 @@ var BasicComposer = Widget.extend({
* @param {string} model
* @param {string} method
* @param {Object} kwargs
- * @return {$.Deferred}
+ * @return {Promise}
*/
_mentionFetchThrottled: function (model, method, kwargs) {
var self = this;
// Delays the execution of the RPC to prevent unnecessary RPCs when the user is still typing
- var def = $.Deferred();
- clearTimeout(this.mentionFetchTimer);
- this.mentionFetchTimer = setTimeout(function () {
- return self._rpc({model: model, method: method, kwargs: kwargs})
+ return new Promise(function (resolve, reject) {
+ clearTimeout(self.mentionFetchTimer);
+ self.mentionFetchTimer = setTimeout(function () {
+ return self._rpc({model: model, method: method, kwargs: kwargs})
.then(function (results) {
- def.resolve(results);
+ resolve(results);
});
- }, this.MENTION_THROTTLE);
- return def;
+ }, self.MENTION_THROTTLE);
+ });
},
/**
* @private
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
_preprocessMessage: function () {
- // Return a deferred as this function is extended with asynchronous
+ // Return a promise as this function is extended with asynchronous
// behavior for the chatter composer
//Removing unwanted extra spaces from message
@@ -420,7 +421,7 @@ var BasicComposer = Widget.extend({
var commands = this.options.commandsEnabled ?
this._mentionManager.getListenerSelection('/') :
[];
- return $.when({
+ return Promise.resolve({
content: this._mentionManager.generateLinks(value),
attachment_ids: _.pluck(this.get('attachment_ids'), 'id'),
partner_ids: _.uniq(_.pluck(this._mentionManager.getListenerSelection('@'), 'id')),
diff --git a/addons/mail/static/src/js/composers/chatter_composer.js b/addons/mail/static/src/js/composers/chatter_composer.js
index 777467e6eb8..8aaaf08dd6d 100644
--- a/addons/mail/static/src/js/composers/chatter_composer.js
+++ b/addons/mail/static/src/js/composers/chatter_composer.js
@@ -59,109 +59,112 @@ var ChatterComposer = BasicComposer.extend({
* @private
* @param {Array} checkedSuggestedPartners list of 'recipient' partners to
* complete informations or validate
- * @returns {Deferred} resolved with the list of checked suggested partners
+ * @returns {Promise} resolved with the list of checked suggested partners
* (real partner)
**/
_checkSuggestedPartners: function (checkedSuggestedPartners) {
var self = this;
- var checkDone = $.Deferred();
+ var checkDone = new Promise(function (resolve, reject) {
+ var recipients = _.filter(checkedSuggestedPartners, function (recipient) {
+ return recipient.checked;
+ });
+ var recipientsToFind = _.filter(recipients, function (recipient) {
+ return (! recipient.partner_id);
+ });
+ var namesToFind = _.pluck(recipientsToFind, 'full_name');
+ var recipientsToCheck = _.filter(recipients, function (recipient) {
+ return (recipient.partner_id && ! recipient.email_address);
+ });
+ var recipientIDs = _.pluck(_.filter(recipients, function (recipient) {
+ return recipient.partner_id && recipient.email_address;
+ }), 'partner_id');
- var recipients = _.filter(checkedSuggestedPartners, function (recipient) {
- return recipient.checked;
- });
- var recipientsToFind = _.filter(recipients, function (recipient) {
- return (! recipient.partner_id);
- });
- var namesToFind = _.pluck(recipientsToFind, 'full_name');
- var recipientsToCheck = _.filter(recipients, function (recipient) {
- return (recipient.partner_id && ! recipient.email_address);
- });
- var recipientIDs = _.pluck(_.filter(recipients, function (recipient) {
- return recipient.partner_id && recipient.email_address;
- }), 'partner_id');
+ var namesToRemove = [];
+ var recipientIDsToRemove = [];
- var namesToRemove = [];
- var recipientIDsToRemove = [];
+ // have unknown names
+ // -> call message_get_partner_info_from_emails to try to find
+ // partner_id
+ var def;
+ if (namesToFind.length > 0) {
+ def = self._rpc({
+ model: self._model,
+ method: 'message_partner_info_from_emails',
+ args: [[self.context.default_res_id], namesToFind],
+ });
+ }
- // have unknown names
- // -> call message_get_partner_info_from_emails to try to find
- // partner_id
- var def;
- if (namesToFind.length > 0) {
- def = this._rpc({
- model: this._model,
- method: 'message_partner_info_from_emails',
- args: [[this.context.default_res_id], namesToFind],
- });
- }
+ // for unknown names + incomplete partners
+ // -> open popup - cancel = remove from recipients
+ Promise.resolve(def).then(function (result) {
+ result = result || [];
+ var emailDefs = [];
+ var recipientPopups = result.concat(recipientsToCheck);
- // for unknown names + incomplete partners
- // -> open popup - cancel = remove from recipients
- $.when(def).pipe(function (result) {
- result = result || [];
- var emailDefs = [];
- var recipientPopups = result.concat(recipientsToCheck);
+ _.each(recipientPopups, function (partnerInfo) {
+ var prom = new Promise(function(innerResolve, innerReject) {
+ var partnerName = partnerInfo.full_name;
+ var partnerID = partnerInfo.partner_id;
+ var parsedEmail = mailUtils.parseEmail(partnerName);
- _.each(recipientPopups, function (partnerInfo) {
- var deferred = $.Deferred();
- emailDefs.push(deferred);
+ var dialog = new viewDialogs.FormViewDialog(self, {
+ res_model: 'res.partner',
+ res_id: partnerID,
+ context: {
+ active_model: self._model,
+ active_id: self.context.default_res_id,
+ force_email: true,
+ ref: 'compound_context',
+ default_name: parsedEmail[0],
+ default_email: parsedEmail[1],
+ },
+ title: _t("Please complete customer's informations"),
+ disable_multiple_selection: true,
+ }).open();
+ dialog.on('closed', self, function () {
+ innerResolve();
+ });
+ dialog.opened().then(function () {
+ dialog.form_view.on('on_button_cancel', self, function () {
+ namesToRemove.push(partnerName);
+ if (partnerID) {
+ recipientIDsToRemove.push(partnerID);
+ }
+ });
+ });
+ });
- var partnerName = partnerInfo.full_name;
- var partnerID = partnerInfo.partner_id;
- var parsedEmail = mailUtils.parseEmail(partnerName);
+ emailDefs.push(prom);
- var dialog = new viewDialogs.FormViewDialog(self, {
- res_model: 'res.partner',
- res_id: partnerID,
- context: {
- active_model: self._model,
- active_id: self.context.default_res_id,
- force_email: true,
- ref: 'compound_context',
- default_name: parsedEmail[0],
- default_email: parsedEmail[1],
- },
- title: _t("Please complete customer's informations"),
- disable_multiple_selection: true,
- }).open();
- dialog.on('closed', self, function () {
- deferred.resolve();
- });
- dialog.opened().then(function () {
- dialog.form_view.on('on_button_cancel', self, function () {
- namesToRemove.push(partnerName);
- if (partnerID) {
- recipientIDsToRemove.push(partnerID);
- }
- });
});
- });
- $.when.apply($, emailDefs).then(function () {
- var newNamesToFind = _.difference(namesToFind, namesToRemove);
- var def;
- if (newNamesToFind.length > 0) {
- def = self._rpc({
- model: self._model,
- method: 'message_partner_info_from_emails',
- args: [[self.context.default_res_id], newNamesToFind, true],
+ Promise.all(emailDefs).then(function () {
+ var newNamesToFind = _.difference(namesToFind, namesToRemove);
+ var def;
+ if (newNamesToFind.length > 0) {
+ def = self._rpc({
+ model: self._model,
+ method: 'message_partner_info_from_emails',
+ args: [[self.context.default_res_id], newNamesToFind, true],
+ });
+ }
+ Promise.resolve(def).then(function (result) {
+ result = result || [];
+ var recipientPopups = result.concat(recipientsToCheck);
+ _.each(recipientPopups, function (partnerInfo) {
+ if (
+ partnerInfo.partner_id &&
+ _.indexOf(partnerInfo.partner_id, recipientIDsToRemove) === -1
+ ) {
+ recipientIDs.push(partnerInfo.partner_id);
+ }
});
- }
- $.when(def).pipe(function (result) {
- result = result || [];
- var recipientPopups = result.concat(recipientsToCheck);
- _.each(recipientPopups, function (partnerInfo) {
- if (
- partnerInfo.partner_id &&
- _.indexOf(partnerInfo.partner_id, recipientIDsToRemove) === -1
- ) {
- recipientIDs.push(partnerInfo.partner_id);
- }
+ }).then(function () {
+ resolve(recipientIDs);
});
- }).pipe(function () {
- checkDone.resolve(recipientIDs);
});
});
});
+
return checkDone;
},
/**
@@ -187,41 +190,40 @@ var ChatterComposer = BasicComposer.extend({
/**
* @override
* @private
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
_preprocessMessage: function () {
var self = this;
- var def = $.Deferred();
- this._super().then(function (message) {
- message = _.extend(message, {
- subtype: 'mail.mt_comment',
- message_type: 'comment',
- context: _.defaults({}, self.context, session.user_context),
- });
+ return new Promise(function (resolve, reject) {
+ self._super().then(function (message) {
+ message = _.extend(message, {
+ subtype: 'mail.mt_comment',
+ message_type: 'comment',
+ context: _.defaults({}, self.context, session.user_context),
+ });
- // Subtype
- if (self.options.isLog) {
- message.subtype = 'mail.mt_note';
- }
+ // Subtype
+ if (self.options.isLog) {
+ message.subtype = 'mail.mt_note';
+ }
- // Partner_ids
- if (!self.options.isLog) {
- var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
- self._checkSuggestedPartners(checkedSuggestedPartners).done(function (partnerIDs) {
- message.partner_ids = (message.partner_ids || []).concat(partnerIDs);
- // update context
- message.context = _.defaults({}, message.context, {
- mail_post_autofollow: true,
+ // Partner_ids
+ if (!self.options.isLog) {
+ var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
+ self._checkSuggestedPartners(checkedSuggestedPartners).then(function (partnerIDs) {
+ message.partner_ids = (message.partner_ids || []).concat(partnerIDs);
+ // update context
+ message.context = _.defaults({}, message.context, {
+ mail_post_autofollow: true,
+ });
+ resolve(message);
});
- def.resolve(message);
- });
- } else {
- def.resolve(message);
- }
+ } else {
+ resolve(message);
+ }
+ });
});
-
- return def;
},
/**
* @override
@@ -244,20 +246,20 @@ var ChatterComposer = BasicComposer.extend({
}
var self = this;
- var recipientDoneDef = $.Deferred();
-
- // any operation on the full-composer will reload the record, so
- // warn the user that any unsaved changes on the record will be lost.
- this.trigger_up('discard_record_changes', {
- proceed: function () {
- if (self.options.isLog) {
- recipientDoneDef.resolve([]);
- } else {
- var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
- self._checkSuggestedPartners(checkedSuggestedPartners)
- .then(recipientDoneDef.resolve.bind(recipientDoneDef));
- }
- },
+ var recipientDoneDef = new Promise(function (resolve, reject) {
+ // any operation on the full-composer will reload the record, so
+ // warn the user that any unsaved changes on the record will be lost.
+ self.trigger_up('discard_record_changes', {
+ proceed: function () {
+ if (self.options.isLog) {
+ resolve([]);
+ } else {
+ var checkedSuggestedPartners = self._getCheckedSuggestedPartners();
+ self._checkSuggestedPartners(checkedSuggestedPartners)
+ .then(resolve);
+ }
+ },
+ });
});
recipientDoneDef.then(function (partnerIDs) {
diff --git a/addons/mail/static/src/js/composers/extended_composer.js b/addons/mail/static/src/js/composers/extended_composer.js
index 917b71fa880..1acfba1058c 100644
--- a/addons/mail/static/src/js/composers/extended_composer.js
+++ b/addons/mail/static/src/js/composers/extended_composer.js
@@ -102,7 +102,7 @@ var ExtendedComposer = BasicComposer.extend({
/**
* @override
* @private
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
_preprocessMessage: function () {
var self = this;
diff --git a/addons/mail/static/src/js/composers/mention_manager.js b/addons/mail/static/src/js/composers/mention_manager.js
index 6cbaab5002a..7ad8a36b39a 100644
--- a/addons/mail/static/src/js/composers/mention_manager.js
+++ b/addons/mail/static/src/js/composers/mention_manager.js
@@ -114,7 +114,7 @@ var MentionManager = Widget.extend({
if (this._activeListener) {
var mentionWord = this._mentionWord;
- $.when(this._activeListener.fetchCallback(mentionWord))
+ Promise.resolve(this._activeListener.fetchCallback(mentionWord))
.then(function (suggestions) {
if (mentionWord === self._mentionWord) {
// update suggestions only if mentionWord didn't change
diff --git a/addons/mail/static/src/js/discuss.js b/addons/mail/static/src/js/discuss.js
index 0e3b66dd720..4e88434f86d 100644
--- a/addons/mail/static/src/js/discuss.js
+++ b/addons/mail/static/src/js/discuss.js
@@ -82,7 +82,7 @@ var PartnerInviteDialog = Dialog.extend({
/**
* @private
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_addChannel: function () {
var self = this;
@@ -297,7 +297,7 @@ var Discuss = AbstractAction.extend({
* @override
*/
willStart: function () {
- return $.when(this._super(), this.call('mail_service', 'isReady'));
+ return Promise.all([this._super(), this.call('mail_service', 'isReady')]);
},
/**
* @override
@@ -331,7 +331,7 @@ var Discuss = AbstractAction.extend({
this._extendedComposer.appendTo(this.$('.o_mail_discuss_content')));
defs.push(this._super.apply(this, arguments));
- return $.when.apply($, defs)
+ return Promise.all(defs)
.then(function () {
return self._setThread(self._defaultThreadID);
})
@@ -474,7 +474,7 @@ var Discuss = AbstractAction.extend({
},
/**
* @private
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_fetchAndRenderThread: function () {
var self = this;
@@ -567,7 +567,7 @@ var Discuss = AbstractAction.extend({
* loaded when scrolling to the top, so they can't be loaded if there is no
* scrollbar)
*
- * @returns {Deferred} resolved when there are enough messages to fill the
+ * @returns {Promise} resolved when there are enough messages to fill the
* screen, or when there is no more message to fetch
*/
_loadEnoughMessages: function () {
@@ -583,7 +583,7 @@ var Discuss = AbstractAction.extend({
* Load more messages for the current thread
*
* @private
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_loadMoreMessages: function () {
var self = this;
@@ -647,7 +647,7 @@ var Discuss = AbstractAction.extend({
autoFocus: true,
source: function (request, response) {
self._lastSearchVal = _.escape(request.term);
- self._searchChannel(self._lastSearchVal).done(function (result){
+ self._searchChannel(self._lastSearchVal).then(function (result){
result.push({
label: _.str.sprintf(
'<strong>' + _t("Create %s (Public)") + '</strong>',
@@ -689,7 +689,7 @@ var Discuss = AbstractAction.extend({
autoFocus: true,
source: function (request, response) {
self._lastSearchVal = _.escape(request.term);
- self.call('mail_service', 'searchPartner', self._lastSearchVal, 10).done(response);
+ self.call('mail_service', 'searchPartner', self._lastSearchVal, 10).then(response);
},
select: function (ev, ui) {
var partnerID = ui.item.id;
@@ -819,7 +819,7 @@ var Discuss = AbstractAction.extend({
* Renders, binds events and appends a thread widget.
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderThread: function () {
this._threadWidget = new ThreadWidget(this, {
@@ -877,7 +877,7 @@ var Discuss = AbstractAction.extend({
/**
* @private
* @param {string} searchVal
- * @returns {$.Promise<Array>}
+ * @returns {Promise<Array>}
*/
_searchChannel: function (searchVal){
return this._rpc({
@@ -915,7 +915,7 @@ var Discuss = AbstractAction.extend({
this._extendedComposer.do_show();
this._threadWidget.scrollToMessage({
- msgID: messageID,
+ messageID: messageID,
duration: 200,
onlyIfNecessary: true
});
@@ -927,7 +927,7 @@ var Discuss = AbstractAction.extend({
*
* @private
* @param {integer} threadID a thread with such ID
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_setThread: function (threadID) {
var self = this;
@@ -1483,9 +1483,6 @@ var Discuss = AbstractAction.extend({
} else {
self._threadWidget.scrollToBottom();
}
- })
- .fail(function () {
- // todo: display notifications
});
},
/**
diff --git a/addons/mail/static/src/js/discuss_mobile.js b/addons/mail/static/src/js/discuss_mobile.js
index 549e05b78fd..617700c20c1 100644
--- a/addons/mail/static/src/js/discuss_mobile.js
+++ b/addons/mail/static/src/js/discuss_mobile.js
@@ -116,7 +116,7 @@ Discuss.include({
this._thread = thread;
if (thread.getType() !== 'mailbox') {
this.call('mail_service', 'openThreadWindow', threadID);
- return $.when();
+ return Promise.resolve();
} else {
return this._super.apply(this, arguments);
}
@@ -179,7 +179,7 @@ Discuss.include({
});
def = this.call('mail_service', 'getChannelPreviews', channels);
}
- return $.when(def).then(function (previews) {
+ return Promise.resolve(def).then(function (previews) {
// update content
if (inMailbox) {
if (!previouslyInInbox) {
diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js
index 9affc3f41cf..77f33d152c0 100644
--- a/addons/mail/static/src/js/document_viewer.js
+++ b/addons/mail/static/src/js/document_viewer.js
@@ -76,7 +76,7 @@ var DocumentViewer = Widget.extend({
start: function () {
this.$el.modal('show');
this.$el.on('hidden.bs.modal', _.bind(this._onDestroy, this));
- this.$('.o_viewer_img').load(_.bind(this._onImageLoaded, this));
+ this.$('.o_viewer_img').on("load", _.bind(this._onImageLoaded, this));
this.$('[data-toggle="tooltip"]').tooltip({delay: 0});
return this._super.apply(this, arguments);
},
@@ -132,7 +132,7 @@ var DocumentViewer = Widget.extend({
this.$('.o_viewer_content').html(QWeb.render('DocumentViewer.Content', {
widget: this
}));
- this.$('.o_viewer_img').load(_.bind(this._onImageLoaded, this));
+ this.$('.o_viewer_img').on("load", _.bind(this._onImageLoaded, this));
this.$('[data-toggle="tooltip"]').tooltip({delay: 0});
this._reset();
},
diff --git a/addons/mail/static/src/js/followers.js b/addons/mail/static/src/js/followers.js
index 0a760516607..a8475f43219 100644
--- a/addons/mail/static/src/js/followers.js
+++ b/addons/mail/static/src/js/followers.js
@@ -55,14 +55,14 @@ var Followers = AbstractField.extend({
// note: the rendering of this widget is asynchronous as it needs to
// fetch the details of the followers, but it performs a first rendering
// synchronously (_displayGeneric), and updates its rendering once it
- // has fetched the required data, so this function doesn't return a deferred
+ // has fetched the required data, so this function doesn't return a promise
// as we don't want to wait to the data to be loaded to display the widget
var self = this;
var fetch_def = this.dp.add(this._readFollowers());
concurrency.rejectAfter(concurrency.delay(0), fetch_def).then(this._displayGeneric.bind(this));
- fetch_def.then(function () {
+ return fetch_def.then(function () {
self._displayButtons();
self._displayFollowers(self.followers);
if (self.subtypes) { // current user is follower
@@ -203,7 +203,7 @@ var Followers = AbstractField.extend({
params: { follower_ids: missing_ids, res_model: this.model }
});
}
- return $.when(def).then(function (results) {
+ return Promise.resolve(def).then(function (results) {
if (results) {
self.followers = _.uniq(results.followers.concat(self.followers), 'id');
if (results.subtypes) { //read_followers will return False if current user is not in the list
@@ -241,27 +241,27 @@ var Followers = AbstractField.extend({
*/
_unfollow: function (ids) {
var self = this;
- var def = $.Deferred();
- var text = _t("Warning! \n If you remove a follower, he won't be notified of any email or discussion on this document.\n Do you really want to remove this follower ?");
- Dialog.confirm(this, text, {
- confirm_callback: function () {
- var args = [
- [self.res_id],
- ids.partner_ids,
- ids.channel_ids,
- {}, // FIXME
- ];
- self._rpc({
+ return new Promise(function (resolve, reject) {
+ var text = _t("Warning! \n If you remove a follower, he won't be notified of any email or discussion on this document.\n Do you really want to remove this follower ?");
+ Dialog.confirm(this, text, {
+ confirm_callback: function () {
+ var args = [
+ [self.res_id],
+ ids.partner_ids,
+ ids.channel_ids,
+ {}, // FIXME
+ ];
+ self._rpc({
model: self.model,
method: 'message_unsubscribe',
args: args
})
.then(self._reload.bind(self));
- def.resolve();
- },
- cancel_callback: def.reject.bind(def),
+ resolve();
+ },
+ cancel_callback: reject,
+ });
});
- return def;
},
_updateSubscription: function (event, followerID, isChannel) {
var ids = {};
@@ -290,7 +290,7 @@ var Followers = AbstractField.extend({
// If no more subtype followed, unsubscribe the follower
if (!checklist.length) {
- this._unfollow(ids).fail(function () {
+ this._unfollow(ids).guardedCatch(function () {
$(event.currentTarget).find('input').addBack('input').prop('checked', true);
});
} else {
diff --git a/addons/mail/static/src/js/form_renderer.js b/addons/mail/static/src/js/form_renderer.js
index 91d2c2033c4..e7b767c0b2f 100644
--- a/addons/mail/static/src/js/form_renderer.js
+++ b/addons/mail/static/src/js/form_renderer.js
@@ -50,18 +50,24 @@ FormRenderer.include({
* @private
*/
_renderNode: function (node) {
+ var self = this;
if (node.tag === 'div' && node.attrs.class === 'oe_chatter') {
if (!this.chatter) {
this.chatter = new Chatter(this, this.state, this.mailFields, {
isEditable: this.activeActions.edit,
viewType: 'form',
});
- this.chatter.appendTo($('<div>'));
- this._handleAttributes(this.chatter.$el, node);
+
+ var $temporaryParentDiv = $('<div>');
+ this.defs.push(this.chatter.appendTo($temporaryParentDiv).then(function () {
+ self.chatter.$el.unwrap();
+ self._handleAttributes(self.chatter.$el, node);
+ }));
+ return $temporaryParentDiv;
} else {
this.chatter.update(this.state);
+ return this.chatter.$el;
}
- return this.chatter.$el;
} else {
return this._super.apply(this, arguments);
}
diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js
index e66412a7a2c..6648ef50423 100644
--- a/addons/mail/static/src/js/many2many_tags_email.js
+++ b/addons/mail/static/src/js/many2many_tags_email.js
@@ -20,7 +20,7 @@ BasicModel.include({
* @private
* @param {Object} record - an element from the localData
* @param {string} fieldName
- * @return {Deferred<Object>} the deferred is resolved with the
+ * @return {Promise<Object>} the promise is resolved with the
* invalidPartnerIds
*/
_setInvalidMany2ManyTagsEmail: function (record, fieldName) {
@@ -42,10 +42,10 @@ BasicModel.include({
var changes = {operation: 'DELETE', ids: _.pluck(invalidPartnerIds, 'id')};
def = this._applyX2ManyChange(record, fieldName, changes);
}
- return $.when(def).then(function () {
- return $.when({
+ return Promise.resolve(def).then(function () {
+ return {
invalidPartnerIds: _.pluck(invalidPartnerIds, 'res_id'),
- });
+ };
});
},
});
@@ -65,7 +65,7 @@ var FieldMany2ManyTagsEmail = M2MTags.extend({
* Open a popup for each invalid partners (without email) to fill the email.
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_checkEmailPopup: function () {
var self = this;
@@ -75,25 +75,25 @@ var FieldMany2ManyTagsEmail = M2MTags.extend({
// propose the user to correct invalid partners
_.each(this.record.specialData[this.name].invalidPartnerIds, function (resID) {
- var def = $.Deferred();
- popupDefs.push(def);
-
- var pop = new form_common.FormViewDialog(self, {
- res_model: self.field.relation,
- res_id: resID,
- context: self.record.context,
- title: "",
- on_saved: function (record) {
- if (record.data.email) {
- validPartners.push(record.res_id);
- }
- },
- }).open();
- pop.on('closed', self, function () {
- def.resolve();
+ var def = new Promise(function (resolve, reject) {
+ var pop = new form_common.FormViewDialog(self, {
+ res_model: self.field.relation,
+ res_id: resID,
+ context: self.record.context,
+ title: "",
+ on_saved: function (record) {
+ if (record.data.email) {
+ validPartners.push(record.res_id);
+ }
+ },
+ }).open();
+ pop.on('closed', self, function () {
+ resolve();
+ });
});
+ popupDefs.push(def);
});
- return $.when.apply($, popupDefs).then(function() {
+ return Promise.all(popupDefs).then(function() {
// All popups have been processed for the given ids
// It is now time to set the final value with valid partners ids.
validPartners = _.uniq(validPartners);
@@ -117,14 +117,14 @@ var FieldMany2ManyTagsEmail = M2MTags.extend({
*/
_render: function () {
var self = this;
- var def = $.Deferred();
var _super = this._super.bind(this);
- if (this.record.specialData[this.name].invalidPartnerIds.length) {
- def = this._checkEmailPopup();
- } else {
- def.resolve();
- }
- return def.then(function () {
+ return new Promise(function (resolve, reject) {
+ if (self.record.specialData[self.name].invalidPartnerIds.length) {
+ resolve(self._checkEmailPopup());
+ } else {
+ resolve();
+ }
+ }).then(function () {
return _super.apply(self, arguments);
});
},
diff --git a/addons/mail/static/src/js/models/messages/message.js b/addons/mail/static/src/js/models/messages/message.js
index a414a11874b..77e4120da29 100644
--- a/addons/mail/static/src/js/models/messages/message.js
+++ b/addons/mail/static/src/js/models/messages/message.js
@@ -511,7 +511,7 @@ var Message = AbstractMessage.extend(Mixins.EventDispatcherMixin, ServicesMixin
* @see {mail.Manager.Notification} for the receipt of 'toggle_star'
* notification after this rpc.
*
- * @return {$.Promise}
+ * @return {Promise}
*/
toggleStarStatus: function () {
return this._rpc({
diff --git a/addons/mail/static/src/js/models/threads/abstract_thread.js b/addons/mail/static/src/js/models/threads/abstract_thread.js
index a515c4d2f8a..192d0e58c93 100644
--- a/addons/mail/static/src/js/models/threads/abstract_thread.js
+++ b/addons/mail/static/src/js/models/threads/abstract_thread.js
@@ -150,18 +150,18 @@ var AbstractThread = Class.extend(Mixins.EventDispatcherMixin, {
* Mark the thread as read, which resets the unread counter to 0. This is
* only performed if the unread counter is not 0.
*
- * @returns {$.Promise}
+ * @returns {Promise}
*/
markAsRead: function () {
if (this._unreadCounter > 0) {
return this._markAsRead();
}
- return $.when();
+ return Promise.resolve();
},
/**
* Post a message on this thread
*
- * @returns {$.Promise} resolved with the message object to be sent to the
+ * @returns {Promise} resolved with the message object to be sent to the
* server
*/
postMessage: function () {
@@ -200,22 +200,22 @@ var AbstractThread = Class.extend(Mixins.EventDispatcherMixin, {
* Mark the thread as read
*
* @private
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_markAsRead: function () {
this.resetUnreadCounter();
- return $.when();
+ return Promise.resolve();
},
/**
* Post a message on this thread
*
* @abstract
* @private
- * @returns {$.Promise} resolved with the message object to be sent to the
+ * @returns {Promise} resolved with the message object to be sent to the
* server
*/
_postMessage: function () {
- return $.when();
+ return Promise.resolve();
},
/**
* Warn views (e.g. discuss app, thread window, etc.) to update visually
diff --git a/addons/mail/static/src/js/models/threads/channel.js b/addons/mail/static/src/js/models/threads/channel.js
index 9f0f37264db..9e9f3ac6a39 100644
--- a/addons/mail/static/src/js/models/threads/channel.js
+++ b/addons/mail/static/src/js/models/threads/channel.js
@@ -70,7 +70,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
this._isMyselfModerator = data.is_moderator;
this._lastMessageDate = undefined;
this._members = data.members || [];
- // Deferred that is resolved on fetched members of this channel.
+ // Promise that is resolved on fetched members of this channel.
this._membersDef = undefined;
// number of messages that are 'needaction', which is equivalent to the
// number of messages in this channel that are in inbox.
@@ -129,19 +129,21 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
* @pverride
*/
detach: function () {
- this._super.apply(this, arguments);
- this._rpc({
- model: 'mail.channel',
- method: 'channel_minimize',
- args: [this.getUUID(), true],
- }, {
- shadow: true,
+ var self = this;
+ return this._super.apply(this, arguments).then(function () {
+ self._rpc({
+ model: 'mail.channel',
+ method: 'channel_minimize',
+ args: [self.getUUID(), true],
+ }, {
+ shadow: true,
+ });
});
},
/**
* Force fetch members of the channel
*
- * @returns {$.Promise<Object[]>} resolved with list of channel listeners
+ * @returns {Promise<Object[]>} resolved with list of channel listeners
*/
forceFetchMembers: function () {
this._membersDef = undefined;
@@ -186,7 +188,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
/**
* Get listeners of a channel
*
- * @returns {$.Promise<Array<Object[]>>} resolved with list of list of
+ * @returns {Promise<Object[]>} resolved with list of list of
* channel listeners.
*/
getMentionPartnerSuggestions: function () {
@@ -302,7 +304,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
* Unsubscribes from channel
*
* @abstract
- * @returns {$.Promise} resolve when unsubscribed
+ * @returns {Promise} resolve when unsubscribed
*/
unsubscribe: function () {},
/**
@@ -381,19 +383,19 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
*
* @override
* @private
- * @returns {$.Promise} resolved when message has been marked as read
+ * @returns {Promise} resolved when message has been marked as read
*/
_markAsRead: function () {
var superDef = this._super.apply(this, arguments);
var seenDef = this._notifySeen();
- return $.when(superDef, seenDef);
+ return Promise.all([superDef, seenDef]);
},
/**
* @override {mail.model.ThreadTypingMixin}
* @private
* @param {Object} params
* @param {boolean} params.typing
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_notifyMyselfTyping: function (params) {
return this._rpc({
@@ -424,7 +426,7 @@ var Channel = SearchableThread.extend(ThreadTypingMixin, {
* @override
* @private
* @param {Object} data data related to the new message
- * @returns {$.Promise<Object>} resolved when the message has been sent to
+ * @returns {Promise<Object>} resolved when the message has been sent to
* the server, with the object message that has been sent to the server.
*/
_postMessage: function (data) {
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 6c15b39d25e..08e441610ee 100644
--- a/addons/mail/static/src/js/models/threads/document_thread.js
+++ b/addons/mail/static/src/js/models/threads/document_thread.js
@@ -92,7 +92,7 @@ var DocumentThread = Thread.extend({
* @param {Object} options
* @param {boolean} [options.forceFetch] if true, fetch anyway, as user
* clicked on 'load more'.
- * @returns {$.Promise<mail.model.Message[]>}
+ * @returns {Promise<mail.model.Message[]>}
*/
fetchMessages: function (options) {
var self = this;
@@ -217,14 +217,14 @@ var DocumentThread = Thread.extend({
* Get most up to date messageIDs
*
* @private
- * @returns {$.Promise} resolved when message IDs have been fetched and set
+ * @returns {Promise} resolved when message IDs have been fetched and set
* in the model
*/
_fetchMessageIDs: function () {
var self = this;
var resID = this.getDocumentID();
if (!resID || !this._mustFetchMessageIDs) {
- return $.when();
+ return Promise.resolve();
}
return this._rpc({
model: this.getDocumentModel(),
@@ -239,7 +239,7 @@ var DocumentThread = Thread.extend({
* @private
* @param {Object} options
* @param {boolean} [options.forceFetch]
- * @returns {$.Promise} resolved when messages have been fetched + document
+ * @returns {Promise} resolved when messages have been fetched + document
* thread has updated messages
*/
_fetchMessages: function (options) {
@@ -273,7 +273,7 @@ var DocumentThread = Thread.extend({
});
});
} else {
- return $.when();
+ return Promise.resolve();
}
});
@@ -284,7 +284,7 @@ var DocumentThread = Thread.extend({
*
* @override
* @private
- * @returns {$.Promise} resolved when messages have been marked as read on
+ * @returns {Promise} resolved when messages have been marked as read on
* the server.
*/
_markAsRead: function () {
@@ -299,7 +299,7 @@ var DocumentThread = Thread.extend({
* @override
* @private
* @param {Object} data data related to the new message
- * @return {$.Promise<Object>} resolved when the message has been sent to
+ * @return {Promise<Object>} resolved when the message has been sent to
* the server, with the object message that has been sent to the server.
*/
_postMessage: function (data) {
diff --git a/addons/mail/static/src/js/models/threads/livechat.js b/addons/mail/static/src/js/models/threads/livechat.js
index 45cab5aef10..c3b4a5e2b4d 100644
--- a/addons/mail/static/src/js/models/threads/livechat.js
+++ b/addons/mail/static/src/js/models/threads/livechat.js
@@ -34,7 +34,7 @@ var Livechat = TwoUserChannel.extend({
* display of a user that is typing.
*
* @override
- * @returns {$.Promise<Array<Object[]>>} resolved with list of list of
+ * @returns {Promise<Object[]>} resolved with list of list of
* livechat members.
*/
getMentionPartnerSuggestions: function () {
diff --git a/addons/mail/static/src/js/models/threads/mailbox.js b/addons/mail/static/src/js/models/threads/mailbox.js
index 263072f575e..bedd6af27e1 100644
--- a/addons/mail/static/src/js/models/threads/mailbox.js
+++ b/addons/mail/static/src/js/models/threads/mailbox.js
@@ -59,7 +59,7 @@ var Mailbox = SearchableThread.extend({
* channel, only keep the lastest message of this document/channel in the
* previews.
*
- * @returns {$.Promise<Object[]>}
+ * @returns {Promise<Object[]>}
*/
getMessagePreviews: function () {
var self = this;
@@ -119,7 +119,7 @@ var Mailbox = SearchableThread.extend({
* makes only sense for 'Inbox'.
*
* @param {Array} domain
- * @return {$.Promise} resolved when all messages have been marked as read
+ * @return {Promise} resolved when all messages have been marked as read
* on the server
*/
markAllMessagesAsRead: function (domain) {
@@ -133,7 +133,7 @@ var Mailbox = SearchableThread.extend({
},
});
}
- return $.when();
+ return Promise.resolve();
},
//--------------------------------------------------------------------------
diff --git a/addons/mail/static/src/js/models/threads/mixins/thread_typing_mixin.js b/addons/mail/static/src/js/models/threads/mixins/thread_typing_mixin.js
index f995b4e09b3..7d97538dbb9 100644
--- a/addons/mail/static/src/js/models/threads/mixins/thread_typing_mixin.js
+++ b/addons/mail/static/src/js/models/threads/mixins/thread_typing_mixin.js
@@ -239,11 +239,11 @@ var ThreadTypingMixin = {
* @private
* @param {Object} params
* @param {boolean} params.typing whether we are typing something or not
- * @returns {$.Promise} resolved if the server is notified, rejected
+ * @returns {Promise} resolved if the server is notified, rejected
* otherwise
*/
_notifyMyselfTyping: function (params) {
- return $.when();
+ return Promise.resolve();
},
/**
* Warn views that the list of users that are currently typing on this
diff --git a/addons/mail/static/src/js/models/threads/multi_user_channel.js b/addons/mail/static/src/js/models/threads/multi_user_channel.js
index bac417c361d..3dab9337502 100644
--- a/addons/mail/static/src/js/models/threads/multi_user_channel.js
+++ b/addons/mail/static/src/js/models/threads/multi_user_channel.js
@@ -56,7 +56,7 @@ var MultiUserChannel = Channel.extend({
* Unsubscribes from channel
*
* @override
- * @returns {$.Promise} resolve when unsubscribed
+ * @returns {Promise} resolve when unsubscribed
*/
unsubscribe: function () {
return this._rpc({
diff --git a/addons/mail/static/src/js/models/threads/searchable_thread.js b/addons/mail/static/src/js/models/threads/searchable_thread.js
index 8ddff5457af..511bc6348c8 100644
--- a/addons/mail/static/src/js/models/threads/searchable_thread.js
+++ b/addons/mail/static/src/js/models/threads/searchable_thread.js
@@ -49,7 +49,7 @@ var SearchableThread = Thread.extend({
}
var cache = this._getCache(domain);
if (cache.loaded) {
- return $.when(cache.messages);
+ return Promise.all(cache.messages);
} else {
return this._fetchMessages(domain);
}
@@ -159,7 +159,7 @@ var SearchableThread = Thread.extend({
* @private
* @param {Array} [pDomain] filter on the messages of the channel
* @param {boolean} [loadMore] Whether it should load more message
- * @return {$.Promise<mail.model.Message[]>} resolved with list of messages
+ * @return {Promise<mail.model.Message[]>} resolved with list of messages
*/
_fetchMessages: function (pDomain, loadMore) {
var self = this;
diff --git a/addons/mail/static/src/js/models/threads/thread.js b/addons/mail/static/src/js/models/threads/thread.js
index 8c622779bb3..8f4e8956d27 100644
--- a/addons/mail/static/src/js/models/threads/thread.js
+++ b/addons/mail/static/src/js/models/threads/thread.js
@@ -58,12 +58,13 @@ var Thread = AbstractThread.extend(ServicesMixin, {
* of this thread. Otherwise unfold it while detaching it.
* @param {boolean} [options.passively=false] if set, if the thread window
* will be created passively.
+ * @returns {Promise}
*/
detach: function (options) {
options = options || {};
this._detached = true;
this._folded = options.keepFoldState ? this._folded : false;
- this._warnUpdatedWindowState({
+ return this._warnUpdatedWindowState({
passively: options.passively,
});
},
@@ -79,10 +80,10 @@ var Thread = AbstractThread.extend(ServicesMixin, {
* `this.LIMIT` number of messages at a time.
*
* @abstract
- * @returns {$.Promise<mail.model.Message[]>}
+ * @returns {Promise<mail.model.Message[]>}
*/
fetchMessages: function () {
- return $.when([]);
+ return Promise.resolve([]);
},
/**
* Updates the folded state of the thread. Must be overriden to reflect
@@ -110,10 +111,10 @@ var Thread = AbstractThread.extend(ServicesMixin, {
* By default, a thread has not listener.
*
* @abstract
- * @returns {$.Promise<Array<Object[]>>}
+ * @returns {Promise<Array<Object[]>>}
*/
getMentionPartnerSuggestions: function () {
- return $.when([]);
+ return Promise.resolve([]);
},
/**
* Returns the information required to render the preview of this channel.
@@ -287,10 +288,10 @@ var Thread = AbstractThread.extend(ServicesMixin, {
/**
* @abstract
* @private
- * @return {$.Promise}
+ * @return {Promise}
*/
_fetchMessages: function () {
- return $.when();
+ return Promise.resolve();
},
/**
* Replace character representations of emojis by their unicode
@@ -330,7 +331,7 @@ var Thread = AbstractThread.extend(ServicesMixin, {
* @abstract
* @private
* @param {Object} data
- * @returns {$.Promise<Object>} resolved with the message object to be sent
+ * @returns {Promise<Object>} resolved with the message object to be sent
* to the server
*/
_postMessage: function (data) {
@@ -355,7 +356,7 @@ var Thread = AbstractThread.extend(ServicesMixin, {
messageData.subject = data.subject;
}
return this._super.apply(this, arguments).then(function () {
- return $.when(messageData);
+ return messageData;
});
},
/**
@@ -374,10 +375,11 @@ var Thread = AbstractThread.extend(ServicesMixin, {
* @private
* @param {Object} [options={}]
* @param {boolean} [options.passively=false]
+ * @returns {Promise}
*/
_warnUpdatedWindowState: function (options) {
options = options || {};
- this.call('mail_service', 'updateThreadWindow', this.getID(), options);
+ return this.call('mail_service', 'updateThreadWindow', this.getID(), options);
},
});
diff --git a/addons/mail/static/src/js/models/threads/two_user_channel.js b/addons/mail/static/src/js/models/threads/two_user_channel.js
index 204fd95eb82..54a4145bd13 100644
--- a/addons/mail/static/src/js/models/threads/two_user_channel.js
+++ b/addons/mail/static/src/js/models/threads/two_user_channel.js
@@ -15,7 +15,7 @@ var TwoUserChannel = Channel.extend({
* Unpin from two-user thread
*
* @override
- * @returns {$.Promise} resolve when unsubscribed
+ * @returns {Promise} resolve when unsubscribed
*/
unsubscribe: function () {
return this._rpc({
diff --git a/addons/mail/static/src/js/services/mail_document_thread_manager.js b/addons/mail/static/src/js/services/mail_document_thread_manager.js
index a98ae317c9d..f1d9eefb44a 100644
--- a/addons/mail/static/src/js/services/mail_document_thread_manager.js
+++ b/addons/mail/static/src/js/services/mail_document_thread_manager.js
@@ -182,7 +182,7 @@ MailManager.include({
resModel: resModel,
});
}
- this._super.apply(this, arguments);
+ return this._super.apply(this, arguments);
},
/**
* Updates the thread windows related to document threads.
diff --git a/addons/mail/static/src/js/services/mail_manager.js b/addons/mail/static/src/js/services/mail_manager.js
index 5eb588d24e7..27a7183ec88 100644
--- a/addons/mail/static/src/js/services/mail_manager.js
+++ b/addons/mail/static/src/js/services/mail_manager.js
@@ -80,13 +80,14 @@ var MailManager = AbstractService.extend({
* the unread_counter of channel.
* @param {boolean} [options.silent] whether it should inform in the mailBus
* of the newly created message.
- * @returns {mail.model.Message} message object
+ * @returns {Promise<mail.model.Message>}
*/
addMessage: function (data, options) {
options = options || {};
var message = this.getMessage(data.id);
+ var prom = Promise.resolve();
if (!message) {
- message = this._addNewMessage(data, options);
+ prom = this._addNewMessage(data, options);
} else {
if (data.moderation_status === 'accepted') {
message.setModerationStatus('accepted', {
@@ -97,7 +98,7 @@ var MailManager = AbstractService.extend({
this._addMessageToThreads(message, options);
}
}
- return message;
+ return prom;
},
/**
* Creates a channel, can be either a true channel or a DM chat based on
@@ -105,7 +106,7 @@ var MailManager = AbstractService.extend({
*
* @param {integer|string} name id of partner (in case of dm) or name
* @param {string} type ['dm_chat', 'public', 'private']
- * @returns {$.Promise<integer>} resolved with ID of the newly created
+ * @returns {Promise<integer>} resolved with ID of the newly created
* channel
*/
createChannel: function (name, type) {
@@ -150,7 +151,7 @@ var MailManager = AbstractService.extend({
* Returns the content that will be shown in the mail navbar dropdown
*
* @param {mail.model.Channel[]} channels
- * @returns {$.Promise<Object[]>} resolved with list of channel previews
+ * @returns {Promise<Object[]>} resolved with list of channel previews
*/
getChannelPreviews: function (channels) {
var self = this;
@@ -227,23 +228,22 @@ var MailManager = AbstractService.extend({
*
* @param {string} [filter=undefined] specify 'chat' or 'channels' to only
* get previews for that type of threads
- * @returns {$.Promise<Object[]>} resolved with list of objects that have a
+ * @returns {Promise<Object[]>} resolved with list of objects that have a
* valid format for rendering a messaging menu preview items.
*/
getSystrayPreviews: function (filter) {
var self = this;
- var defs = [];
var channelDef = this._getSystrayChannelPreviews(filter);
var inboxDef = this._getSystrayInboxPreviews(filter);
var failureDef = this._getSystrayMailFailurePreviews(filter);
- defs = defs.concat([channelDef, inboxDef, failureDef]);
- return $.when.apply($, defs)
- .then(function (previewsChannel, previewsInbox, previewsFailure) {
+
+ return Promise.all([channelDef, inboxDef, failureDef])
+ .then(function (result) { //previewsChannel, previewsInbox, previewsFailure
// order: failures > inbox > channel, each group must be sorted
- previewsChannel = self._sortPreviews(previewsChannel);
- previewsInbox = self._sortPreviews(previewsInbox);
- previewsFailure = self._sortPreviews(previewsFailure);
+ var previewsChannel = self._sortPreviews(result[0]);
+ var previewsInbox = self._sortPreviews(result[1]);
+ var previewsFailure = self._sortPreviews(result[2]);
return _.union(previewsFailure, previewsInbox, previewsChannel);
});
},
@@ -295,7 +295,7 @@ var MailManager = AbstractService.extend({
* This is the case when it has fetched the initial state from the server,
* by means of the route 'mail/init_messaging'
*
- * @returns {$.Promise}
+ * @returns {Promise}
*/
isReady: function () {
return this._isReady;
@@ -306,24 +306,24 @@ var MailManager = AbstractService.extend({
*
* @param {integer} channelID
* @param {Object} [options] options to be passed on channel add
- * @returns {$.Promise<integer>} resolved with channelID joined
+ * @returns {Promise<integer>} resolved with channelID joined
*/
joinChannel: function (channelID, options) {
- var def;
+ var prom;
var channel = this.getChannel(channelID);
if (channel) {
// channel already joined
- def = $.when(channelID);
+ prom = Promise.resolve(channelID);
} else {
- def = this._joinAndAddChannel(channelID, options);
+ prom = this._joinAndAddChannel(channelID, options);
}
- return def;
+ return prom;
},
/**
* Mark messages as read
*
* @param {Array} messageIDs list of messages IDs
- * @returns {$.Promise} resolved when messages have been marked as read on
+ * @returns {Promise} resolved when messages have been marked as read on
* the server.
*/
markMessagesAsRead: function (messageIDs) {
@@ -341,7 +341,7 @@ var MailManager = AbstractService.extend({
args: [ids],
});
} else {
- return $.when();
+ return Promise.resolve();
}
},
/**
@@ -396,19 +396,19 @@ var MailManager = AbstractService.extend({
*
* @param {string} searchVal
* @param {integer} limit max number of found partners in the response
- * @returns {$.Promise<Object[]>} list of found partners (matching
+ * @returns {Promise<Object[]>} list of found partners (matching
* 'searchVal')
*/
searchPartner: function (searchVal, limit) {
- var def = $.Deferred();
+ var self = this;
var partners = this._searchPartnerPrefetch(searchVal, limit);
-
- if (!partners.length) {
- def = this._searchPartnerFetch(searchVal, limit);
- } else {
- def = $.when(partners);
- }
- return def.then(function (partners) {
+ return new Promise(function (resolve, reject) {
+ if (!partners.length) {
+ resolve(self._searchPartnerFetch(searchVal, limit));
+ } else {
+ resolve(partners);
+ }
+ }).then(function (partners) {
var suggestions = _.map(partners, function (partner) {
return {
id: partner.id,
@@ -422,7 +422,7 @@ var MailManager = AbstractService.extend({
/**
* Unstars all messages from all channels
*
- * @returns {$.Promise}
+ * @returns {Promise}
*/
unstarAll: function () {
return this._rpc({
@@ -448,11 +448,13 @@ var MailManager = AbstractService.extend({
* @param {string} [data.state] e.g. 'open', 'folded'
* @param {Object|integer} [options=undefined]
* @param {boolean} [options.silent=false]
- * @returns {integer} the ID of the newly or already existing channel
+ * @returns {Promise<integer>} resolves with the ID of the newly or already
+ * existing channel
*/
_addChannel: function (data, options) {
options = typeof options === 'object' ? options : {};
var channel = this.getChannel(data.id);
+ var proms = [];
if (!channel) {
channel = this._makeChannel(data, options);
if (channel.getType() === 'dm_chat') {
@@ -462,14 +464,16 @@ var MailManager = AbstractService.extend({
if (data.last_message) {
// channel_info in mobile, necessary for showing channel
// preview in mobile
- this.addMessage(data.last_message);
+ proms.push(this.addMessage(data.last_message));
}
this._sortThreads();
if (!options.silent) {
- this._mailBus.trigger('new_channel', channel);
+ this._mailBus.trigger('new_channel', channel, proms);
}
}
- return channel.getID();
+ return Promise.all(proms).then(function () {
+ return channel.getID();
+ });
},
/**
* Add a new mailbox
@@ -516,21 +520,23 @@ var MailManager = AbstractService.extend({
* @private
* @param {Object} data
* @param {Object} options
- * @returns {mail.model.Message}
+ * @return {Promise<mail.model.Message>}
*/
_addNewMessage: function (data, options) {
+ var self = this;
var message = this._makeMessage(data);
// Keep the array ordered by ID when inserting the new message
var index = _.sortedIndex(this._messages, message, function (msg) {
return msg.getID();
});
this._messages.splice(index, 0, message);
- this._addNewMessagePostprocessThread(message, options);
- this._addMessageToThreads(message, options);
- if (!options.silent) {
- this._mailBus.trigger('new_message', message);
- }
- return message;
+ return this._addNewMessagePostprocessThread(message, options).then(function () {
+ self._addMessageToThreads(message, options);
+ if (!options.silent) {
+ self._mailBus.trigger('new_message', message);
+ }
+ return message;
+ });
},
/**
* For newly added message, postprocess threads linked to this message
@@ -541,9 +547,11 @@ var MailManager = AbstractService.extend({
* @param {Array} [options.domain]
* @param {boolean} [options.incrementUnread]
* @param {boolean} [options.showNotification]
+ * @returns {Promise}
*/
_addNewMessagePostprocessThread: function (message, options) {
var self = this;
+ var proms = [];
_.each(message.getThreadIDs(), function (threadID) {
var thread = self.getThread(threadID);
if (thread) {
@@ -553,6 +561,7 @@ var MailManager = AbstractService.extend({
!message.isSystemNotification()
) {
if (thread.isTwoUserThread() && options.showNotification) {
+ var prom = Promise.resolve();
if (
!self._isDiscussOpen() &&
!config.device.isMobile &&
@@ -560,17 +569,21 @@ var MailManager = AbstractService.extend({
) {
// automatically open thread window
// while keeping it unread
- thread.detach({ passively: true });
- }
- var query = { isVisible: false };
- self._mailBus.trigger('is_thread_bottom_visible', thread, query);
- if (!self.call('bus_service', 'isOdooFocused') || !query.isVisible) {
- self._notifyIncomingMessage(message);
+ prom = thread.detach({ passively: true });
}
+ proms.push(prom);
+ prom.then(function () {
+ var query = { isVisible: false };
+ self._mailBus.trigger('is_thread_bottom_visible', thread, query);
+ if (!self.call('bus_service', 'isOdooFocused') || !query.isVisible) {
+ self._notifyIncomingMessage(message);
+ }
+ });
}
}
}
});
+ return Promise.all(proms);
},
/**
* Create a Channel (other than a DM)
@@ -578,7 +591,7 @@ var MailManager = AbstractService.extend({
* @private
* @param {string} name
* @param {string} type
- * @returns {$.Promise<integer>} ID of the created channel
+ * @returns {Promise<integer>} ID of the created channel
*/
_createChannel: function (name, type) {
var context = _.extend({ isMobile: config.device.isMobile }, session.user_context);
@@ -595,7 +608,7 @@ var MailManager = AbstractService.extend({
*
* @private
* @param {string} name
- * @returns {$.Promise<integer>} ID of the created channel
+ * @returns {Promise<integer>} ID of the created channel
*/
_createDMChat: function (name) {
var context = _.extend({ isMobile: config.device.isMobile }, session.user_context);
@@ -610,7 +623,7 @@ var MailManager = AbstractService.extend({
/**
* @private
* @param {integer[]} channelIDs
- * @returns {$.Promise<Object[]>} resolved with list of channel preview
+ * @returns {Promise<Object[]>} resolved with list of channel preview
*/
_fetchChannelPreviews: function (channelIDs) {
return this._rpc({
@@ -652,7 +665,7 @@ var MailManager = AbstractService.extend({
*
* @private
* @param {mail.model.Channel[]} channels
- * @returns {$.Deferred<Object[]>} resolved with list of channel previews
+ * @returns {Promise<Object[]>} resolved with list of channel previews
*/
_getChannelPreviews: function (channels) {
var self = this;
@@ -667,19 +680,22 @@ var MailManager = AbstractService.extend({
});
fetchDef = this._fetchChannelPreviews(ids);
} else {
- fetchDef = $.when();
+ fetchDef = Promise.resolve();
}
return fetchDef.then(function (fetchedPreviews) {
// add fetched messages
+ var proms = [];
_.each(fetchedPreviews, function (fetchedPreview) {
if (fetchedPreview.last_message) {
- self.addMessage(fetchedPreview.last_message);
+ proms.push(self.addMessage(fetchedPreview.last_message));
}
// mark the channel as previewed, so that we do not need to
// fetch preview again
var channel = self.getChannel(fetchedPreview.id);
channel.markAsPreviewed();
});
+ return Promise.all(proms);
+ }).then(function () {
return _.map(channels, function (channel) {
return channel.getPreview();
});
@@ -694,7 +710,7 @@ var MailManager = AbstractService.extend({
* the documentID is omitted for a model preview, whereas it is set for a
* preview of a failure related to a document.
*
- * @returns {$.Promise<Object[]>} resolved with previews of mail failures
+ * @returns {Promise<Object[]>} resolved with previews of mail failures
*/
_getMailFailurePreviews: function () {
// items = list of objects:
@@ -754,7 +770,7 @@ var MailManager = AbstractService.extend({
* @private
* @param {string|undefined} [filter] the filter to apply on channel
* previews in systray messaging menu
- * @returns {$.Promise<Object[]>} resolved with object valid for template
+ * @returns {Promise<Object[]>} resolved with object valid for template
* mail.Preview on channel previews, based on selected filter
*/
_getSystrayChannelPreviews: function (filter) {
@@ -796,7 +812,7 @@ var MailManager = AbstractService.extend({
*
* @private
* @param {string|undefined} [filter]
- * @returns {$.Deferred<Object[]>} resolved with valid objects for template
+ * @returns {Promise<Object[]>} resolved with valid objects for template
* mail.Preview on inbox message previews
*/
_getSystrayInboxPreviews: function (filter) {
@@ -806,7 +822,7 @@ var MailManager = AbstractService.extend({
var inbox = this.getMailbox('inbox');
return inbox.getMessagePreviews();
} else {
- return $.when([]);
+ return Promise.resolve([]);
}
},
/**
@@ -820,7 +836,7 @@ var MailManager = AbstractService.extend({
if (filter === 'mailbox_inbox' || !filter) {
return this._getMailFailurePreviews();
} else {
- return $.when([]);
+ return Promise.resolve([]);
}
},
/**
@@ -863,7 +879,7 @@ var MailManager = AbstractService.extend({
* @private
* @param {integer|string} channelID
* @param {Object} options options passed on channel add
- * @returns {$.Promise<integer>} channelID of joined and added channel
+ * @returns {Promise<integer>} channelID of joined and added channel
*/
_joinAndAddChannel: function (channelID, options) {
var self = this;
@@ -941,7 +957,7 @@ var MailManager = AbstractService.extend({
this._toNotifyChannelFetchedIDs = [];
if (_.isEmpty(channelIDs)) {
// no channel to notify fetched
- return $.when();
+ return Promise.resolve();
}
return this._rpc({
model: 'mail.channel',
@@ -1098,7 +1114,7 @@ var MailManager = AbstractService.extend({
* @private
* @param {string} searchVal
* @param {integer} limit
- * @returns {$.Promise<Object[]>} fetched partners matching 'searchVal'
+ * @returns {Promise<Object[]>} fetched partners matching 'searchVal'
*/
_searchPartnerFetch: function (searchVal, limit) {
return this._rpc({
@@ -1194,12 +1210,17 @@ var MailManager = AbstractService.extend({
* (e.g. list of public channel data are stored in 'channel_channel')
* @param {Object[]} [data.channel_slots[i] list of data of channel of type
* `i`
+ * @returns {Promise}
*/
_updateChannelsFromServer: function (data) {
var self = this;
+ var proms = [];
_.each(data.channel_slots, function (channels) {
- _.each(channels, self._addChannel.bind(self));
+ _.each(channels, function (channel) {
+ proms.push(self._addChannel(channel));
+ });
});
+ return Promise.all(proms);
},
/**
* Update commands from mail data fetched from the server
@@ -1221,11 +1242,12 @@ var MailManager = AbstractService.extend({
* @param {Array<Object[]>} result.mention_partner_suggestions list of
* suggestions.
* @param {integer} result.menu_id the menu ID of discuss app
+ * @returns {Promise}
*/
_updateInternalStateFromServer: function (result) {
// commands are needed for channel instantiation
this._updateCommandsFromServer(result);
- this._updateChannelsFromServer(result);
+ var prom = this._updateChannelsFromServer(result);
this._updateModerationSettingsFromServer(result);
this._updateMailboxesFromServer(result);
this._updateMailFailuresFromServer(result);
@@ -1233,6 +1255,8 @@ var MailManager = AbstractService.extend({
this._mentionPartnerSuggestions = result.mention_partner_suggestions;
this._discussMenuID = result.menu_id;
+
+ return prom;
},
/**
* Update the mailboxes with mail data fetched from server, namely 'Inbox',
diff --git a/addons/mail/static/src/js/services/mail_notification_manager.js b/addons/mail/static/src/js/services/mail_notification_manager.js
index fb3527b2b90..75754f375d8 100644
--- a/addons/mail/static/src/js/services/mail_notification_manager.js
+++ b/addons/mail/static/src/js/services/mail_notification_manager.js
@@ -101,12 +101,12 @@ MailManager.include({
channelAlreadyInCache = !!this.getChannel(messageData.channel_ids[0]);
def = this.joinChannel(messageData.channel_ids[0], { autoswitch: false });
} else {
- def = $.when();
+ def = Promise.resolve();
}
def.then(function () {
// don't increment unread if channel wasn't in cache yet as
// its unread counter has just been fetched
- self.addMessage(messageData, {
+ return self.addMessage(messageData, {
showNotification: true,
incrementUnread: channelAlreadyInCache
});
@@ -179,18 +179,19 @@ MailManager.include({
_handleNeedactionNotification: function (messageData) {
var self = this;
var inbox = this.getMailbox('inbox');
- var message = this.addMessage(messageData, {
+ this.addMessage(messageData, {
incrementUnread: true,
showNotification: true,
+ }).then(function (message) {
+ inbox.incrementMailboxCounter();
+ _.each(message.getThreadIDs(), function (threadID) {
+ var channel = self.getChannel(threadID);
+ if (channel) {
+ channel.incrementNeedactionCounter();
+ }
+ });
+ self._mailBus.trigger('update_needaction', inbox.getMailboxCounter());
});
- inbox.incrementMailboxCounter();
- _.each(message.getThreadIDs(), function (threadID) {
- var channel = self.getChannel(threadID);
- if (channel) {
- channel.incrementNeedactionCounter();
- }
- });
- this._mailBus.trigger('update_needaction', inbox.getMailboxCounter());
},
/**
* Called when an activity record has been updated on the server
@@ -381,8 +382,10 @@ MailManager.include({
* @param {Object} data.message data of message
*/
_handlePartnerMessageModeratorNotification: function (data) {
- this.addMessage(data.message);
- this._mailBus.trigger('update_moderation_counter');
+ var self = this;
+ this.addMessage(data.message).then(function () {
+ self._mailBus.trigger('update_moderation_counter');
+ });
},
/**
* On receiving a notification that is specific to a user
diff --git a/addons/mail/static/src/js/services/mail_status_manager.js b/addons/mail/static/src/js/services/mail_status_manager.js
index 5ca151d47bf..4a2df2af94f 100644
--- a/addons/mail/static/src/js/services/mail_status_manager.js
+++ b/addons/mail/static/src/js/services/mail_status_manager.js
@@ -81,7 +81,7 @@ MailManager.include({
var self = this;
var partnerIDs = data.partnerIDs;
if (_.isEmpty(partnerIDs)) {
- return $.when();
+ return Promise.resolve();
}
return this._rpc({
model: 'res.partner',
diff --git a/addons/mail/static/src/js/services/mail_window_manager.js b/addons/mail/static/src/js/services/mail_window_manager.js
index 4e481d6892a..083b46c9ff2 100644
--- a/addons/mail/static/src/js/services/mail_window_manager.js
+++ b/addons/mail/static/src/js/services/mail_window_manager.js
@@ -94,6 +94,7 @@ MailManager.include({
* is not open yet, and do nothing otherwise.
* @param {boolean} [options.keepFoldState=false] if set to true, keep the
* fold state of the thread
+ * @returns {Promise}
*/
openThreadWindow: function (threadID, options) {
var self = this;
@@ -108,10 +109,10 @@ MailManager.include({
return;
}
var threadWindow = this._getThreadWindow(threadID);
- var def = $.when();
+ var prom = Promise.resolve();
if (!threadWindow) {
thread.isCreatingWindow = true;
- def = thread.fetchMessages().then(function () {
+ prom = thread.fetchMessages().then(function () {
threadWindow = self._makeNewThreadWindow(thread, options);
self._placeNewThreadWindow(threadWindow, options.passively);
return threadWindow.appendTo($(self.THREAD_WINDOW_APPENDTO));
@@ -126,12 +127,12 @@ MailManager.include({
) {
thread.markAsRead();
}
- }).fail(function () {
+ thread.isCreatingWindow = false;
+ }).guardedCatch(function () {
// thread window could not be open, which may happen due to
// access error while fetching messages to the document.
// abort opening the thread window in this case.
thread.close();
- }).always(function () {
thread.isCreatingWindow = false;
});
} else if (!options.passively) {
@@ -139,7 +140,7 @@ MailManager.include({
this._makeThreadWindowVisible(threadWindow);
}
}
- def.then(function () {
+ return prom.then(function () {
threadWindow.updateVisualFoldState();
});
},
@@ -155,14 +156,16 @@ MailManager.include({
*/
updateThreadWindow: function (threadID, options) {
var thread = this.getThread(threadID);
+ var prom = Promise.resolve();
if (thread) {
if (thread.isDetached()) {
_.extend(options, { keepFoldState: true });
- this.openThreadWindow(threadID, options);
+ prom = this.openThreadWindow(threadID, options);
} else {
this._closeThreadWindow(threadID);
}
}
+ return prom;
},
//--------------------------------------------------------------------------
@@ -429,7 +432,7 @@ MailManager.include({
*
* @private
* @param {integer} partnerID
- * @returns {$.Promise<integer>} resolved with ID of the DM chat
+ * @returns {Promise<integer>} resolved with ID of the DM chat
*/
_openAndDetachDMChat: function (partnerID) {
return this._rpc({
@@ -647,10 +650,16 @@ MailManager.include({
*
* @private
* @param {mail.model.Channel} channel
+ * @param {Promise[]} proms used to synchronize async operations on the
+ * channel (like the rendering of its window)
*/
- _onNewChannel: function (channel) {
+ _onNewChannel: function (channel, proms) {
if (channel.isDetached()) {
- this.openThreadWindow(channel.getID(), { keepFoldState: true, passively: true });
+ var prom = this.openThreadWindow(channel.getID(), {
+ keepFoldState: true,
+ passively: true,
+ });
+ proms.push(prom);
} else {
this._closeThreadWindow(channel.getID());
}
diff --git a/addons/mail/static/src/js/systray/systray_activity_menu.js b/addons/mail/static/src/js/systray/systray_activity_menu.js
index 593cac91506..fae95a78c2f 100644
--- a/addons/mail/static/src/js/systray/systray_activity_menu.js
+++ b/addons/mail/static/src/js/systray/systray_activity_menu.js
@@ -20,7 +20,7 @@ var ActivityMenu = Widget.extend({
'show.bs.dropdown': '_onActivityMenuShow',
},
willStart: function () {
- return $.when(this.call('mail_service', 'isReady'));
+ return Promise.resolve(this.call('mail_service', 'isReady'));
},
start: function () {
this._$activitiesPreview = this.$('.o_mail_systray_dropdown_items');
diff --git a/addons/mail/static/src/js/systray/systray_messaging_menu.js b/addons/mail/static/src/js/systray/systray_messaging_menu.js
index df35de47174..4dacae435d4 100644
--- a/addons/mail/static/src/js/systray/systray_messaging_menu.js
+++ b/addons/mail/static/src/js/systray/systray_messaging_menu.js
@@ -30,7 +30,7 @@ var MessagingMenu = Widget.extend({
* @override
*/
willStart: function () {
- return $.when(this._super.apply(this, arguments), this.call('mail_service', 'isReady'));
+ return Promise.all([this._super.apply(this, arguments), this.call('mail_service', 'isReady')]);
},
/**
* @override
@@ -112,7 +112,7 @@ var MessagingMenu = Widget.extend({
},
/**
* @private
- * @returns {$.Promise<Object[]>} resolved with list of previews that are
+ * @returns {Promise<Object[]>} resolved with list of previews that are
* compatible with the 'mail.Preview' template.
*/
_getPreviews: function () {
diff --git a/addons/mail/static/src/js/thread_field.js b/addons/mail/static/src/js/thread_field.js
index a3807802ad7..ab8023b06ad 100644
--- a/addons/mail/static/src/js/thread_field.js
+++ b/addons/mail/static/src/js/thread_field.js
@@ -57,7 +57,7 @@ var ThreadField = AbstractField.extend({
var def1 = this._threadWidget.appendTo(this.$el);
var def2 = this._super.apply(this, arguments);
- return this.alive($.when(def1, def2)).then(function () {
+ return this.alive(Promise.all([def1, def2])).then(function () {
// unwrap the thread to remove an unnecessary level on div
self.setElement(self._threadWidget.$el);
var mailBus = self.call('mail_service', 'getMailBus');
@@ -86,7 +86,7 @@ var ThreadField = AbstractField.extend({
/**
* @param {Object} message
* @param {integer[]} message.partner_ids
- * @return {$.Promise}
+ * @return {Promise}
*/
postMessage: function (message) {
var self = this;
@@ -95,9 +95,9 @@ var ThreadField = AbstractField.extend({
if (message.partner_ids.length) {
self.trigger_up('reload_mail_fields', { followers: true });
}
- })
- .fail(function () {
+ }).guardedCatch(function () {
self.do_notify(_t("Sending Error"), _t("Your message has not been sent."));
+ return Promise.reject();
});
},
@@ -109,7 +109,7 @@ var ThreadField = AbstractField.extend({
* @private
* @param {Object} [options]
* @param {boolean} [options.forceFetch]
- * @return {$.Deferred}
+ * @return {Promise}
*/
_fetchAndRenderThread: function (options) {
var self = this;
@@ -117,7 +117,7 @@ var ThreadField = AbstractField.extend({
var thread = new CreateModeDocumentThread();
options = { isCreateMode: true };
self._threadWidget.render(thread, options);
- return $.when();
+ return Promise.resolve();
} else {
var fetchDef = this.dp.add(this._documentThread.fetchMessages(options));
return fetchDef.then(function () {
@@ -134,7 +134,7 @@ var ThreadField = AbstractField.extend({
/**
* @override
* @private
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
_render: function () {
return this._fetchAndRenderThread();
diff --git a/addons/mail/static/src/js/thread_widget.js b/addons/mail/static/src/js/thread_widget.js
index cbac2c3b417..56945533946 100644
--- a/addons/mail/static/src/js/thread_widget.js
+++ b/addons/mail/static/src/js/thread_widget.js
@@ -248,16 +248,16 @@ var ThreadWidget = Widget.extend({
*/
removeMessageAndRender: function (messageID, thread, options) {
var self = this;
- var done = $.Deferred();
- this.$('.o_thread_message[data-message-id="' + messageID + '"]')
+ return new Promise(function (resolve, reject) {
+ self.$('.o_thread_message[data-message-id="' + messageID + '"]')
.fadeOut({
done: function () {
self.render(thread, options);
- done.resolve();
+ resolve();
},
duration: 200,
});
- return done;
+ });
},
/**
* Scroll to the bottom of the thread
@@ -273,7 +273,7 @@ var ThreadWidget = Widget.extend({
* @param {boolean} [options.onlyIfNecessary]
*/
scrollToMessage: function (options) {
- var $target = this.$('.o_thread_message[data-message-id="' + options.msgID + '"]');
+ var $target = this.$('.o_thread_message[data-message-id="' + options.messageID + '"]');
if (options.onlyIfNecessary) {
var delta = $target.parent().height() - $target.height();
var offset = delta < 0 ?
diff --git a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
index 300bfb11a3e..ff5acfea0d2 100644
--- a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
+++ b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
@@ -95,7 +95,7 @@ var AbstractThreadWindow = Widget.extend({
var def = this._threadWidget.replace(this.$('.o_thread_window_content')).then(function () {
self._threadWidget.$el.on('scroll', self, self._debouncedOnScroll);
});
- return $.when(this._super(), def);
+ return Promise.all([this._super(), def]);
},
/**
* @override
diff --git a/addons/mail/static/src/js/thread_windows/thread_window.js b/addons/mail/static/src/js/thread_windows/thread_window.js
index e5496e0bc3c..9999014a08d 100644
--- a/addons/mail/static/src/js/thread_windows/thread_window.js
+++ b/addons/mail/static/src/js/thread_windows/thread_window.js
@@ -83,7 +83,7 @@ var ThreadWindow = AbstractThreadWindow.extend({
}
this._updateOutOfOfficeReadMoreLessButton();
- return $.when(superDef, composerDef);
+ return Promise.all([superDef, composerDef]);
},
//--------------------------------------------------------------------------
@@ -241,7 +241,7 @@ var ThreadWindow = AbstractThreadWindow.extend({
autoFocus: true,
source: function (request, response) {
self.call('mail_service', 'searchPartner', request.term, 10)
- .done(response);
+ .then(response);
},
select: function (event, ui) {
// remember partner ID so that we can replace this window
diff --git a/addons/mail/static/src/js/views/activity/activity_model.js b/addons/mail/static/src/js/views/activity/activity_model.js
index 738cdb55ca1..f5a2feee988 100644
--- a/addons/mail/static/src/js/views/activity/activity_model.js
+++ b/addons/mail/static/src/js/views/activity/activity_model.js
@@ -19,7 +19,7 @@ var ActivityModel = AbstractModel.extend({
* @override
* @param {Object} params
* @param {Array[]} params.domain
- * @returns {Deferred}
+ * @returns {Promise}
*/
load: function (params) {
this.domain = params.domain;
@@ -31,7 +31,7 @@ var ActivityModel = AbstractModel.extend({
* @param {any} handle
* @param {Object} params
* @param {Array[]} params.domain
- * @returns {Deferred}
+ * @returns {Promise}
*/
reload: function (handle, params) {
if (params && 'domain' in params) {
@@ -48,7 +48,7 @@ var ActivityModel = AbstractModel.extend({
* Fetch activity data.
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchData: function () {
var self = this;
diff --git a/addons/mail/static/src/js/views/activity/activity_renderer.js b/addons/mail/static/src/js/views/activity/activity_renderer.js
index d139a4e84cd..75eb25367e4 100644
--- a/addons/mail/static/src/js/views/activity/activity_renderer.js
+++ b/addons/mail/static/src/js/views/activity/activity_renderer.js
@@ -5,8 +5,8 @@ var AbstractRenderer = require('web.AbstractRenderer');
var core = require('web.core');
var field_registry = require('web.field_registry');
-var QWeb = core.qweb;
var _t = core._t;
+var QWeb = core.qweb;
var ActivityRenderer = AbstractRenderer.extend({
className: 'o_activity_view',
@@ -125,21 +125,22 @@ var ActivityRenderer = AbstractRenderer.extend({
};
var KanbanActivity = field_registry.get('kanban_activity');
var widget = new KanbanActivity(self, "activity_ids", record, {});
- widget.appendTo($td);
- // replace clock by closest deadline
- var $date = $('<div>');
- var formated_date = moment(activity_group.o_closest_deadline).format('ll');
- var current_year = (new Date()).getFullYear();
- if (formated_date.endsWith(current_year)) { // Dummy logic to remove year (only if current year), we will maybe need to improve it
- formated_date = formated_date.slice(0, -4);
- formated_date = formated_date.replace(/( |,)*$/g, "");
- }
- $date
- .text(formated_date)
- .addClass('o_closest_deadline');
- $td.find('a')
- .empty()
- .append($date);
+ widget.appendTo($td).then(function() {
+ // replace clock by closest deadline
+ var $date = $('<div>');
+ var formated_date = moment(activity_group.o_closest_deadline).format('ll');
+ var current_year = (new Date()).getFullYear();
+ if (formated_date.endsWith(current_year)) { // Dummy logic to remove year (only if current year), we will maybe need to improve it
+ formated_date = formated_date.slice(0, -4);
+ formated_date = formated_date.replace(/( |,)*$/g, "");
+ }
+ $date
+ .text(formated_date)
+ .addClass('o_closest_deadline');
+ $td.find('a')
+ .empty()
+ .append($date);
+ });
return $td;
});
var $tr = $('<tr/>', {class: 'o_data_row'})