summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorGéry Debongnie <ged@odoo.com>2021-03-15 11:27:05 +0000
committerGéry Debongnie <ged@odoo.com>2021-03-15 15:04:16 +0000
commitb88b634a0363a55411290e54e37806cfec1b2de5 (patch)
tree21a551bb817646e638e6ead255c14f0d6d354c1f /addons
parent4445207161c84d2854055df63013c1361e5d4697 (diff)
[FIX] web_tour: make tour system more resilient
The tour system is based on many assumptions, some of those not being true all the time. In practice, it works most of the time, but when some slight changes occurs, we may observe undeterministic behavior. This was actually the case in a dev branch working on assets: the order of some files was changed, and it caused crashes in various tours. This helped us identify two issues in the Tip class: - the Tip class may be destroyed before it is completely started (so, the destroy method should not assume that the code in start was called - the attach_to method should not resolve if the tip was destroyed meanwhile. This is critical, because some code uses that promise to act on the widget. This commit fixes both of these issues. closes odoo/odoo#67872 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Diffstat (limited to 'addons')
-rw-r--r--addons/web_tour/static/src/js/tip.js30
1 files changed, 23 insertions, 7 deletions
diff --git a/addons/web_tour/static/src/js/tip.js b/addons/web_tour/static/src/js/tip.js
index 98372d33dc2..f1b4a6a0d4a 100644
--- a/addons/web_tour/static/src/js/tip.js
+++ b/addons/web_tour/static/src/js/tip.js
@@ -57,12 +57,15 @@ var Tip = Widget.extend({
* Attaches the tip to the provided $anchor and $altAnchor.
* $altAnchor is an alternative trigger that can consume the step. The tip is
* however only displayed on the $anchor.
+ *
+ * Note that the returned promise stays pending if the Tip widget was
+ * destroyed in the meantime.
*
* @param {jQuery} $anchor the node on which the tip should be placed
* @param {jQuery} $altAnchor an alternative node that can consume the step
* @return {Promise}
*/
- attach_to: function ($anchor, $altAnchor) {
+ attach_to: async function ($anchor, $altAnchor) {
this._setupAnchor($anchor, $altAnchor);
this.is_anchor_fixed_position = this.$anchor.css("position") === "fixed";
@@ -70,7 +73,10 @@ var Tip = Widget.extend({
// The body never needs to have the o_tooltip_parent class. It is a
// safe place to put the tip in the DOM at initialization and be able
// to compute its dimensions and reposition it if required.
- return this.appendTo(document.body);
+ await this.appendTo(document.body);
+ if (this.isDestroyed()) {
+ return new Promise(() => {});
+ }
},
start() {
this.$tooltip_overlay = this.$(".o_tooltip_overlay");
@@ -132,8 +138,12 @@ var Tip = Widget.extend({
$el.removeClass("o_tooltip_parent");
}
};
- _removeParentClass(this.$ideal_location);
- _removeParentClass(this.$furtherIdealLocation);
+ if (this.$el && this.$ideal_location) {
+ _removeParentClass(this.$ideal_location);
+ }
+ if (this.$el && this.$furtherIdealLocation) {
+ _removeParentClass(this.$furtherIdealLocation);
+ }
return this._super.apply(this, arguments);
},
@@ -393,9 +403,15 @@ var Tip = Widget.extend({
return $consumeEventAnchors;
},
_unbind_anchor_events: function () {
- this.$anchor.off(".anchor");
- this.$consumeEventAnchors.off(".anchor");
- this.$scrolableElement.off('.Tip');
+ if (this.$anchor) {
+ this.$anchor.off(".anchor");
+ }
+ if (this.$consumeEventAnchors) {
+ this.$consumeEventAnchors.off(".anchor");
+ }
+ if (this.$scrolableElement) {
+ this.$scrolableElement.off('.Tip');
+ }
},
_get_spaced_inverted_position: function (position) {
if (position === "right") return "left+" + this.info.space;