jquery-atwho-rails 0.3.3 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f23f3dd69a13e3d32ba15c24cf482ae50f7c25de
4
- data.tar.gz: 515be810af285936cdb4bf39a92f6a0c9b831f96
3
+ metadata.gz: ee0d4a6e119e2f77127b810901f3572f95cf1d62
4
+ data.tar.gz: 02c7cea94f2a89ff6eff5ffdeb74eb57b3dc1c64
5
5
  SHA512:
6
- metadata.gz: b65e6355e267e761c7235fafcff88510a3fa3e7453fb40be0d726351875bcbe7ac6805a268172af0af53412939b99c5421d227df286c455ad9ff410467109af1
7
- data.tar.gz: 93d434497c9da9508767bf21bf7c1fe673f869f1e25abfc35ce1d3426d732499273c3d96467887d55fedb1d15341a6131e1e725a9e33757f6af38b7e9ab04a09
6
+ metadata.gz: 37fb91bd4a88c5dae9c152eda4cedf20be7270b3a567581e51e510f791b4c44cae23c53a42c502a1342f8f89ff13b67a3a035780689b3e28caf20a4a56e2e64e
7
+ data.tar.gz: b65c453e756f540f774b5cc32e6d9ef9b9c402852fbb3528432c1f2ada50a89ef154e648552a36d0bb2204144cd5855ecd8b42519f75f89f573d4880c75c8f89
@@ -24,110 +24,196 @@
24
24
  }
