summaryrefslogtreecommitdiff
path: root/addons/website_mail/static/src/js
diff options
context:
space:
mode:
authorRomain Derie <rde@odoo.com>2020-02-20 12:56:51 +0000
committerRomain Derie <rde@odoo.com>2020-02-27 16:54:25 +0000
commitc593e7d5985f2332d3d0534eb46a742d459d4fd1 (patch)
treecf76459419d881ce821b63595445b707a4079f2b /addons/website_mail/static/src/js
parent7485177be1802893c8088c39a44447a183dae908 (diff)
[FIX] website_mail: avoid sending too many RPCs
Before this commit, a JS widget would be instanciated for every `.js_follow` on the page. Every widget would then perform a RPC to know if the object was followed. That would be an issue if there was too many `.js_follow` on the DOM. Eg: on the forum tag page (/forum/1/tag), there might be unlimited tags. This is where the biggest issue is ATM, on Odoo.com we have over 5500 tags, which performs 5500 RPC. Your browser will most of the time just crash. This commit improves that behavior by sending only one RPC to get the tags info in once. With 5000 tags, there was 5000 RPCs, now there will only be one for the tags. Also, each RPC were doing 8 requests each, so this will bring requests from 40.000 to 80. Fixes #45576 closes odoo/odoo#46278 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
Diffstat (limited to 'addons/website_mail/static/src/js')
-rw-r--r--addons/website_mail/static/src/js/follow.js117
1 files changed, 84 insertions, 33 deletions
diff --git a/addons/website_mail/static/src/js/follow.js b/addons/website_mail/static/src/js/follow.js
index a6b4dcc6777..02ec8196b09 100644
--- a/addons/website_mail/static/src/js/follow.js
+++ b/addons/website_mail/static/src/js/follow.js
@@ -4,25 +4,41 @@ odoo.define('website_mail.follow', function (require) {
var publicWidget = require('web.public.widget');
publicWidget.registry.follow = publicWidget.Widget.extend({
- selector: '.js_follow',
+ selector: '#wrapwrap:has(.js_follow)',
disabledInEditableMode: false,
+ /**
+ * @override
+ */
start: function () {
var self = this;
- this.is_user = false;
+ this.isUser = false;
+ var $jsFollowEls = this.$el.find('.js_follow');
var always = function (data) {
- self.is_user = data.is_user;
- self.email = data.email;
- self.toggle_subscription(data.is_follower, data.email);
- self.$target.removeClass('d-none');
+ self.isUser = data[0].is_user;
+ const $jsFollowToEnable = $jsFollowEls.filter(function () {
+ const model = this.dataset.object;
+ return model in data[1] && data[1][model].includes(parseInt(this.dataset.id));
+ });
+ self._toggleSubscription(true, data[0].email, $jsFollowToEnable);
+ self._toggleSubscription(false, data[0].email, $jsFollowEls.not($jsFollowToEnable));
+ $jsFollowEls.removeClass('d-none');
};
+ const records = {};
+ for (const el of $jsFollowEls) {
+ const model = el.dataset.object;
+ if (!(model in records)) {
+ records[model] = [];
+ }
+ records[model].push(parseInt(el.dataset.id));
+ }
+
this._rpc({
route: '/website_mail/is_follower',
params: {
- model: this.$target.data('object'),
- res_id: this.$target.data('id'),
+ records: records,
},
}).then(always).guardedCatch(always);
@@ -31,50 +47,85 @@ publicWidget.registry.follow = publicWidget.Widget.extend({
$('.js_follow > .input-group-append.d-none').removeClass('d-none');
this.$target.find('.js_follow_btn, .js_unfollow_btn').on('click', function (event) {
event.preventDefault();
- self._onClick();
+ self._onClick(event);
});
}
return this._super.apply(this, arguments);
},
- _onClick: function () {
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Toggles subscription state for every given records.
+ *
+ * @private
+ * @param {boolean} follow
+ * @param {string} email
+ * @param {jQuery} $jsFollowEls
+ */
+ _toggleSubscription: function (follow, email, $jsFollowEls) {
+ if (follow) {
+ this._updateSubscriptionDOM(follow, email, $jsFollowEls);
+ } else {
+ for (const el of $jsFollowEls) {
+ const follow = !email && el.getAttribute('data-unsubscribe');
+ this._updateSubscriptionDOM(follow, email, $(el));
+ }
+ }
+ },
+ /**
+ * Updates subscription DOM for every given records.
+ * This should not be called directly, use `_toggleSubscription`.
+ *
+ * @private
+ * @param {boolean} follow
+ * @param {string} email
+ * @param {jQuery} $jsFollowEls
+ */
+ _updateSubscriptionDOM: function (follow, email, $jsFollowEls) {
+ $jsFollowEls.find(".js_follow_btn").toggleClass('d-none', follow);
+ $jsFollowEls.find(".js_unfollow_btn").toggleClass('d-none', !follow);
+ $jsFollowEls.find('input.js_follow_email')
+ .val(email || "")
+ .attr("disabled", email && (follow || this.isUser) ? "disabled" : false);
+ $jsFollowEls.attr("data-follow", follow ? 'on' : 'off');
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ * @param {Event} ev
+ */
+ _onClick: function (ev) {
var self = this;
- var $email = this.$target.find(".js_follow_email");
+ var $jsFollow = $(ev.currentTarget).closest('.js_follow');
+ var $email = $jsFollow.find(".js_follow_email");
if ($email.length && !$email.val().match(/.+@.+/)) {
- this.$target.addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
+ $jsFollow.addClass('o_has_error').find('.form-control, .custom-select').addClass('is-invalid');
return false;
}
- this.$target.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
+ $jsFollow.removeClass('o_has_error').find('.form-control, .custom-select').removeClass('is-invalid');
var email = $email.length ? $email.val() : false;
- if (email || this.is_user) {
+ if (email || this.isUser) {
this._rpc({
route: '/website_mail/follow',
params: {
- 'id': +this.$target.data('id'),
- 'object': this.$target.data('object'),
- 'message_is_follower': this.$target.attr("data-follow") || "off",
+ 'id': +$jsFollow.data('id'),
+ 'object': $jsFollow.data('object'),
+ 'message_is_follower': $jsFollow.attr("data-follow") || "off",
'email': email,
},
}).then(function (follow) {
- self.toggle_subscription(follow, email);
+ self._toggleSubscription(follow, email, $jsFollow);
});
}
},
- toggle_subscription: function (follow, email) {
- follow = follow || (!email && this.$target.attr('data-unsubscribe'));
- if (follow) {
- this.$target.find(".js_follow_btn").addClass('d-none');
- this.$target.find(".js_unfollow_btn").removeClass('d-none');
- }
- else {
- this.$target.find(".js_follow_btn").removeClass('d-none');
- this.$target.find(".js_unfollow_btn").addClass('d-none');
- }
- this.$target.find('input.js_follow_email')
- .val(email || "")
- .attr("disabled", email && (follow || this.is_user) ? "disabled" : false);
- this.$target.attr("data-follow", follow ? 'on' : 'off');
- },
});
});