jquery-atwho-rails 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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'
|