/**
* @fileOverview jQuery 1.6+ plugin for making popup bubbles.
* @author David Huynh
* @author Ryan Lee
*/
(function($) {
var defaultBubbleConfig, methods, _init;
_init = false;
defaultBubbleConfig = {
containerCSSClass: "simileAjax-bubble-container",
innerContainerCSSClass: "simileAjax-bubble-innerContainer",
contentContainerCSSClass: "simileAjax-bubble-contentContainer",
borderGraphicSize: 50,
borderGraphicCSSClassPrefix: "simileAjax-bubble-border-",
arrowGraphicTargetOffset: 33, // from tip of arrow to the side of the graphic that touches the content of the bubble
arrowGraphicLength: 100, // dimension of arrow graphic along the direction that the arrow points
arrowGraphicWidth: 49, // dimension of arrow graphic perpendicular to the direction that the arrow points
arrowGraphicCSSClassPrefix: "simileAjax-bubble-arrow-",
closeGraphicCSSClass: "simileAjax-bubble-close",
extraPadding: 20
};
methods = {
"configure": function(options) {
var opt;
for (opt in options) {
if (options.hasOwnProperty(opt)) {
defaultBubbleConfig[opt] = options[opt];
}
}
},
"createBubbleForContentAndPoint": function(div, pageX, pageY, contentWidth, orientation, maxHeight) {
if (typeof contentWidth !== "number") {
contentWidth = 300;
}
if (typeof maxHeight !== "number") {
maxHeight = 0;
}
div = $(div);
div.css("position", "absolute").
css("left", "-5000px").
css("top", "0px").
css("width", contentWidth + "px");
$(document.body).append(div);
window.setTimeout(function() {
var width, height, scrollDivW, bubble, scrollDiv;
width = div.prop("scrollWidth") + 10;
height = div.prop("scrollHeight") + 10;
scrollDivW = 0; // width of the possible inner container when we want vertical scrolling
if (maxHeight > 0 && height > maxHeight) {
height = maxHeight;
scrollDivW = width - 25;
}
bubble = methods.createBubbleForPoint(pageX, pageY, width, height, orientation);
div.remove();
div.css("position", "static");
div.css("left", null);
div.css("top", null);
// create a scroll div if needed
if (scrollDivW > 0) {
scrollDiv = $("
");
div.css("width", null);
scrollDiv.css("width", scrollDivW + "px");
scrollDiv.append(div);
$(bubble.content).append(scrollDiv);
} else {
div.css("width", width + "px");
$(bubble.content).append(div);
}
}, 200);
},
"createBubbleForPoint": function(pageX, pageY, contentWidth, contentHeight, orientation) {
var bubbleConfig, pnTransparencyClassSuffix, bubbleWidth, bubbleHeight, generatePngSensitiveClass, div, divInnerContainer, bubble, close, layer, createBorder, divContentContainer, divClose;
contentWidth = parseInt(contentWidth, 10);
contentHeight = parseInt(contentHeight, 10);
bubbleConfig = defaultBubbleConfig;
pngTransparencyClassSuffix = "pngTranslucent";
bubbleWidth = contentWidth + 2 * bubbleConfig.borderGraphicSize;
bubbleHeight = contentHeight + 2 * bubbleConfig.borderGraphicSize;
generatePngSensitiveClass = function(className) {
return className + " " + className + "-" + pngTransparencyClassSuffix;
};
/*
* Render container divs
*/
div = $("
").
attr("class", generatePngSensitiveClass(bubbleConfig.containerCSSClass)).
css("width", contentWidth + "px").
css("height", contentHeight + "px");
divInnerContainer = $("
").
attr("class", generatePngSensitiveClass(bubbleConfig.innerContainerCSSClass));
div.append(divInnerContainer);
/*
* Create layer for bubble
*/
close = function() {
if (!bubble._closed) {
$(bubble._div).remove();
bubble._doc = null;
bubble._div = null;
bubble._content = null;
bubble._closed = true;
}
};
bubble = { _closed: false };
bubble._div = div.get(0);
// @@@ not entirely correct, former layers material
bubble.close = function() { close(); };
/*
* Render border graphics
*/
createBorder = function(classNameSuffix) {
var divBorderGraphic = $("
").
attr("class",generatePngSensitiveClass(bubbleConfig.borderGraphicCSSClassPrefix + classNameSuffix));
divInnerContainer.append(divBorderGraphic);
};
createBorder("top-left");
createBorder("top-right");
createBorder("bottom-left");
createBorder("bottom-right");
createBorder("left");
createBorder("right");
createBorder("top");
createBorder("bottom");
/*
* Render content
*/
divContentContainer = $("
").
attr("class", generatePngSensitiveClass(bubbleConfig.contentContainerCSSClass));
divInnerContainer.append(divContentContainer);
bubble.content = divContentContainer.get(0);
/*
* Render close button
*/
divClose = $("
").
attr("class", generatePngSensitiveClass(bubbleConfig.closeGraphicCSSClass));
divInnerContainer.append(divClose);
divClose.bind("click", bubble.close);
(function() {
var docWidth, docHeight, halfArrowGraphicWidth, createArrow, left, divArrow, top;
docWidth = $(window).width();
docHeight = $(window).height();
halfArrowGraphicWidth = Math.ceil(bubbleConfig.arrowGraphicWidth / 2);
createArrow = function(classNameSuffix) {
var divArrowGraphic = $("
").
attr("class", generatePngSensitiveClass(bubbleConfig.arrowGraphicCSSClassPrefix + "point-" + classNameSuffix));
divInnerContainer.append(divArrowGraphic);
return divArrowGraphic;
};
if (pageX - halfArrowGraphicWidth - bubbleConfig.borderGraphicSize - bubbleConfig.extraPadding > 0 &&
pageX + halfArrowGraphicWidth + bubbleConfig.borderGraphicSize + bubbleConfig.extraPadding < docWidth) {
/*
* Bubble can be positioned above or below the target point.
*/
left = pageX - Math.round(contentWidth / 2);
left = pageX < (docWidth / 2) ?
Math.max(left, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
Math.min(left, docWidth - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentWidth);
if ((orientation && orientation === "top") ||
(!orientation &&
(pageY
- bubbleConfig.arrowGraphicTargetOffset
- contentHeight
- bubbleConfig.borderGraphicSize
- bubbleConfig.extraPadding > 0))) {
/*
* Position bubble above the target point.
*/
divArrow = createArrow("down");
divArrow.css("left", (pageX - halfArrowGraphicWidth - left) + "px");
div.css("left", left + "px");
div.css("top", (pageY - bubbleConfig.arrowGraphicTargetOffset - contentHeight) + "px");
return;
} else if ((orientation && orientation === "bottom") ||
(!orientation &&
(pageY
+ bubbleConfig.arrowGraphicTargetOffset
+ contentHeight
+ bubbleConfig.borderGraphicSize
+ bubbleConfig.extraPadding < docHeight))) {
/*
* Position bubble below the target point.
*/
divArrow = createArrow("up");
divArrow.css("left", (pageX - halfArrowGraphicWidth - left) + "px");
div.css("left", left + "px");
div.css("top", (pageY + bubbleConfig.arrowGraphicTargetOffset) + "px");
return;
}
}
top = pageY - Math.round(contentHeight / 2);
top = pageY < (docHeight / 2) ?
Math.max(top, bubbleConfig.extraPadding + bubbleConfig.borderGraphicSize) :
Math.min(top, docHeight - bubbleConfig.extraPadding - bubbleConfig.borderGraphicSize - contentHeight);
if ((orientation && orientation === "left") ||
(!orientation &&
(pageX
- bubbleConfig.arrowGraphicTargetOffset
- contentWidth
- bubbleConfig.borderGraphicSize
- bubbleConfig.extraPadding > 0))) {
/*
* Position bubble left of the target point.
*/
divArrow = createArrow("right");
divArrow.css("top", (pageY - halfArrowGraphicWidth - top) + "px");
div.css("top", top + "px");
div.css("left", (pageX - bubbleConfig.arrowGraphicTargetOffset - contentWidth) + "px");
} else {
/*
* Position bubble right of the target point, as the last resort.
*/
divArrow = createArrow("left");
divArrow.css("top", (pageY - halfArrowGraphicWidth - top) + "px");
div.css("top", top + "px");
div.css("left", (pageX + bubbleConfig.arrowGraphicTargetOffset) + "px");
}
}());
$(document.body).append(div);
return bubble;
},
"createMessageBubble": function() {
var containerDiv, topDiv, topRightDiv, middleDiv, middleRightDiv, contentDiv, bottomDiv, bottomRightDiv;
containerDiv = $("
");
topDiv = $("
").css({
"height": 33,
"background": "url(" + Exhibit.urlPrefix + "images/message-top-left.png) top left no-repeat",
"padding-left": 44
});
containerDiv.append(topDiv);
topRightDiv = $("
").css({
"height": 33,
"background": "url(" + Exhibit.urlPrefix + "images/message-top-right.png) top right no-repeat"
});
topDiv.append(topRightDiv);
middleDiv = $("
").css({
"background": "url(" + Exhibit.urlPrefix + "images/message-left.png) top left repeat-y",
"padding-left": 44
});
containerDiv.append(middleDiv);
middleRightDiv = $("
").css({
"background": "url(" + Exhibit.urlPrefix + "images/message-right.png) top right repeat-y",
"padding-right": 44
});
middleDiv.append(middleRightDiv);
contentDiv = $("
");
middleRightDiv.append(contentDiv);
bottomDiv = $("
").css({
"height": 55,
"background": "url(" + Exhibit.urlPrefix + "images/message-bottom-left.png) bottom left no-repeat",
"padding-left": 44
});
containerDiv.append(bottomDiv);
bottomRightDiv = $("
").css({
"height": 55,
"background": "url(" + Exhibit.urlPrefix + "images/message-bottom-right.png) bottom right no-repeat"
});
bottomDiv.append(bottomRightDiv);
return {
containerDiv: containerDiv,
contentDiv: contentDiv
};
},
"createTranslucentImage": function(url, verticalAlign) {
var elmt = $("
");
elmt.attr("src", url);
if (typeof verticalAlign !== "undefined" &&
verticalAlign !== null) {
elmt.css("vertical-align", verticalAlign);
} else {
elmt.css("vertical-align", "middle");
}
return elmt.get(0);
},
"createTranslucentImageHTML": function(url, verticalAlign) {
return "
";
},
"pngIsTranslucent": function() {
return true;
}
};
$.simileBubble = function(method) {
if (typeof method !== "undefined" &&
method !== null &&
typeof method === "string" &&
method.indexOf("_") !== 0 &&
typeof methods[method] !== "undefined") {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === "object" ||
typeof method === "undefined" ||
method === null) {
return methods.configure.apply(this, arguments);
} else {
$.error("Method " + method + " does not exist on jQuery.simileBubble");
}
};
}(jQuery));