jquery-atwho-rails 0.1.7 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +6 -1
- data/Rakefile +11 -15
- data/changelog.md +1 -0
- data/jquery-atwho-rails.gemspec +2 -2
- data/lib/assets/javascripts/jquery.atwho.js +435 -439
- data/lib/assets/stylesheets/jquery.atwho.css +1 -47
- data/lib/jquery-atwho-rails/version.rb +1 -1
- data/lib/jquery-atwho-rails.rb +1 -0
- metadata +9 -5
data/README.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
### Notice
|
2
|
+
updated to `v0.2.0`.
|
3
|
+
The stable and old one would live in branch `stable-v0.1.x` branch taged `v0.1.7`
|
4
|
+
More details in [At.js](https://github.com/ichord/At.js) project.
|
5
|
+
|
1
6
|
### Usage
|
2
7
|
---
|
3
8
|
bind your textarea
|
@@ -8,7 +13,7 @@ $('textarea').atWho("@",{'data':data});
|
|
8
13
|
```
|
9
14
|
|
10
15
|
that's it, check it out!
|
11
|
-
more details in [At.js](
|
16
|
+
more details in [At.js Home Page](http://ichord.github.com/At.js/)
|
12
17
|
|
13
18
|
### Installtion
|
14
19
|
---
|
data/Rakefile
CHANGED
@@ -1,27 +1,23 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
#require "uglifier"
|
3
2
|
|
4
3
|
desc "sync from At.js"
|
5
4
|
task :sync do
|
5
|
+
puts " * syncing..."
|
6
6
|
at_dir = "tmp/At.js"
|
7
|
-
FileUtils.mkdir_p("tmp")
|
8
|
-
|
7
|
+
FileUtils.mkdir_p("tmp") unless Dir.exist? "tmp"
|
8
|
+
unless Dir.exist? at_dir
|
9
9
|
system "git clone git://github.com/ichord/At.js.git #{at_dir}"
|
10
10
|
else
|
11
|
-
Dir.chdir(at_dir)
|
12
|
-
puts %x{git pull}
|
13
|
-
end
|
11
|
+
Dir.chdir(at_dir) { puts %x{git pull -X theirs} }
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
17
|
-
desc "
|
15
|
+
desc "copy assets"
|
18
16
|
task :fresh => :sync do
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
#
|
23
|
-
|
24
|
-
#}
|
25
|
-
FileUtils.copy_file "tmp/atwho.js", the_js
|
26
|
-
FileUtils.copy_file "#{at_dir}/css/jquery.atwho.css", "lib/assets/stylesheets/jquery.atwho.css"
|
17
|
+
puts "", " * Copying..."
|
18
|
+
source_dir = "tmp/At.js/dist"
|
19
|
+
dist_dir = "lib/assets"
|
20
|
+
FileUtils.copy "#{source_dir}/js/jquery.atwho.js", "#{dist_dir}/javascripts/"
|
21
|
+
FileUtils.copy "#{source_dir}/css/jquery.atwho.css", "#{dist_dir}/stylesheets/"
|
22
|
+
puts `ls -R #{dist_dir}`
|
27
23
|
end
|
data/changelog.md
CHANGED
data/jquery-atwho-rails.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ["chord.luo@gmail.com"]
|
10
10
|
s.homepage = "http://ichord.github.com/jquery-atwho-rails"
|
11
11
|
s.summary = %q{jquery plugin: @mentions}
|
12
|
-
s.description = %q{This is a jQuery plugin
|
13
|
-
that implement
|
12
|
+
s.description = %q{This is a jQuery plugin
|
13
|
+
that implement Github-like mentions.}
|
14
14
|
|
15
15
|
s.rubyforge_project = "jquery-atwho-rails"
|
16
16
|
|
@@ -1,41 +1,34 @@
|
|
1
|
-
// Generated by CoffeeScript 1.3.3
|
2
1
|
|
3
2
|
/*
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
a copy of this software and associated documentation files (the
|
10
|
-
"Software"), to deal in the Software without restriction, including
|
11
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
12
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
13
|
-
permit persons to whom the Software is furnished to do so, subject to
|
14
|
-
the following conditions:
|
15
|
-
|
16
|
-
The above copyright notice and this permission notice shall be
|
17
|
-
included in all copies or substantial portions of the Software.
|
18
|
-
|
19
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
20
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
21
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
22
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
23
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
24
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
25
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
3
|
+
Implement Github like autocomplete mentions
|
4
|
+
http://ichord.github.com/At.js
|
5
|
+
|
6
|
+
Copyright (c) 2013 chord.luo@gmail.com
|
7
|
+
Licensed under the MIT license.
|
26
8
|
*/
|
27
9
|
|
28
10
|
|
29
11
|
(function() {
|
30
12
|
|
31
|
-
(function(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
13
|
+
(function(factory) {
|
14
|
+
if (typeof define === 'function' && define.amd) {
|
15
|
+
return define(['jquery'], factory);
|
16
|
+
} else {
|
17
|
+
return factory(window.jQuery);
|
18
|
+
}
|
19
|
+
})(function($) {
|
20
|
+
var Controller, DEFAULT_CALLBACKS, DEFAULT_TPL, KEY_CODE, Mirror, View;
|
21
|
+
Mirror = (function() {
|
22
|
+
|
23
|
+
Mirror.prototype.css_attr = ["overflowY", "height", "width", "paddingTop", "paddingLeft", "paddingRight", "paddingBottom", "marginTop", "marginLeft", "marginRight", "marginBottom", 'fontFamily', 'borderStyle', 'borderWidth', 'wordWrap', 'fontSize', 'lineHeight', 'overflowX'];
|
24
|
+
|
25
|
+
function Mirror($inputor) {
|
26
|
+
this.$inputor = $inputor;
|
27
|
+
}
|
28
|
+
|
29
|
+
Mirror.prototype.copy_inputor_css = function() {
|
30
|
+
var css,
|
31
|
+
_this = this;
|
39
32
|
css = {
|
40
33
|
position: 'absolute',
|
41
34
|
left: -9999,
|
@@ -43,19 +36,21 @@
|
|
43
36
|
zIndex: -20000,
|
44
37
|
'white-space': 'pre-wrap'
|
45
38
|
};
|
46
|
-
$.each(this.
|
47
|
-
return css[p] =
|
39
|
+
$.each(this.css_attr, function(i, p) {
|
40
|
+
return css[p] = _this.$inputor.css(p);
|
48
41
|
});
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
return css;
|
43
|
+
};
|
44
|
+
|
45
|
+
Mirror.prototype.create = function(html) {
|
46
|
+
this.$mirror = $('<div></div>');
|
47
|
+
this.$mirror.css(this.copy_inputor_css());
|
55
48
|
this.$mirror.html(html);
|
49
|
+
this.$inputor.after(this.$mirror);
|
56
50
|
return this;
|
57
|
-
}
|
58
|
-
|
51
|
+
};
|
52
|
+
|
53
|
+
Mirror.prototype.get_flag_rect = function() {
|
59
54
|
var $flag, pos, rect;
|
60
55
|
$flag = this.$mirror.find("span#flag");
|
61
56
|
pos = $flag.position();
|
@@ -66,83 +61,174 @@
|
|
66
61
|
};
|
67
62
|
this.$mirror.remove();
|
68
63
|
return rect;
|
69
|
-
}
|
70
|
-
};
|
71
|
-
At = function(inputor) {
|
72
|
-
var $inputor,
|
73
|
-
_this = this;
|
74
|
-
$inputor = this.$inputor = $(inputor);
|
75
|
-
this.options = {};
|
76
|
-
this.query = {
|
77
|
-
text: "",
|
78
|
-
start: 0,
|
79
|
-
stop: 0
|
80
64
|
};
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
lookup = !(stop && _this.view.isShowing());
|
92
|
-
if (lookup) {
|
93
|
-
return _this.lookup();
|
94
|
-
}
|
95
|
-
}).on("mouseup.inputor", function(e) {
|
96
|
-
return _this.lookup();
|
97
|
-
});
|
98
|
-
this.init();
|
99
|
-
log("At.new", $inputor[0]);
|
100
|
-
return this;
|
65
|
+
|
66
|
+
return Mirror;
|
67
|
+
|
68
|
+
})();
|
69
|
+
KEY_CODE = {
|
70
|
+
DOWN: 40,
|
71
|
+
UP: 38,
|
72
|
+
ESC: 27,
|
73
|
+
TAB: 9,
|
74
|
+
ENTER: 13
|
101
75
|
};
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
return _this.view.hide();
|
112
|
-
}).on('blur.inputor', function(e) {
|
113
|
-
return _this.view.hide(1000);
|
76
|
+
DEFAULT_CALLBACKS = {
|
77
|
+
data_refactor: function(data) {
|
78
|
+
return $.map(data, function(item, k) {
|
79
|
+
if (!$.isPlainObject(item)) {
|
80
|
+
item = {
|
81
|
+
name: item
|
82
|
+
};
|
83
|
+
}
|
84
|
+
return item;
|
114
85
|
});
|
115
|
-
return log("At.init", this.$inputor[0]);
|
116
86
|
},
|
117
|
-
|
118
|
-
var
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
87
|
+
matcher: function(flag, subtext) {
|
88
|
+
var match, matched, regexp;
|
89
|
+
regexp = new RegExp(flag + '([A-Za-z0-9_\+\-]*)$|' + flag + '([^\\x00-\\xff]*)$', 'gi');
|
90
|
+
match = regexp.exec(subtext);
|
91
|
+
matched = null;
|
92
|
+
if (match) {
|
93
|
+
matched = match[2] ? match[2] : match[1];
|
124
94
|
}
|
125
|
-
|
126
|
-
|
127
|
-
|
95
|
+
return matched;
|
96
|
+
},
|
97
|
+
filter: function(query, data, search_key) {
|
98
|
+
var _this = this;
|
99
|
+
return $.map(data, function(item, i) {
|
100
|
+
var name;
|
101
|
+
name = $.isPlainObject(item) ? item[search_key] : item;
|
102
|
+
if (name.toLowerCase().indexOf(query) >= 0) {
|
103
|
+
return item;
|
104
|
+
}
|
105
|
+
});
|
106
|
+
},
|
107
|
+
remote_filter: function(params, url, render_view) {
|
108
|
+
return $.ajax(url, {
|
109
|
+
data: params,
|
110
|
+
success: function(data) {
|
111
|
+
return render_view(data);
|
112
|
+
}
|
113
|
+
});
|
128
114
|
},
|
129
|
-
|
130
|
-
var
|
131
|
-
|
132
|
-
|
133
|
-
|
115
|
+
sorter: function(query, items, search_key) {
|
116
|
+
var item, results, text, _i, _len;
|
117
|
+
if (!query) {
|
118
|
+
items;
|
119
|
+
|
134
120
|
}
|
135
|
-
|
136
|
-
|
121
|
+
results = [];
|
122
|
+
for (_i = 0, _len = items.length; _i < _len; _i++) {
|
123
|
+
item = items[_i];
|
124
|
+
text = item[search_key];
|
125
|
+
item.order = text.toLowerCase().indexOf(query);
|
126
|
+
results.push(item);
|
127
|
+
}
|
128
|
+
return results.sort(function(a, b) {
|
129
|
+
return a.order - b.order;
|
130
|
+
});
|
137
131
|
},
|
138
|
-
|
132
|
+
tpl_eval: function(tpl, map) {
|
133
|
+
var el;
|
139
134
|
try {
|
140
|
-
return
|
135
|
+
return el = tpl.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) {
|
136
|
+
return map[key];
|
137
|
+
});
|
141
138
|
} catch (error) {
|
142
|
-
return
|
139
|
+
return "";
|
143
140
|
}
|
144
141
|
},
|
145
|
-
|
142
|
+
highlighter: function(li, query) {
|
143
|
+
if (!query) {
|
144
|
+
return li;
|
145
|
+
}
|
146
|
+
return li.replace(new RegExp(">\\s*(\\w*)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig'), function(str, $1, $2, $3) {
|
147
|
+
return '> ' + $1 + '<strong>' + $2 + '</strong>' + $3 + ' <';
|
148
|
+
});
|
149
|
+
},
|
150
|
+
selector: function($li) {
|
151
|
+
if ($li.length > 0) {
|
152
|
+
return this.replace_str($li.data("value") || "");
|
153
|
+
}
|
154
|
+
}
|
155
|
+
};
|
156
|
+
Controller = (function() {
|
157
|
+
|
158
|
+
function Controller(inputor) {
|
159
|
+
this.settings = {};
|
160
|
+
this.common_settings = {};
|
161
|
+
this.pos = 0;
|
162
|
+
this.flags = null;
|
163
|
+
this.current_flag = null;
|
164
|
+
this.query = null;
|
165
|
+
this.$inputor = $(inputor);
|
166
|
+
this.mirror = new Mirror(this.$inputor);
|
167
|
+
this.common_settings = $.extend({}, $.fn.atwho["default"]);
|
168
|
+
this.view = new View(this, this.$el);
|
169
|
+
this.listen();
|
170
|
+
}
|
171
|
+
|
172
|
+
Controller.prototype.listen = function() {
|
173
|
+
var _this = this;
|
174
|
+
return this.$inputor.on('keyup.atwho', function(e) {
|
175
|
+
return _this.on_keyup(e);
|
176
|
+
}).on('keydown.atwho', function(e) {
|
177
|
+
return _this.on_keydown(e);
|
178
|
+
}).on('scroll.atwho', function(e) {
|
179
|
+
return _this.view.hide();
|
180
|
+
}).on('blur.atwho', function(e) {
|
181
|
+
return _this.view.hide(_this.get_opt("display_timeout"));
|
182
|
+
});
|
183
|
+
};
|
184
|
+
|
185
|
+
Controller.prototype.reg = function(flag, settings) {
|
186
|
+
var current_settings, data;
|
187
|
+
current_settings = {};
|
188
|
+
current_settings = $.isPlainObject(flag) ? this.common_settings = $.extend({}, this.common_settings, flag) : !this.settings[flag] ? this.settings[flag] = $.extend({}, settings) : this.settings[flag] = $.extend({}, this.settings[flag], settings);
|
189
|
+
data = current_settings["data"];
|
190
|
+
if (typeof data === "string") {
|
191
|
+
current_settings["data"] = data;
|
192
|
+
} else if (data) {
|
193
|
+
current_settings["data"] = this.callbacks("data_refactor").call(this, data);
|
194
|
+
}
|
195
|
+
return this;
|
196
|
+
};
|
197
|
+
|
198
|
+
Controller.prototype.trigger = function(name, data) {
|
199
|
+
data || (data = []);
|
200
|
+
data.push(this);
|
201
|
+
return this.$inputor.trigger("" + name + ".atwho", data);
|
202
|
+
};
|
203
|
+
|
204
|
+
Controller.prototype.data = function() {
|
205
|
+
return this.get_opt("data");
|
206
|
+
};
|
207
|
+
|
208
|
+
Controller.prototype.callbacks = function(func_name) {
|
209
|
+
var func;
|
210
|
+
if (!(func = this.get_opt("callbacks", {})[func_name])) {
|
211
|
+
func = this.common_settings["callbacks"][func_name];
|
212
|
+
}
|
213
|
+
return func;
|
214
|
+
};
|
215
|
+
|
216
|
+
Controller.prototype.get_opt = function(key, default_value) {
|
217
|
+
var value;
|
218
|
+
try {
|
219
|
+
if (this.current_flag) {
|
220
|
+
value = this.settings[this.current_flag][key];
|
221
|
+
}
|
222
|
+
if (value === void 0) {
|
223
|
+
value = this.common_settings[key];
|
224
|
+
}
|
225
|
+
return value = value === void 0 ? default_value : value;
|
226
|
+
} catch (e) {
|
227
|
+
return value = default_value === void 0 ? null : default_value;
|
228
|
+
}
|
229
|
+
};
|
230
|
+
|
231
|
+
Controller.prototype.rect = function() {
|
146
232
|
var $inputor, Sel, at_rect, bottom, format, html, offset, start_range, x, y;
|
147
233
|
$inputor = this.$inputor;
|
148
234
|
if (document.selection) {
|
@@ -165,16 +251,16 @@
|
|
165
251
|
|
166
252
|
start_range = $inputor.val().slice(0, this.pos - 1);
|
167
253
|
html = "<span>" + format(start_range) + "</span>";
|
168
|
-
html += "<span id='flag'
|
254
|
+
html += "<span id='flag'>?</span>";
|
169
255
|
/*
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
256
|
+
将inputor的 offset(相对于document)
|
257
|
+
和@在inputor里的position相加
|
258
|
+
就得到了@相对于document的offset.
|
259
|
+
当然,还要加上行高和滚动条的偏移量.
|
174
260
|
*/
|
175
261
|
|
176
262
|
offset = $inputor.offset();
|
177
|
-
at_rect = this.mirror.
|
263
|
+
at_rect = this.mirror.create(html).get_flag_rect();
|
178
264
|
x = offset.left + at_rect.left - $inputor.scrollLeft();
|
179
265
|
y = offset.top - $inputor.scrollTop();
|
180
266
|
bottom = y + at_rect.bottom;
|
@@ -184,263 +270,244 @@
|
|
184
270
|
left: x,
|
185
271
|
bottom: bottom + 2
|
186
272
|
};
|
187
|
-
}
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
if (!this.getOpt("cache") || !key) {
|
192
|
-
return null;
|
193
|
-
}
|
194
|
-
return (_base = this._cache)[key] || (_base[key] = value);
|
195
|
-
},
|
196
|
-
getKeyname: function() {
|
197
|
-
var $inputor, caret_pos, end, key, matched, start, subtext, text,
|
273
|
+
};
|
274
|
+
|
275
|
+
Controller.prototype.catch_query = function() {
|
276
|
+
var caret_pos, content, end, query, start, subtext,
|
198
277
|
_this = this;
|
199
|
-
|
200
|
-
|
201
|
-
caret_pos = $inputor.caretPos();
|
278
|
+
content = this.$inputor.val();
|
279
|
+
caret_pos = this.$inputor.caretPos();
|
202
280
|
/* 向在插入符前的的文本进行正则匹配
|
203
281
|
* 考虑会有多个 @ 的存在, 匹配离插入符最近的一个
|
204
282
|
*/
|
205
283
|
|
206
|
-
subtext =
|
207
|
-
|
208
|
-
$.each(this.
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
if (!_isNil(match)) {
|
213
|
-
matched = match[2] ? match[2] : match[1];
|
214
|
-
_this.theflag = flag;
|
284
|
+
subtext = content.slice(0, caret_pos);
|
285
|
+
query = null;
|
286
|
+
$.each(this.settings, function(flag, settings) {
|
287
|
+
query = _this.callbacks("matcher").call(_this, flag, subtext);
|
288
|
+
if (query != null) {
|
289
|
+
_this.current_flag = flag;
|
215
290
|
return false;
|
216
291
|
}
|
217
292
|
});
|
218
|
-
if (typeof
|
219
|
-
start = caret_pos -
|
220
|
-
end = start +
|
293
|
+
if (typeof query === "string" && query.length <= 20) {
|
294
|
+
start = caret_pos - query.length;
|
295
|
+
end = start + query.length;
|
221
296
|
this.pos = start;
|
222
|
-
|
223
|
-
'text':
|
224
|
-
'
|
225
|
-
'
|
297
|
+
query = {
|
298
|
+
'text': query.toLowerCase(),
|
299
|
+
'head_pos': start,
|
300
|
+
'end_pos': end
|
226
301
|
};
|
302
|
+
this.trigger("matched", [this.current_flag, query.text]);
|
227
303
|
} else {
|
228
304
|
this.view.hide();
|
229
305
|
}
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
var $inputor, flag_len,
|
306
|
+
return this.query = query;
|
307
|
+
};
|
308
|
+
|
309
|
+
Controller.prototype.replace_str = function(str) {
|
310
|
+
var $inputor, flag_len, source, start_str, text;
|
235
311
|
$inputor = this.$inputor;
|
236
|
-
key = this.query;
|
237
312
|
source = $inputor.val();
|
238
|
-
flag_len = this.
|
239
|
-
start_str = source.slice(0,
|
240
|
-
text = start_str + str + source.slice(
|
313
|
+
flag_len = this.get_opt("display_flag") ? 0 : this.current_flag.length;
|
314
|
+
start_str = source.slice(0, (this.query['head_pos'] || 0) - flag_len);
|
315
|
+
text = "" + start_str + str + " " + (source.slice(this.query['end_pos'] || 0));
|
241
316
|
$inputor.val(text);
|
242
|
-
$inputor.caretPos(start_str.length + str.length);
|
243
|
-
$inputor.change();
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
var view;
|
248
|
-
view = this.view;
|
249
|
-
if (!view.isShowing()) {
|
250
|
-
return;
|
251
|
-
}
|
317
|
+
$inputor.caretPos(start_str.length + str.length + 1);
|
318
|
+
return $inputor.change();
|
319
|
+
};
|
320
|
+
|
321
|
+
Controller.prototype.on_keyup = function(e) {
|
252
322
|
switch (e.keyCode) {
|
253
|
-
case
|
323
|
+
case KEY_CODE.ESC:
|
254
324
|
e.preventDefault();
|
255
|
-
view.hide();
|
325
|
+
this.view.hide();
|
256
326
|
break;
|
257
|
-
|
327
|
+
case KEY_CODE.DOWN:
|
328
|
+
case KEY_CODE.UP:
|
258
329
|
$.noop();
|
330
|
+
break;
|
331
|
+
default:
|
332
|
+
this.look_up();
|
259
333
|
}
|
260
334
|
return e.stopPropagation();
|
261
|
-
}
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
if (!view.isShowing()) {
|
335
|
+
};
|
336
|
+
|
337
|
+
Controller.prototype.on_keydown = function(e) {
|
338
|
+
if (!this.view.visible()) {
|
266
339
|
return;
|
267
340
|
}
|
268
341
|
switch (e.keyCode) {
|
269
|
-
case
|
342
|
+
case KEY_CODE.ESC:
|
270
343
|
e.preventDefault();
|
271
|
-
view.hide();
|
344
|
+
this.view.hide();
|
272
345
|
break;
|
273
|
-
case
|
346
|
+
case KEY_CODE.UP:
|
274
347
|
e.preventDefault();
|
275
|
-
view.prev();
|
348
|
+
this.view.prev();
|
276
349
|
break;
|
277
|
-
case
|
350
|
+
case KEY_CODE.DOWN:
|
278
351
|
e.preventDefault();
|
279
|
-
view.next();
|
352
|
+
this.view.next();
|
280
353
|
break;
|
281
|
-
case
|
282
|
-
case
|
283
|
-
if (!view.
|
354
|
+
case KEY_CODE.TAB:
|
355
|
+
case KEY_CODE.ENTER:
|
356
|
+
if (!this.view.visible()) {
|
284
357
|
return;
|
285
358
|
}
|
286
359
|
e.preventDefault();
|
287
|
-
view.choose();
|
360
|
+
this.view.choose();
|
288
361
|
break;
|
289
362
|
default:
|
290
363
|
$.noop();
|
291
364
|
}
|
292
365
|
return e.stopPropagation();
|
293
|
-
}
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
return this.view.render(
|
301
|
-
}
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
366
|
+
};
|
367
|
+
|
368
|
+
Controller.prototype.render_view = function(data) {
|
369
|
+
var search_key;
|
370
|
+
search_key = this.get_opt("search_key");
|
371
|
+
data = this.callbacks("sorter").call(this, this.query.text, data, search_key);
|
372
|
+
data = data.splice(0, this.get_opt('limit'));
|
373
|
+
return this.view.render(data);
|
374
|
+
};
|
375
|
+
|
376
|
+
Controller.prototype.look_up = function() {
|
377
|
+
var data, origin_data, params, query, search_key;
|
378
|
+
query = this.catch_query();
|
379
|
+
if (!query) {
|
306
380
|
return false;
|
307
381
|
}
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
382
|
+
origin_data = this.get_opt("data");
|
383
|
+
search_key = this.get_opt("search_key");
|
384
|
+
if (typeof origin_data === "string") {
|
385
|
+
params = {
|
386
|
+
q: query.text,
|
387
|
+
limit: this.get_opt("limit")
|
388
|
+
};
|
389
|
+
this.callbacks('remote_filter').call(this, params, origin_data, $.proxy(this.render_view, this));
|
390
|
+
} else if ((data = this.callbacks('filter').call(this, query.text, origin_data, search_key))) {
|
391
|
+
this.render_view(data);
|
315
392
|
} else {
|
316
393
|
this.view.hide();
|
317
394
|
}
|
318
395
|
return $.noop();
|
319
|
-
}
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
return null;
|
333
|
-
}
|
334
|
-
if (match) {
|
335
|
-
return item;
|
336
|
-
} else {
|
337
|
-
return null;
|
338
|
-
}
|
339
|
-
});
|
340
|
-
}
|
341
|
-
return items;
|
396
|
+
};
|
397
|
+
|
398
|
+
return Controller;
|
399
|
+
|
400
|
+
})();
|
401
|
+
View = (function() {
|
402
|
+
|
403
|
+
function View(controller) {
|
404
|
+
this.controller = controller;
|
405
|
+
this.id = this.controller.get_opt("view_id", "at-view");
|
406
|
+
this.timeout_id = null;
|
407
|
+
this.$el = $("#" + this.id);
|
408
|
+
this.create_view();
|
342
409
|
}
|
343
|
-
|
344
|
-
|
345
|
-
timeout_id: null,
|
346
|
-
id: '#at-view',
|
347
|
-
holder: null,
|
348
|
-
_jqo: null,
|
349
|
-
jqo: function() {
|
350
|
-
var jqo;
|
351
|
-
jqo = this._jqo;
|
352
|
-
return jqo = _isNil(jqo) ? (this._jqo = $(this.id)) : jqo;
|
353
|
-
},
|
354
|
-
init: function() {
|
410
|
+
|
411
|
+
View.prototype.create_view = function() {
|
355
412
|
var $menu, tpl,
|
356
413
|
_this = this;
|
357
|
-
if (
|
414
|
+
if (this.exist()) {
|
358
415
|
return;
|
359
416
|
}
|
360
|
-
tpl = "<div id='" + this.id
|
417
|
+
tpl = "<div id='" + this.id + "' class='at-view'><ul id='" + this.id + "-ul'></ul></div>";
|
361
418
|
$("body").append(tpl);
|
362
|
-
|
419
|
+
this.$el = $("#" + this.id);
|
420
|
+
$menu = this.$el.find('ul');
|
363
421
|
return $menu.on('mouseenter.view', 'li', function(e) {
|
364
422
|
$menu.find('.cur').removeClass('cur');
|
365
423
|
return $(e.currentTarget).addClass('cur');
|
366
424
|
}).on('click', function(e) {
|
367
425
|
e.stopPropagation();
|
368
426
|
e.preventDefault();
|
369
|
-
return _this.choose();
|
427
|
+
return _this.$el.data("_view").choose();
|
370
428
|
});
|
371
|
-
}
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
429
|
+
};
|
430
|
+
|
431
|
+
View.prototype.exist = function() {
|
432
|
+
return $("#" + this.id).length > 0;
|
433
|
+
};
|
434
|
+
|
435
|
+
View.prototype.visible = function() {
|
436
|
+
return this.$el.is(":visible");
|
437
|
+
};
|
438
|
+
|
439
|
+
View.prototype.choose = function() {
|
440
|
+
var $li;
|
441
|
+
$li = this.$el.find(".cur");
|
442
|
+
this.controller.callbacks("selector").call(this.controller, $li);
|
443
|
+
this.controller.trigger("choose", [$li]);
|
380
444
|
return this.hide();
|
381
|
-
}
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
445
|
+
};
|
446
|
+
|
447
|
+
View.prototype.reposition = function() {
|
448
|
+
var offset, rect;
|
449
|
+
rect = this.controller.rect();
|
450
|
+
if (rect.bottom + this.$el.height() - $(window).scrollTop() > $(window).height()) {
|
451
|
+
rect.bottom = rect.top - this.$el.height();
|
387
452
|
}
|
388
|
-
|
389
|
-
left: rect.left,
|
390
|
-
top: rect.bottom
|
391
|
-
});
|
392
|
-
return this.jqo().offset({
|
453
|
+
offset = {
|
393
454
|
left: rect.left,
|
394
455
|
top: rect.bottom
|
395
|
-
}
|
396
|
-
|
397
|
-
|
456
|
+
};
|
457
|
+
this.$el.offset(offset);
|
458
|
+
return this.controller.trigger("reposition", [offset]);
|
459
|
+
};
|
460
|
+
|
461
|
+
View.prototype.next = function() {
|
398
462
|
var cur, next;
|
399
|
-
cur = this.
|
463
|
+
cur = this.$el.find('.cur').removeClass('cur');
|
400
464
|
next = cur.next();
|
401
465
|
if (!next.length) {
|
402
|
-
next = $(this.
|
466
|
+
next = $(this.$el.find('li')[0]);
|
403
467
|
}
|
404
468
|
return next.addClass('cur');
|
405
|
-
}
|
406
|
-
|
469
|
+
};
|
470
|
+
|
471
|
+
View.prototype.prev = function() {
|
407
472
|
var cur, prev;
|
408
|
-
cur = this.
|
473
|
+
cur = this.$el.find('.cur').removeClass('cur');
|
409
474
|
prev = cur.prev();
|
410
475
|
if (!prev.length) {
|
411
|
-
prev = this.
|
476
|
+
prev = this.$el.find('li').last();
|
412
477
|
}
|
413
478
|
return prev.addClass('cur');
|
414
|
-
}
|
415
|
-
|
416
|
-
|
417
|
-
|
479
|
+
};
|
480
|
+
|
481
|
+
View.prototype.show = function() {
|
482
|
+
if (!this.visible()) {
|
483
|
+
this.$el.show();
|
418
484
|
}
|
419
|
-
return this.
|
420
|
-
}
|
421
|
-
|
485
|
+
return this.reposition();
|
486
|
+
};
|
487
|
+
|
488
|
+
View.prototype.hide = function(time) {
|
422
489
|
var callback,
|
423
490
|
_this = this;
|
424
491
|
if (isNaN(time)) {
|
425
|
-
if (this.
|
426
|
-
return this.
|
492
|
+
if (this.visible()) {
|
493
|
+
return this.$el.hide();
|
427
494
|
}
|
428
495
|
} else {
|
429
496
|
callback = function() {
|
430
497
|
return _this.hide();
|
431
498
|
};
|
432
499
|
clearTimeout(this.timeout_id);
|
433
|
-
return this.timeout_id = setTimeout(callback,
|
434
|
-
}
|
435
|
-
},
|
436
|
-
clear: function(clear_all) {
|
437
|
-
if (clear_all === true) {
|
438
|
-
this._cache = {};
|
500
|
+
return this.timeout_id = setTimeout(callback, time);
|
439
501
|
}
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
502
|
+
};
|
503
|
+
|
504
|
+
View.prototype.clear = function() {
|
505
|
+
return this.$el.find('ul').empty();
|
506
|
+
};
|
507
|
+
|
508
|
+
View.prototype.render = function(list) {
|
509
|
+
var $ul, tpl,
|
510
|
+
_this = this;
|
444
511
|
if (!$.isArray(list)) {
|
445
512
|
return false;
|
446
513
|
}
|
@@ -448,169 +515,98 @@
|
|
448
515
|
this.hide();
|
449
516
|
return true;
|
450
517
|
}
|
451
|
-
this.holder = holder;
|
452
|
-
holder.cache(list);
|
453
518
|
this.clear();
|
454
|
-
|
455
|
-
|
519
|
+
this.$el.data("_view", this);
|
520
|
+
$ul = this.$el.find('ul');
|
521
|
+
tpl = this.controller.get_opt('tpl', DEFAULT_TPL);
|
456
522
|
$.each(list, function(i, item) {
|
457
|
-
var li;
|
458
|
-
|
459
|
-
li =
|
460
|
-
|
461
|
-
return $ul.append(
|
523
|
+
var $li, li;
|
524
|
+
li = _this.controller.callbacks("tpl_eval").call(_this.controller, tpl, item);
|
525
|
+
$li = $(_this.controller.callbacks("highlighter").call(_this.controller, li, _this.controller.query.text));
|
526
|
+
$li.data("info", item);
|
527
|
+
return $ul.append($li);
|
462
528
|
});
|
463
529
|
this.show();
|
464
530
|
return $ul.find("li:eq(0)").addClass("cur");
|
465
|
-
}
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
name: item
|
473
|
-
};
|
474
|
-
}
|
475
|
-
return item;
|
476
|
-
});
|
477
|
-
};
|
478
|
-
_evalTpl = function(tpl, map) {
|
479
|
-
var el;
|
480
|
-
try {
|
481
|
-
return el = tpl.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) {
|
482
|
-
return map[key];
|
483
|
-
});
|
484
|
-
} catch (error) {
|
485
|
-
return "";
|
486
|
-
}
|
487
|
-
};
|
488
|
-
_highlighter = function(li, query) {
|
489
|
-
if (_isNil(query)) {
|
490
|
-
return li;
|
491
|
-
}
|
492
|
-
return li.replace(new RegExp(">\\s*(\\w*)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig'), function(str, $1, $2, $3) {
|
493
|
-
return '> ' + $1 + '<strong>' + $2 + '</strong>' + $3 + ' <';
|
494
|
-
});
|
495
|
-
};
|
496
|
-
_sorter = function(items) {
|
497
|
-
var data_value, item, query, results, text, _i, _len;
|
498
|
-
data_value = this.dataValue();
|
499
|
-
query = this.query.text;
|
500
|
-
results = [];
|
501
|
-
for (_i = 0, _len = items.length; _i < _len; _i++) {
|
502
|
-
item = items[_i];
|
503
|
-
text = item[data_value];
|
504
|
-
if (text.toLowerCase().indexOf(query) === -1) {
|
505
|
-
continue;
|
506
|
-
}
|
507
|
-
item.order = text.toLowerCase().indexOf(query);
|
508
|
-
results.push(item);
|
509
|
-
}
|
510
|
-
results.sort(function(a, b) {
|
511
|
-
return a.order - b.order;
|
512
|
-
});
|
513
|
-
return results;
|
514
|
-
};
|
515
|
-
/*
|
516
|
-
maybe we can use $._unique.
|
517
|
-
But i don't know it will delete li element frequently or not.
|
518
|
-
I think we should not change DOM element frequently.
|
519
|
-
more, It seems batter not to call evalTpl function too much times.
|
520
|
-
*/
|
521
|
-
|
522
|
-
_unique = function(list, query) {
|
523
|
-
var record;
|
524
|
-
record = [];
|
525
|
-
return $.map(list, function(v, id) {
|
526
|
-
var value;
|
527
|
-
value = $.isPlainObject(v) ? v[query] : v;
|
528
|
-
if ($.inArray(value, record) < 0) {
|
529
|
-
record.push(value);
|
530
|
-
return v;
|
531
|
-
}
|
532
|
-
});
|
533
|
-
};
|
534
|
-
_isNil = function(target) {
|
535
|
-
return !target || ($.isPlainObject(target) && $.isEmptyObject(target)) || ($.isArray(target) && target.length === 0) || (target instanceof $ && target.length === 0) || target === void 0;
|
536
|
-
};
|
537
|
-
_DEFAULT_TPL = "<li id='${id}' data-value='${name}'>${name}</li>";
|
538
|
-
log = function() {};
|
539
|
-
$.fn.atWho = function(flag, options) {
|
540
|
-
AtView.init();
|
531
|
+
};
|
532
|
+
|
533
|
+
return View;
|
534
|
+
|
535
|
+
})();
|
536
|
+
DEFAULT_TPL = "<li data-value='${name}'>${name}</li>";
|
537
|
+
$.fn.atwho = function(flag, options) {
|
541
538
|
return this.filter('textarea, input').each(function() {
|
542
539
|
var $this, data;
|
543
540
|
$this = $(this);
|
544
|
-
data = $this.data("
|
541
|
+
data = $this.data("atwho");
|
545
542
|
if (!data) {
|
546
|
-
$this.data('
|
543
|
+
$this.data('atwho', (data = new Controller(this)));
|
547
544
|
}
|
548
545
|
return data.reg(flag, options);
|
549
546
|
});
|
550
547
|
};
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
548
|
+
$.fn.atwho.Controller = Controller;
|
549
|
+
$.fn.atwho.View = View;
|
550
|
+
$.fn.atwho.Mirror = Mirror;
|
551
|
+
return $.fn.atwho["default"] = {
|
552
|
+
data: null,
|
553
|
+
search_key: "name",
|
554
|
+
callbacks: DEFAULT_CALLBACKS,
|
556
555
|
limit: 5,
|
557
556
|
display_flag: true,
|
558
|
-
|
557
|
+
display_timeout: 300,
|
558
|
+
tpl: DEFAULT_TPL
|
559
559
|
};
|
560
|
-
})
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
*/
|
593
|
-
|
594
|
-
|
595
|
-
(function($) {
|
560
|
+
});
|
561
|
+
|
562
|
+
}).call(this);
|
563
|
+
|
564
|
+
|
565
|
+
/*
|
566
|
+
Implement Github like autocomplete mentions
|
567
|
+
http://ichord.github.com/At.js
|
568
|
+
|
569
|
+
Copyright (c) 2013 chord.luo@gmail.com
|
570
|
+
Licensed under the MIT license.
|
571
|
+
*/
|
572
|
+
|
573
|
+
|
574
|
+
/*
|
575
|
+
本插件操作 textarea 或者 input 内的插入符
|
576
|
+
只实现了获得插入符在文本框中的位置,我设置
|
577
|
+
插入符的位置.
|
578
|
+
*/
|
579
|
+
|
580
|
+
|
581
|
+
(function() {
|
582
|
+
|
583
|
+
(function(factory) {
|
584
|
+
if (typeof exports === 'object') {
|
585
|
+
return factory(require('jquery'));
|
586
|
+
} else if (typeof define === 'function' && define.amd) {
|
587
|
+
return define(['jquery']);
|
588
|
+
} else {
|
589
|
+
return factory(window.jQuery);
|
590
|
+
}
|
591
|
+
})(function($) {
|
596
592
|
var getCaretPos, setCaretPos;
|
597
593
|
getCaretPos = function(inputor) {
|
598
594
|
var end, endRange, len, normalizedValue, pos, range, start, textInputRange;
|
599
595
|
if (document.selection) {
|
600
596
|
/*
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
597
|
+
#assume we select "HATE" in the inputor such as textarea -> { }.
|
598
|
+
* start end-point.
|
599
|
+
* /
|
600
|
+
* < I really [HATE] IE > between the brackets is the selection range.
|
601
|
+
* \
|
602
|
+
* end end-point.
|
607
603
|
*/
|
608
604
|
|
609
605
|
range = document.selection.createRange();
|
610
606
|
pos = 0;
|
611
607
|
if (range && range.parentElement() === inputor) {
|
612
608
|
normalizedValue = inputor.value.replace(/\r\n/g, "\n");
|
613
|
-
/* SOMETIME !!!
|
609
|
+
/* SOMETIME !!!
|
614
610
|
"/r/n" is counted as two char.
|
615
611
|
one line is two, two will be four. balalala.
|
616
612
|
so we have to using the normalized one's length.;
|
@@ -618,8 +614,8 @@
|
|
618
614
|
|
619
615
|
len = normalizedValue.length;
|
620
616
|
/*
|
621
|
-
|
622
|
-
|
617
|
+
<[ I really HATE IE ]>:
|
618
|
+
the whole content in the inputor will be the textInputRange.
|
623
619
|
*/
|
624
620
|
|
625
621
|
textInputRange = inputor.createTextRange();
|
@@ -639,26 +635,26 @@
|
|
639
635
|
|
640
636
|
endRange.collapse(false);
|
641
637
|
/*
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
638
|
+
___VS____
|
639
|
+
/ \
|
640
|
+
< I really [[HATE] IE []]>
|
641
|
+
\_endRange end-point.
|
642
|
+
|
643
|
+
" > -1" mean the start end-point will be the same or right to the end end-point
|
644
|
+
* simplelly, all in the end.
|
649
645
|
*/
|
650
646
|
|
651
647
|
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
|
652
648
|
start = end = len;
|
653
649
|
} else {
|
654
650
|
/*
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
651
|
+
I really |HATE] IE ]>
|
652
|
+
<-|
|
653
|
+
I really[ [HATE] IE ]>
|
654
|
+
<-[
|
655
|
+
I reall[y [HATE] IE ]>
|
656
|
+
|
657
|
+
will return how many unit have moved.
|
662
658
|
*/
|
663
659
|
|
664
660
|
start = -textInputRange.moveStart("character", -len);
|
@@ -690,6 +686,6 @@
|
|
690
686
|
return getCaretPos(inputor);
|
691
687
|
}
|
692
688
|
};
|
693
|
-
})
|
689
|
+
});
|
694
690
|
|
695
691
|
}).call(this);
|
@@ -1,47 +1 @@
|
|
1
|
-
#at-view {
|
2
|
-
position:absolute;
|
3
|
-
top: 0;
|
4
|
-
left: 0;
|
5
|
-
display: none;
|
6
|
-
margin-top: 18px;
|
7
|
-
background: white;
|
8
|
-
border: 1px solid #DDD;
|
9
|
-
border-radius: 3px;
|
10
|
-
box-shadow: 0 0 5px rgba(0,0,0,0.1);
|
11
|
-
min-width: 120px;
|
12
|
-
}
|
13
|
-
|
14
|
-
#at-view .cur {
|
15
|
-
background: #3366FF;
|
16
|
-
color: white;
|
17
|
-
}
|
18
|
-
#at-view .cur small {
|
19
|
-
color: white;
|
20
|
-
}
|
21
|
-
#at-view strong {
|
22
|
-
color: #3366FF;
|
23
|
-
}
|
24
|
-
#at-view .cur strong {
|
25
|
-
color: white;
|
26
|
-
font:bold;
|
27
|
-
}
|
28
|
-
#at-view ul {
|
29
|
-
/* width: 100px; */
|
30
|
-
list-style:none;
|
31
|
-
padding:0;
|
32
|
-
margin:auto;
|
33
|
-
}
|
34
|
-
#at-view ul li {
|
35
|
-
display: block;
|
36
|
-
padding: 5px 10px;
|
37
|
-
border-bottom: 1px solid #DDD;
|
38
|
-
cursor: pointer;
|
39
|
-
/* border-top: 1px solid #C8C8C8; */
|
40
|
-
}
|
41
|
-
#at-view small {
|
42
|
-
font-size: smaller;
|
43
|
-
color: #777;
|
44
|
-
font-weight: normal;
|
45
|
-
}
|
46
|
-
|
47
|
-
|
1
|
+
#at-view{position:absolute;top:0;left:0;display:none;margin-top:18px;background:#fff;border:1px solid #DDD;border-radius:3px;box-shadow:0 0 5px rgba(0,0,0,.1);min-width:120px;z-index:10}#at-view .cur{background:#36F;color:#fff}#at-view .cur small{color:#fff}#at-view strong{color:#36F}#at-view .cur strong{color:#fff;font:bold}#at-view ul{list-style:none;padding:0;margin:auto}#at-view ul li{display:block;padding:5px 10px;border-bottom:1px solid #DDD;cursor:pointer}#at-view small{font-size:smaller;color:#777;font-weight:400}
|
data/lib/jquery-atwho-rails.rb
CHANGED
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.1
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -43,8 +43,7 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
-
description: ! "This is a jQuery plugin
|
47
|
-
mentions."
|
46
|
+
description: ! "This is a jQuery plugin\n that implement Github-like mentions."
|
48
47
|
email:
|
49
48
|
- chord.luo@gmail.com
|
50
49
|
executables: []
|
@@ -76,12 +75,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
76
75
|
- - ! '>='
|
77
76
|
- !ruby/object:Gem::Version
|
78
77
|
version: '0'
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
hash: -3411578706402898122
|
79
81
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
82
|
none: false
|
81
83
|
requirements:
|
82
84
|
- - ! '>='
|
83
85
|
- !ruby/object:Gem::Version
|
84
86
|
version: '0'
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
hash: -3411578706402898122
|
85
90
|
requirements: []
|
86
91
|
rubyforge_project: jquery-atwho-rails
|
87
92
|
rubygems_version: 1.8.24
|
@@ -91,4 +96,3 @@ summary: ! 'jquery plugin: @mentions'
|
|
91
96
|
test_files:
|
92
97
|
- spec/generators/install_generator_spec.rb
|
93
98
|
- spec/spec_helper.rb
|
94
|
-
has_rdoc:
|