keeweb/app/scripts/util/tip.js

127 lines
3.7 KiB
JavaScript
Raw Normal View History

2016-01-10 21:58:21 +01:00
'use strict';
2016-01-11 18:56:52 +01:00
var Tip = function(el, config) {
2016-01-10 21:58:21 +01:00
this.el = el;
2016-01-11 18:56:52 +01:00
this.title = config && config.title || el.attr('title');
this.placement = config && config.placement || el.attr('tip-placement');
2016-01-12 22:08:24 +01:00
this.fast = config && config.fast || false;
2016-01-10 21:58:21 +01:00
this.tipEl = null;
this.showTimeout = null;
this.hideTimeout = null;
};
Tip.prototype.init = function() {
this.el.removeAttr('title');
this.el.mouseenter(this.mouseenter.bind(this)).mouseleave(this.mouseleave.bind(this));
};
2016-01-11 18:56:52 +01:00
Tip.prototype.show = function() {
if (this.tipEl) {
this.tipEl.remove();
if (this.hideTimeout) {
clearTimeout(this.hideTimeout);
this.hideTimeout = null;
}
}
var tipEl = this.tipEl = $('<div></div>').addClass('tip').appendTo('body').html(this.title);
var rect = this.el[0].getBoundingClientRect(),
tipRect = this.tipEl[0].getBoundingClientRect();
var placement = this.placement || this.getAutoPlacement(rect, tipRect);
tipEl.addClass('tip--' + placement);
2016-01-12 22:08:24 +01:00
if (this.fast) {
tipEl.addClass('tip--fast');
}
2016-01-11 18:56:52 +01:00
var top, left;
var offset = 10;
switch (placement) {
case 'top':
top = rect.top - tipRect.height - offset;
left = rect.left + rect.width / 2 - tipRect.width / 2;
break;
case 'bottom':
top = rect.bottom + offset;
left = rect.left + rect.width / 2 - tipRect.width / 2;
break;
case 'left':
top = rect.top + rect.height / 2 - tipRect.height / 2;
left = rect.left - tipRect.width - offset;
break;
case 'right':
top = rect.top + rect.height / 2 - tipRect.height / 2;
left = rect.right + offset;
break;
}
tipEl.css({ top: top, left: left });
};
Tip.prototype.hide = function() {
if (this.tipEl) {
this.tipEl.remove();
this.tipEl = null;
}
};
2016-01-10 21:58:21 +01:00
Tip.prototype.mouseenter = function() {
var that = this;
if (this.showTimeout) {
return;
}
this.showTimeout = setTimeout(function() {
that.showTimeout = null;
2016-01-11 18:56:52 +01:00
that.show();
2016-01-10 21:58:21 +01:00
}, 200);
};
Tip.prototype.mouseleave = function() {
var that = this;
if (this.tipEl) {
that.tipEl.addClass('tip--hide');
this.hideTimeout = setTimeout(function () {
that.hideTimeout = null;
2016-01-11 18:56:52 +01:00
that.hide();
2016-01-10 21:58:21 +01:00
}, 500);
}
if (this.showTimeout) {
clearTimeout(this.showTimeout);
this.showTimeout = null;
}
};
Tip.prototype.getAutoPlacement = function(rect, tipRect) {
var padding = 20;
var bodyRect = document.body.getBoundingClientRect();
var canShowToBottom = bodyRect.bottom - rect.bottom > padding + tipRect.height,
canShowToHalfRight = bodyRect.right - rect.right > padding + tipRect.width / 2,
canShowToRight = bodyRect.right - rect.right > padding + tipRect.width,
canShowToHalfLeft = rect.left > padding + tipRect.width / 2,
canShowToLeft = rect.left > padding + tipRect.width;
if (canShowToBottom) {
if (canShowToLeft && !canShowToHalfRight) {
return 'left';
} else if (canShowToRight && !canShowToHalfLeft) {
return 'right';
} else {
return 'bottom';
}
}
if (canShowToLeft && !canShowToHalfRight) {
return 'left';
} else if (canShowToRight && !canShowToHalfLeft) {
return 'right';
} else {
return 'top';
}
};
Tip.createTips = function(container) {
container.find('[title]').each(function(ix, el) {
if (!el._tip) {
2016-01-11 18:56:52 +01:00
var tip = new Tip($(el));
tip.init();
el._tip = tip;
2016-01-10 21:58:21 +01:00
}
});
};
module.exports = Tip;