Created
September 11, 2012 09:57
-
-
Save losingle/3697340 to your computer and use it in GitHub Desktop.
javascript mentions(模拟新浪微博@功能)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{"uname":"中文"},{"uname":"hello"}] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html lang="en"> | |
<head> | |
<title>JQuery Mentions</title> | |
<meta charset="utf-8"/> | |
<meta name="viewport" content="width=device-width,maximum-scale=1.0" /> | |
<meta name="apple-mobile-web-app-capable" content="yes" /> | |
<meta name="apple-mobile-web-app-status-bar-style" content="black" /> | |
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.3.min.js"></script> | |
<script type="text/javascript" src="mentions.js"></script> | |
<style> | |
.recipients-tips { | |
background: none repeat scroll 0 0 #F8F8F8; | |
border: 1px solid #666666; | |
border-radius: 3px 3px 3px 3px; | |
box-shadow: 0 0 3px rgba(0, 0, 0, 0.3); | |
display: none; | |
padding: 0; | |
position: absolute; | |
z-index: 2147483647; | |
} | |
#autoTipsUserList { | |
padding: 0; | |
} | |
ul, ol { | |
list-style: none outside none; | |
} | |
.autoSelected { | |
background: none repeat scroll 0 0 #E8E8E8; | |
font-family: Tahoma,Arial; | |
} | |
</style> | |
<script language="javascript"> | |
$(function(){ | |
userAutoTips({id:'_widget_content', url:'data.json'}); | |
}); | |
</script> | |
</head> | |
<body> | |
<textarea id="_widget_content" name="content" style="font-family: Tahoma; overflow: hidden; border: 1px solid #ccc; background-color:#F8F8F8; word-wrap: break-word; font-size: 12px; line-height: 18px; height: 65px; width:380px;"></textarea> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 输入框 @用户 列表 | |
(function () { | |
var config = { | |
boxID: "autoTalkBox", | |
valuepWrap: 'autoTalkText', | |
wrap: 'recipientsTips', | |
listWrap: "autoTipsUserList", | |
position: 'autoUserTipsPosition', | |
positionHTML: '<span id="autoUserTipsPosition"> 123</span>', | |
className: 'autoSelected' | |
}; | |
//var html = '<div id="autoTalkBox" style="text-align:left;z-index:-2000;top:$top$px;left:$left$px;width:$width$px;height:$height$px;z-index:1;position:absolute;scroll-top:$SCTOP$px;overflow:hidden;overflow-y:auto;visibility:hidden;word-break:break-all;word-wrap:break-word;"><span id="autoTalkText" style="font-size:14px;margin:0;"></span></div><div id="recipientsTips" class="recipients-tips"><div style="font-size:12px;text-align:left;font-weight: bold;padding:2px;">格式:@+W3帐号、姓名</div><ul id="autoTipsUserList"></ul></div>'; | |
//var listHTML = '<li style="text-align:left"><a title="$ACCOUNT$" rel="$ID$" >$NAME$(@$SACCOUNT$)</a></li>'; | |
var html = '<div id="autoTalkBox" style="text-align:left;z-index:-2000;top:$top$px;left:$left$px;width:$width$px;height:$height$px;z-index:1;position:absolute;scroll-top:$SCTOP$px;overflow:hidden;overflow-y:auto;visibility:hidden;word-break:break-all;word-wrap:break-word;"><span id="autoTalkText" style="font-size:14px;margin:0;"></span></div><div id="recipientsTips" class="recipients-tips"><h4>格式:@用户昵称</h4><ul id="autoTipsUserList"></ul></div>'; | |
var listHTML = '<li style="text-align:left"><a rel="$ID$" >@$SACCOUNT$</a></li>'; | |
/* | |
* D 基本DOM操作 | |
* $(ID) | |
* DC(tn) TagName | |
* EA(a,b,c,e) | |
* ER(a,b,c) | |
* BS() | |
* FF | |
*/ | |
var D = { | |
$: function (ID) { | |
return document.getElementById(ID) | |
}, | |
DC: function (tn) { | |
return document.createElement(tn); | |
}, | |
EA: function (a, b, c, e) { | |
if (a.addEventListener) { | |
if (b == "mousewheel") b = "DOMMouseScroll"; | |
a.addEventListener(b, c, e); | |
return true | |
} else return a.attachEvent ? a.attachEvent("on" + b, c) : false | |
}, | |
ER: function (a, b, c) { | |
if (a.removeEventListener) { | |
a.removeEventListener(b, c, false); | |
return true | |
} else return a.detachEvent ? a.detachEvent("on" + b, c) : false | |
}, | |
BS: function () { | |
var db = document.body, | |
dd = document.documentElement, | |
top = db.scrollTop + dd.scrollTop; | |
left = db.scrollLeft + dd.scrollLeft; | |
return { | |
'top': top, | |
'left': left | |
}; | |
}, | |
FF: (function () { | |
var ua = navigator.userAgent.toLowerCase(); | |
return /firefox\/([\d\.]+)/.test(ua); | |
})() | |
}; | |
/* | |
* TT textarea 操作函数 | |
* info(t) 基本信息 | |
* getCursorPosition(t) 光标位置 | |
* setCursorPosition(t, p) 设置光标位置 | |
* add(t,txt) 添加内容到光标处 | |
*/ | |
var TT = { | |
info: function (t) { | |
var o = t.getBoundingClientRect(); | |
var w = t.offsetWidth; | |
var h = t.offsetHeight; | |
var s = t.style; | |
return { | |
top: o.top, | |
left: o.left, | |
width: w, | |
height: h, | |
style: s | |
}; | |
}, | |
getCursorPosition: function (t) { | |
if (document.selection) { | |
t.focus(); | |
var ds = document.selection; | |
var range = null; | |
range = ds.createRange(); | |
var stored_range = range.duplicate(); | |
stored_range.moveToElementText(t); | |
stored_range.setEndPoint("EndToEnd", range); | |
t.selectionStart = stored_range.text.length - range.text.length; | |
t.selectionEnd = t.selectionStart + range.text.length; | |
return t.selectionStart; | |
} else return t.selectionStart | |
}, | |
setCursorPosition: function (t, p) { | |
var n = p == 'end' ? t.value.length : p; | |
if (document.selection) { | |
var range = t.createTextRange(); | |
range.moveEnd('character', -t.value.length); | |
range.moveEnd('character', n); | |
range.moveStart('character', n); | |
range.select(); | |
} else { | |
t.setSelectionRange(n, n); | |
t.focus(); | |
} | |
}, | |
add: function (t, txt) { | |
var val = t.value; | |
var wrap = wrap || ''; | |
if (document.selection) { | |
document.selection.createRange().text = txt; | |
} else { | |
var cp = t.selectionStart; | |
var ubbLength = t.value.length; | |
t.value = t.value.slice(0, t.selectionStart) + txt + t.value.slice(t.selectionStart, ubbLength); | |
this.setCursorPosition(t, cp + txt.length); | |
}; | |
}, | |
del: function (t, n) { | |
var p = this.getCursorPosition(t); | |
var s = t.scrollTop; | |
t.value = t.value.slice(0, p - n) + t.value.slice(p); | |
this.setCursorPosition(t, p - n); | |
D.FF && setTimeout(function () { | |
t.scrollTop = s | |
}, 10); | |
} | |
} | |
/* | |
* DS 数据查找 | |
* inquiry(data, str, num) 数据, 关键词, 个数 | |
* | |
*/ | |
var DS = { | |
inquiry: function (data, str, num) { | |
//if(str == '') return friendsData.slice(0, num); | |
var reg = new RegExp(str, 'i'); | |
var i = 0; | |
//var dataUserName = {}; | |
var sd = []; | |
while (sd.length < num && i < data.length) { | |
if (reg.test(data[i]['user'])) { | |
sd.push(data[i]); | |
//dataUserName[data[i]['user']] = true; | |
} | |
i++; | |
} | |
return sd; | |
} | |
} | |
/* | |
* selectList | |
* _this | |
* index | |
* list | |
* selectIndex(code) code : e.keyCode | |
* setSelected(ind) ind:Number | |
*/ | |
var selectList = { | |
_this: null, | |
index: -1, | |
list: null, | |
selectIndex: function (code) { | |
if (D.$(config.wrap).style.display == 'none') return true; | |
var i = selectList.index; | |
switch (code) { | |
case 40: | |
i = i + 1; | |
break | |
case 38: | |
i = i - 1; | |
break | |
case 13: | |
return selectList._this.enter(); | |
break | |
case 32: | |
return selectList._this.enter(); | |
break | |
} | |
i = i >= selectList.list.length ? 0 : i < 0 ? selectList.list.length - 1 : i; | |
return selectList.setSelected(i); | |
}, | |
setSelected: function (ind) { | |
if (selectList.index >= 0) selectList.list[selectList.index].className = ''; | |
if (selectList.list[ind]) selectList.list[ind].className = config.className; | |
selectList.index = ind; | |
return false; | |
} | |
} | |
var AutoTips = function (A) { | |
var elem = A.id ? D.$(A.id) : A.elem; | |
var checkLength = 10; | |
var _this = {}; | |
var key = ''; | |
_this.start = function () { | |
if (!D.$(config.boxID)) { | |
var h = html.slice(); | |
var info = TT.info(elem); | |
var div = D.DC('DIV'); | |
var bs = D.BS(); | |
h = h.replace('$top$', (info.top + bs.top)). | |
replace('$left$', (info.left + bs.left)). | |
replace('$width$', info.width). | |
replace('$height$', info.height). | |
replace('$SCTOP$', '0'); | |
div.innerHTML = h; | |
var last = document.body.lastChild; | |
document.body.insertBefore(div, last); | |
//document.body.appendChild(div); // IE6 下报错的问题 | |
} else { | |
_this.updatePosstion(); | |
} | |
} | |
_this.keyupFn = function (e) { | |
var e = e || window.event; | |
var code = e.keyCode; | |
if (code == 38 || code == 40 || code == 13) { | |
if (code == 13 && D.$(config.wrap).style.display != 'none') { | |
//_this.enter(); | |
} | |
return false; | |
} | |
var cp = TT.getCursorPosition(elem); | |
if (!cp) return _this.hide(); | |
var valuep = elem.value.slice(0, cp); | |
var val = valuep.slice(-checkLength); | |
var chars = val.match(/(\w+)?@(\S+)$|@$/); | |
if (chars == null) return _this.hide(); | |
var char = chars[2] ? chars[2] : ''; | |
D.$(config.valuepWrap).innerHTML = valuep.slice(0, valuep.length - char.length).replace(/\n/g, '<br/>'). | |
replace(/\s/g, ' ') + config.positionHTML; | |
_this.showList(char); | |
} | |
_this.showList = function (char) { | |
key = char; | |
if (key.length < 1) { | |
return; | |
} | |
$.get(A.url, { | |
key: key | |
}, function (txt) { | |
if (txt == '') { | |
_this.hide(); | |
return; | |
} | |
var data = eval(txt); | |
//var data = DS.inquiry(txt, char, 5); | |
var html = listHTML.slice(); | |
var h = ''; | |
var len = data.length; | |
if (len == 0) { | |
_this.hide(); | |
return; | |
} | |
var reg = new RegExp(char); | |
var em = '<em>' + char + '</em>'; | |
for (var i = 0; i < len; i++) { | |
var hm = data[i]['uname'].replace(reg, em); | |
h += html.replace('$SACCOUNT$', hm).replace('$ID$', data[i]['uname']); | |
/*h += html.replace(/\$ACCOUNT\$|\$NAME\$/g,data[i]['fullname']). | |
replace('$SACCOUNT$',hm).replace('$ID$',data[i]['uname']);*/ | |
} | |
// alert(txt); | |
_this.updatePosstion(); | |
var p = D.$(config.position).getBoundingClientRect(); | |
var bs = D.BS(); | |
var d = D.$(config.wrap).style; | |
d.top = p.top + 20 + bs.top + 'px'; | |
d.left = p.left - 5 + 'px'; | |
D.$(config.listWrap).innerHTML = h; | |
_this.show(); | |
}); | |
} | |
_this.KeyDown = function (e) { | |
var e = e || window.event; | |
var code = e.keyCode; | |
if (code == 38 || code == 40 || code == 13 || code == 32) { | |
return selectList.selectIndex(code); | |
} | |
return true; | |
} | |
_this.updatePosstion = function () { | |
var p = TT.info(elem); | |
var bs = D.BS(); | |
var d = D.$(config.boxID).style; | |
d.top = p.top + bs.top + 'px'; | |
d.left = p.left + bs.left + 'px'; | |
d.width = p.width + 'px'; | |
d.height = p.height + 'px'; | |
D.$(config.boxID).scrollTop = elem.scrollTop; | |
} | |
_this.show = function () { | |
selectList.list = D.$(config.listWrap).getElementsByTagName('li'); | |
selectList.index = -1; | |
selectList._this = _this; | |
_this.cursorSelect(selectList.list); | |
elem.onkeydown = _this.KeyDown; | |
selectList.setSelected(0); | |
//D.$(config.wrap).style.display = 'block'; | |
$("#" + config.wrap).fadeIn("fast"); | |
} | |
_this.cursorSelect = function (list) { | |
for (var i = 0; i < list.length; i++) { | |
list[i].onmouseover = (function (i) { | |
return function () { | |
selectList.setSelected(i) | |
}; | |
})(i); | |
list[i].onclick = _this.enter; | |
//D.EA(list[i], 'click', function(){alert(1)}, false); | |
} | |
} | |
_this.hide = function () { | |
selectList.list = null; | |
selectList.index = -1; | |
selectList._this = null; | |
D.ER(elem, 'keydown', _this.KeyDown); | |
//D.$(config.wrap).style.display = 'none'; | |
$("#" + config.wrap).fadeOut("fast"); | |
} | |
_this.bind = function () { | |
elem.onkeyup = _this.keyupFn; | |
elem.onclick = _this.keyupFn; | |
if (navigator.userAgent.indexOf("MSIE") == -1) { | |
elem.oninput = _this.keyupFn; | |
} | |
$('body').live('click', function () { | |
setTimeout(_this.hide, 100) | |
}); | |
//elem.onblur = function(){setTimeout(_this.hide, 100)} | |
} | |
_this.enter = function () { | |
TT.del(elem, key.length, key); | |
TT.add(elem, selectList.list[selectList.index].getElementsByTagName('A')[0].rel + ' '); | |
_this.hide(); | |
return false; | |
} | |
return _this; | |
} | |
window.userAutoTips = function (args) { | |
var a = AutoTips(args); | |
a.start(); | |
a.bind(); | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment