jquery-atwho-rails 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/lib/assets/javascripts/jquery.atwho.js +96 -80
- data/lib/jquery-atwho-rails/version.rb +1 -1
- metadata +17 -7
data/.gitignore
CHANGED
@@ -63,7 +63,6 @@
|
|
63
63
|
};
|
64
64
|
At = {
|
65
65
|
keyword : {'text':"",'start':0,'stop':0},
|
66
|
-
search_word: "",
|
67
66
|
_cache : {},
|
68
67
|
// textarea, input.
|
69
68
|
$inputor : null,
|
@@ -72,11 +71,27 @@
|
|
72
71
|
lenght : 0,
|
73
72
|
/* @ position in inputor */
|
74
73
|
pos: 0,
|
74
|
+
flags:{},
|
75
|
+
theflag:null,
|
76
|
+
options:{},
|
77
|
+
searchWord:function() {
|
78
|
+
// just used in At.watchWithData
|
79
|
+
var match = /data-keyname=['?]\$\{(\w+)\}/g.exec(this.getOpt('tpl'));
|
80
|
+
return !_isNil(match) ? match[1] : null;
|
81
|
+
},
|
82
|
+
getOpt: function(key) {
|
83
|
+
var flag = this.theflag;
|
84
|
+
try {
|
85
|
+
return this.options[flag][key];
|
86
|
+
} catch (e) {
|
87
|
+
return null
|
88
|
+
}
|
89
|
+
},
|
75
90
|
/* @ offset*/
|
76
91
|
offset: function() {
|
77
92
|
$inputor = this.$inputor;
|
78
93
|
mirror = $inputor.data("mirror");
|
79
|
-
if (
|
94
|
+
if (_isNil(mirror)) {
|
80
95
|
mirror = new Mirror($inputor);
|
81
96
|
$inputor.data("mirror",mirror);
|
82
97
|
}
|
@@ -128,13 +143,13 @@
|
|
128
143
|
return {'top':y,'left':x};
|
129
144
|
},
|
130
145
|
cache: function(key,value) {
|
131
|
-
if (!
|
132
|
-
|
146
|
+
if (!this.getOpt('cache')) return null;
|
147
|
+
_log("cacheing",key,value);
|
133
148
|
if (value)
|
134
149
|
this._cache[key] = value;
|
135
150
|
return this._cache[key];
|
136
151
|
},
|
137
|
-
|
152
|
+
getKeyname: function() {
|
138
153
|
$inputor = this.$inputor;
|
139
154
|
text = $inputor.val();
|
140
155
|
//获得inputor中插入符的position.
|
@@ -143,17 +158,29 @@
|
|
143
158
|
* 考虑会有多个 @ 的存在, 匹配离插入符最近的一个*/
|
144
159
|
subtext = text.slice(0,caret_pos);
|
145
160
|
// word = subtext.exec(/@(\w+)$|@[^\x00-\xff]+$/g);
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
161
|
+
var self = this;
|
162
|
+
var matched = null;
|
163
|
+
$.each(this.options,function(flag) {
|
164
|
+
regexp = new RegExp(flag+'(\\w*)$|'+flag+'([^\\x00-\\xff]*)$','gi');
|
165
|
+
match = regexp.exec(subtext);
|
166
|
+
if (!_isNil(match)) {
|
167
|
+
matched = match[1] == undefined ? match[2] : match[1];
|
168
|
+
self.theflag = flag;
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
});
|
172
|
+
var key = null;
|
173
|
+
_log("matched",matched);
|
174
|
+
if (typeof matched == "string" && matched.length <= 20) {
|
175
|
+
start = caret_pos - matched.length;
|
176
|
+
end = start + matched.length;
|
151
177
|
this.pos = start;
|
152
|
-
key = {'text':
|
178
|
+
key = {'text':matched, 'start':start, 'end':end};
|
153
179
|
} else
|
154
180
|
this.view.hide();
|
181
|
+
|
155
182
|
this.keyword = key;
|
156
|
-
|
183
|
+
_log("getKeyname",key);
|
157
184
|
return key;
|
158
185
|
},
|
159
186
|
/* 捕捉inputor的上下回车键.
|
@@ -163,7 +190,7 @@
|
|
163
190
|
onkeydown:function(e) {
|
164
191
|
view = this.view;
|
165
192
|
// 当列表没显示时不捕捉inputor相关事件.
|
166
|
-
if (!view.
|
193
|
+
if (!view.watching()) return true;
|
167
194
|
last_idx = view.items.length - 1;
|
168
195
|
var return_val = false;
|
169
196
|
switch (e.keyCode) {
|
@@ -214,7 +241,7 @@
|
|
214
241
|
this.$inputor.caretPos(start_str.length + str.length);
|
215
242
|
},
|
216
243
|
choose: function($li) {
|
217
|
-
str =
|
244
|
+
str = _isNil($li) ? this.keyword.text+" " : $li.attr("data-keyname")+" ";
|
218
245
|
this.replaceStr(str);
|
219
246
|
this.view.hide();
|
220
247
|
},
|
@@ -226,11 +253,13 @@
|
|
226
253
|
* 注册过的key将不再进行绑定
|
227
254
|
* */
|
228
255
|
key = $inputor.data("@reg-key");
|
229
|
-
log("reg",inputor,key);
|
230
256
|
if ($.inArray(key,this.inputor_keys) >= 0)
|
231
257
|
return null;
|
258
|
+
_log("reg",inputor,key);
|
259
|
+
|
232
260
|
key = "@-"+$.now();
|
233
|
-
|
261
|
+
$inputor.data("@reg-key",key);
|
262
|
+
this.inputor_keys.push(key);
|
234
263
|
// 捕捉inputor事件
|
235
264
|
var self = this;
|
236
265
|
$inputor.bind("keydown",function(e) {
|
@@ -244,40 +273,41 @@
|
|
244
273
|
});
|
245
274
|
return key;
|
246
275
|
},
|
247
|
-
|
276
|
+
watch: function(inputor) {
|
248
277
|
this.$inputor = $(inputor);
|
249
|
-
key = this.
|
278
|
+
key = this.getKeyname();
|
250
279
|
if (!key) return false;
|
251
280
|
/*
|
252
281
|
* 支持多渠道获得用户数据.
|
253
282
|
* 可以设置静态数据的同时从服务器动态获取.
|
254
283
|
* 获取级别从先到后: cache -> statis data -> ajax.
|
255
284
|
*/
|
256
|
-
if (!
|
257
|
-
|
285
|
+
if (!_isNil(names = this.cache(this.keyword.text))) {
|
286
|
+
_log("cache data",names);
|
258
287
|
this.view.load(names,false);
|
259
|
-
} else if (!
|
260
|
-
|
288
|
+
} else if (!_isNil(names = this.watchWithData(key))) {
|
289
|
+
_log("statis data",names);
|
261
290
|
this.view.load(names,false);
|
262
|
-
} else {
|
263
|
-
callback
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
}
|
268
|
-
}
|
291
|
+
} else if ($.isFunction(callback = this.getOpt('callback'))){
|
292
|
+
_log("callbacking",callback);
|
293
|
+
callback(At);
|
294
|
+
} else
|
295
|
+
this.view.hide();
|
269
296
|
},
|
270
|
-
|
297
|
+
watchWithData:function(key) {
|
298
|
+
data = this.getOpt("data");
|
299
|
+
_log("watchWithData",data);
|
271
300
|
var items = null;
|
272
301
|
var self = this;
|
273
302
|
if($.isArray(data) && data.length != 0) {
|
274
303
|
items = $.map(data,function(item,i) {
|
275
304
|
//support plain object also
|
276
|
-
var name = $.isPlainObject(item) ? item[self.
|
305
|
+
var name = $.isPlainObject(item) ? item[self.searchWord()] : item;
|
277
306
|
match = name.match((new RegExp(key.text,"i")));
|
278
307
|
return match ? item : null;
|
279
308
|
});
|
280
309
|
}
|
310
|
+
_log("watch with data.item",items)
|
281
311
|
return items;
|
282
312
|
}
|
283
313
|
};
|
@@ -288,25 +318,19 @@
|
|
288
318
|
cur_li_idx : 0,
|
289
319
|
timeout_id : null,
|
290
320
|
id : '#at-view',
|
291
|
-
//at view jquery object
|
292
|
-
jqo : null,
|
293
321
|
items : [],
|
294
322
|
// 列表框是否显示中.
|
295
|
-
|
323
|
+
watching :function() {
|
296
324
|
return $(this.id).is(":visible");
|
297
325
|
},
|
298
326
|
evalTpl: function(tpl,map) {
|
299
|
-
if(
|
327
|
+
if(_isNil(tpl)) return;
|
300
328
|
el = tpl.replace(/\$\{([^\}]*)\}/g,function(tag,key,pos){
|
301
329
|
return map[key];
|
302
330
|
});
|
303
|
-
|
331
|
+
_log("evalTpl",el);
|
304
332
|
return el;
|
305
333
|
},
|
306
|
-
jqObject : function(o) {
|
307
|
-
if (!isNil(o)) this.jqo = o;
|
308
|
-
return isNil(this.jqo) ? $(this.id) : this.jqo;
|
309
|
-
},
|
310
334
|
onLoaded: function($view) {
|
311
335
|
$view.find('li').live('click',function(e) {
|
312
336
|
At.choose($(this));
|
@@ -323,23 +347,21 @@
|
|
323
347
|
$view.offset(At.offset());
|
324
348
|
},
|
325
349
|
show: function(){
|
326
|
-
if (!this.
|
350
|
+
if (!this.watching())
|
327
351
|
$view = $(this.id).show();
|
328
352
|
this.rePosition($view);
|
329
353
|
},
|
330
354
|
hide: function() {
|
331
|
-
if (!this.
|
355
|
+
if (!this.watching()) return;
|
332
356
|
this.cur_li_idx = 0;
|
333
357
|
$(this.id).hide();
|
334
358
|
},
|
335
359
|
load: function(list,cacheable) {
|
336
360
|
// 是否已经加载了列表视图
|
337
|
-
if (
|
338
|
-
tpl = "<div id='"+this.id.slice(1)+"' class='at-view'><
|
339
|
-
$
|
340
|
-
$(
|
341
|
-
this.jqObject($at_view = $(this.id));
|
342
|
-
this.onLoaded($at_view);
|
361
|
+
if (_isNil($(this.id))) {
|
362
|
+
tpl = "<div id='"+this.id.slice(1)+"' class='at-view'><ul id='"+this.id.slice(1)+"-ul'></ul></div>";
|
363
|
+
$('body').append(tpl);
|
364
|
+
this.onLoaded($(this.id));
|
343
365
|
}
|
344
366
|
return this.update(list,cacheable);
|
345
367
|
},
|
@@ -347,19 +369,19 @@
|
|
347
369
|
if (clear_all == true)
|
348
370
|
this._cache = {};
|
349
371
|
this.items = [];
|
350
|
-
this.
|
372
|
+
$(this.id).find('ul').empty();
|
351
373
|
},
|
352
374
|
update: function(list,cacheable) {
|
353
375
|
if (!$.isArray(list)) return false;
|
354
376
|
if (cacheable != false) At.cache(At.keyword.text,list);
|
355
377
|
|
356
|
-
$ul = this.
|
378
|
+
$ul = $(this.id).find('ul');
|
357
379
|
this.clear();
|
358
380
|
$.merge(this.items,list);
|
359
|
-
var tpl =
|
381
|
+
var tpl = At.getOpt('tpl');
|
360
382
|
var self = this;
|
361
|
-
var list =
|
362
|
-
$.each(list.splice(0,
|
383
|
+
var list = _unique(list,At.searchWord());
|
384
|
+
$.each(list.splice(0, At.getOpt('limit')), function(i,item) {
|
363
385
|
if (!$.isPlainObject(item)) {
|
364
386
|
item = {'id':i,'name':item};
|
365
387
|
tpl = DEFAULT_TPL;
|
@@ -371,14 +393,14 @@
|
|
371
393
|
}
|
372
394
|
};
|
373
395
|
|
374
|
-
/* maybe we can use $.
|
396
|
+
/* maybe we can use $._unique.
|
375
397
|
* But i don't know it will delete li element frequently or not.
|
376
398
|
* I think we should not change DOM element frequently.
|
377
399
|
* more, It seems batter not to call evalTpl function too much times.
|
378
400
|
* */
|
379
|
-
function
|
401
|
+
function _unique(list,keyword) {
|
380
402
|
var record = [];
|
381
|
-
|
403
|
+
_log(list,keyword);
|
382
404
|
return $.map(list,function(v,idx){
|
383
405
|
var value = $.isPlainObject(v) ? v[keyword] : v;
|
384
406
|
if ($.inArray(value,record) < 0) {
|
@@ -388,7 +410,7 @@
|
|
388
410
|
});
|
389
411
|
}
|
390
412
|
|
391
|
-
function
|
413
|
+
function _isNil(target) {
|
392
414
|
return !target
|
393
415
|
//empty_object =
|
394
416
|
|| ($.isPlainObject(target) && $.isEmptyObject(target))
|
@@ -399,52 +421,46 @@
|
|
399
421
|
|| target === undefined;
|
400
422
|
}
|
401
423
|
|
402
|
-
function
|
403
|
-
if (!
|
424
|
+
function _log() {
|
425
|
+
if (!At.getOpt('debug') || $.browser.msie)
|
404
426
|
return;
|
405
427
|
console.log(arguments);
|
406
428
|
}
|
407
429
|
|
408
|
-
function
|
430
|
+
function _setSettings(options) {
|
409
431
|
opt = {};
|
410
432
|
if ($.isFunction(options))
|
411
433
|
opt['callback'] = options;
|
412
434
|
else
|
413
435
|
opt = options;
|
414
436
|
return $.extend({
|
415
|
-
//must return array;
|
416
|
-
'callback': function(context) {return []},
|
417
437
|
'cache' : true,
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
'data':[]
|
438
|
+
'debug' : false,
|
439
|
+
'limit' : 5,
|
440
|
+
'tpl' : DEFAULT_TPL
|
422
441
|
},opt);
|
423
442
|
}
|
424
443
|
|
425
|
-
DEFAULT_TPL = "<li id='${id}' data-
|
426
|
-
|
427
|
-
$.fn.atWho = function (options) {
|
428
|
-
|
429
|
-
|
430
|
-
// just used in At.runWithData
|
431
|
-
var match = /data-insert=['?]\$\{(\w+)\}/g.exec(settings['tpl']);
|
432
|
-
At.search_word = match[1];
|
444
|
+
DEFAULT_TPL = "<li id='${id}' data-keyname='${name}'>${name}</li>";
|
445
|
+
|
446
|
+
$.fn.atWho = function (flag,options) {
|
447
|
+
At.options[flag] = _setSettings(options);
|
448
|
+
_log("options",At.options);
|
433
449
|
return this.filter('textarea, input').each(function() {
|
434
450
|
if (!At.reg(this)) return;
|
435
451
|
$(this).bind("keyup",function(e) {
|
436
452
|
/* 当用户列表框显示时, 上下键不触发查询 */
|
437
453
|
var stop_key = e.keyCode == 40 || e.keyCode == 38;
|
438
|
-
|
439
|
-
if (
|
454
|
+
watch = !(At.view.watching() && stop_key);
|
455
|
+
if (watch) At.watch(this);
|
440
456
|
})
|
441
457
|
.mouseup(function(e) {
|
442
|
-
At.
|
458
|
+
At.watch(this);
|
443
459
|
});
|
444
460
|
});
|
461
|
+
return At;
|
445
462
|
}
|
446
|
-
})(jQuery);
|
447
|
-
|
463
|
+
})(window.jQuery);
|
448
464
|
/* 本插件操作 textarea 或者 input 内的插入符
|
449
465
|
* 只实现了获得插入符在文本框中的位置,我设置
|
450
466
|
* 插入符的位置.
|
@@ -544,4 +560,4 @@
|
|
544
560
|
return getCaretPos(inputor);
|
545
561
|
}
|
546
562
|
}
|
547
|
-
})(jQuery);
|
563
|
+
})(window.jQuery);
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jquery-atwho-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: generator_spec
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,7 +37,12 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
description: ! "This is a jQuery plugin \n that implement Twitter/Weibo like @
|
37
47
|
mentions."
|
38
48
|
email:
|
@@ -73,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
83
|
version: '0'
|
74
84
|
requirements: []
|
75
85
|
rubyforge_project: jquery-atwho-rails
|
76
|
-
rubygems_version: 1.8.
|
86
|
+
rubygems_version: 1.8.19
|
77
87
|
signing_key:
|
78
88
|
specification_version: 3
|
79
89
|
summary: ! 'jquery plugin: @mentions'
|