25
25
  })(function($) {
26
26
  "use strict";
27
- var Caret, Mirror, methods, pluginName;
27
+ var EditableCaret, InputCaret, Mirror, Utils, methods, pluginName;
28
28
 
29
29
  pluginName = 'caret';
30
- Caret = (function() {
31
- function Caret($inputor) {
30
+ EditableCaret = (function() {
31
+ function EditableCaret($inputor) {
32
32
  this.$inputor = $inputor;
33
33
  this.domInputor = this.$inputor[0];
34
34
  }
35
35
 
36
- Caret.prototype.getPos = function() {
37
- var end, endRange, inputor, len, normalizedValue, pos, range, start, textInputRange;
36
+ EditableCaret.prototype.setPos = function(pos) {
37
+ return this.domInputor;
38
+ };
38
39
 
39
- inputor = this.domInputor;
40
- inputor.focus();
41
- if (document.selection) {
42
- /*
43
- #assume we select "HATE" in the inputor such as textarea -> { }.
44
- * start end-point.
45
- * /
46
- * < I really [HATE] IE > between the brackets is the selection range.
47
- * \
48
- * end end-point.
49
- */
40
+ EditableCaret.prototype.getIEPosition = function() {
41
+ return $.noop();
42
+ };
50
43
 
51
- range = document.selection.createRange();
52
- pos = 0;
53
- if (range && range.parentElement() === inputor) {
54
- normalizedValue = inputor.value.replace(/\r\n/g, "\n");
55
- /* SOMETIME !!!
56
- "/r/n" is counted as two char.
57
- one line is two, two will be four. balalala.
58
- so we have to using the normalized one's length.;
59
- */
60
-
61
- len = normalizedValue.length;
62
- /*
63
- <[ I really HATE IE ]>:
64
- the whole content in the inputor will be the textInputRange.
65
- */
66
-
67
- textInputRange = inputor.createTextRange();
68
- /* _here must be the position of bookmark.
69
- /
70
- <[ I really [HATE] IE ]>
71
- [---------->[ ] : this is what moveToBookmark do.
72
- < I really [[HATE] IE ]> : here is result.
73
- \ two brackets in should be in line.
74
- */
75
-
76
- textInputRange.moveToBookmark(range.getBookmark());
77
- endRange = inputor.createTextRange();
78
- /* [--------------------->[] : if set false all end-point goto end.
79
- < I really [[HATE] IE []]>
80
- */
81
-
82
- endRange.collapse(false);
83
- /*
84
- ___VS____
85
- / \
86
- < I really [[HATE] IE []]>
87
- \_endRange end-point.
88
-
89
- " > -1" mean the start end-point will be the same or right to the end end-point
90
- * simplelly, all in the end.
91
- */
92
-
93
- if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
94
- start = end = len;
95
- } else {
96
- /*
97
- I really |HATE] IE ]>
98
- <-|
99
- I really[ [HATE] IE ]>
100
- <-[
101
- I reall[y [HATE] IE ]>
102
-
103
- will return how many unit have moved.
104
- */
105
-
106
- start = -textInputRange.moveStart("character", -len);
107
- end = -textInputRange.moveEnd("character", -len);
108
- }
44
+ EditableCaret.prototype.getPosition = function() {
45
+ return $.noop();
46
+ };
47
+
48
+ EditableCaret.prototype.getOldIEPos = function() {
49
+ var preCaretTextRange, textRange;
50
+
51
+ textRange = document.selection.createRange();
52
+ preCaretTextRange = document.body.createTextRange();
53
+ preCaretTextRange.moveToElementText(this.domInputor);
54
+ preCaretTextRange.setEndPoint("EndToEnd", textRange);
55
+ return preCaretTextRange.text.length;
56
+ };
57
+
58
+ EditableCaret.prototype.getPos = function() {
59
+ var clonedRange, pos, range;
60
+
61
+ if (range = this.range()) {
62
+ clonedRange = range.cloneRange();
63
+ clonedRange.selectNodeContents(this.domInputor);
64
+ clonedRange.setEnd(range.endContainer, range.endOffset);
65
+ pos = clonedRange.toString().length;
66
+ clonedRange.detach();
67
+ return pos;
68
+ } else if (document.selection) {
69
+ return this.getOldIEPos();
70
+ }
71
+ };
72
+
73
+ EditableCaret.prototype.getOldIEOffset = function() {
74
+ var range, rect;
75
+
76
+ range = document.selection.createRange().duplicate();
77
+ range.moveStart("character", -1);
78
+ rect = range.getBoundingClientRect();
79
+ return {
80
+ height: rect.bottom - rect.top,
81
+ left: rect.left,
82
+ top: rect.top
83
+ };
84
+ };
85
+
86
+ EditableCaret.prototype.getOffset = function(pos) {
87
+ var clonedRange, offset, range, rect;
88
+
89
+ offset = null;
90
+ if (window.getSelection && (range = this.range())) {
91
+ if (range.endOffset - 1 < 0) {
92
+ return null;
93
+ }
94
+ clonedRange = range.cloneRange();
95
+ clonedRange.setStart(range.endContainer, range.endOffset - 1);
96
+ clonedRange.setEnd(range.endContainer, range.endOffset);
97
+ rect = clonedRange.getBoundingClientRect();
98
+ offset = {
99
+ height: rect.height,
100
+ left: rect.left + rect.width,
101
+ top: rect.top
102
+ };
103
+ clonedRange.detach();
104
+ offset;
105
+ } else if (document.selection) {
106
+ this.getOldIEOffset();
107
+ }
108
+ return Utils.adjustOffset(offset, this.$inputor);
109
+ };
110
+
111
+ EditableCaret.prototype.range = function() {
112
+ var sel;
113
+
114
+ if (!window.getSelection) {
115
+ return;
116
+ }
117
+ sel = window.getSelection();
118
+ if (sel.rangeCount > 0) {
119
+ return sel.getRangeAt(0);
120
+ } else {
121
+ return null;
122
+ }
123
+ };
124
+
125
+ return EditableCaret;
126
+
127
+ })();
128
+ InputCaret = (function() {
129
+ function InputCaret($inputor) {
130
+ this.$inputor = $inputor;
131
+ this.domInputor = this.$inputor[0];
132
+ }
133
+
134
+ InputCaret.prototype.getIEPos = function() {
135
+ var endRange, inputor, len, normalizedValue, pos, range, textInputRange;
136
+
137
+ inputor = this.domInputor;
138
+ range = document.selection.createRange();
139
+ pos = 0;
140
+ if (range && range.parentElement() === inputor) {
141
+ normalizedValue = inputor.value.replace(/\r\n/g, "\n");
142
+ len = normalizedValue.length;
143
+ textInputRange = inputor.createTextRange();
144
+ textInputRange.moveToBookmark(range.getBookmark());
145
+ endRange = inputor.createTextRange();
146
+ endRange.collapse(false);
147
+ if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
148
+ pos = len;
149
+ } else {
150
+ pos = -textInputRange.moveStart("character", -len);
109
151
  }
152
+ }
153
+ return pos;
154
+ };
155
+
156
+ InputCaret.prototype.getPos = function() {
157
+ if (document.selection) {
158
+ return this.getIEPos();
110
159
  } else {
111
- start = inputor.selectionStart;
160
+ return this.domInputor.selectionStart;
112
161
  }
113
- return start;
114
162
  };
115
163
 
116
- Caret.prototype.setPos = function(pos) {
164
+ InputCaret.prototype.setPos = function(pos) {
117
165
  var inputor, range;
118
166
 
119
167
  inputor = this.domInputor;
120
168
  if (document.selection) {
121
169
  range = inputor.createTextRange();
122
170
  range.move("character", pos);
123
- return range.select();
171
+ range.select();
172
+ } else if (inputor.setSelectionRange) {
173
+ inputor.setSelectionRange(pos, pos);
174
+ }
175
+ return inputor;
176
+ };
177
+
178
+ InputCaret.prototype.getIEOffset = function(pos) {
179
+ var h, range, textRange, x, y;
180
+
181
+ textRange = this.domInputor.createTextRange();
182
+ if (pos) {
183
+ textRange.move('character', pos);
184
+ } else {
185
+ range = document.selection.createRange();
186
+ textRange.moveToBookmark(range.getBookmark());
187
+ }
188
+ x = textRange.boundingLeft;
189
+ y = textRange.boundingTop;
190
+ h = textRange.boundingHeight;
191
+ return {
192
+ left: x,
193
+ top: y,
194
+ height: h
195
+ };
196
+ };
197
+
198
+ InputCaret.prototype.getOffset = function(pos) {
199
+ var $inputor, offset, position;
200
+
201
+ $inputor = this.$inputor;
202
+ if (document.selection) {
203
+ return Utils.adjustOffset(this.getIEOffset(pos), $inputor);
124
204
  } else {
125
- return inputor.setSelectionRange(pos, pos);
205
+ offset = $inputor.offset();
206
+ position = this.getPosition(pos);
207
+ return offset = {
208
+ left: offset.left + position.left,
209
+ top: offset.top + position.top,
210
+ height: position.height
211
+ };
126
212
  }
127
213
  };
128
214
 
129
- Caret.prototype.getPosition = function(pos) {
130
- var $inputor, at_rect, format, h, html, mirror, start_range, x, y;
215
+ InputCaret.prototype.getPosition = function(pos) {
216
+ var $inputor, at_rect, format, html, mirror, start_range;
131
217
 
132
218
  $inputor = this.$inputor;
133
219
  format = function(value) {
@@ -140,34 +226,10 @@
140
226
  html = "<span>" + format(start_range) + "</span>";
141
227
  html += "<span id='caret'>|</span>";
142
228
  mirror = new Mirror($inputor);
143
- at_rect = mirror.create(html).rect();
144
- x = at_rect.left - $inputor.scrollLeft();
145
- y = at_rect.top - $inputor.scrollTop();
146
- h = at_rect.height;
147
- return {
148
- left: x,
149
- top: y,
150
- height: h
151
- };
152
- };
153
-
154
- Caret.prototype.getOffset = function(pos) {
155
- var $inputor, h, offset, position, x, y;
156
-
157
- $inputor = this.$inputor;
158
- offset = $inputor.offset();
159
- position = this.getPosition(pos);
160
- x = offset.left + position.left;
161
- y = offset.top + position.top;
162
- h = position.height;
163
- return {
164
- left: x,
165
- top: y,
166
- height: h
167
- };
229
+ return at_rect = mirror.create(html).rect();
168
230
  };
169
231
 
170
- Caret.prototype.getIEPosition = function(pos) {
232
+ InputCaret.prototype.getIEPosition = function(pos) {
171
233
  var h, inputorOffset, offset, x, y;
172
234
 
173
235
  offset = this.getIEOffset(pos);
@@ -182,27 +244,7 @@
182
244
  };
183
245
  };
184
246
 
185
- Caret.prototype.getIEOffset = function(pos) {
186
- var h, range, textRange, x, y;
187
-
188
- textRange = this.domInputor.createTextRange();
189
- if (pos) {
190
- textRange.move('character', pos);
191
- } else {
192
- range = document.selection.createRange();
193
- textRange.moveToBookmark(range.getBookmark());
194
- }
195
- x = textRange.boundingLeft + this.$inputor.scrollLeft();
196
- y = textRange.boundingTop + $(window).scrollTop() + this.$inputor.scrollTop();
197
- h = textRange.boundingHeight;
198
- return {
199
- left: x,
200
- top: y,
201
- height: h
202
- };
203
- };
204
-
205
- return Caret;
247
+ return InputCaret;
206
248
 
207
249
  })();
208
250
  Mirror = (function() {
@@ -254,6 +296,19 @@
254
296
  return Mirror;
255
297
 
256
298
  })();
299
+ Utils = {
300
+ adjustOffset: function(offset, $inputor) {
301
+ if (!offset) {
302
+ return;
303
+ }
304
+ offset.top += $(window).scrollTop() + $inputor.scrollTop();
305
+ offset.left += +$(window).scrollLeft() + $inputor.scrollLeft();
306
+ return offset;
307
+ },
308
+ contentEditable: function($inputor) {
309
+ return !!($inputor[0].contentEditable && $inputor[0].contentEditable === 'true');
310
+ }
311
+ };
257
312
  methods = {
258
313
  pos: function(pos) {
259
314
  if (pos) {
@@ -270,23 +325,23 @@
270
325
  }
271
326
  },
272
327
  offset: function(pos) {
273
- if (document.selection) {
274
- return this.getIEOffset(pos);
275
- } else {
276
- return this.getOffset(pos);
277
- }
328
+ return this.getOffset(pos);
278
329
  }
279
330
  };
280
- return $.fn.caret = function(method) {
331
+ $.fn.caret = function(method) {
281
332
  var caret;
282
333
 
283
- caret = new Caret(this);
334
+ caret = Utils.contentEditable(this) ? new EditableCaret(this) : new InputCaret(this);
284
335
  if (methods[method]) {
285
336
  return methods[method].apply(caret, Array.prototype.slice.call(arguments, 1));
286
337
  } else {
287
338
  return $.error("Method " + method + " does not exist on jQuery.caret");
288
339
  }
289
340
  };
341
+ $.fn.caret.EditableCaret = EditableCaret;
342
+ $.fn.caret.InputCaret = InputCaret;
343
+ $.fn.caret.Utils = Utils;
344
+ return $.fn.caret.apis = methods;
290
345
  });
291
346
 
292
347
  }).call(this);
@@ -311,7 +366,7 @@
311
366
  return factory(window.jQuery);
312
367
  }
313
368
  })(function($) {
314
- var $CONTAINER, Api, App, Controller, DEFAULT_CALLBACKS, DEFAULT_TPL, KEY_CODE, Model, View;
369
+ var $CONTAINER, Api, App, Atwho, Controller, DEFAULT_CALLBACKS, KEY_CODE, Model, View;
315
370
  App = (function() {
316
371
 
317
372
  function App(inputor) {
@@ -321,12 +376,12 @@
321
376
  this.listen();
322
377
  }
323
378
 
324
- App.prototype.controller = function(key) {
325
- return this.controllers[key || this.current_flag];
379
+ App.prototype.controller = function(at) {
380
+ return this.controllers[at || this.current_flag];
326
381
  };
327
382
 
328
- App.prototype.set_context_for = function(key) {
329
- this.current_flag = key;
383
+ App.prototype.set_context_for = function(at) {
384
+ this.current_flag = at;
330
385
  return this;
331
386
  };
332
387
 
@@ -361,7 +416,7 @@
361
416
  var _this = this;
362
417
  return $.map(this.controllers, function(c) {
363
418
  if (c.look_up()) {
364
- return _this.set_context_for(c.key);
419
+ return _this.set_context_for(c.at);
365
420
  }
366
421
  });
367
422
  };
@@ -428,14 +483,16 @@
428
483
  return _uuid += 1;
429
484
  };
430
485
 
431
- function Controller(app, key) {
486
+ function Controller(app, at) {
432
487
  this.app = app;
433
- this.key = key;
488
+ this.at = at;
434
489
  this.$inputor = this.app.$inputor;
435
490
  this.id = this.$inputor[0].id || uuid();
436
491
  this.setting = null;
437
492
  this.query = null;
438
493
  this.pos = 0;
494
+ this.cur_rect = null;
495
+ this.range = null;
439
496
  $CONTAINER.append(this.$el = $("<div id='atwho-ground-" + this.id + "'></div>"));
440
497
  this.model = new Model(this);
441
498
  this.view = new View(this);
@@ -443,6 +500,7 @@
443
500
 
444
501
  Controller.prototype.init = function(setting) {
445
502
  this.setting = $.extend({}, this.setting || $.fn.atwho["default"], setting);
503
+ this.view.init();
446
504
  return this.model.reload(this.setting.data);
447
505
  };
448
506
 
@@ -468,20 +526,28 @@
468
526
  return this.get_opt("callbacks")[func_name] || DEFAULT_CALLBACKS[func_name];
469
527
  };
470
528
 
471
- Controller.prototype.get_opt = function(key, default_value) {
529
+ Controller.prototype.get_opt = function(at, default_value) {
472
530
  try {
473
- return this.setting[key];
531
+ return this.setting[at];
474
532
  } catch (e) {
475
533
  return null;
476
534
  }
477
535
  };
478
536
 
537
+ Controller.prototype.content = function() {
538
+ if (this.$inputor.is('textarea, input')) {
539
+ return this.$inputor.val();
540
+ } else {
541
+ return this.$inputor.text();
542
+ }
543
+ };
544
+
479
545
  Controller.prototype.catch_query = function() {
480
546
  var caret_pos, content, end, query, start, subtext;
481
- content = this.$inputor.val();
547
+ content = this.content();
482
548
  caret_pos = this.$inputor.caret('pos');
483
549
  subtext = content.slice(0, caret_pos);
484
- query = this.callbacks("matcher").call(this, this.key, subtext, this.get_opt('start_with_space'));
550
+ query = this.callbacks("matcher").call(this, this.at, subtext, this.get_opt('start_with_space'));
485
551
  if (typeof query === "string" && query.length <= this.get_opt('max_len', 20)) {
486
552
  start = caret_pos - query.length;
487
553
  end = start + query.length;
@@ -491,7 +557,7 @@
491
557
  'head_pos': start,
492
558
  'end_pos': end
493
559
  };
494
- this.trigger("matched", [this.key, query.text]);
560
+ this.trigger("matched", [this.at, query.text]);
495
561
  } else {
496
562
  this.view.hide();
497
563
  }
@@ -500,7 +566,12 @@
500
566
 
501
567
  Controller.prototype.rect = function() {
502
568
  var c, scale_bottom;
503
- c = this.$inputor.caret('offset', this.pos - 1);
569
+ if (!(c = this.$inputor.caret('offset', this.pos - 1))) {
570
+ return;
571
+ }
572
+ if (this.$inputor.attr('contentEditable') === 'true') {
573
+ c = (this.cur_rect || (this.cur_rect = c)) || c;
574
+ }
504
575
  scale_bottom = document.selection ? 0 : 2;
505
576
  return {
506
577
  left: c.left,
@@ -509,15 +580,78 @@
509
580
  };
510
581
  };
511
582
 
512
- Controller.prototype.insert = function(str) {
513
- var $inputor, source, start_str, text;
583
+ Controller.prototype.reset_rect = function() {
584
+ if (this.$inputor.attr('contentEditable') === 'true') {
585
+ return this.cur_rect = null;
586
+ }
587
+ };
588
+
589
+ Controller.prototype.mark_range = function() {
590
+ return this.range = this.get_range() || this.get_ie_range();
591
+ };
592
+
593
+ Controller.prototype.clear_range = function() {
594
+ return this.range = null;
595
+ };
596
+
597
+ Controller.prototype.get_range = function() {
598
+ return this.range || (window.getSelection ? window.getSelection().getRangeAt(0) : void 0);
599
+ };
600
+
601
+ Controller.prototype.get_ie_range = function() {
602
+ return this.range || (document.selection ? document.selection.createRange() : void 0);
603
+ };
604
+
605
+ Controller.prototype.insert_content_for = function($li) {
606
+ var data, data_value, tpl;
607
+ data_value = $li.data('value');
608
+ tpl = this.get_opt('insert_tpl');
609
+ if (this.$inputor.is('textarea, input') || !tpl) {
610
+ return data_value;
611
+ }
612
+ data = $.extend({}, $li.data('item-data'), {
613
+ 'atwho-data-value': data_value,
614
+ 'atwho-at': this.at
615
+ });
616
+ return this.callbacks("tpl_eval").call(this, tpl, data);
617
+ };
618
+
619
+ Controller.prototype.insert = function(content, $li) {
620
+ var $inputor, $insert_node, class_name, content_node, insert_node, pos, range, sel, source, start_str, text;
514
621
  $inputor = this.$inputor;
515
- str = '' + str;
516
- source = $inputor.val();
517
- start_str = source.slice(0, this.query['head_pos'] || 0);
518
- text = "" + start_str + str + " " + (source.slice(this.query['end_pos'] || 0));
519
- $inputor.val(text);
520
- $inputor.caret('pos', start_str.length + str.length + 1);
622
+ if ($inputor.attr('contentEditable') === 'true') {
623
+ class_name = "atwho-view-flag atwho-view-flag-" + (this.get_opt('alias') || this.at);
624
+ content_node = "" + content + "<span contenteditable='false'>&nbsp;<span>";
625
+ insert_node = "<span contenteditable='false' class='" + class_name + "'>" + content_node + "</span>";
626
+ $insert_node = $(insert_node).data('atwho-data-item', $li.data('item-data'));
627
+ if (document.selection) {
628
+ $insert_node = $("<span contenteditable='true'></span>").html($insert_node);
629
+ }
630
+ }
631
+ if ($inputor.is('textarea, input')) {
632
+ content = '' + content;
633
+ source = $inputor.val();
634
+ start_str = source.slice(0, Math.max(this.query.head_pos - this.at.length, 0));
635
+ text = "" + start_str + content + " " + (source.slice(this.query['end_pos'] || 0));
636
+ $inputor.val(text);
637
+ $inputor.caret('pos', start_str.length + content.length + 1);
638
+ } else if (range = this.get_range()) {
639
+ pos = range.startOffset - (this.query.end_pos - this.query.head_pos) - this.at.length;
640
+ range.setStart(range.endContainer, Math.max(pos, 0));
641
+ range.setEnd(range.endContainer, range.endOffset);
642
+ range.deleteContents();
643
+ range.insertNode($insert_node[0]);
644
+ range.collapse(false);
645
+ sel = window.getSelection();
646
+ sel.removeAllRanges();
647
+ sel.addRange(range);
648
+ } else if (range = this.get_ie_range()) {
649
+ range.moveStart('character', this.query.end_pos - this.query.head_pos - this.at.length);
650
+ range.pasteHTML($insert_node[0]);
651
+ range.collapse(false);
652
+ range.select();
653
+ }
654
+ $inputor.focus();
521
655
  return $inputor.change();
522
656
  };
523
657
 
@@ -554,7 +688,7 @@
554
688
 
555
689
  function Model(context) {
556
690
  this.context = context;
557
- this.key = this.context.key;
691
+ this.at = this.context.at;
558
692
  }
559
693
 
560
694
  Model.prototype.saved = function() {
@@ -572,11 +706,11 @@
572
706
  };
573
707
 
574
708
  Model.prototype.fetch = function() {
575
- return _storage[this.key] || [];
709
+ return _storage[this.at] || [];
576
710
  };
577
711
 
578
712
  Model.prototype.save = function(data) {
579
- return _storage[this.key] = this.context.callbacks("before_save").call(this.context, data || []);
713
+ return _storage[this.at] = this.context.callbacks("before_save").call(this.context, data || []);
580
714
  };
581
715
 
582
716
  Model.prototype.load = function(data) {
@@ -609,25 +743,36 @@
609
743
 
610
744
  function View(context) {
611
745
  this.context = context;
612
- this.key = this.context.key;
613
- this.id = this.context.get_opt("alias") || ("at-view-" + (this.key.charCodeAt(0)));
614
- this.$el = $("<div id='" + this.id + "' class='atwho-view'><ul id='" + this.id + "-ul' class='atwho-view-url'></ul></div>");
746
+ this.$el = $("<div class='atwho-view'><ul class='atwho-view-ul'></ul></div>");
615
747
  this.timeout_id = null;
616
748
  this.context.$el.append(this.$el);
617
749
  this.bind_event();
618
750
  }
619
751
 
752
+ View.prototype.init = function() {
753
+ var id;
754
+ id = this.context.get_opt("alias") || this.context.at.charCodeAt(0);
755
+ return this.$el.attr({
756
+ 'id': "at-view-" + id
757
+ });
758
+ };
759
+
620
760
  View.prototype.bind_event = function() {
621
761
  var $menu,
622
762
  _this = this;
623
763
  $menu = this.$el.find('ul');
624
- return $menu.on('mouseenter.view', 'li', function(e) {
764
+ $menu.on('mouseenter.atwho-view', 'li', function(e) {
625
765
  $menu.find('.cur').removeClass('cur');
626
766
  return $(e.currentTarget).addClass('cur');
627
767
  }).on('click', function(e) {
628
768
  _this.choose();
629
769
  return e.preventDefault();
630
770
  });
771
+ return this.$el.on('mouseenter.atwho-view', 'ul', function(e) {
772
+ return _this.context.mark_range();
773
+ }).on('mouseleave.atwho-view', 'ul', function(e) {
774
+ return _this.context.clear_range();
775
+ });
631
776
  };
632
777
 
633
778
  View.prototype.visible = function() {
@@ -635,16 +780,16 @@
635
780
  };
636
781
 
637
782
  View.prototype.choose = function() {
638
- var $li;
783
+ var $li, content;
639
784
  $li = this.$el.find(".cur");
640
- this.context.insert(this.context.callbacks("before_insert").call(this.context, $li.data("value"), $li));
785
+ content = this.context.insert_content_for($li);
786
+ this.context.insert(this.context.callbacks("before_insert").call(this.context, content, $li), $li);
641
787
  this.context.trigger("inserted", [$li]);
642
788
  return this.hide();
643
789
  };
644
790
 
645
- View.prototype.reposition = function() {
646
- var offset, rect;
647
- rect = this.context.rect();
791
+ View.prototype.reposition = function(rect) {
792
+ var offset;
648
793
  if (rect.bottom + this.$el.height() - $(window).scrollTop() > $(window).height()) {
649
794
  rect.bottom = rect.top - this.$el.height();
650
795
  }
@@ -677,16 +822,20 @@
677
822
  };
678
823
 
679
824
  View.prototype.show = function() {
825
+ var rect;
680
826
  if (!this.visible()) {
681
827
  this.$el.show();
682
828
  }
683
- return this.reposition();
829
+ if (rect = this.context.rect()) {
830
+ return this.reposition(rect);
831
+ }
684
832
  };
685
833
 
686
834
  View.prototype.hide = function(time) {
687
835
  var callback,
688
836
  _this = this;
689
837
  if (isNaN(time && this.visible())) {
838
+ this.context.reset_rect();
690
839
  return this.$el.hide();
691
840
  } else {
692
841
  callback = function() {
@@ -705,12 +854,15 @@
705
854
  }
706
855
  this.$el.find('ul').empty();
707
856
  $ul = this.$el.find('ul');
708
- tpl = this.context.get_opt('tpl', DEFAULT_TPL);
857
+ tpl = this.context.get_opt('tpl');
709
858
  for (_i = 0, _len = list.length; _i < _len; _i++) {
710
859
  item = list[_i];
860
+ item = $.extend({}, item, {
861
+ 'atwho-at': this.context.at
862
+ });
711
863
  li = this.context.callbacks("tpl_eval").call(this.context, tpl, item);
712
864
  $li = $(this.context.callbacks("highlighter").call(this.context, li, this.context.query.text));
713
- $li.data("atwho-info", item);
865
+ $li.data("item-data", item);
714
866
  $ul.append($li);
715
867
  }
716
868
  this.show();
@@ -812,54 +964,87 @@
812
964
  return value;
813
965
  }
814
966
  };
815
- DEFAULT_TPL = "<li data-value='${name}'>${name}</li>";
816
967
  Api = {
817
- init: function(options) {
818
- var $this, app;
819
- app = ($this = $(this)).data("atwho");
820
- if (!app) {
821
- $this.data('atwho', (app = new App(this)));
822
- }
823
- return app.reg(options.at, options);
824
- },
825
- load: function(key, data) {
968
+ load: function(at, data) {
826
969
  var c;
827
- if (c = this.controller(key)) {
970
+ if (c = this.controller(at)) {
828
971
  return c.model.load(data);
829
972
  }
830
973
  },
974
+ getInsertedItemsWithIDs: function(at) {
975
+ var c, ids, items;
976
+ if (!(c = this.controller(at))) {
977
+ return [null, null];
978
+ }
979
+ if (at) {
980
+ at = "-" + (c.get_opt('alias') || c.at);
981
+ }
982
+ ids = [];
983
+ items = $.map(this.$inputor.find("span.atwho-view-flag" + (at || "")), function(item) {
984
+ var data;
985
+ data = $(item).data('atwho-data-item');
986
+ if (ids.indexOf(data.id) > -1) {
987
+ return;
988
+ }
989
+ if (data.id) {
990
+ ids.push = data.id;
991
+ }
992
+ return data;
993
+ });
994
+ return [ids, items];
995
+ },
996
+ getInsertedItems: function(at) {
997
+ return Api.getInsertedItemsWithIDs.apply(this, [at])[1];
998
+ },
999
+ getInsertedIDs: function(at) {
1000
+ return Api.getInsertedItemsWithIDs.apply(this, [at])[0];
1001
+ },
831
1002
  run: function() {
832
1003
  return this.dispatch();
833
1004
  }
834
1005
  };
1006
+ Atwho = {
1007
+ init: function(options) {
1008
+ var $this, app;
1009
+ app = ($this = $(this)).data("atwho");
1010
+ if (!app) {
1011
+ $this.data('atwho', (app = new App(this)));
1012
+ }
1013
+ app.reg(options.at, options);
1014
+ return this;
1015
+ }
1016
+ };
835
1017
  $CONTAINER = $("<div id='atwho-container'></div>");
836
1018
  $.fn.atwho = function(method) {
837
- var _args;
1019
+ var result, _args;
838
1020
  _args = arguments;
839
1021
  $('body').append($CONTAINER);
840
- return this.filter('textarea, input').each(function() {
1022
+ result = null;
1023
+ this.filter('textarea, input, [contenteditable=true]').each(function() {
841
1024
  var app;
842
1025
  if (typeof method === 'object' || !method) {
843
- return Api.init.apply(this, _args);
1026
+ return Atwho.init.apply(this, _args);
844
1027
  } else if (Api[method]) {
845
1028
  if (app = $(this).data('atwho')) {
846
- return Api[method].apply(app, Array.prototype.slice.call(_args, 1));
1029
+ return result = Api[method].apply(app, Array.prototype.slice.call(_args, 1));
847
1030
  }
848
1031
  } else {
849
1032
  return $.error("Method " + method + " does not exist on jQuery.caret");
850
1033
  }
851
1034
  });
1035
+ return result || this;
852
1036
  };
853
1037
  return $.fn.atwho["default"] = {
854
1038
  at: void 0,
855
1039
  alias: void 0,
856
1040
  data: null,
857
- tpl: DEFAULT_TPL,
1041
+ tpl: "<li data-value='${atwho-at}${name}'>${name}</li>",
1042
+ insert_tpl: "<span>${atwho-data-value}</span>",
858
1043
  callbacks: DEFAULT_CALLBACKS,
859
1044
  search_key: "name",
1045
+ start_with_space: true,
860
1046
  limit: 5,
861
1047
  max_len: 20,
862
- start_with_space: true,
863
1048
  display_timeout: 300
864
1049
  };
865
1050
  });
@@ -1,7 +1,7 @@
1
1
  module Jquery
2
2
  module Atwho
3
3
  module Rails
4
- VERSION = "0.3.3"
4
+ VERSION = "0.4.1"
5
5
  end
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jquery-atwho-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ichord
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-24 00:00:00.000000000 Z
11
+ date: 2013-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -87,4 +87,3 @@ summary: 'jquery plugin: @mentions'
87
87
  test_files:
88
88
  - spec/generators/install_generator_spec.rb
89
89
  - spec/spec_helper.rb
90
- has_rdoc: