diff --git a/addons/web_tour/static/src/js/tip.js b/addons/web_tour/static/src/js/tip.js index a505a692255..23db51babcf 100644 --- a/addons/web_tour/static/src/js/tip.js +++ b/addons/web_tour/static/src/js/tip.js @@ -11,7 +11,6 @@ return Widget.extend({ mouseleave: "_to_bubble_mode", }, /** - * @param {$anchor} [JQuery] the node on which the tip should be placed * @param {info} [Object] description of the tip, containing the following keys: * - content [String] the html content of the tip * - event_handlers [Object] description of optional event handlers to bind to the tip: @@ -24,9 +23,8 @@ return Widget.extend({ * - overlay [Object] x and y values for the number of pixels the mouseout detection area * overlaps the opened tip, default {x: 50, y: 50} */ - init: function(parent, $anchor, info) { + init: function(parent, info) { this._super(parent); - this.$anchor = $anchor; this.info = _.defaults(info, { position: "right", width: 270, @@ -36,6 +34,24 @@ return Widget.extend({ y: 50, }, }); + this.position = { + top: "50%", + left: "50%", + }; + }, + /** + * @param {$anchor} [JQuery] the node on which the tip should be placed + */ + attach_to: function ($anchor) { + this.$anchor = $anchor; + this.$ideal_location = this._get_ideal_location(); + + var position = this.$ideal_location.css("position"); + if (position === "static") { + this.$ideal_location.addClass("o_tooltip_parent"); + } + + return this.appendTo(this.$ideal_location); }, start: function() { this.$tooltip_overlay = this.$(".o_tooltip_overlay"); @@ -59,30 +75,58 @@ return Widget.extend({ this._reposition(); this.$el.css("opacity", 1); - core.bus.on('scroll resize', this, function() { + core.bus.on("resize", this, function () { if (this.tip_opened) { this._to_bubble_mode(true); } this._reposition(); }); + this.$el.on("transitionend oTransitionEnd webkitTransitionEnd", (function () { + if (!this.tip_opened && this.$el.parent()[0] === document.body) { + this.$el.detach(); + this.$el.css(this.position); + this.$el.appendTo(this.$ideal_location); + } + }).bind(this)); + return this._super.apply(this, arguments); }, destroy: function () { this._unbind_anchor_events(); clearTimeout(this.timerIn); clearTimeout(this.timerOut); + + // Do not remove the parent class if it contains other tooltips + if (this.$ideal_location.children(".o_tooltip").not(this.$el[0]).length === 0) { + this.$ideal_location.removeClass("o_tooltip_parent"); + } + return this._super.apply(this, arguments); }, - update: function($anchor) { + update: function ($anchor) { if (!$anchor.is(this.$anchor)) { this._unbind_anchor_events(); this.$anchor = $anchor; + this.$ideal_location = this._get_ideal_location(); + if (this.$el.parent()[0] !== document.body) { + this.$el.appendTo(this.$ideal_location); + } this._bind_anchor_events(); } this._reposition(); }, - _reposition: function() { + _get_ideal_location: function () { + var $location = this.$anchor; + var o; + do { + $location = $location.parent(); + o = $location.css("overflow"); + } while ((o === "visible" || o === "hidden") && $location[0] !== document.body); + + return $location; + }, + _reposition: function () { if (this.tip_opened) return; this.$el.removeClass("o_animated"); @@ -101,6 +145,8 @@ return Widget.extend({ left: -Math.min((this.info.position === "right" ? this.info.space : this.info.overlay.x), offset.left), }); + this.position = this.$el.position(); + this.$el.addClass("o_animated"); }, _bind_anchor_events: function () { @@ -135,6 +181,9 @@ return Widget.extend({ this.timerOut = undefined; return; } + if (this.tip_opened) { + return; + } if (force === true) { this._build_info_mode(); @@ -149,6 +198,13 @@ return Widget.extend({ this.tip_opened = true; var offset = this.$el.offset(); + + if (this.$el.parent()[0] !== document.body) { + this.$el.detach(); + this.$el.css(offset); + this.$el.appendTo(document.body); + } + var mbLeft = 0; var mbTop = 0; var overflow = false; @@ -180,6 +236,9 @@ return Widget.extend({ this.timerIn = undefined; return; } + if (!this.tip_opened) { + return; + } if (force === true) { this._build_bubble_mode(); diff --git a/addons/web_tour/static/src/js/tour_manager.js b/addons/web_tour/static/src/js/tour_manager.js index 7e1a4c54006..d19b27b4888 100644 --- a/addons/web_tour/static/src/js/tour_manager.js +++ b/addons/web_tour/static/src/js/tour_manager.js @@ -125,9 +125,9 @@ return core.Class.extend({ }], }); } - tip.widget = new Tip(this, $anchor, tip_info); - tip.widget.appendTo(document.body); + tip.widget = new Tip(this, tip_info); tip.widget.on('tip_consumed', this, this._consume_tip.bind(this, tip, tour_name)); + tip.widget.attach_to($anchor); if (this.running_tour === tour_name) { clearTimeout(this.running_tour_timeout); diff --git a/addons/web_tour/static/src/less/tip.less b/addons/web_tour/static/src/less/tip.less index 4dca388b074..a9145b97121 100644 --- a/addons/web_tour/static/src/less/tip.less +++ b/addons/web_tour/static/src/less/tip.less @@ -1,4 +1,8 @@ +.o_tooltip_parent { + position: relative!important; +} + .o_tooltip { @o-tip-background-color: lighten(@odoo-brand-primary, 5%); @o-tip-size: 26px;