/*
* jQuery tui tuihotkey plugin 0.3
*
* Copyright (c) 2010 china
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*
* Create: 2010-10-21 11:33:15 yewf $
* Revision: $Id: tui.hotkey.js 2010-02-18 17:44:23 yewf $
*
* Notes:1、IE环境下alt键会聚焦菜单,因此尽量不要使用alt键,目前可选ctrl,shift,alt,但由于键盘布局,目前使用了alt键,在IE环境下需要按两次alt键;
* 2、html tag标签id必须区分大小写;
* 3、由于使用了document.click与keydown事件,因此存件事件冒泡问题;
* 4、多键请使用半角逗号分隔;
* 5、只能支持两个按键;
* 6、由于$("#obj").height()的值,同一个UL下的li都会有不一样的情况,
* 因此无法准确设置top值,解决方法是给每个key增加一个top属性,用过手动定义top值。默认使用keyStyle.top值。
* keyTop = $("#obj").offset().top + key.top;
* 7、最后一个按键必须定义event,否则会提示未定义event;
* 8、不能使用一个JS进行全局定义,必须分页面定义。原因如下:
* (1)跳转冲突,例如:一级菜单,公司管理,系统管理需要互相跳转,就需要定义跳转事件,
* 如果当前停在公司管理,而又执行了事件跳转,在显示二级菜单热键时,就会降低用户体验。
* (2)使用全局定义,如果定义有几百行,会导致每个页面下载的数据过大;
* (3)对于某个页面来说,全局定义有跟本页面无关的定义;
* Sample:
* $(function() {
* $.tuihotkey({
* "primaryId": 0,
* "keyStyle": {
* "top": 20,
* "align": "center"
* },
* "keys": [
* { "key": "a", "id": 1, "pid": 0, "objId": "menu0", "event": function() { goMyoffice(); } },
* { "key": "b,o", "id": 2, "pid": 0, "objId": "menu1", "event": function() { goOrder(); } },
* { "key": "c", "id": 3, "pid": 0, "objId": "menu2", "event": function() { goGoods(); } },
* { "key": "d", "id": 7, "pid": 0, "objId": "menu7" },
* { "key": "g", "id": 700, "pid": 7, "objId": "Company0" },
* { "key": "j", "id": 701, "pid": 7, "objId": "Company1" },
* { "key": "c", "id": 702, "pid": 7, "objId": "Company2" },
* { "key": "k", "id": 703, "pid": 7, "objId": "Company3" },
* { "key": "a", "id": 7001, "pid": 700, "objId": "liTest1", top: 70, "event": function() { org_Add(); } },
* { "key": "b", "id": 7002, "pid": 700, "objId": "liTest2", top: 10, "event": function() { testTT2(); } },
* { "key": "c", "id": 7003, "pid": 700, "objId": "liTest3", top: 10, "event": function() { testTT3(); } }
* ]
* });
* });
*
*
*/jQuery.tuihotkey = function(options) {
var defaults = {
"primaryKey": "alt",
"primaryId": 0,
"keyStyle": {
"top": 20,
"align": "center"
},
"focusId": null,
"keys": null
}; var options = jQuery.extend({}, defaults, options); var HOTKEY_PRESS = false; // 如果是hotkey跳转,则为true,否则为false。
var HOTKEY_WIDTH = 20;
var HOTKEY_HEIGHT = 20;
var KEY =
{
ALT: 18,
CTRL: 17,
SHIFT: 16,
ESC: 27,
C: 67,
V: 86
}; // 存储在Cookie中的按键,格式: { "key": "17", "id": 0, "pid": 0 } 或者 { "key": "65,66", "id": 1, "pid": 0}
var _objDIV = new Array(); // 存储显示层的ID号
var _objFirstKey = new Array(); //第一次按键
// 热键进行页面跳转时,热键必须保持状态
init(); jQuery(document).keydown(function(e) {
var event = window.event || e;
var pressKey = event.keyCode; if (KEY.ESC === pressKey) {
clearHotkey(true);
}
else if ((KEY.SHIFT === pressKey && options.primaryKey.toUpperCase() === "SHIFT")
|| (KEY.CTRL === pressKey && options.primaryKey.toUpperCase() === "CTRL")
|| (KEY.ALT === pressKey && options.primaryKey.toUpperCase() === "ALT")) {
// 只要使用了快捷键,就将当前焦点从当前控件移开(比如当前是textbox时,保证输入的热键不会在textbox中出现)
//alert("您正在使用快捷键提示功能,请参照提示使用");
if ($.browser.msie)
jQuery(document.body).focus();
else {
// 其它浏览器的情况下,无法使用document.body.focus()
// 先用尝试使用配置的id号,然后再使用div,再尝试使用table的focus()
var d;
if (options.focusId != null) {
d = jQuery("#" + options.focusId);
}
else {
d = $("div:first");
if (d.length == 0) {
d = jQuery("table:frist");
}
}
d.attr("tabindex", "9999").css("outline", "none");
d.focus();
} firstKeyPress(pressKey);
}
else {
processKeyPress(pressKey); ;
}
})
.keyup(function(e) {
// 这里对firefox有效,对ie无效。
_stopBubble(e);
})
.click(function() {
clearHotkey(true);
}); // 页面离开时
jQuery(window).unload(function() {
// 如果不是用热键离开的页面,则清除cookie。
if (HOTKEY_PRESS === false) {
deleteCookie();
}
}); // 页面载入时,承接上一页的按键提示
function init() {
// 最后一次按钮
processKeyPress();
}; // 第一次按键操作,功能键
function firstKeyPress(keycode) {
clearHotkey(true); _objFirstKey = new Array(); // 处理keys
var objCurrent = keysByPID(options.primaryId);
if (objCurrent.length === 0) return; jQuery.each(objCurrent, function(i, n) {
displayHotkey(n);
}); // 做了热键提示,则保存alt键
if (objCurrent.length > 0) {
// 保存Cookie
var t = "{ \"key\": \"" + keycode + "\", \"id\": 0, \"pid\": 0 }";
setCookie(t);
}
}; // 处理其它按键操作,字母键
function processKeyPress(keycode) {
// 如果是功能键,则不处理
if (keycode == KEY.CTRL || keycode == KEY.ALT || keycode == KEY.SHIFT) {
return;
} // 最后一次按键
var lastKey = getCookieObject();
if (lastKey === null) {
return;
} var lastKeyCode, lastKeyId,
hotkeyPageRedirect = true; //该参数在使用热键跳转时,不执行热键事件。 if (typeof keycode === "undefined") {
// 页面跳转后的初始化热键显示
lastKeyCode = lastKey.key;
lastKeyId = lastKey.pid; // 这里使用pid,才能找到上一次的按钮定义
hotkeyPageRedirect = false;
}
else {
// 当前页
lastKeyCode = keycode;
lastKeyId = lastKey.id; // 没有跳转,使用上次按键的id查找下一级按键定义 // 第一次按错误的,第二次按正确的。必须再次判断
var fk = findKey(String.fromCharCode(lastKeyCode), lastKeyId);
if (fk === "none") {
if (_objFirstKey.length > 0) {
lastKeyCode = _objFirstKey.pop() + "," + lastKeyCode;
}
}
} // 将逗号分隔的按钮进行字符转换,如68,67转换为D,C
var keyary = lastKeyCode.toString().split(",");
var keych = ""; for (var j = 0; j < keyary.length; j++) {
if (keych === "") {
keych = String.fromCharCode(keyary[j]);
}
else {
keych = keych + "," + String.fromCharCode(keyary[j]);
}
} // 查找当前按键是否定义
var curkey = findKey(keych, lastKeyId); if (curkey === "none") {
// 支持两个按钮,第一个按键找不到,则有可能是两个按键定义。
_objFirstKey.push(keycode);
return;
}
else if (curkey === "repeat") {
alert("Error:\nCan not repeat definition of hotkeys at the same level.");
return;
} // 如果当前key的父对象为空或隐藏,执行到对应的热键时,不执行事件。
var objTarget = jQuery("#" + curkey.objId);
if (objTarget.length === 0 || objTarget.is(":hidden")) {
return;
} var t = "{ \"key\": \"" + lastKeyCode + "\", \"id\": " + curkey.id + ", \"pid\": " + curkey.pid + " }"; // 返回符合pid条件的数组
var objCurrent = keysByPID(curkey.id);
if (objCurrent.length === 0) {
// 如果没有子节点,则必须有事件执行,否则按键就没有意义
if (typeof curkey.event === "undefined" || curkey.event === null) {
alert("Error:\nLast key must be define [event] argument,please check [\"key\": \"" + curkey.key + "\"],[ \"id\": " + curkey.id + "]。");
return;
} // 保存最后一次按键
setCookie(t); if (hotkeyPageRedirect) {
// 清除提示层,并执行事件
clearHotkey(false); HOTKEY_PRESS = true;
_objFirstKey = new Array(); curkey.event();
}
return;
} // 移除上一次的按键提示层
clearHotkey(false);
// 保存最后一次按键
setCookie(t);
// 执行事件
curkey.event && curkey.event(); // 显示按键
jQuery.each(objCurrent, function(i, n) {
displayHotkey(n);
}); // 清除储存多键的数组。
_objFirstKey = new Array();
};
// 显示热键提示层(div)
function displayHotkey(term) {
var keyName = term.key, objId = term.objId; var objTag = jQuery("#" + objId);
if (objTag.length === 0 || objTag.is(":hidden")) return; // throw new Error("Final Error:Html Object [" + objId + "] not exist, the application is not work."); var t = objTag.offset().top;
var l = objTag.offset().left;
var w = objTag.width();
var padl = jQuery.browser.mozilla ? "1" : "0"; if (term.top) {
t = t + term.top;
}
else {
t = t + options.keyStyle.top;
} // 根据个数计算宽度
var cc = keyName.split(",").length;
//var kwidth = cc === 1 ? HOTKEY_WIDTH : cc * HOTKEY_WIDTH * 0.6;//动态宽度
var kwidth = HOTKEY_WIDTH; if (options.keyStyle.align === "center") {
l = l + w / 2 - kwidth / 2;
}
var tagid = objId + "_hotkey_" + keyName.substr(0, 1);
var tagdiv = jQuery("#" + tagid);
if (tagdiv.length === 0) {
jQuery("<div/>")
.attr("id", tagid)
.text(keyName.replace(/\,/g, "").toUpperCase())
.css({
"top": t + "px",
"left": l + "px",
"position": "absolute",
"width": kwidth + "px",
"height": HOTKEY_HEIGHT + "px",
"text-align": "center",
"font-weight": "bold",
"padding-left": padl + "px",
"z-index": 999999
})
.addClass("tui-hotkey-bg")
.appendTo(document.body); // 将当前显示的div存储,以便移除操作。
_objDIV.push(tagid);
}
}; // 移除热键提示层,并且传入是否移除Cookie的bool值。
function clearHotkey(isDeleteCookie) {
jQuery.each(_objDIV, function(i, n) {
jQuery("#" + n).remove();
}); if (isDeleteCookie) {
deleteCookie();
} // 重置显示层与当前按键key数组。
_objDIV = new Array();
}; // 返回符合pid条件的key
function keysByPID(pid) {
var temp = new Array();
jQuery.each(options.keys, function(i, n) {
if (n.pid === pid) {
temp.push(n);
}
}); return temp;
}; // 根据key与pid查找key对象,只返回第一个符合条件的,如果是两个就说明同层进行了重复定义。
function findKey(key, pid) {
var temp, c = 0;
jQuery.each(options.keys, function(i, n) {
if (n.pid === pid && n.key.toUpperCase() === key.toUpperCase()) {
temp = n;
c++;
}
});
if (c === 0) return "none";
if (c > 1) return "repeat";
return temp;
}; // Cookie操作,调用jquery.cookie.js
function setCookie(value) {
_cookie("tuihotkey", value, { path: '/' });
}; // 返回保存的按键数组
function getCookieObject() {
if (_cookie("tuihotkey") != null) {
if (_cookie("tuihotkey") === "") {
return null;
}
return eval("(" + _cookie("tuihotkey") + ")");
}
return null;
}; // 删除cookie
function deleteCookie() {
_cookie("tuihotkey", null, { path: '/' });
}; // 从jquery.cookie.js中复制过来的cookie操作
function _cookie(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options = jQuery.extend({}, options); // clone object since it's unexpected behavior if the expired property were changed
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// NOTE Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
}; //阻止浏览器的默认行为
function _stopDefault(e) {
//阻止默认浏览器动作(W3C)
if (e && e.preventDefault)
e.preventDefault();
//IE中阻止函数器默认动作的方式
else
window.event.returnValue = false;
return false;
}; function _stopBubble(e) {
//如果提供了事件对象,则这是一个非IE浏览器
if (e && e.stopPropagation)
//因此它支持W3C的stopPropagation()方法
e.stopPropagation();
else
//否则,我们需要使用IE的方式来取消事件冒泡
window.event.cancelBubble = true;
};
};
需要交流请到如下博客地址,谢谢。
http://blog.csdn.net/SaRoot/archive/2011/03/03/6220412.aspx