1
spance 2014-08-07 20:19:06 +08:00
这个通常都是服务端来做的。
用类似这样的正则来提取 @(\w+)\b 提取到以后,拼到sql where里面检查是不是有这个人,查询输出的是存在的用户; 然后对这些用户的消息表里面写新消息,具体写什么就你自己定了,或者发到客户端。 这是一个精简的逻辑结构,你可以补充你的业务上去。 |
2
zhiyongyici OP @spance 我不是很懂的,你可以帮忙实现吗?
|
3
spance 2014-08-07 20:26:19 +08:00
@zhiyongyici 不好意思,我不搞php的东西。
|
4
zts1993 2014-08-07 20:38:55 +08:00
text上js监听输入。检测到@ 之后ajax 加载用户,每输入一个字或者字母都查询一次,然后显示出来。。。
|
5
zhiyongyici OP @zts1993 能帮忙实现一下吗?
|
6
zhiyongyici OP |
7
qq5775548 2014-08-07 21:07:26 +08:00 1
这个说起来简单 实际操作起来 要注意的问题挺多的:
方法同上面说的基本一样,就像微博@TA, 弹出输入框。 1: 控制textarea本身网上大把,记得要兼容ie 所以找个好点得小型库吧,insert,insertAfterStart, insertAfterSelect, del(删除x-y位置的字), getSelectText, getpos, select,selectAll,selectString,getCursorOffset 一些常用的函数还是要写得 juquery 貌似没有这些功能,至少我找不到。 2: 确定光标位置(getCursorOffset函数),因为具体pageX/Y 无法通过直接形式获得,常用方法建一个大小完全跟textarea一样的div 里面 的html跟 textarea 一样,记着要br来实现换行,然后在结尾添加一个自定义 span或其他标签 然后获取这个标签的位置就可以获取其相对于页面的位置鸟 3: 获取@ 的对象,这个形式是 "@mygirl" 当后面还有一大段的时候 就如: "@mygril 草泥马" 你应该确定我@的是mygril 而不是 mygril 草泥马。此外还需确定是当前光标对应前面的@ 而非后面或开始的@。这里还处理到点会之前的@, 修改@的人,要将@后面的人名字删除然后替换成新的人。 4还有几点应该都是小问题,努力尝试下做吧,主要注意就这个点 |
8
mahone3297 2014-08-07 21:13:45 +08:00
好奇这个功能多少钱。。。
不过这个要看效果做成如何。如果只是@还好一点,如果要输入人名的时候,自动提示,那又要麻烦一点。 |
9
Sunyanzi 2014-08-07 21:18:59 +08:00 1
提前占位吧 ... 如果到这周六还没人接的话这活我做了 ...
V2 做 php 的人不少 ... 有其他人想接的话只管接 ... 我只是提供个兜底而已 ... |
10
zhiyongyici OP @qq5775548 谢谢,虽然我不是很懂,但是可以给后面的人提供帮助。
|
11
skyshy 2014-08-07 21:22:40 +08:00 1
参考 At.js: https://github.com/ichord/At.js
|
12
zhiyongyici OP @mahone3297 不用自动提示,和 V2 一样,点击回复按钮,输入框出现 @user 即可。另外,我现在的问题可能更加简单,如果不用可视化编辑 ,点击回复按钮会出现 <a href="">@user</a> 的代码,如果使用了可视化编辑器就没有反应。
|
13
zhiyongyici OP @skyshy 这个我看了,不是很喜欢这种方式。
|
14
greatdk 2014-08-07 21:33:18 +08:00
我以为我屏幕右下角钻了一直虫子、、、、
|
15
zhiyongyici OP @greatdk 哈哈,都这么认为,还有人专门拿抹布去擦呢~~
|
16
qq5775548 2014-08-07 21:35:21 +08:00
我贴份2年前的代码吧 这里没有md 格式化样子不太好 可能要分开来看 回复两段代码吧,认为我倒米的可以吐槽。但烂代码没什么意义。希望对你有用,一直都没怎么理,找找代码,还是在一个旧项目中找到:一个jquery插件包括 emot @ 的实现 可以扩展更多的其他功能。
|
17
qq5775548 2014-08-07 21:35:38 +08:00
;(function() {
var ShareBox = function() {}; ShareBox.TextEdit = function() {}; ShareBox.Emotion = function() {}; ShareBox.SuggestBox = function() {}; ShareBox.SuggestBox = function() {}; ShareBox.SuggestBox.Box = function() {}; var KEY_CODE = { 32: [' '], 48: ['0', ')'], 49: ['1', '!'], 50: ['2', '@'], 51: ['3', '#'], 52: ['4', '$'], 53: ['5', '%'], 54: ['6', '^'], 55: ['7', '&'], 56: ['8', '*'], 57: ['9', '('], 65: ['a', 'A'], 66: ['b', 'B'], 67: ['c', 'C'], 68: ['d', 'D'], 69: ['e', 'E'], 70: ['f', 'F'], 71: ['g', 'G'], 72: ['h', 'H'], 73: ['i', 'I'], 74: ['j', 'J'], 75: ['k', 'K'], 76: ['l', 'L'], 77: ['m', 'M'], 78: ['n', 'N'], 79: ['o', 'O'], 80: ['p', 'P'], 81: ['q', 'Q'], 82: ['r', 'R'], 83: ['s', 'S'], 84: ['t', 'T'], 85: ['u', 'U'], 86: ['v', 'V'], 87: ['w', 'W'], 88: ['x', 'X'], 89: ['y', 'Y'], 90: ['z', 'Z'], 96: ['0'], 97: ['1'], 98: ['2'], 99: ['3'], 100: ['4'], 101: ['5'], 102: ['6'], 103: ['7'], 104: ['8'], 105: ['9'], 106: ['*'], 107: ['+'], 109: ['-'], 110: ['.'], 111: ['/'], 186: [';', ': '], 187: ['=', '+'], 188: [',', '<'], 189: ['-', '_'], 190: ['.', '>'], 191: ['/', '?'], 192: ['`', '~'], 219: ['[', '{'], 220: ['\'', '"'], 221: [']', '}'], 222: ['', '"'] }; var OPTIONS = { ShareBox: { label: "<li data-link='{datas}'><a>{view}</a></li>" }, Emotion: { tagPrefix: '[', tagSuffix: ']', perPage: 60, autoHide: true, autoReset: true, defaultNav: '默认', path: ('object' === typeof $.EmotionOptions ? $.EmotionOptions.path : false) || {'默认':{}}, emot: ('object' === typeof $.EmotionOptions ? $.EmotionOptions.emot : false) || {'默认':{}} } }; var trace = function(msg, type) { if ('object' === typeof console) { type = type || 'log'; console[type](msg); } else if ('object' === typeof opera) { opera.postError(msg); } else if ('object' === typeof java && 'object' === typeof java.lang) { java.lang.System.out.println(msg); } }; var toJSON = function(obj) { switch (typeof(obj)) { case 'object': var ret = []; if (obj instanceof Array) { for (var i = 0, len = obj.length; i < len; i++) { ret.push(toJSON(obj[i])); } return '[' + ret.join(',') + ']'; } else if (obj instanceof RegExp) { return obj.toString(); } else { for (var a in obj) { ret.push("\"" + a + "\"" + ':' + toJSON(obj[a])); } return '{' + ret.join(',') + '}'; } case 'function': return 'function() {}'; case 'number': return obj.toString(); case 'string': return "\"" + obj.replace(/(\\|\")/g, "\\$1").replace(/\n|\r|\t/g, function(a) { return("\n" == a) ? "\\n" : ("\r" == a) ? "\\r" : ("\t" == a) ? "\\t" : ""; }) + "\""; case 'boolean': return obj.toString(); default: return obj.toString(); } }; var getIndex = function(obj, index) { var k = 0; for (var i in obj) { if (index === k ++) { return i; } } }; |
18
qq5775548 2014-08-07 21:36:11 +08:00
ShareBox.TextEdit.prototype = {
_constructor: function(field) { this.field = $(field).get(0); return this; }, getLenInCh: function() { var str = this.field.value; var ch = str.match(/[\u4E00-\uFA29]/ig); var en = str.match(/[^\u4E00-\uFA29]/ig); var cl = ch ? ch.length * 2 : 0; var el = en ? en.length : 0; return Math.ceil((cl + el) / 2); }, insert: function(value, type) { var field = this.getField(); value = value.toString(); if (document.selection) { //IE field.focus(); var seltext = this.getSelectText(field), startPos = 'string' === typeof seltext ? field.value.length - seltext.length : field.value.length, sel = document.selection.createRange(); sel.text = value; sel.select(); if (type) { var rng = field.createTextRange(); if (type == 'select') { rng.moveStart('character', startPos); } else if (type == 'start') { rng.moveEnd('character', - value.length); rng.moveStart('character', startPos); } rng.select(); } } else if (field.selectionStart || field.selectionStart == '0') { //^IE var startPos = field.selectionStart, endPos = field.selectionEnd, restoreTop = field.scrollTop; field.value = field.value.substring(0, startPos) + value + field.value.substring(endPos, field.value.length); if (restoreTop > 0) field.scrollTop = restoreTop; field.focus(); if (type == 'select') { field.selectionStart = startPos; field.selectionEnd = startPos + value.length; } else if (type == 'start') { field.selectionStart = field.selectionEnd = startPos; } else { field.selectionStart = field.selectionEnd = startPos + value.length; } } else{ //others field.value += value; field.focus(); } return this; }, insertAfterStart: function(value) { this.insert(value, 'start'); return this; }, insertAfterSelect: function(value) { this.insert(value, 'select'); return this; }, del: function(del_num) { var field = this.getField(); var pos = this.getPos(field); if (pos.startPos == 0) { //如果位置为0, 则会 自动在加上匹配内容; return false; } var ft = field.scrollTop; var val = field.value; field.value = del_num > 0 ? val.slice(0, pos - del_num) + val.slice(pos): val.slice(0, pos) + val.slice(pos - num); setPos(field, pos - (del_num < 0 ? 0 : del_num)); setTimeout(function() { if (field.scrollTop != ft) field.scrollTop = ft; }, 10); return this; }, getSelectText: function() { var field = this.getField(); field.focus(); if (typeof document.selection != 'undefined') { return document.selection.createRange().text; } if (field.selectionStart || field.selectionStart == '0') { return field.value.substr(field.selectionStart, field.selectionEnd - field.selectionStart); } }, getPos: function() { var field = this.getField(); if (document.selection) { field.focus(); var rng = document.selection.createRange(); var tx_rng = document.body.createTextRange(); tx_rng.moveToElementText(field); for (var startPos = 0; tx_rng.compareEndPoints('StartToStart' , rng) < 0; startPos ++) { tx_rng.moveStart('character', 1); } for (var endPos = 0; tx_rng.compareEndPoints('StartToEnd' , rng) < 0; endPos ++) { tx_rng.moveStart('character', 1); } return { startPos: startPos, endPos: endPos }; } else if (field.selectionStart || field.selectionStart == '0') { return { startPos: field.selectionStart, endPos: field.selectionEnd }; } }, select: function(start_pos, end_pos) { var field = this.getField(); if (start_pos == undefined || end_pos == undefined || start_pos < 0 || end_pos > field.value.length) { return false; } if (document.selection) { //IE var rng = field.createTextRange(); rng.moveEnd('character', - field.value.length); rng.moveEnd('character', end_pos); rng.moveStart('character', start_pos); rng.select(); } else { //^IE; field.setSelectionRange(start_pos, end_pos); field.focus(); } return this; }, setPos: function(pos) { this.select(pos , pos); return this; }, selectAll:function() { var field = this.getField(); this.select(0, field.value.length); return this; }, selectString: function(str) { var field = this.getField(); var index = field.value.indexOf(str); return index != -1 ? this.select(field, index, index + str.length) : false; }, getCursorOffset: function(cursor_pos) { var field = this.getField(); if (document.selection) { var range = document.selection.createRange(); var $win = $(window); return { left: range.boundingLeft + $win.scrollLeft(), top: range.boundingTop + $win.scrollTop() + range.boundingHeight }; } var $field = $(field), $editor = $field.shareBox(), w = $field.width(), h = $field.height(), pos = $field.offset(), x = pos.left, y = pos.top, end_pos = $editor.getPos().endPos, str = $field.val(), start_str = str.substr(0, end_pos).replace(/[(^*\n*)|(^*\r*)]/g, '<br />'), end_str = str.substr(end_pos, str.length).replace(/[(^*\n*)|(^*\r*)]/g, '<br />'), fontSize = $field.css('fontSize'), padding = $field.css('padding'), lineHeight = $field.css('lineHeight'), overflow = $field.css('overflow'), scrollTop = $field.scrollTop(); if (! this.fake) this.fake = $('<div>').appendTo('body'); this.fake.html(start_str + '<span>x</span>' + end_str) .css({ padding: padding, width: w, height: h, opacity: 0, overflow: overflow, position: 'absolute', left: x, top: y, zIndex: -9999, lineHeight: lineHeight, wordWrap: 'break-word', fontSize: fontSize }) .scrollTop(scrollTop); var marker = this.fake.children('span'), height = marker.outerHeight(), ofs = marker.offset(), left = ofs.left, top = ofs.top, st = marker.scrollTop(); return { left: left, top: top + height - st }; }, getField: function() { return this.field; } }; |
19
qq5775548 2014-08-07 21:36:51 +08:00
ShareBox.Emotion.prototype = {
_constructor: function(options) { this.nav_list = []; this.page_list = []; this.curNav = ''; this.emot_list = {}; this.active = false; this.config = $.extend({}, OPTIONS.Emotion, options); var $emot = $('<div class="shareEdit-emot">').bind('click', function(e) { e.stopPropagation(); }); this.oEmot = $emot.get(0); this.oNav = $('<ul class="emot-nav">').appendTo(this.oEmot).get(0); this.oList = $('<ul class="emot-list">').appendTo(this.oEmot).get(0); this.oPage = $('<ul class="emot-page">').appendTo(this.oEmot).get(0); this.oEmot = $emot = $('<div class="shareEdit-emot-pure">') .append(this.oEmot) .appendTo('body') .bind('click', function(e) { e.stopPropagation(); }); //注册导航栏 var self = this; for (var i in this.config.emot) { var $emot = $('<li class="emotNav" data-nav="' + i + '"><a title="' + i + '">' + i + '</a></li>') .appendTo(this.oNav) .bind('click', function(e) { e.stopPropagation(); self.nav($(this).attr('data-nav')); }); this.nav_list.push($emot[0]); } //注册分页 for (var i = 1; i < 10; i ++) { var $page = $('<li class="emotPage" data-page="' + i + '"><a title="' + i + '">' + i + '</a></li>') .appendTo(this.oPage) .bind('click', function(e) { e.stopPropagation(); self.page($(this).attr('data-page')); }) this.page_list.push($page[0]); } if (this.config.autoHide) { $(document).bind('click', function() { self.hide(); }); } return this; }, emot: function(nav) { if (! this.config.emot[nav]) return; var self = this, num = page = 0; this.emot_list[nav] = []; for (var i in this.config.emot[nav]) { if (0 === num % this.config.perPage) { var $list = $('<ul class="emotList"></ul>') .appendTo(this.oList); this.emot_list[nav][page ++] = $list[0]; } $('<li class="ShareBoxEmotIcons" data-emot="' + i + '"><a title="' + i + '"><img src="' + self.config.path[nav] + self.config.emot[nav][i] + '" alt="' + i + '"/></a></li>') .appendTo($list) .bind('click', function(e) { e.stopPropagation(); var emot = self.config.tagPrefix + $(this).attr('data-emot') + self.config.tagSuffix; var $editor = $(self.field) $editor.shareBox().insert(emot) $editor.keyup(); /** * 上面 autoHide 已在window 绑定 hide事件 * 同时更好处理 在window click warpper hide 出现问题 * 即 <div>...<emots dialog><div> * $(document).bind('click', function(){$(div).hide()}) * $(div).live('click', function(){return false;}) * 此时 点击表情 div 不会消失 因此将 document 设置成 全局方法载体 */ $(document).click(); }); num ++; } //补空 while (! (0 === num ++ % this.config.perPage)) { $('<li class="ShareBoxEmotIcons"><a><img src="' + this.config.path[nav] + 'blank.gif" /></a></li>') .appendTo($list) .bind('click', function(e) { e.stopPropagation(); }); } return this; }, showPage: function(nav) { $(this.page_list).hide() .filter(':lt(' + this.emot_list[nav].length + ')') .show(); return this; }, page: function(page) { $(this.page_list) .removeClass('active') .filter('[data-page="' + page + '"]') .addClass('active'); for (var i in this.emot_list) { $(this.emot_list[i]).hide(); } $(this.emot_list[this.curNav][page - 1]).show(); return this; }, nav: function(nav) { if (this.curNav === nav || 'string' !== typeof nav) return; if (! this.config.emot[nav]) nav = getIndex(this.config.path, 0); $(this.nav_list).removeClass('active') .filter('[data-nav="' + nav + '"]') .addClass('active'); if ('undefined' === typeof this.emot_list[nav]) this.emot(nav); this.curNav = nav; this.showPage(nav); this.page(1); return this; }, show: function(field, reset, place) { var self = this; this.field = $(field)[0]; //重置或设置 导航 if (reset || this.config.autoReset) { this.nav(getIndex(this.config.path, 0)); this.page(1); } else { this.nav(this.curNav); } //居中显示 $(this.oEmot).show(); if (place) this.to(place); else this.toCenter(); this.active = true; return this; }, hide: function() { $(this.oEmot).hide(); this.active = false; return this; }, to: function(place) { var $win = $(window), $ct = $(this.oEmot), $place = $(place), ofs = $place.offset(); var ww = $win.width(), wh = $win.height(), wl = $win.scrollLeft(), wt = $win.scrollTop(); var cw = $ct.outerWidth(), ch = $ct.outerHeight(), cl = ct = 0; var pw = $place.outerWidth(), ph = $place.outerHeight(), pl = ofs.left, pt = ofs.top; if (pl + cw/2 >= wl + ww/1.5) cl = pl + pw - cw; else cl = pl; if (pt - ch/2 <= wt + wh/3) ct = pt + ph + 4; else ct = pt - ch - 4; $ct.css({left:cl, top:ct}); return this; }, toCenter: function() { var $win = $(window), $emot = $(this.oEmot), wh = $win.height(), ww = $win.width(), wl = $win.scrollLeft(), wt = $win.scrollTop(), mh = $emot.outerHeight(), mw = $emot.outerWidth(); $emot.css({ left: (ww - mw)/2 + wl, top: (wh - mh)/2 + wt }); return this; } }; |
20
qq5775548 2014-08-07 21:36:57 +08:00
ShareBox.SuggestBox.prototype = {
label: '<li data-link="{datas}"><a>{view}</a></li>', uid: 0, queue: [], // '@' suggest box at: (function() { var FORBID_CODE = [9, 13, 16 ,17 ,18, 27, 38, 40, 229]; //格式化数据 var format = function(datas) { var s = []; if ($.isArray(datas)) { for (var i = 0; i < datas.length; i ++) { s.push({view: datas[i], datas: {value: datas[i]}}) } return s; } if ($.isPlainObject(datas)) { for (var i in datas) { s.push({view: datas[i], datas: {value: datas[i]}}) } return s; } return []; }; //get string of '@' //获取 当前光标 对应的 '@xxx' 字符串 并返回其match string, start & end pos var getAtObject = function(str, cursor_pos) { var p = l = 0, m = ''; while(! (p <= cursor_pos - 1 && p + l > cursor_pos - 1)) { p = str.search(/@[^\s\@\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}]*/g); if (p == -1) { return; } m = str.match(/@[^\s\@\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}]*/g)[0]; l = m.length; str = str.replace('@', ' '); } return { match: m, startPos: p, endPos: p + l }; }; return function(options) { var self = this; var box = new ShareBox.SuggestBox.Box(); box._constructor(); var field = options.field, defaultList = options.defaultList, url = options.url, name = options.name, handle = options.ajaxGet; //弹出自动完成窗口 var popHandle = function() { var $this = $(this); var $editor = $this.shareBox(); var v = $this.val(), pos = $editor.getPos(); //不能 match 到 @xxx 形式并定位则隐藏 var at = getAtObject(v, pos.startPos); if (! ('object' === typeof at)) { box.hide(); return; }; var matchStr = at['match'] .replace('@', '') .replace(/\s/g, ''); //获取 选中的字符串 若有选中字符串 则必须把 match到的字符串进行过滤 //这里 形式为 '@xxx_' 或 '@xxx' 则可以将 '_' 和 select 的字符串进行 /xx$/的替换 var sel = $editor.getSelectText(); if (sel.length > 0) { var reg = sel.replace(/\s/g, '') + '$'; matchStr = matchStr.replace(new RegExp(reg), ''); } if (matchStr != '' && 'string' === typeof url) { //通过ajax 拿数据 source 获取数据后 再进行 生成列表 $.getJSON(url, [{ name: name, value: matchStr }], function(r) { if ($.isFunction(handle)) options.source = handle.call(self, r, format); else options.source = format(r); box.at(options, { startPos: at.startPos, endPos: at.endPos }); }); } else { //刚打 '@' 时读取默认列表 setTimeout(function() { //若没有 url 则 自己过滤默认数据 if (matchStr != '') { for (var i = 0, l = defaultList, reg = new RegExp('^' + matchStr, 'im'), s = []; i < l.length; i ++ ) { if (l[i].match(reg)) { s.push(l[i]); } } } options.source = format(s || defaultList); box.at(options, { startPos: at.startPos, endPos: at.endPos }); }, 1); } }; //绑定 textarea 事件 $(field).bind('keydown', function(e) { if (-1 != $.inArray(e.keyCode, [9])) return false; }) .bind('keyup', function(e) { //禁止组合键与功能键 if ('undefined' != typeof e.keyCode && -1 == $.inArray(e.keyCode, FORBID_CODE)) popHandle.apply(this, arguments); if (KEY_CODE[e.keyCode]) box.hide(); }) .bind('click', function() { popHandle.apply(this, arguments); }); return box; }; })(), suggest: function(options) { if (options.type) return this[options.type](options); } }; |
21
qq5775548 2014-08-07 21:37:09 +08:00
ShareBox.SuggestBox.Box.prototype = {
_constructor: function(options) { this.handler = []; this.container = $('<div class="suggest-box"></div>').hide().appendTo('body').get(0); this.warp = $('<ul class="warpper"></ul>').appendTo(this.container).get(0); }, _transform: function(html, source) { var fixes = html.match(/\{[^\{]*\}/ig); if (fixes == null) return; fixes = fixes.toString() .replace(/[\{\}]+/g, '') .split(','); //写入 data-link 属性 for (var i = 0, f = fixes, s = source; i < f.length; i ++) { if (s.hasOwnProperty(f[i])) { if ('object' === typeof s[f[i]]) { var datas = toJSON(s[f[i]]); html = html.replace('{' + f[i] + '}', datas); continue; } html = html.replace('{' + f[i] + '}', s[f[i]]); } } return html; }, //将source转化成html transform: function(source, code) { var list = []; if (source && source.length > 0) { for (var i = 0, s = source; i < s.length; i ++) { list.push(this._transform(code || OPTIONS.ShareBox.label, s[i])); } } return list.join(''); }, empty: function() { $(this.warp).empty(); return this; }, put: function(list) { $(this.warp).append(list); return this; }, getDatas: function(item) { var datas = (item ? $(item) : $(this.warp).children().filter('.focus')) .attr('data-link'); return $.parseJSON(datas); }, hide: function() { $(this.container).hide(); this.logout(); return this; }, at: function(options, cursor_pos) { var self = this; var type = options.type, source = options.source, field = options.field, $field = $(field); this.field = field; this.empty(); this.put(this.transform(source)); this.logout(); var insert = function() { setTimeout(function() { var $eidtor = $field.shareBox(); $eidtor.select(cursor_pos.startPos + 1, cursor_pos.endPos); var datas = self.getDatas(); $eidtor.insert(datas.value + ' '); }, 1); }; this.boxKeyDownHandle = function(e) { var $l = $(self.warp).children(); switch(e.keyCode) { //focus prev case 38: //key ↑ var k = $l.index($l.filter('.focus')); k = k <= 0 ? $l.length : k; $l.removeClass('focus') .eq(k-1) .mouseover(); return false; //prohibit browers scroll event //focus next case 40: //key ↓ var k = $l.index($l.filter('.focus')); k = k >= $l.length - 1 ? -1 : k; $l.removeClass('focus') .eq(k+1) .mouseover(); return false; //insert case 9: //key Tab case 13: //key Enter insert(); self.hide(); return false; //cancle case 8: //key Backspace case 27: //key Esc $field.shareBox().insert(''); self.hide(); return; } }; //focus style this.listMouseoverHandle = function(e) { $(self.warp).children().removeClass('focus'); $(this).addClass('focus'); }; //select auto insert this.listClickHandle = function(e) { insert(); self.hide(); }; this.docClickHandle = function() { self.hide(); }; $field.bind('keydown', this.boxKeyDownHandle); $(this.warp).children().bind('mouseover', this.listMouseoverHandle) .bind('click', this.listClickHandle) .eq(0).mouseover(); $(document).bind('click', this.docClickHandle); //position var pos = $field.shareBox().getCursorOffset(); $(this.container).css({left: pos.left,top: pos.top}).show(); suggestBox.active = this; return this; }, logout: function() { if ($.isFunction(this.boxKeyDownHandle)) $(this.field).unbind('keydown', this.boxKeyDownHandle); if ($.isFunction(this.boxKeyDownHandle)) $(this.field).unbind('keydown', this.boxKeyDownHandle); var $c = $(this.warp).children(); if ($.isFunction(this.listMouseoverHandle)) $c.unbind('mouseover', this.listMouseoverHandle); if ($.isFunction(this.listMouseoverHandle)) $c.unbind('click', this.listMouseoverHandle); if ($.isFunction(this.docClickHandle)) $(document).unbind('click', this.docClickHandle); this.boxKeyDownHandle = this.listMouseoverHandle = this.listClickHandle = this.docClickHandle = undefined; } }; |
22
qq5775548 2014-08-07 21:37:16 +08:00
$.extend(ShareBox.prototype, ShareBox.TextEdit.prototype, {
_emotions: {}, emot: function(options) { var emot = this._emotions[options.id || 'box']; if (! (emot instanceof ShareBox.Emotion)) { emot = this._emotions[options.id || 'box'] = new ShareBox.Emotion(options); emot._constructor(options); } var field = this.field; if (emot.field == field) { emot.active == false ? emot.show(field, false, options.to) : emot; return emot; } emot.show(field, true, options.to); return emot; }, parseEmot: function(text) { var path = OPTIONS.Emotion.path; var emot = OPTIONS.Emotion.emot; for (var i in emot) { for (var j in emot[i]) { var reg = new RegExp('\\[' + j + '\\]', 'g'); text = text.replace(reg, function($1) { return '<a title="' + j + '"><img src="' + path[i] + emot[i][j] + '" alt="' + j + '" /></a>'; }); } } return text; }, suggest: function(options) { if (! this._suggest) { options = options || {}; options.field = this.field; this._suggest = suggestBox.suggest(options); return this._suggest; } } }); var suggestBox = new ShareBox.SuggestBox(); $.fn.extend({ shareBox: function(options) { var edits = []; this.filter('input[type="text"], textarea').each(function() { var edit = new ShareBox(); edit._constructor(this); if ($.isPlainObject(options)) { if ('undefined' === typeof this.suggest && options.suggest) this.suggest = edit.suggest(options.suggest); if (options.emot) edit.emot(options.emot); if ('undefined' === typeof this._autogrow && options.autogrow) this._autogrow = $(this).autogrow(); } edits.push(edit); }); return edits.length > 1 ? edits : edits[0]; }, /** * Auto-growing textareas; technique ripped from Facebook * (Textarea need set style "overflow:hidden" under IE) * https://github.com/jaz303/jquery-grab-bag/blob/master/javascripts/jquery.autogrow-textarea.js */ autogrow: (function() { function times(string, number) { for (var i = 0, r = ''; i < number; i ++) r += string; return r; }; return function() { this.filter('textarea').each(function() { this.timeoutId = null; var $this = $(this).css('overflow', 'hidden'), minH = $this.height(); var shadow = $('<div></div>') .css({ position: 'absolute', wordWrap: 'break-word', top: 0, left: -9999, display: 'none', width: $this.width(), fontSize: $this.css('fontSize'), fontFamily: $this.css('fontFamily'), lineHeight: $this.css('lineHeight') }) .appendTo(document.body); var update = function() { var val = this.value .replace(/</g, '<') .replace(/>/g, '>') .replace(/&/g, '&') .replace(/\n$/, '<br/> ') .replace(/\n/g, '<br/>') .replace(/ {2,}/g, function(space) { return times(' ', space.length -1) + ' '; }); shadow.html(val); $(this).css('height', Math.max(shadow.height(), minH)); } var updateTimeout = function() { clearTimeout(this.timeoutId); var that = this; this.timeoutId = setTimeout(function(){ update.apply(that); }, 100); }; $(this).bind('change', update).bind('keyup keydown', updateTimeout); update.apply(this); }); return this; }; })() }); })(jQuery); |
23
qq5775548 2014-08-07 21:38:53 +08:00 1
对不起各位 我发第一条已经后悔了 可惜不能删除 你妹 竟然回复字数这么少,删不到 还是直接发吧 没有CSS的 研究写这份代码应该都会明白的~~~~~~
哎 不再在V2X 上贴代码了 欢迎拍砖 ~~~woyun~~ |
24
hahastudio 2014-08-07 21:44:12 +08:00
你知道么,v2ex 支持 gist 的= =
|
25
zhiyongyici OP @Sunyanzi 我现在的问题可能更加简单,如果不用可视化编辑 ,点击 [回复] 按钮回复框中会出现 <a href="">@user</a> 的代码,如果加载了可视化编辑器(simditor)就没有反应,我感觉应该不是很麻烦。
|
26
zhiyongyici OP @qq5775548 是的,v2ex 不能删帖挺不方便的。你的代码我真的看不懂(小白用户,莫鄙视 ^_^)。你能帮忙解决这个问题吗?可以加我Q详谈。
|
27
mahone3297 2014-08-07 21:51:21 +08:00
lz直接上个价格吧,大家哄抢。。。
功能应该不难,我觉得,难在读懂wordpress+bbpress 代码 |
28
zhiyongyici OP @mahone3297 额,,100可以吗(胆怯)?
|
29
Mihuwa 2014-08-07 21:59:32 +08:00
建议去猪八戒上发个任务。
|
30
zhiyongyici OP 因为不懂,所以不知道工作量有多少,报价没有谱,会弄的朋友可以直接加我Q聊。如果没有我就去猪八戒试试看。
|
31
qq5775548 2014-08-07 22:07:21 +08:00
@zhiyongyici 还是算了, 还在忙着找工作呢...
|
32
sampeng 2014-08-07 22:22:58 +08:00
这个题目是我每次面试必问的一个。。。。。
|
33
kmvan 2014-08-07 22:37:27 +08:00 via Android
楼主的需求跟php完全无关的只是js而已。
|
34
zhiyongyici OP @kmvan 是的,我也感觉是 Js 的事,而且是编辑器的事,但是我一头雾水,一点不懂~
|
35
kmvan 2014-08-07 22:53:05 +08:00 via Android
@zhiyongyici 你不是会js吗?编辑器有api的,绑定点击事件,调用api写入文本就可以了啊。
|
36
kmvan 2014-08-07 22:54:13 +08:00 via Android
这帖子好长,手机差点卡死
|
37
shajiquan 2014-08-07 23:02:51 +08:00
@zhiyongyici 似乎已经解决了。
|
38
yinheli 2014-08-07 23:35:14 +08:00 2
@给你写了个插件. 用的 coffeescript, 把编译后的文件放到你的博客试试
https://gist.github.com/yinheli/2ea1c51710c452e9b81d#file-simditor-replay-js |
39
zhiyongyici OP @shajiquan 已经解决了~ 一个朋友用了一段JS就完事了。。。免费的,好感动~!
|
41
zhiyongyici OP @yinheli 兄弟,感动死我了,你这么操心!!现在问题已经解决了,你的代码可以让更多人看到,也能帮更多人解决类似问题。无比感激~!不过V2贴出来的代码把屏幕都撑破了!好囧。^_^
|
42
yinheli 2014-08-07 23:46:30 +08:00
@zhiyongyici 恩. 看到了. 不过不如写插件的方式好. 比如写了一段文字. 才想起来要去点一下回复的话. 插件的机制会自动判断你的光标的位置的.
|
43
zhiyongyici OP @yinheli 对,我来试试你的代码~ ^_^
|
44
zhiyongyici OP @yinheli 确实非常好用,而且我还省了一个PHP插件!有一个小问题,点击回复之后,链接后面加了一个# 整个页面就跑开头了
|
45
yinheli 2014-08-08 00:00:58 +08:00
@zhiyongyici 那是因为你把以前的代码搞坏了. 页面有个 bbpress_direct_quotes_quotePost 的方法, 应该是以前的那个哥们改的吧.
|
46
zhiyongyici OP @yinheli 是的,已经改回来了,问题完美解决!!太感谢你了,我送你半年广告吧,在自然志上面,虽然没多少流量,但是能帮一点是一点,这样我的心里好受一些。^_^
|
47
ianva 2014-08-08 00:49:11 +08:00
我是来看戈达尔的
|
48
yuankui 2014-08-08 09:38:55 +08:00
|
49
yinheli 2014-08-08 09:48:36 +08:00
@zhiyongyici 没有这个需求. 如果你心情好, 可以开源社区捐赠, 比如 beego. http://beego.me/donate
|
50
xiaop 2014-08-08 13:32:15 +08:00
非常喜欢你们的网站!
|
51
zhiyongyici OP @yinheli 有捐助人民币的吗。我找了半天发现只能是美元。
|
52
yinheli 2014-08-18 21:20:45 +08:00
@zhiyongyici 有个支付宝的二维码.
|
53
zhiyongyici OP @yinheli OK 我试试
|
54
zhiyongyici OP @yinheli 成功了,捐了50元,不多,但是心是热的,感谢这样的开源项目为大家提供方便。敬意!
|
55
lyqds 2015-06-28 11:41:50 +08:00
|
57
lyqds 2015-06-29 17:32:06 +08:00
|
59
lyqds 2015-07-01 19:24:18 +08:00
@yinheli 谢谢你, [email protected]
|