diff options
Diffstat (limited to 'addons/web_tour/static/src/js/tip.js')
| -rw-r--r-- | addons/web_tour/static/src/js/tip.js | 165 |
1 files changed, 129 insertions, 36 deletions
diff --git a/addons/web_tour/static/src/js/tip.js b/addons/web_tour/static/src/js/tip.js index ab5eac5033c..56ea24f2981 100644 --- a/addons/web_tour/static/src/js/tip.js +++ b/addons/web_tour/static/src/js/tip.js @@ -1,23 +1,59 @@ odoo.define('web_tour.Tip', function(require) { "use strict"; +var core = require('web.core'); var Widget = require('web.Widget'); return Widget.extend({ template: "Tip", + events: { + mouseenter: "_to_info_mode", + 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: + * - event [String] the event name + * - selector [String] the jQuery selector on which the event should be bound + * - handler [function] the handler + * - position [String] tip's position ('top', 'right', 'left' or 'bottom'), default 'right' + * - width [int] the width in px of the tip when opened, default 270 + * - space [int] space in px between anchor and tip, default 10 + * - 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) { this._super(parent); this.$anchor = $anchor; this.info = _.defaults(info, { - position: 'right', + position: "right", + width: 270, + space: 10, + overlay: { + x: 50, + y: 50, + }, }); - this.consumed = false; }, start: function() { - this.$breathing = this.$('.o_breathing'); - this.$breathing.on('mouseenter', this._to_info_mode.bind(this)); + this.init_width = this.$el.innerWidth(); + this.init_height = this.$el.innerHeight(); + this.$tooltip_overlay = this.$(".o_tooltip_overlay"); + this.$tooltip_content = this.$(".o_tooltip_content"); + _.each(this.info.event_handlers, (function(data) { + this.$tooltip_content.on(data.event, data.selector, data.handler); + }).bind(this)); this._bind_anchor_events(); this._reposition(); + core.bus.on('scroll resize', this, function() { + if (this.tip_opened) { + this._to_bubble_mode(); + } + this._reposition(); + }); + return this._super.apply(this, arguments); }, update: function($anchor) { if (!$anchor.is(this.$anchor)) { @@ -28,50 +64,107 @@ return Widget.extend({ this._reposition(); }, _reposition: function() { - this.$breathing.position({ - my: this._invert_position(this.info.position), + if (this.tip_opened) return; + this.$el.removeClass("o_animated"); + this.$el.position({ + my: this._get_spaced_inverted_position(this.info.position), at: this.info.position, of: this.$anchor, - collision: 'fit', + collision: "none", + }); + this.$tooltip_overlay.css({ + top: -(this.info.position === "bottom" ? this.info.space : this.info.overlay.y), + right: -(this.info.position === "left" ? this.info.space : this.info.overlay.x), + bottom: -(this.info.position === "top" ? this.info.space : this.info.overlay.y), + left: -(this.info.position === "right" ? this.info.space : this.info.overlay.x), }); + this.$el.addClass("o_animated"); }, _bind_anchor_events: function () { - var self = this; + var consume_event = this.$anchor.is('input,textarea') ? 'change' : 'mousedown'; + this.$anchor.one(consume_event, this.trigger.bind(this, 'tip_consumed')); this.$anchor.on('mouseenter', this._to_info_mode.bind(this)); this.$anchor.on('mouseleave', this._to_bubble_mode.bind(this)); - this.$anchor.on(this.$anchor.is('input,textarea') ? 'change' : 'mousedown', function () { - if (self.consumed) return; - self.consumed = true; - self.trigger('tip_consumed'); - }); }, - _invert_position: function (position) { - if (position === "right") return "left"; - if (position === "left") return "right"; - if (position === "bottom") return "top"; - return "bottom"; + _get_spaced_inverted_position: function (position) { + if (position === "right") return "left+" + this.info.space; + if (position === "left") return "right-" + this.info.space; + if (position === "bottom") return "top+" + this.info.space; + return "bottom-" + this.info.space; }, - _to_info_mode: function() { - this.$breathing.fadeOut(300); - this.$popover = this.$popover || this.$anchor.popover({ - content: this.info.content + (this.info.extra_content || ''), - html: true, - animation: false, - container: this.$el, - placement: this.info.position, + _to_info_mode: function(force) { + if (this.timerOut !== undefined) { + clearTimeout(this.timerOut); + this.timerOut = undefined; + return; + } + + if (force === true) { + this.__to_info_mode(); + } else { + this.timerIn = setTimeout(this.__to_info_mode.bind(this), 100); + } + }, + __to_info_mode: function() { + clearTimeout(this.timerIn); + this.timerIn = undefined; + + var content_width = this.$tooltip_content.outerWidth(); + var content_height = this.$tooltip_content.outerHeight(); + + this.tip_opened = true; + + var offset = this.$el.offset(); + var mbLeft = 0; + var mbTop = 0; + var overflow = false; + var posVertical = (this.info.position === "top" || this.info.position === "bottom"); + if (posVertical) { + overflow = (offset.left + content_width + this.info.overlay.x > $(window).width()); + } else { + overflow = (offset.top + content_height + this.info.overlay.y > $(window).height()); + } + if (posVertical && overflow || this.info.position === "left") { + mbLeft -= (content_width - this.init_width); + } + if (!posVertical && overflow || this.info.position === "top") { + mbTop -= (content_height - this.init_height); + } + + this.$el.toggleClass("inverse", overflow); + this.$el.removeClass("o_animated").addClass("active"); + this.$el.css({ + width: content_width, + height: content_height, + "margin-left": mbLeft, + "margin-top": mbTop, }); - this.$popover.popover('show'); - this.$('.popover').on('mouseleave.to_bubble_mode', this._to_bubble_mode.bind(this)); - this.$('.popover').on('click', this.trigger.bind(this, 'popover_clicked')); }, - _to_bubble_mode: function () { - this.$breathing.fadeIn(300); - if (this.$popover) { - this.$popover.popover('hide'); - this.$('.popover').off('mouseleave.to_bubble_mode'); - this.$('.popover').off('click'); + _to_bubble_mode: function (force) { + if (this.timerIn !== undefined) { + clearTimeout(this.timerIn); + this.timerIn = undefined; + return; + } + + if (force === true) { + this.__to_bubble_mode(); + } else { + this.timerOut = setTimeout(this.__to_bubble_mode.bind(this), 300); } }, -}); + __to_bubble_mode: function() { + clearTimeout(this.timerOut); + this.timerOut = undefined; + + this.tip_opened = false; + this.$el.removeClass("active").addClass("o_animated"); + this.$el.css({ + width: this.init_width, + height: this.init_height, + margin: 0, + }); + }, +}); }); |
