aced
Version:
php+node light FE/BE framework
199 lines (186 loc) • 5.21 kB
JavaScript
/*
To Do
- #positionBug01 Fix bug where sometimes first tooltip is positioned incorrectly
- The text box is off, but the arrow is correctly positioned
- If hover off and back on, fixes itself
ace.tooltip($('#look-at-me'),{
content: 'I do cool things!'
});
*/
(function(){
function Tooltip($el,opts){
var z = this;
z.opts = $.extend(true,{},z.config.defaults,opts);
z.id = z.s.count++;
z.tooltips[z.id] = z;
z.open = false;
z.$ = {
target: $el
};
if (z.opts.group)
z.groups[z.opts.group] ? z.groups[z.opts.group].push(z) : (z.groups[z.opts.group] = [z]);
if (ace.util.onTouchDevice())
return console.log(z.config.key,'disabled for touch devices');
$el.bind(z.opts.showEvt,function(){
z.hideAll(z);
if (z.opts.group !== null) {
$.each(z.groups[z.opts.group],function(k,tip){
tip.show();
});
} else
z.show();
});
$el.bind(z.opts.hideEvt,function(){
if (z.opts.group !== null) {
$.each(z.groups[z.opts.group],function(k,tip){
tip.hide();
});
} else
z.hide();
});
};
Tooltip.prototype.config = {
key: 'tooltip'
,defaults: {
content: ''
,offset: null // null = width of arrow
,pos: 'top' // top bot left right
,fixed: false
,group: null // tips with the same group will show/hide at the same time
,classes: ''
,showEvt: 'mouseover'
,hideEvt: 'mouseout'
}
}
Tooltip.prototype.tooltips = {};
Tooltip.prototype.groups = {};
Tooltip.prototype.s = {
count: 0
}
Tooltip.prototype.build = function(){
var z = this
,x = ace.cssKey(z)
,posType = z.opts.fixed ? 'fixed' : 'absolute'
;
if (z.built)
return false;
z.built = true;
z.$.cont = $('<div class="'+x+' pos-'+z.opts.pos+' '+z.opts.classes+'" style="position:'+posType+';">'
+ '<div class="'+x+'-content">'+z.opts.content+'</div>'
+ '<div class="'+x+'-arrow" style="position:absolute;"></div>'
+ '</div>');
z.$.arrow = z.$.cont.find('div.'+x+'-arrow');
return true;
}
Tooltip.prototype.show = function(){
var z = this;
if (z.open)
return;
z.open = true;
z.build();
z.$.cont.css('visibility','hidden');
$('body').append(z.$.cont);
z.position();
z.$.cont.css('visibility','');
// #positionBug01 - this is a tad risky w/o unit tests but seems to fix my current issue
z.position();
}
Tooltip.prototype.hide = function(){
var z = this;
if (!z.open || !z.built)
return;
z.open = false;
z.$.cont.remove();
}
Tooltip.prototype.hideAll = function(except){
var z = this;
$.each(z.tooltips,function(k,tooltip){
if (tooltip != except && !(except && except.opts.group !== null && except.opts.group == tooltip.opts.group))
tooltip.hide();
});
}
Tooltip.prototype.position = function(){
var z = this
,$w = $(window)
,$d = $(document)
,tipDims = ace.util.trueDim(z.$.cont)
,arrowDims = ace.util.trueDim(z.$.arrow)
,targetDims = ace.util.trueDim(z.$.target)
,targetOffset = z.$.target.offset()
,windowWidth = $w.width()
,windowHeight = $w.height()
,documentWidth = $d.width()
,offset = z.opts.offset
,x,y,arrowX,arrowY
;
if (windowWidth < documentWidth) // account for horizontal scrollbar
windowWidth = documentWidth
if (offset === null) {
if (z.opts.pos == 'top' || z.opts.pos == 'bot')
offset = arrowDims.h;
else
offset = arrowDims.w;
}
if (z.opts.pos == 'top') {
x = targetOffset.left + (targetDims.w-tipDims.w)/2;
y = targetOffset.top - tipDims.h - offset;
} else if (z.opts.pos == 'bot') {
x = targetOffset.left + (targetDims.w-tipDims.w)/2;
y = targetOffset.top + targetDims.h + offset;
} else if (z.opts.pos == 'left') {
x = targetOffset.left - tipDims.w - offset;
y = targetOffset.top + (targetDims.h-tipDims.h)/2;
} else {
x = targetOffset.left + targetDims.w + offset;
y = targetOffset.top + (targetDims.h-tipDims.h)/2;
}
if (z.opts.fixed)
y -= ace.util.getViewportScrollY();
// keep within window
if (x < 0)
x = 0;
else if (x+tipDims.w > windowWidth)
x = windowWidth - tipDims.w;
if (z.opts.fixed) {
if (y < 0)
y = 0;
else if (y+tipDims.h > windowHeight)
y = windowHeight - tipDims.h;
}
if (z.opts.pos == 'top') {
arrowX = targetOffset.left + (targetDims.w-arrowDims.w)/2 - x;
arrowY = tipDims.h;
} else if (z.opts.pos == 'bot') {
arrowX = targetOffset.left + (targetDims.w-arrowDims.w)/2 - x;
arrowY = 0 - arrowDims.h;
} else if (z.opts.pos == 'left') {
arrowX = tipDims.w;
arrowY = targetOffset.top + (targetDims.h-arrowDims.h)/2 - y;
} else {
arrowX = 0 - arrowDims.w;
arrowY = targetOffset.top + (targetDims.h-arrowDims.h)/2 - y;
}
z.$.cont.css({
left: x+'px'
,top: y+'px'
});
z.$.arrow.css({
left: arrowX+'px'
,top: arrowY+'px'
});
}
ace.tooltip = function($el,opts){
// backwards compatibility for returning Tooltip for single elements
if ($el.length == 1)
return new Tooltip($el,opts);
$el.each(function(){
new Tooltip($(this),opts)
})
}
ace.tooltip.hideAll = function(except){
Tooltip.prototype.hideAll(except);
}
ace.tooltip.get = function(id){
return Tooltip.prototype.tooltips[id] ? Tooltip.prototype.tooltips[id] : null;
}
}());