qtip2
Version:
Introducing... qTip2. The second generation of the advanced qTip plugin for the ever popular jQuery framework.
107 lines (90 loc) • 4.18 kB
JavaScript
PLUGINS.viewport = function(api, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight)
{
var target = posOptions.target,
tooltip = api.elements.tooltip,
my = posOptions.my,
at = posOptions.at,
adjust = posOptions.adjust,
method = adjust.method.split(' '),
methodX = method[0],
methodY = method[1] || method[0],
viewport = posOptions.viewport,
container = posOptions.container,
adjusted = { left: 0, top: 0 },
fixed, newMy, containerOffset, containerStatic,
viewportWidth, viewportHeight, viewportScroll, viewportOffset;
// If viewport is not a jQuery element, or it's the window/document, or no adjustment method is used... return
if(!viewport.jquery || target[0] === window || target[0] === document.body || adjust.method === 'none') {
return adjusted;
}
// Cach container details
containerOffset = container.offset() || adjusted;
containerStatic = container.css('position') === 'static';
// Cache our viewport details
fixed = tooltip.css('position') === 'fixed';
viewportWidth = viewport[0] === window ? viewport.width() : viewport.outerWidth(FALSE);
viewportHeight = viewport[0] === window ? viewport.height() : viewport.outerHeight(FALSE);
viewportScroll = { left: fixed ? 0 : viewport.scrollLeft(), top: fixed ? 0 : viewport.scrollTop() };
viewportOffset = viewport.offset() || adjusted;
// Generic calculation method
function calculate(side, otherSide, type, adjustment, side1, side2, lengthName, targetLength, elemLength) {
var initialPos = position[side1],
mySide = my[side],
atSide = at[side],
isShift = type === SHIFT,
myLength = mySide === side1 ? elemLength : mySide === side2 ? -elemLength : -elemLength / 2,
atLength = atSide === side1 ? targetLength : atSide === side2 ? -targetLength : -targetLength / 2,
sideOffset = viewportScroll[side1] + viewportOffset[side1] - (containerStatic ? 0 : containerOffset[side1]),
overflow1 = sideOffset - initialPos,
overflow2 = initialPos + elemLength - (lengthName === WIDTH ? viewportWidth : viewportHeight) - sideOffset,
offset = myLength - (my.precedance === side || mySide === my[otherSide] ? atLength : 0) - (atSide === CENTER ? targetLength / 2 : 0);
// shift
if(isShift) {
offset = (mySide === side1 ? 1 : -1) * myLength;
// Adjust position but keep it within viewport dimensions
position[side1] += overflow1 > 0 ? overflow1 : overflow2 > 0 ? -overflow2 : 0;
position[side1] = Math.max(
-containerOffset[side1] + viewportOffset[side1],
initialPos - offset,
Math.min(
Math.max(
-containerOffset[side1] + viewportOffset[side1] + (lengthName === WIDTH ? viewportWidth : viewportHeight),
initialPos + offset
),
position[side1],
// Make sure we don't adjust complete off the element when using 'center'
mySide === 'center' ? initialPos - myLength : 1E9
)
);
}
// flip/flipinvert
else {
// Update adjustment amount depending on if using flipinvert or flip
adjustment *= type === FLIPINVERT ? 2 : 0;
// Check for overflow on the left/top
if(overflow1 > 0 && (mySide !== side1 || overflow2 > 0)) {
position[side1] -= offset + adjustment;
newMy.invert(side, side1);
}
// Check for overflow on the bottom/right
else if(overflow2 > 0 && (mySide !== side2 || overflow1 > 0) ) {
position[side1] -= (mySide === CENTER ? -offset : offset) + adjustment;
newMy.invert(side, side2);
}
// Make sure we haven't made things worse with the adjustment and reset if so
if(position[side1] < viewportScroll[side1] && -position[side1] > overflow2) {
position[side1] = initialPos; newMy = my.clone();
}
}
return position[side1] - initialPos;
}
// Set newMy if using flip or flipinvert methods
if(methodX !== 'shift' || methodY !== 'shift') { newMy = my.clone(); }
// Adjust position based onviewport and adjustment options
adjusted = {
left: methodX !== 'none' ? calculate( X, Y, methodX, adjust.x, LEFT, RIGHT, WIDTH, targetWidth, elemWidth ) : 0,
top: methodY !== 'none' ? calculate( Y, X, methodY, adjust.y, TOP, BOTTOM, HEIGHT, targetHeight, elemHeight ) : 0,
my: newMy
};
return adjusted;
};