summaryrefslogtreecommitdiff
path: root/addons/web_tour/static/src/js/tip.js
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web_tour/static/src/js/tip.js')
-rw-r--r--addons/web_tour/static/src/js/tip.js165
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,
+ });
+ },
+});
});