diff --git a/app/assets/javascripts/admin/posts.js.coffee b/app/assets/javascripts/admin/posts.js.coffee
index d4162ca..81f67cd 100644
--- a/app/assets/javascripts/admin/posts.js.coffee
+++ b/app/assets/javascripts/admin/posts.js.coffee
@@ -12,7 +12,15 @@ $(document).ready ->
type: 'POST'
url: "/photos"
success: (data,status,xhr)->
- insertAtCaret('post_content', data)
+ txtBox = $("#post_content")
+ caret_pos = txtBox.caret('pos')
+ src_merged = "\n" + data + "\n"
+ source = txtBox.val()
+ before_text = source.slice(0, caret_pos)
+ txtBox.val(before_text + src_merged + source.slice(caret_pos+1, source.count))
+ txtBox.caret('pos',caret_pos + src_merged.length)
+ txtBox.scope().content = txtBox.val()
+ txtBox.focus()
$('input[type=file]').fileUpload opt
diff --git a/app/assets/javascripts/insert.js b/app/assets/javascripts/insert.js
deleted file mode 100644
index 209ff8b..0000000
--- a/app/assets/javascripts/insert.js
+++ /dev/null
@@ -1,34 +0,0 @@
-function insertAtCaret(areaId,text) {
- var txtarea = document.getElementById(areaId);
- var scrollPos = txtarea.scrollTop;
- var strPos = 0;
- var br = ((txtarea.selectionStart || txtarea.selectionStart == '0') ?
- "ff" : (document.selection ? "ie" : false ) );
- if (br == "ie") {
- txtarea.focus();
- var range = document.selection.createRange();
- range.moveStart ('character', -txtarea.value.length);
- strPos = range.text.length;
- }
- else if (br == "ff") strPos = txtarea.selectionStart;
-
- var front = (txtarea.value).substring(0,strPos);
- var back = (txtarea.value).substring(strPos,txtarea.value.length);
- txtarea.value=front+text+back;
- strPos = strPos + text.length;
- if (br == "ie") {
- txtarea.focus();
- var range = document.selection.createRange();
- range.moveStart ('character', -txtarea.value.length);
- range.moveStart ('character', strPos);
- range.moveEnd ('character', 0);
- range.select();
- }
- else if (br == "ff") {
- txtarea.selectionStart = strPos;
- txtarea.selectionEnd = strPos;
- txtarea.focus();
- }
- txtarea.scrollTop = scrollPos;
-}
-
diff --git a/app/assets/javascripts/jquery.atwho.js b/app/assets/javascripts/jquery.atwho.js
new file mode 100755
index 0000000..ea88dce
--- /dev/null
+++ b/app/assets/javascripts/jquery.atwho.js
@@ -0,0 +1,864 @@
+//@ sourceMappingURL=jquery.caret.map
+/*
+ Implement Github like autocomplete mentions
+ http://ichord.github.com/At.js
+
+ Copyright (c) 2013 chord.luo@gmail.com
+ Licensed under the MIT license.
+*/
+
+
+/*
+本插件操作 textarea 或者 input 内的插入符
+只实现了获得插入符在文本框中的位置,我设置
+插入符的位置.
+*/
+
+
+(function() {
+ (function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ return define(['jquery'], factory);
+ } else {
+ return factory(window.jQuery);
+ }
+ })(function($) {
+ "use strict";
+ var Caret, Mirror, methods, pluginName;
+
+ pluginName = 'caret';
+ Caret = (function() {
+ function Caret($inputor) {
+ this.$inputor = $inputor;
+ this.domInputor = this.$inputor[0];
+ }
+
+ Caret.prototype.getPos = function() {
+ var end, endRange, inputor, len, normalizedValue, pos, range, start, textInputRange;
+
+ inputor = this.domInputor;
+ inputor.focus();
+ if (document.selection) {
+ /*
+ #assume we select "HATE" in the inputor such as textarea -> { }.
+ * start end-point.
+ * /
+ * < I really [HATE] IE > between the brackets is the selection range.
+ * \
+ * end end-point.
+ */
+
+ range = document.selection.createRange();
+ pos = 0;
+ if (range && range.parentElement() === inputor) {
+ normalizedValue = inputor.value.replace(/\r\n/g, "\n");
+ /* SOMETIME !!!
+ "/r/n" is counted as two char.
+ one line is two, two will be four. balalala.
+ so we have to using the normalized one's length.;
+ */
+
+ len = normalizedValue.length;
+ /*
+ <[ I really HATE IE ]>:
+ the whole content in the inputor will be the textInputRange.
+ */
+
+ textInputRange = inputor.createTextRange();
+ /* _here must be the position of bookmark.
+ /
+ <[ I really [HATE] IE ]>
+ [---------->[ ] : this is what moveToBookmark do.
+ < I really [[HATE] IE ]> : here is result.
+ \ two brackets in should be in line.
+ */
+
+ textInputRange.moveToBookmark(range.getBookmark());
+ endRange = inputor.createTextRange();
+ /* [--------------------->[] : if set false all end-point goto end.
+ < I really [[HATE] IE []]>
+ */
+
+ endRange.collapse(false);
+ /*
+ ___VS____
+ / \
+ < I really [[HATE] IE []]>
+ \_endRange end-point.
+
+ " > -1" mean the start end-point will be the same or right to the end end-point
+ * simplelly, all in the end.
+ */
+
+ if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
+ start = end = len;
+ } else {
+ /*
+ I really |HATE] IE ]>
+ <-|
+ I really[ [HATE] IE ]>
+ <-[
+ I reall[y [HATE] IE ]>
+
+ will return how many unit have moved.
+ */
+
+ start = -textInputRange.moveStart("character", -len);
+ end = -textInputRange.moveEnd("character", -len);
+ }
+ }
+ } else {
+ start = inputor.selectionStart;
+ }
+ return start;
+ };
+
+ Caret.prototype.setPos = function(pos) {
+ var inputor, range;
+
+ inputor = this.domInputor;
+ if (document.selection) {
+ range = inputor.createTextRange();
+ range.move("character", pos);
+ return range.select();
+ } else {
+ return inputor.setSelectionRange(pos, pos);
+ }
+ };
+
+ Caret.prototype.getPosition = function(pos) {
+ var $inputor, at_rect, format, h, html, mirror, start_range, x, y;
+
+ $inputor = this.$inputor;
+ format = function(value) {
+ return value.replace(//g, '>').replace(/`/g, '`').replace(/"/g, '"').replace(/\r\n|\r|\n/g, "
");
+ };
+ if (pos === void 0) {
+ pos = this.getPos();
+ }
+ start_range = $inputor.val().slice(0, pos);
+ html = "" + format(start_range) + "";
+ html += "|";
+ mirror = new Mirror($inputor);
+ at_rect = mirror.create(html).rect();
+ x = at_rect.left - $inputor.scrollLeft();
+ y = at_rect.top - $inputor.scrollTop();
+ h = at_rect.height;
+ return {
+ left: x,
+ top: y,
+ height: h
+ };
+ };
+
+ Caret.prototype.getOffset = function(pos) {
+ var $inputor, h, offset, position, x, y;
+
+ $inputor = this.$inputor;
+ offset = $inputor.offset();
+ position = this.getPosition(pos);
+ x = offset.left + position.left;
+ y = offset.top + position.top;
+ h = position.height;
+ return {
+ left: x,
+ top: y,
+ height: h
+ };
+ };
+
+ Caret.prototype.getIEPosition = function(pos) {
+ var h, inputorOffset, offset, x, y;
+
+ offset = this.getIEOffset(pos);
+ inputorOffset = this.$inputor.offset();
+ x = offset.left - inputorOffset.left;
+ y = offset.top - inputorOffset.top;
+ h = offset.height;
+ return {
+ left: x,
+ top: y,
+ height: h
+ };
+ };
+
+ Caret.prototype.getIEOffset = function(pos) {
+ var h, range, x, y;
+
+ range = this.domInputor.createTextRange();
+ if (pos) {
+ range.move('character', pos);
+ }
+ x = range.boundingLeft + $inputor.scrollLeft();
+ y = range.boundingTop + $(window).scrollTop() + $inputor.scrollTop();
+ h = range.boundingHeight;
+ return {
+ left: x,
+ top: y,
+ height: h
+ };
+ };
+
+ return Caret;
+
+ })();
+ Mirror = (function() {
+ Mirror.prototype.css_attr = ["overflowY", "height", "width", "paddingTop", "paddingLeft", "paddingRight", "paddingBottom", "marginTop", "marginLeft", "marginRight", "marginBottom", "fontFamily", "borderStyle", "borderWidth", "wordWrap", "fontSize", "lineHeight", "overflowX", "text-align"];
+
+ function Mirror($inputor) {
+ this.$inputor = $inputor;
+ }
+
+ Mirror.prototype.mirrorCss = function() {
+ var css,
+ _this = this;
+
+ css = {
+ position: 'absolute',
+ left: -9999,
+ top: 0,
+ zIndex: -20000,
+ 'white-space': 'pre-wrap'
+ };
+ $.each(this.css_attr, function(i, p) {
+ return css[p] = _this.$inputor.css(p);
+ });
+ return css;
+ };
+
+ Mirror.prototype.create = function(html) {
+ this.$mirror = $('
');
+ this.$mirror.css(this.mirrorCss());
+ this.$mirror.html(html);
+ this.$inputor.after(this.$mirror);
+ return this;
+ };
+
+ Mirror.prototype.rect = function() {
+ var $flag, pos, rect;
+
+ $flag = this.$mirror.find("#caret");
+ pos = $flag.position();
+ rect = {
+ left: pos.left,
+ top: pos.top,
+ height: $flag.height()
+ };
+ this.$mirror.remove();
+ return rect;
+ };
+
+ return Mirror;
+
+ })();
+ methods = {
+ pos: function(pos) {
+ if (pos) {
+ return this.setPos(pos);
+ } else {
+ return this.getPos();
+ }
+ },
+ position: function(pos) {
+ if (document.selection) {
+ return this.getIEPosition(pos);
+ } else {
+ return this.getPosition(pos);
+ }
+ },
+ offset: function(pos) {
+ if (document.selection) {
+ return this.getIEOffset(pos);
+ } else {
+ return this.getOffset(pos);
+ }
+ }
+ };
+ return $.fn.caret = function(method) {
+ var caret;
+
+ caret = new Caret(this);
+ if (methods[method]) {
+ return methods[method].apply(caret, Array.prototype.slice.call(arguments, 1));
+ } else {
+ return $.error("Method " + method + " does not exist on jQuery.caret");
+ }
+ };
+ });
+
+}).call(this);
+
+
+/*
+ Implement Github like autocomplete mentions
+ http://ichord.github.com/At.js
+
+ Copyright (c) 2013 chord.luo@gmail.com
+ Licensed under the MIT license.
+*/
+
+
+(function() {
+ var __slice = [].slice;
+
+ (function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ return define(['jquery'], factory);
+ } else {
+ return factory(window.jQuery);
+ }
+ })(function($) {
+ var $CONTAINER, Api, App, Controller, DEFAULT_CALLBACKS, DEFAULT_TPL, KEY_CODE, Model, View;
+ App = (function() {
+
+ function App(inputor) {
+ this.current_flag = null;
+ this.controllers = {};
+ this.$inputor = $(inputor);
+ this.listen();
+ }
+
+ App.prototype.controller = function(key) {
+ return this.controllers[key || this.current_flag];
+ };
+
+ App.prototype.set_context_for = function(key) {
+ this.current_flag = key;
+ return this;
+ };
+
+ App.prototype.reg = function(flag, setting) {
+ var controller, _base;
+ controller = (_base = this.controllers)[flag] || (_base[flag] = new Controller(this, flag));
+ if (setting.alias) {
+ this.controllers[setting.alias] = controller;
+ }
+ controller.init(setting);
+ return this;
+ };
+
+ App.prototype.listen = function() {
+ var _this = this;
+ return this.$inputor.on('keyup.atwho', function(e) {
+ return _this.on_keyup(e);
+ }).on('keydown.atwho', function(e) {
+ return _this.on_keydown(e);
+ }).on('scroll.atwho', function(e) {
+ var _ref;
+ return (_ref = _this.controller()) != null ? _ref.view.hide() : void 0;
+ }).on('blur.atwho', function(e) {
+ var c;
+ if (c = _this.controller()) {
+ return c.view.hide(c.get_opt("display_timeout"));
+ }
+ });
+ };
+
+ App.prototype.dispatch = function() {
+ var _this = this;
+ return $.map(this.controllers, function(c) {
+ if (c.look_up()) {
+ return _this.set_context_for(c.key);
+ }
+ });
+ };
+
+ App.prototype.on_keyup = function(e) {
+ var _ref;
+ switch (e.keyCode) {
+ case KEY_CODE.ESC:
+ e.preventDefault();
+ if ((_ref = this.controller()) != null) {
+ _ref.view.hide();
+ }
+ break;
+ case KEY_CODE.DOWN:
+ case KEY_CODE.UP:
+ $.noop();
+ break;
+ default:
+ this.dispatch();
+ }
+ };
+
+ App.prototype.on_keydown = function(e) {
+ var view, _ref;
+ view = (_ref = this.controller()) != null ? _ref.view : void 0;
+ if (!(view && view.visible())) {
+ return;
+ }
+ switch (e.keyCode) {
+ case KEY_CODE.ESC:
+ e.preventDefault();
+ view.hide();
+ break;
+ case KEY_CODE.UP:
+ e.preventDefault();
+ view.prev();
+ break;
+ case KEY_CODE.DOWN:
+ e.preventDefault();
+ view.next();
+ break;
+ case KEY_CODE.TAB:
+ case KEY_CODE.ENTER:
+ if (!view.visible()) {
+ return;
+ }
+ e.preventDefault();
+ view.choose();
+ break;
+ default:
+ $.noop();
+ }
+ };
+
+ return App;
+
+ })();
+ Controller = (function() {
+ var uuid, _uuid;
+
+ _uuid = 0;
+
+ uuid = function() {
+ return _uuid += 1;
+ };
+
+ function Controller(app, key) {
+ this.app = app;
+ this.key = key;
+ this.$inputor = this.app.$inputor;
+ this.id = this.$inputor[0].id || uuid();
+ this.setting = null;
+ this.query = null;
+ this.pos = 0;
+ $CONTAINER.append(this.$el = $(""));
+ this.model = new Model(this);
+ this.view = new View(this);
+ }
+
+ Controller.prototype.init = function(setting) {
+ this.setting = $.extend({}, this.setting || $.fn.atwho["default"], setting);
+ return this.model.reload(this.setting.data);
+ };
+
+ Controller.prototype.call_default = function() {
+ var args, func_name;
+ func_name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+ try {
+ return DEFAULT_CALLBACKS[func_name].apply(this, args);
+ } catch (error) {
+ return $.error("" + error + " Or maybe At.js doesn't have function " + func_name);
+ }
+ };
+
+ Controller.prototype.trigger = function(name, data) {
+ var alias, event_name;
+ data.push(this);
+ alias = this.get_opt('alias');
+ event_name = alias ? "" + name + "-" + alias + ".atwho" : "" + name + ".atwho";
+ return this.$inputor.trigger(event_name, data);
+ };
+
+ Controller.prototype.callbacks = function(func_name) {
+ return this.get_opt("callbacks")[func_name] || DEFAULT_CALLBACKS[func_name];
+ };
+
+ Controller.prototype.get_opt = function(key, default_value) {
+ try {
+ return this.setting[key];
+ } catch (e) {
+ return null;
+ }
+ };
+
+ Controller.prototype.catch_query = function() {
+ var caret_pos, content, end, query, start, subtext;
+ content = this.$inputor.val();
+ caret_pos = this.$inputor.caret('pos');
+ subtext = content.slice(0, caret_pos);
+ query = this.callbacks("matcher").call(this, this.key, subtext, this.get_opt('start_with_space'));
+ if (typeof query === "string" && query.length <= this.get_opt('max_len', 20)) {
+ start = caret_pos - query.length;
+ end = start + query.length;
+ this.pos = start;
+ query = {
+ 'text': query.toLowerCase(),
+ 'head_pos': start,
+ 'end_pos': end
+ };
+ this.trigger("matched", [this.key, query.text]);
+ } else {
+ this.view.hide();
+ }
+ return this.query = query;
+ };
+
+ Controller.prototype.rect = function() {
+ var c, scale_bottom;
+ c = this.$inputor.caret('offset', this.pos - 1);
+ scale_bottom = document.selection ? 0 : 2;
+ return {
+ left: c.left,
+ top: c.top,
+ bottom: c.top + c.height + scale_bottom
+ };
+ };
+
+ Controller.prototype.insert = function(str) {
+ var $inputor, source, start_str, text;
+ $inputor = this.$inputor;
+ str = '' + str;
+ source = $inputor.val();
+ start_str = source.slice(0, this.query['head_pos'] || 0);
+ text = "" + start_str + str + " " + (source.slice(this.query['end_pos'] || 0));
+ $inputor.val(text);
+ $inputor.caret('pos', start_str.length + str.length + 1);
+ return $inputor.change();
+ };
+
+ Controller.prototype.render_view = function(data) {
+ var search_key;
+ search_key = this.get_opt("search_key");
+ data = this.callbacks("sorter").call(this, this.query.text, data.slice(0, 1001), search_key);
+ return this.view.render(data.slice(0, this.get_opt('limit')));
+ };
+
+ Controller.prototype.look_up = function() {
+ var query, _callback;
+ if (!(query = this.catch_query())) {
+ return;
+ }
+ _callback = function(data) {
+ if (data && data.length > 0) {
+ return this.render_view(data);
+ } else {
+ return this.view.hide();
+ }
+ };
+ this.model.query(query.text, $.proxy(_callback, this));
+ return query;
+ };
+
+ return Controller;
+
+ })();
+ Model = (function() {
+ var _storage;
+
+ _storage = {};
+
+ function Model(context) {
+ this.context = context;
+ this.key = this.context.key;
+ }
+
+ Model.prototype.saved = function() {
+ return this.fetch() > 0;
+ };
+
+ Model.prototype.query = function(query, callback) {
+ var data, search_key, _ref;
+ data = this.fetch();
+ search_key = this.context.get_opt("search_key");
+ callback(data = this.context.callbacks('filter').call(this.context, query, data, search_key));
+ if (!(data && data.length > 0)) {
+ return (_ref = this.context.callbacks('remote_filter')) != null ? _ref.call(this.context, query, callback) : void 0;
+ }
+ };
+
+ Model.prototype.fetch = function() {
+ return _storage[this.key] || [];
+ };
+
+ Model.prototype.save = function(data) {
+ return _storage[this.key] = this.context.callbacks("before_save").call(this.context, data || []);
+ };
+
+ Model.prototype.load = function(data) {
+ if (!(this.saved() || !data)) {
+ return this._load(data);
+ }
+ };
+
+ Model.prototype.reload = function(data) {
+ return this._load(data);
+ };
+
+ Model.prototype._load = function(data) {
+ var _this = this;
+ if (typeof data === "string") {
+ return $.ajax(data, {
+ dataType: "json"
+ }).done(function(data) {
+ return _this.save(data);
+ });
+ } else {
+ return this.save(data);
+ }
+ };
+
+ return Model;
+
+ })();
+ View = (function() {
+
+ function View(context) {
+ this.context = context;
+ this.key = this.context.key;
+ this.id = this.context.get_opt("alias") || ("at-view-" + (this.key.charCodeAt(0)));
+ this.$el = $("");
+ this.timeout_id = null;
+ this.context.$el.append(this.$el);
+ this.bind_event();
+ }
+
+ View.prototype.bind_event = function() {
+ var $menu,
+ _this = this;
+ $menu = this.$el.find('ul');
+ return $menu.on('mouseenter.view', 'li', function(e) {
+ $menu.find('.cur').removeClass('cur');
+ return $(e.currentTarget).addClass('cur');
+ }).on('click', function(e) {
+ _this.choose();
+ return e.preventDefault();
+ });
+ };
+
+ View.prototype.visible = function() {
+ return this.$el.is(":visible");
+ };
+
+ View.prototype.choose = function() {
+ var $li;
+ $li = this.$el.find(".cur");
+ this.context.insert(this.context.callbacks("before_insert").call(this.context, $li.data("value"), $li));
+ this.context.trigger("inserted", [$li]);
+ return this.hide();
+ };
+
+ View.prototype.reposition = function() {
+ var offset, rect;
+ rect = this.context.rect();
+ if (rect.bottom + this.$el.height() - $(window).scrollTop() > $(window).height()) {
+ rect.bottom = rect.top - this.$el.height();
+ }
+ offset = {
+ left: rect.left,
+ top: rect.bottom
+ };
+ this.$el.offset(offset);
+ return this.context.trigger("reposition", [offset]);
+ };
+
+ View.prototype.next = function() {
+ var cur, next;
+ cur = this.$el.find('.cur').removeClass('cur');
+ next = cur.next();
+ if (!next.length) {
+ next = this.$el.find('li:first');
+ }
+ return next.addClass('cur');
+ };
+
+ View.prototype.prev = function() {
+ var cur, prev;
+ cur = this.$el.find('.cur').removeClass('cur');
+ prev = cur.prev();
+ if (!prev.length) {
+ prev = this.$el.find('li:last');
+ }
+ return prev.addClass('cur');
+ };
+
+ View.prototype.show = function() {
+ if (!this.visible()) {
+ this.$el.show();
+ }
+ return this.reposition();
+ };
+
+ View.prototype.hide = function(time) {
+ var callback,
+ _this = this;
+ if (isNaN(time && this.visible())) {
+ return this.$el.hide();
+ } else {
+ callback = function() {
+ return _this.hide();
+ };
+ clearTimeout(this.timeout_id);
+ return this.timeout_id = setTimeout(callback, time);
+ }
+ };
+
+ View.prototype.render = function(list) {
+ var $li, $ul, item, li, tpl, _i, _len;
+ if (!$.isArray(list || list.length <= 0)) {
+ this.hide();
+ return;
+ }
+ this.$el.find('ul').empty();
+ $ul = this.$el.find('ul');
+ tpl = this.context.get_opt('tpl', DEFAULT_TPL);
+ for (_i = 0, _len = list.length; _i < _len; _i++) {
+ item = list[_i];
+ li = this.context.callbacks("tpl_eval").call(this.context, tpl, item);
+ $li = $(this.context.callbacks("highlighter").call(this.context, li, this.context.query.text));
+ $li.data("atwho-info", item);
+ $ul.append($li);
+ }
+ this.show();
+ return $ul.find("li:first").addClass("cur");
+ };
+
+ return View;
+
+ })();
+ KEY_CODE = {
+ DOWN: 40,
+ UP: 38,
+ ESC: 27,
+ TAB: 9,
+ ENTER: 13
+ };
+ DEFAULT_CALLBACKS = {
+ before_save: function(data) {
+ var item, _i, _len, _results;
+ if (!$.isArray(data)) {
+ return data;
+ }
+ _results = [];
+ for (_i = 0, _len = data.length; _i < _len; _i++) {
+ item = data[_i];
+ if ($.isPlainObject(item)) {
+ _results.push(item);
+ } else {
+ _results.push({
+ name: item
+ });
+ }
+ }
+ return _results;
+ },
+ matcher: function(flag, subtext, should_start_with_space) {
+ var match, regexp;
+ flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
+ if (should_start_with_space) {
+ flag = '(?:^|\\s)' + flag;
+ }
+ regexp = new RegExp(flag + '([A-Za-z0-9_\+\-]*)$|' + flag + '([^\\x00-\\xff]*)$', 'gi');
+ match = regexp.exec(subtext);
+ if (match) {
+ return match[2] || match[1];
+ } else {
+ return null;
+ }
+ },
+ filter: function(query, data, search_key) {
+ var item, _i, _len, _results;
+ _results = [];
+ for (_i = 0, _len = data.length; _i < _len; _i++) {
+ item = data[_i];
+ if (~item[search_key].toLowerCase().indexOf(query)) {
+ _results.push(item);
+ }
+ }
+ return _results;
+ },
+ remote_filter: null,
+ sorter: function(query, items, search_key) {
+ var item, _i, _len, _results;
+ if (!query) {
+ return items;
+ }
+ _results = [];
+ for (_i = 0, _len = items.length; _i < _len; _i++) {
+ item = items[_i];
+ item.atwho_order = item[search_key].toLowerCase().indexOf(query);
+ if (item.atwho_order > -1) {
+ _results.push(item);
+ }
+ }
+ return _results.sort(function(a, b) {
+ return a.atwho_order - b.atwho_order;
+ });
+ },
+ tpl_eval: function(tpl, map) {
+ try {
+ return tpl.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) {
+ return map[key];
+ });
+ } catch (error) {
+ return "";
+ }
+ },
+ highlighter: function(li, query) {
+ var regexp;
+ if (!query) {
+ return li;
+ }
+ regexp = new RegExp(">\\s*(\\w*)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig');
+ return li.replace(regexp, function(str, $1, $2, $3) {
+ return '> ' + $1 + '' + $2 + '' + $3 + ' <';
+ });
+ },
+ before_insert: function(value, $li) {
+ return value;
+ }
+ };
+ DEFAULT_TPL = "${name}";
+ Api = {
+ init: function(options) {
+ var $this, app;
+ app = ($this = $(this)).data("atwho");
+ if (!app) {
+ $this.data('atwho', (app = new App(this)));
+ }
+ return app.reg(options.at, options);
+ },
+ load: function(key, data) {
+ var c;
+ if (c = this.controller(key)) {
+ return c.model.load(data);
+ }
+ },
+ run: function() {
+ return this.dispatch();
+ }
+ };
+ $CONTAINER = $("");
+ $.fn.atwho = function(method) {
+ var _args;
+ _args = arguments;
+ $('body').append($CONTAINER);
+ return this.filter('textarea, input').each(function() {
+ var app;
+ if (typeof method === 'object' || !method) {
+ return Api.init.apply(this, _args);
+ } else if (Api[method]) {
+ if (app = $(this).data('atwho')) {
+ return Api[method].apply(app, Array.prototype.slice.call(_args, 1));
+ }
+ } else {
+ return $.error("Method " + method + " does not exist on jQuery.caret");
+ }
+ });
+ };
+ return $.fn.atwho["default"] = {
+ at: void 0,
+ alias: void 0,
+ data: null,
+ tpl: DEFAULT_TPL,
+ callbacks: DEFAULT_CALLBACKS,
+ search_key: "name",
+ limit: 5,
+ max_len: 20,
+ start_with_space: true,
+ display_timeout: 300
+ };
+ });
+
+}).call(this);