/*
* jquery.powerFloat.js
* jQuery 万能浮动层插件
* http://www.zhangxinxu.com/wordpress/?p=1328
* by zhangxinxu
* 2010-12-06 v1.0.0 插件编写,初步调试
* 2010-12-30 v1.0.1 限定尖角字符字体,避免受浏览器自定义字体干扰
* 2011-01-03 v1.1.0 修复连续获得焦点显示后又隐藏的bug
修复图片加载正则判断不准确的问题
* 2011-02-15 v1.1.1 关于居中对齐位置判断的特殊处理
* 2011-04-15 v1.2.0 修复浮动层含有过高select框在IE下点击会隐藏浮动层的问题,同时优化事件绑定
*/
(function($) {
$.fn.powerFloat = function(options) {
return $(this).each(function() {
var s = $.extend({}, defaults, options || {});
var init = function(pms, trigger) {
if (o.target && o.target.css("display") !== "none") {
o.targetClear();
}
o.s = pms;
o.trigger = trigger;
};
switch (s.eventType) {
case "hover": {
$(this).hover(function() {
init(s, $(this));
var numShowDelay = parseInt(s.showDelay, 10), hoverTimer;
//鼠标hover延时
if (numShowDelay) {
if (hoverTimer) {
clearTimeout(hoverTimer);
}
hoverTimer = setTimeout(function() {
o.targetGet();
}, numShowDelay);
} else {
o.targetGet();
}
}, function() {
o.flagDisplay = false;
o.targetHold();
if (s.hoverHold) {
setTimeout(function() {
o.displayDetect();
}, 200);
} else {
o.displayDetect();
}
});
if (s.hoverFollow) {
//鼠标跟随
$(this).mousemove(function(e) {
o.cacheData.left = e.pageX;
o.cacheData.top = e.pageY;
o.targetGet();
return false;
});
}
break;
}
case "click": {
$(this).click(function(e) {
if (o.flagDisplay && e.target === o.trigger.get(0)) {
o.flagDisplay = false;
o.displayDetect();
} else {
init(s, $(this));
o.targetGet();
if (!$(document).data("mouseupBind")) {
$(document).bind("mouseup", function(e) {
var flag = false;
$(e.target).parents().each(function() {
if (o.target && $(this).attr("id") == o.target.attr("id") ) {
flag = true;
}
});
if (s.eventType === "click" && o.flagDisplay && e.target != o.trigger.get(0) && !flag) {
o.flagDisplay = false;
o.displayDetect();
}
return false;
}).data("mouseupBind", true);
}
}
});
break;
}
case "focus": {
$(this).focus(function() {
var self = $(this);
setTimeout(function() {
init(s, self);
o.targetGet();
}, 200);
}).blur(function() {
o.flagDisplay = false;
setTimeout(function() {
o.displayDetect();
}, 190);
});
break;
}
default: {
init(s, $(this));
o.targetGet();
$(document).unbind("mouseup");
}
}
});
};
var o = {
targetGet: function() {
//一切显示的触发来源
if (!this.trigger) { return this; }
var attr = this.trigger.attr(this.s.targetAttr), target = this.s.target;
switch (this.s.targetMode) {
case "common": {
if (target) {
var type = typeof(target);
if (type === "object") {
if (target.size()) {
o.target = target.eq(0);
}
} else if (type === "string") {
if ($(target).size()) {
o.target = $(target).eq(0);
}
}
} else {
if (attr && $("#" + attr).size()) {
o.target = $("#" + attr);
}
}
if (o.target) {
o.targetShow();
} else {
return this;
}
break;
}
case "ajax": {
//ajax元素,如图片,页面地址
var url = target || attr;
this.targetProtect = false;
if (/(\.jpg|\.png|\.gif|\.bmp|\.jpeg)$/i.test(url)) {
if (o.cacheData[url]) {
o.target = $(o.cacheData[url]);
o.targetShow();
} else {
var tempImage = new Image();
o.loading();
tempImage.onload = function() {
var w = tempImage.width, h = tempImage.height;
var winw = $(window).width(), winh = $(window).height();
var imgScale = w / h, winScale = winw / winh;
if (imgScale > winScale) {
//图片的宽高比大于显示屏幕
if (w > winw / 2) {
w = winw / 2;
h = w / imgScale;
}
} else {
//图片高度较高
if (h > winh / 2) {
h = winh / 2;
w = h * imgScale;
}
}
var imgHtml = '
';
o.cacheData[url] = imgHtml;
o.target = $(imgHtml);
o.targetShow();
};
tempImage.onerror = function() {
o.target = $('
图片加载失败。
');
o.targetShow();
};
tempImage.src = url;
}
} else {
if (url) {
if (o.cacheData[url]) {
o.target = $('' + o.cacheData[url] + '
');
o.targetShow();
} else {
o.loading();
$.ajax({
url: url,
success: function(data) {
if (typeof(data) === "string") {
o.target = $('' + data + '
');
o.targetShow();
o.cacheData[url] = data;
}
},
error: function() {
o.target = $('数据没有加载成功。
');
o.targetShow();
}
});
}
}
}
break;
}
case "list": {
//下拉列表
var targetHtml = '', arrLength;
if ($.isArray(target) && (arrLength = target.length)) {
$.each(target, function(i, obj) {
var list = "", strClass = "", text, href;
if (i === 0) {
strClass = ' class="float_list_li_first"';
}
if (i === arrLength - 1) {
strClass = ' class="float_list_li_last"';
}
if (typeof(obj) === "object" && (text = obj.text.toString())) {
if (href = (obj.href || "javascript:")) {
list = '' + text + '';
} else {
list = text;
}
} else if (typeof(obj) === "string" && obj) {
list = obj;
}
if (list) {
targetHtml += '- ' + list + '
';
}
});
} else {
targetHtml += '- 列表无数据。
';
}
targetHtml += '
';
o.target = $(targetHtml);
this.targetProtect = false;
o.targetShow();
break;
}
case "remind": {
//内容均是字符串
var strRemind = target || attr;
this.targetProtect = false;
if (typeof(strRemind) === "string") {
o.target = $('' + strRemind + '');
o.targetShow();
}
break;
}
default: {
var objOther = target || attr, type = typeof(objOther);
if (objOther) {
if (type === "string") {
//选择器
if (/<.*>/.test(objOther)) {
//纯粹字符串了
o.target = $('' + objOther + '
');
this.targetProtect = false;
} else if ($(objOther).size()) {
o.target = $(objOther).eq(0);
this.targetProtect = true;
} else if ($("#" + objOther).size()) {
o.target = $("#" + objOther).eq(0);
this.targetProtect = true;
} else {
o.target = $('' + objOther + '
');
this.targetProtect = false;
}
o.targetShow();
} else if (type === "object") {
if (!$.isArray(objOther) && objOther.size()) {
o.target = objOther.eq(0);
this.targetProtect = true;
o.targetShow();
}
}
}
}
}
return this;
},
container: function() {
//容器(如果有)重装target
var cont = this.s.container, mode = this.s.targetMode || "mode";
if (mode === "ajax" || mode === "remind") {
//显示三角
this.s.sharpAngle = true;
} else {
this.s.sharpAngle = false;
}
//是否反向
if (this.s.reverseSharp) {
this.s.sharpAngle = !this.s.sharpAngle;
}
if (mode !== "common") {
//common模式无新容器装载
if (cont === null) {
cont = "plugin";
}
if ( cont === "plugin" ) {
if (!$("#floatBox_" + mode).size()) {
$('').appendTo($("body")).hide();
}
cont = $("#floatBox_" + mode);
}
if (cont && typeof(cont) !== "string" && cont.size()) {
if (this.targetProtect) {
o.target.show().css("position", "static");
}
o.target = cont.empty().append(o.target);
}
}
return this;
},
setWidth: function() {
var w = this.s.width;
if (w === "auto") {
if (this.target.get(0).style.width) {
this.target.css("width", "auto");
}
} else if (w === "inherit") {
this.target.width(this.trigger.width());
} else {
this.target.css("width", w);
}
return this;
},
position: function() {
var pos, tri_h = 0, tri_w = 0, cor_w = 0, cor_h = 0, tri_l, tri_t, tar_l, tar_t, cor_l, cor_t,
tar_h = this.target.data("height"), tar_w = this.target.data("width"),
st = $(window).scrollTop(),
off_x = parseInt(this.s.offsets.x, 10) || 0, off_y = parseInt(this.s.offsets.y, 10) || 0,
mousePos = this.cacheData;
//缓存目标对象高度,宽度,提高鼠标跟随时显示性能,元素隐藏时缓存清除
if (!tar_h) {
tar_h = this.target.outerHeight();
if (this.s.hoverFollow) {
this.target.data("height", tar_h);
}
}
if (!tar_w) {
tar_w = this.target.outerWidth();
if (this.s.hoverFollow) {
this.target.data("width", tar_w);
}
}
pos = this.trigger.offset();
tri_h = this.trigger.outerHeight();
tri_w = this.trigger.outerWidth();
tri_l = pos.left;
tri_t = pos.top;
var funMouseL = function() {
if (tri_l < 0) {
tri_l = 0;
} else if (tri_l + tri_h > $(window).width()) {
tri_l = $(window).width() - tri_h;
}
}, funMouseT = function() {
if (tri_t < 0) {
tri_t = 0;
} else if (tri_t + tri_h > $(document).height()) {
tri_t = $(document).height() - tri_h;
}
};
//如果是鼠标跟随
if (this.s.hoverFollow && mousePos.left && mousePos.top) {
if (this.s.hoverFollow === "x") {
//水平方向移动,说明纵坐标固定
tri_l = mousePos.left
funMouseL();
} else if (this.s.hoverFollow === "y") {
//垂直方向移动,说明横坐标固定,纵坐标跟随鼠标移动
tri_t = mousePos.top;
funMouseT();
} else {
tri_l = mousePos.left;
tri_t = mousePos.top;
funMouseL();
funMouseT();
}
}
var arrLegalPos = ["4-1", "1-4", "5-7", "2-3", "2-1", "6-8", "3-4", "4-3", "8-6", "1-2", "7-5", "3-2"],
align = this.s.position, alignMatch = false, strDirect;
$.each(arrLegalPos, function(i, n) {
if (n === align) {
alignMatch = true;
return;
}
});
if (!alignMatch) {
align = "4-1";
}
var funDirect = function(a) {
var dir = "bottom";
//确定方向
switch (a) {
case "1-4": case "5-7": case "2-3": {
dir = "top";
break;
}
case "2-1": case "6-8": case "3-4": {
dir = "right";
break;
}
case "1-2": case "8-6": case "4-3": {
dir = "left";
break;
}
case "4-1": case "7-5": case "3-2": {
dir = "bottom";
break;
}
}
return dir;
};
//居中判断
var funCenterJudge = function(a) {
if (a === "5-7" || a === "6-8" || a === "8-6" || a === "7-5") {
return true;
}
return false;
};
var funJudge = function(dir) {
var totalHeight = 0, totalWidth = 0, flagCorner = (o.s.sharpAngle && o.corner) ? true: false;
if (dir === "right") {
totalWidth = tri_l + tri_w + tar_w + off_x;
if (flagCorner) {
totalWidth += o.corner.width();
}
if (totalWidth > $(window).width()) {
return false;
}
} else if (dir === "bottom") {
totalHeight = tri_t + tri_h + tar_h + off_y;
if (flagCorner) {
totalHeight += o.corner.height();
}
if (totalHeight > st + $(window).height()) {
return false;
}
} else if (dir === "top") {
totalHeight = tar_h + off_y;
if (flagCorner) {
totalHeight += o.corner.height();
}
if (totalHeight > tri_t - st) {
return false;
}
} else if (dir === "left") {
totalWidth = tar_w + off_x;
if (flagCorner) {
totalWidth += o.corner.width();
}
if (totalWidth > tri_l) {
return false;
}
}
return true;
};
//此时的方向
strDirect = funDirect(align);
if (this.s.sharpAngle) {
//创建尖角
this.createSharp(strDirect);
}
//边缘过界判断
if (this.s.edgeAdjust) {
//根据位置是否溢出显示界面重新判定定位
if (funJudge(strDirect)) {
//该方向不溢出
(function() {
if (funCenterJudge(align)) { return; }
var obj = {
top: {
right: "2-3",
left: "1-4"
},
right: {
top: "2-1",
bottom: "3-4"
},
bottom: {
right: "3-2",
left: "4-1"
},
left: {
top: "1-2",
bottom: "4-3"
}
};
var o = obj[strDirect], name;
if (o) {
for (name in o) {
if (!funJudge(name)) {
align = o[name];
}
}
}
})();
} else {
//该方向溢出
(function() {
if (funCenterJudge(align)) {
var center = {
"5-7": "7-5",
"7-5": "5-7",
"6-8": "8-6",
"8-6": "6-8"
};
align = center[align];
} else {
var obj = {
top: {
left: "3-2",
right: "4-1"
},
right: {
bottom: "1-2",
top: "4-3"
},
bottom: {
left: "2-3",
right: "1-4"
},
left: {
bottom: "2-1",
top: "3-4"
}
};
var o = obj[strDirect], arr = [];
for (name in o) {
arr.push(name);
}
if (funJudge(arr[0]) || !funJudge(arr[1])) {
align = o[arr[0]];
} else {
align = o[arr[1]];
}
}
})();
}
}
//已确定的尖角
var strNewDirect = funDirect(align), strFirst = align.split("-")[0];
if (this.s.sharpAngle) {
//创建尖角
this.createSharp(strNewDirect);
cor_w = this.corner.width(), cor_h = this.corner.height();
}
//确定left, top值
if (this.s.hoverFollow) {
//如果鼠标跟随
if (this.s.hoverFollow === "x") {
//仅水平方向跟随
tar_l = tri_l + off_x;
if (strFirst === "1" || strFirst === "8" || strFirst === "4" ) {
//最左
tar_l = tri_l - (tar_w - tri_w) / 2 + off_x;
} else {
//右侧
tar_l = tri_l - (tar_w - tri_w) + off_x;
}
//这是垂直位置,固定不动
if (strFirst === "1" || strFirst === "5" || strFirst === "2" ) {
tar_t = tri_t - off_y - tar_h - cor_h;
//尖角
cor_t = tri_t - cor_h - off_y - 1;
} else {
//下方
tar_t = tri_t + tri_h + off_y + cor_h;
cor_t = tri_t + tri_h + off_y + 1;
}
cor_l = pos.left - (cor_w - tri_w) / 2;
} else if (this.s.hoverFollow === "y") {
//仅垂直方向跟随
if (strFirst === "1" || strFirst === "5" || strFirst === "2" ) {
//顶部
tar_t = tri_t - (tar_h - tri_h) / 2 + off_y;
} else {
//底部
tar_t = tri_t - (tar_h - tri_h) + off_y;
}
if (strFirst === "1" || strFirst === "8" || strFirst === "4" ) {
//左侧
tar_l = tri_l - tar_w - off_x - cor_w;
cor_l = tri_l - cor_w - off_x - 1;
} else {
//右侧
tar_l = tri_l + tri_w - off_x + cor_w;
cor_l = tri_l + tri_w + off_x + 1;
}
cor_t = pos.top - (cor_h - tri_h) / 2;
} else {
tar_l = tri_l + off_x;
tar_t = tri_t + off_y;
}
} else {
switch (strNewDirect) {
case "top": {
tar_t = tri_t - off_y - tar_h - cor_h;
if (strFirst == "1") {
tar_l = tri_l - off_x;
} else if (strFirst === "5") {
tar_l = tri_l - (tar_w - tri_w) / 2 - off_x;
} else {
tar_l = tri_l - (tar_w - tri_w) - off_x;
}
cor_t = tri_t - cor_h - off_y - 1;
cor_l = tri_l - (cor_w - tri_w) / 2;
break;
}
case "right": {
tar_l = tri_l + tri_w + off_x + cor_w;
if (strFirst == "2") {
tar_t = tri_t + off_y;
} else if (strFirst === "6") {
tar_t = tri_t - (tar_h - tri_h) / 2 + off_y;
} else {
tar_t = tri_t - (tar_h - tri_h) + off_y;
}
cor_l = tri_l + tri_w + off_x + 1;
cor_t = tri_t - (cor_h - tri_h) / 2;
break;
}
case "bottom": {
tar_t = tri_t + tri_h + off_y + cor_h;
if (strFirst == "4") {
tar_l = tri_l + off_x;
} else if (strFirst === "7") {
tar_l = tri_l - (tar_w - tri_w) / 2 + off_x;
} else {
tar_l = tri_l - (tar_w - tri_w) + off_x;
}
cor_t = tri_t + tri_h + off_y + 1;
cor_l = tri_l - (cor_w - tri_w) / 2;
break;
}
case "left": {
tar_l = tri_l - tar_w - off_x - cor_w;
if (strFirst == "2") {
tar_t = tri_t - off_y;
} else if (strFirst === "6") {
tar_t = tri_t - (tar_w - tri_w) / 2 - off_y;
} else {
tar_t = tri_t - (tar_h - tri_h) - off_y;
}
cor_l = tar_l + cor_w;
cor_t = tri_t - (tar_w - cor_w) / 2;
break;
}
}
}
//尖角的显示
if (cor_h && cor_w && this.corner) {
this.corner.css({
left: cor_l,
top: cor_t,
zIndex: this.s.zIndex + 1
});
}
//浮动框显示
this.target.css({
position: "absolute",
left: tar_l,
top: tar_t,
zIndex: this.s.zIndex
});
return this;
},
createSharp: function(dir) {
var bgColor, bdColor, color1 = "", color2 = "";
var objReverse = {
left: "right",
right: "left",
bottom: "top",
top: "bottom"
}, dirReverse = objReverse[dir] || "top";
if (this.target) {
bgColor = this.target.css("background-color");
if (parseInt(this.target.css("border-" + dirReverse + "-width")) > 0) {
bdColor = this.target.css("border-" + dirReverse + "-color");
}
if (bdColor && bdColor !== "transparent") {
color1 = 'style="color:' + bdColor + ';"';
} else {
color1 = 'style="display:none;"';
}
if (bgColor && bgColor !== "transparent") {
color2 = 'style="color:' + bgColor + ';"';
}else {
color2 = 'style="display:none;"';
}
}
var html = '' +
'◆' +
'◆' +
'
';
if (!$("#floatCorner_" + dir).size()) {
$("body").append($(html));
}
this.corner = $("#floatCorner_" + dir);
return this;
},
targetHold: function() {
if (this.s.hoverHold) {
var delay = parseInt(this.s.hideDelay, 10) || 200;
this.target.hover(function() {
o.flagDisplay = true;
}, function() {
o.flagDisplay = false;
//鼠标移出检测是否hover trigger,以决定其显示与否
setTimeout(function() {
o.displayDetect();
}, delay);
});
}
return this;
},
loading: function() {
this.target = $('');
this.targetShow();
this.target.removeData("width").removeData("height");
return this;
},
displayDetect: function() {
//显示与否检测与触发
if (!this.flagDisplay) {
this.targetHide();
}
return this;
},
targetShow: function() {
o.cornerClear();
this.flagDisplay = true;
this.container().setWidth().position();
this.target.show();
if ($.isFunction(this.s.showCall)) {
this.s.showCall.call(this.trigger, this.target);
}
return this;
},
targetHide: function() {
this.flagDisplay = false;
this.targetClear();
this.cornerClear();
if ($.isFunction(this.s.hideCall)) {
this.s.hideCall.call(this.trigger);
}
this.target = null;
this.trigger = null;
this.s = {};
this.targetProtect = false;
return this;
},
targetClear: function() {
if (this.target) {
if (this.target.data("width")) {
this.target.removeData("width").removeData("height");
}
if (this.targetProtect) {
//保护孩子
this.target.children().hide().appendTo($("body"));
}
this.target.unbind().hide();
}
},
cornerClear: function() {
if (this.corner) {
//使用remove避免潜在的尖角颜色冲突问题
this.corner.remove();
}
},
target: null,
trigger: null,
s: {},
cacheData: {},
targetProtect: false
};
$.powerFloat = {};
$.powerFloat.hide = function() {
o.targetHide();
};
var defaults = {
width: "auto", //可选参数:inherit,数值(px)
offsets: {
x: 0,
y: 0
},
zIndex: 999,
eventType: "hover", //事件类型,其他可选参数有:click, focus
showDelay: 0, //鼠标hover显示延迟
hideDelay: 0, //鼠标移出隐藏延时
hoverHold: true,
hoverFollow: false, //true或是关键字x, y
targetMode: "common", //浮动层的类型,其他可选参数有:ajax, list, remind
target: null, //target对象获取来源,优先获取,如果为null,则从targetAttr中获取。
targetAttr: "rel", //target对象获取来源,当targetMode为list时无效
container: null, //转载target的容器,可以使用"plugin"关键字,则表示使用插件自带容器类型
reverseSharp: false, //是否反向小三角的显示,默认ajax, remind是显示三角的,其他如list和自定义形式是不显示的
position: "4-1", //trigger-target
edgeAdjust: true, //边缘位置自动调整
showCall: $.noop,
hideCall: $.noop
};
})(jQuery);