Skip to:
Content

BuddyPress.org

Changeset 11795


Ignore:
Timestamp:
01/05/2018 12:56:40 PM (7 years ago)
Author:
djpaul
Message:

Core, Activity: update at-mentions scripts to latest versions.

See #6640

Location:
trunk/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bp-activity/js/mentions.js

    r10747 r11795  
    2929         */
    3030        var suggestionsDefaults = {
    31             delay:               200,
    32             hide_without_suffix: true,
    33             insert_tpl:          '</>${atwho-data-value}</>', // For contentEditable, the fake tags make jQuery insert a textNode.
    34             limit:               10,
    35             start_with_space:    false,
    36             suffix:              '',
     31            delay:             200,
     32            hideWithoutSuffix: true,
     33            insertTpl:         '</>@${ID}</>', // For contentEditable, the fake tags make jQuery insert a textNode.
     34            limit:             10,
     35            startWithSpace:    false,
     36            suffix:            '',
    3737
    3838            callbacks: {
     
    231231
    232232            at:         '@',
    233             search_key: 'search',
    234             tpl:        '<li data-value="@${ID}"><img src="${image}" /><span class="username">@${ID}</span><small>${name}</small></li>'
     233            searchKey: 'search',
     234            displayTpl: '<li data-value="@${ID}"><img src="${image}" /><span class="username">@${ID}</span><small>${name}</small></li>'
    235235        },
    236236
  • trunk/src/bp-core/js/vendor/jquery.atwho.js

    • Property svn:executable set to *
    r11009 r11795  
    1 /*! jquery.atwho - v0.5.2 %>
    2 * Copyright (c) 2014 chord.luo <chord.luo@gmail.com>;
    3 * homepage: http://ichord.github.com/At.js
    4 * Licensed MIT
    5 */
     1/**
     2 * at.js - 1.5.4
     3 * Copyright (c) 2017 chord.luo <chord.luo@gmail.com>;
     4 * Homepage: http://ichord.github.com/At.js
     5 * License: MIT
     6 */
    67(function (root, factory) {
    78  if (typeof define === 'function' && define.amd) {
    8     // AMD. Register as an anonymous module.
    9     define(["jquery"], function ($) {
    10       return (root.returnExportsGlobal = factory($));
     9    // AMD. Register as an anonymous module unless amdModuleId is set
     10    define(["jquery"], function (a0) {
     11      return (factory(a0));
    1112    });
    1213  } else if (typeof exports === 'object') {
    1314    // Node. Does not work with strict CommonJS, but
    14     // only CommonJS-like enviroments that support module.exports,
     15    // only CommonJS-like environments that support module.exports,
    1516    // like Node.
    1617    module.exports = factory(require("jquery"));
     
    1920  }
    2021}(this, function ($) {
    21 
    22 var Api, App, Controller, DEFAULT_CALLBACKS, KEY_CODE, Model, View,
    23   __slice = [].slice;
     22var DEFAULT_CALLBACKS, KEY_CODE;
     23
     24KEY_CODE = {
     25  ESC: 27,
     26  TAB: 9,
     27  ENTER: 13,
     28  CTRL: 17,
     29  A: 65,
     30  P: 80,
     31  N: 78,
     32  LEFT: 37,
     33  UP: 38,
     34  RIGHT: 39,
     35  DOWN: 40,
     36  BACKSPACE: 8,
     37  SPACE: 32
     38};
     39
     40DEFAULT_CALLBACKS = {
     41  beforeSave: function(data) {
     42    return Controller.arrayToDefaultHash(data);
     43  },
     44  matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) {
     45    var _a, _y, match, regexp, space;
     46    flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
     47    if (should_startWithSpace) {
     48      flag = '(?:^|\\s)' + flag;
     49    }
     50    _a = decodeURI("%C3%80");
     51    _y = decodeURI("%C3%BF");
     52    space = acceptSpaceBar ? "\ " : "";
     53    regexp = new RegExp(flag + "([A-Za-z" + _a + "-" + _y + "0-9_" + space + "\'\.\+\-]*)$|" + flag + "([^\\x00-\\xff]*)$", 'gi');
     54    match = regexp.exec(subtext);
     55    if (match) {
     56      return match[2] || match[1];
     57    } else {
     58      return null;
     59    }
     60  },
     61  filter: function(query, data, searchKey) {
     62    var _results, i, item, len;
     63    _results = [];
     64    for (i = 0, len = data.length; i < len; i++) {
     65      item = data[i];
     66      if (~new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase())) {
     67        _results.push(item);
     68      }
     69    }
     70    return _results;
     71  },
     72  remoteFilter: null,
     73  sorter: function(query, items, searchKey) {
     74    var _results, i, item, len;
     75    if (!query) {
     76      return items;
     77    }
     78    _results = [];
     79    for (i = 0, len = items.length; i < len; i++) {
     80      item = items[i];
     81      item.atwho_order = new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase());
     82      if (item.atwho_order > -1) {
     83        _results.push(item);
     84      }
     85    }
     86    return _results.sort(function(a, b) {
     87      return a.atwho_order - b.atwho_order;
     88    });
     89  },
     90  tplEval: function(tpl, map) {
     91    var error, error1, template;
     92    template = tpl;
     93    try {
     94      if (typeof tpl !== 'string') {
     95        template = tpl(map);
     96      }
     97      return template.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) {
     98        return map[key];
     99      });
     100    } catch (error1) {
     101      error = error1;
     102      return "";
     103    }
     104  },
     105  highlighter: function(li, query) {
     106    var regexp;
     107    if (!query) {
     108      return li;
     109    }
     110    regexp = new RegExp(">\\s*([^\<]*?)(" + query.replace("+", "\\+") + ")([^\<]*)\\s*<", 'ig');
     111    return li.replace(regexp, function(str, $1, $2, $3) {
     112      return '> ' + $1 + '<strong>' + $2 + '</strong>' + $3 + ' <';
     113    });
     114  },
     115  beforeInsert: function(value, $li, e) {
     116    return value;
     117  },
     118  beforeReposition: function(offset) {
     119    return offset;
     120  },
     121  afterMatchFailed: function(at, el) {}
     122};
     123
     124var App;
    24125
    25126App = (function() {
    26127  function App(inputor) {
    27     this.current_flag = null;
     128    this.currentFlag = null;
    28129    this.controllers = {};
    29     this.alias_maps = {};
     130    this.aliasMaps = {};
    30131    this.$inputor = $(inputor);
    31     this.setIframe();
     132    this.setupRootElement();
    32133    this.listen();
    33134  }
    34135
    35136  App.prototype.createContainer = function(doc) {
    36     if ((this.$el = $("#atwho-container", doc)).length === 0) {
    37       return $(doc.body).append(this.$el = $("<div id='atwho-container'></div>"));
    38     }
    39   };
    40 
    41   App.prototype.setIframe = function(iframe, standalone) {
    42     var _ref;
    43     if (standalone == null) {
    44       standalone = false;
     137    var ref;
     138    if ((ref = this.$el) != null) {
     139      ref.remove();
     140    }
     141    return $(doc.body).append(this.$el = $("<div class='atwho-container'></div>"));
     142  };
     143
     144  App.prototype.setupRootElement = function(iframe, asRoot) {
     145    var error, error1;
     146    if (asRoot == null) {
     147      asRoot = false;
    45148    }
    46149    if (iframe) {
     
    49152      this.iframe = iframe;
    50153    } else {
    51       this.document = document;
    52       this.window = window;
    53       this.iframe = null;
    54     }
    55     if (this.iframeStandalone = standalone) {
    56       if ((_ref = this.$el) != null) {
    57         _ref.remove();
    58       }
    59       return this.createContainer(this.document);
    60     } else {
    61       return this.createContainer(document);
    62     }
     154      this.document = this.$inputor[0].ownerDocument;
     155      this.window = this.document.defaultView || this.document.parentWindow;
     156      try {
     157        this.iframe = this.window.frameElement;
     158      } catch (error1) {
     159        error = error1;
     160        this.iframe = null;
     161        if ($.fn.atwho.debug) {
     162          throw new Error("iframe auto-discovery is failed.\nPlease use `setIframe` to set the target iframe manually.\n" + error);
     163        }
     164      }
     165    }
     166    return this.createContainer((this.iframeAsRoot = asRoot) ? this.document : document);
    63167  };
    64168
    65169  App.prototype.controller = function(at) {
    66     var c, current, current_flag, _ref;
    67     if (this.alias_maps[at]) {
    68       current = this.controllers[this.alias_maps[at]];
    69     } else {
    70       _ref = this.controllers;
    71       for (current_flag in _ref) {
    72         c = _ref[current_flag];
    73         if (current_flag === at) {
     170    var c, current, currentFlag, ref;
     171    if (this.aliasMaps[at]) {
     172      current = this.controllers[this.aliasMaps[at]];
     173    } else {
     174      ref = this.controllers;
     175      for (currentFlag in ref) {
     176        c = ref[currentFlag];
     177        if (currentFlag === at) {
    74178          current = c;
    75179          break;
     
    80184      return current;
    81185    } else {
    82       return this.controllers[this.current_flag];
    83     }
    84   };
    85 
    86   App.prototype.set_context_for = function(at) {
    87     this.current_flag = at;
     186      return this.controllers[this.currentFlag];
     187    }
     188  };
     189
     190  App.prototype.setContextFor = function(at) {
     191    this.currentFlag = at;
    88192    return this;
    89193  };
    90194
    91195  App.prototype.reg = function(flag, setting) {
    92     var controller, _base;
    93     controller = (_base = this.controllers)[flag] || (_base[flag] = new Controller(this, flag));
     196    var base, controller;
     197    controller = (base = this.controllers)[flag] || (base[flag] = this.$inputor.is('[contentEditable]') ? new EditableController(this, flag) : new TextareaController(this, flag));
    94198    if (setting.alias) {
    95       this.alias_maps[setting.alias] = flag;
     199      this.aliasMaps[setting.alias] = flag;
    96200    }
    97201    controller.init(setting);
     
    100204
    101205  App.prototype.listen = function() {
    102     return this.$inputor.on('keyup.atwhoInner', (function(_this) {
     206    return this.$inputor.on('compositionstart', (function(_this) {
    103207      return function(e) {
    104         return _this.on_keyup(e);
     208        var ref;
     209        if ((ref = _this.controller()) != null) {
     210          ref.view.hide();
     211        }
     212        _this.isComposing = true;
     213        return null;
     214      };
     215    })(this)).on('compositionend', (function(_this) {
     216      return function(e) {
     217        _this.isComposing = false;
     218        setTimeout(function(e) {
     219          return _this.dispatch(e);
     220        });
     221        return null;
     222      };
     223    })(this)).on('keyup.atwhoInner', (function(_this) {
     224      return function(e) {
     225        return _this.onKeyup(e);
    105226      };
    106227    })(this)).on('keydown.atwhoInner', (function(_this) {
    107228      return function(e) {
    108         return _this.on_keydown(e);
    109       };
    110     })(this)).on('scroll.atwhoInner', (function(_this) {
    111       return function(e) {
    112         var _ref;
    113         return (_ref = _this.controller()) != null ? _ref.view.hide(e) : void 0;
     229        return _this.onKeydown(e);
    114230      };
    115231    })(this)).on('blur.atwhoInner', (function(_this) {
     
    117233        var c;
    118234        if (c = _this.controller()) {
    119           return c.view.hide(e, c.get_opt("display_timeout"));
     235          c.expectedQueryCBId = null;
     236          return c.view.hide(e, c.getOpt("displayTimeout"));
    120237        }
    121238      };
    122239    })(this)).on('click.atwhoInner', (function(_this) {
    123240      return function(e) {
    124         return _this.dispatch();
     241        return _this.dispatch(e);
    125242      };
    126     })(this));
     243    })(this)).on('scroll.atwhoInner', (function(_this) {
     244      return function() {
     245        var lastScrollTop;
     246        lastScrollTop = _this.$inputor.scrollTop();
     247        return function(e) {
     248          var currentScrollTop, ref;
     249          currentScrollTop = e.target.scrollTop;
     250          if (lastScrollTop !== currentScrollTop) {
     251            if ((ref = _this.controller()) != null) {
     252              ref.view.hide(e);
     253            }
     254          }
     255          lastScrollTop = currentScrollTop;
     256          return true;
     257        };
     258      };
     259    })(this)());
    127260  };
    128261
    129262  App.prototype.shutdown = function() {
    130     var c, _, _ref;
    131     _ref = this.controllers;
    132     for (_ in _ref) {
    133       c = _ref[_];
     263    var _, c, ref;
     264    ref = this.controllers;
     265    for (_ in ref) {
     266      c = ref[_];
    134267      c.destroy();
    135268      delete this.controllers[_];
     
    139272  };
    140273
    141   App.prototype.dispatch = function() {
    142     return $.map(this.controllers, (function(_this) {
    143       return function(c) {
    144         var delay;
    145         if (delay = c.get_opt('delay')) {
    146           clearTimeout(_this.delayedCallback);
    147           return _this.delayedCallback = setTimeout(function() {
    148             if (c.look_up()) {
    149               return _this.set_context_for(c.at);
    150             }
    151           }, delay);
    152         } else {
    153           if (c.look_up()) {
    154             return _this.set_context_for(c.at);
    155           }
    156         }
    157       };
    158     })(this));
    159   };
    160 
    161   App.prototype.on_keyup = function(e) {
    162     var _ref;
     274  App.prototype.dispatch = function(e) {
     275    var _, c, ref, results;
     276    ref = this.controllers;
     277    results = [];
     278    for (_ in ref) {
     279      c = ref[_];
     280      results.push(c.lookUp(e));
     281    }
     282    return results;
     283  };
     284
     285  App.prototype.onKeyup = function(e) {
     286    var ref;
    163287    switch (e.keyCode) {
    164288      case KEY_CODE.ESC:
    165289        e.preventDefault();
    166         if ((_ref = this.controller()) != null) {
    167           _ref.view.hide();
     290        if ((ref = this.controller()) != null) {
     291          ref.view.hide();
    168292        }
    169293        break;
     
    171295      case KEY_CODE.UP:
    172296      case KEY_CODE.CTRL:
     297      case KEY_CODE.ENTER:
    173298        $.noop();
    174299        break;
     
    176301      case KEY_CODE.N:
    177302        if (!e.ctrlKey) {
    178           this.dispatch();
     303          this.dispatch(e);
    179304        }
    180305        break;
    181306      default:
    182         this.dispatch();
    183     }
    184   };
    185 
    186   App.prototype.on_keydown = function(e) {
    187     var view, _ref;
    188     view = (_ref = this.controller()) != null ? _ref.view : void 0;
     307        this.dispatch(e);
     308    }
     309  };
     310
     311  App.prototype.onKeydown = function(e) {
     312    var ref, view;
     313    view = (ref = this.controller()) != null ? ref.view : void 0;
    189314    if (!(view && view.visible())) {
    190315      return;
     
    219344      case KEY_CODE.TAB:
    220345      case KEY_CODE.ENTER:
     346      case KEY_CODE.SPACE:
    221347        if (!view.visible()) {
    222348          return;
    223349        }
    224         e.preventDefault();
    225         view.choose(e);
     350        if (!this.controller().getOpt('spaceSelectsMatch') && e.keyCode === KEY_CODE.SPACE) {
     351          return;
     352        }
     353        if (!this.controller().getOpt('tabSelectsMatch') && e.keyCode === KEY_CODE.TAB) {
     354          return;
     355        }
     356        if (view.highlighted()) {
     357          e.preventDefault();
     358          view.choose(e);
     359        } else {
     360          view.hide(e);
     361        }
    226362        break;
    227363      default:
     
    234370})();
    235371
     372var Controller,
     373  slice = [].slice;
     374
    236375Controller = (function() {
    237376  Controller.prototype.uid = function() {
     
    239378  };
    240379
    241   function Controller(app, at) {
     380  function Controller(app, at1) {
    242381    this.app = app;
    243     this.at = at;
     382    this.at = at1;
    244383    this.$inputor = this.app.$inputor;
    245384    this.id = this.$inputor[0].id || this.uid();
     385    this.expectedQueryCBId = null;
    246386    this.setting = null;
    247387    this.query = null;
    248388    this.pos = 0;
    249     this.cur_rect = null;
    250389    this.range = null;
    251390    if ((this.$el = $("#atwho-ground-" + this.id, this.app.$el)).length === 0) {
     
    269408  };
    270409
    271   Controller.prototype.call_default = function() {
    272     var args, error, func_name;
    273     func_name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
     410  Controller.prototype.callDefault = function() {
     411    var args, error, error1, funcName;
     412    funcName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
    274413    try {
    275       return DEFAULT_CALLBACKS[func_name].apply(this, args);
    276     } catch (_error) {
    277       error = _error;
    278       return $.error("" + error + " Or maybe At.js doesn't have function " + func_name);
     414      return DEFAULT_CALLBACKS[funcName].apply(this, args);
     415    } catch (error1) {
     416      error = error1;
     417      return $.error(error + " Or maybe At.js doesn't have function " + funcName);
    279418    }
    280419  };
    281420
    282421  Controller.prototype.trigger = function(name, data) {
    283     var alias, event_name;
     422    var alias, eventName;
    284423    if (data == null) {
    285424      data = [];
    286425    }
    287426    data.push(this);
    288     alias = this.get_opt('alias');
    289     event_name = alias ? "" + name + "-" + alias + ".atwho" : "" + name + ".atwho";
    290     return this.$inputor.trigger(event_name, data);
    291   };
    292 
    293   Controller.prototype.callbacks = function(func_name) {
    294     return this.get_opt("callbacks")[func_name] || DEFAULT_CALLBACKS[func_name];
    295   };
    296 
    297   Controller.prototype.get_opt = function(at, default_value) {
    298     var e;
     427    alias = this.getOpt('alias');
     428    eventName = alias ? name + "-" + alias + ".atwho" : name + ".atwho";
     429    return this.$inputor.trigger(eventName, data);
     430  };
     431
     432  Controller.prototype.callbacks = function(funcName) {
     433    return this.getOpt("callbacks")[funcName] || DEFAULT_CALLBACKS[funcName];
     434  };
     435
     436  Controller.prototype.getOpt = function(at, default_value) {
     437    var e, error1;
    299438    try {
    300439      return this.setting[at];
    301     } catch (_error) {
    302       e = _error;
     440    } catch (error1) {
     441      e = error1;
    303442      return null;
    304443    }
    305444  };
    306445
    307   Controller.prototype.content = function() {
    308     var range;
    309     if (this.$inputor.is('textarea, input')) {
    310       return this.$inputor.val();
    311     } else {
    312       if (!(range = this.mark_range())) {
     446  Controller.prototype.insertContentFor = function($li) {
     447    var data, tpl;
     448    tpl = this.getOpt('insertTpl');
     449    data = $.extend({}, $li.data('item-data'), {
     450      'atwho-at': this.at
     451    });
     452    return this.callbacks("tplEval").call(this, tpl, data, "onInsert");
     453  };
     454
     455  Controller.prototype.renderView = function(data) {
     456    var searchKey;
     457    searchKey = this.getOpt("searchKey");
     458    data = this.callbacks("sorter").call(this, this.query.text, data.slice(0, 1001), searchKey);
     459    return this.view.render(data.slice(0, this.getOpt('limit')));
     460  };
     461
     462  Controller.arrayToDefaultHash = function(data) {
     463    var i, item, len, results;
     464    if (!$.isArray(data)) {
     465      return data;
     466    }
     467    results = [];
     468    for (i = 0, len = data.length; i < len; i++) {
     469      item = data[i];
     470      if ($.isPlainObject(item)) {
     471        results.push(item);
     472      } else {
     473        results.push({
     474          name: item
     475        });
     476      }
     477    }
     478    return results;
     479  };
     480
     481  Controller.prototype.lookUp = function(e) {
     482    var query, wait;
     483    if (e && e.type === 'click' && !this.getOpt('lookUpOnClick')) {
     484      return;
     485    }
     486    if (this.getOpt('suspendOnComposing') && this.app.isComposing) {
     487      return;
     488    }
     489    query = this.catchQuery(e);
     490    if (!query) {
     491      this.expectedQueryCBId = null;
     492      return query;
     493    }
     494    this.app.setContextFor(this.at);
     495    if (wait = this.getOpt('delay')) {
     496      this._delayLookUp(query, wait);
     497    } else {
     498      this._lookUp(query);
     499    }
     500    return query;
     501  };
     502
     503  Controller.prototype._delayLookUp = function(query, wait) {
     504    var now, remaining;
     505    now = Date.now ? Date.now() : new Date().getTime();
     506    this.previousCallTime || (this.previousCallTime = now);
     507    remaining = wait - (now - this.previousCallTime);
     508    if ((0 < remaining && remaining < wait)) {
     509      this.previousCallTime = now;
     510      this._stopDelayedCall();
     511      return this.delayedCallTimeout = setTimeout((function(_this) {
     512        return function() {
     513          _this.previousCallTime = 0;
     514          _this.delayedCallTimeout = null;
     515          return _this._lookUp(query);
     516        };
     517      })(this), wait);
     518    } else {
     519      this._stopDelayedCall();
     520      if (this.previousCallTime !== now) {
     521        this.previousCallTime = 0;
     522      }
     523      return this._lookUp(query);
     524    }
     525  };
     526
     527  Controller.prototype._stopDelayedCall = function() {
     528    if (this.delayedCallTimeout) {
     529      clearTimeout(this.delayedCallTimeout);
     530      return this.delayedCallTimeout = null;
     531    }
     532  };
     533
     534  Controller.prototype._generateQueryCBId = function() {
     535    return {};
     536  };
     537
     538  Controller.prototype._lookUp = function(query) {
     539    var _callback;
     540    _callback = function(queryCBId, data) {
     541      if (queryCBId !== this.expectedQueryCBId) {
    313542        return;
    314543      }
    315       return (range.startContainer.textContent || "").slice(0, range.startOffset);
    316     }
    317   };
    318 
    319   Controller.prototype.catch_query = function() {
    320     var caret_pos, content, end, query, start, subtext;
    321     content = this.content();
    322     caret_pos = this.$inputor.caret('pos', {
     544      if (data && data.length > 0) {
     545        return this.renderView(this.constructor.arrayToDefaultHash(data));
     546      } else {
     547        return this.view.hide();
     548      }
     549    };
     550    this.expectedQueryCBId = this._generateQueryCBId();
     551    return this.model.query(query.text, $.proxy(_callback, this, this.expectedQueryCBId));
     552  };
     553
     554  return Controller;
     555
     556})();
     557
     558var TextareaController,
     559  extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
     560  hasProp = {}.hasOwnProperty;
     561
     562TextareaController = (function(superClass) {
     563  extend(TextareaController, superClass);
     564
     565  function TextareaController() {
     566    return TextareaController.__super__.constructor.apply(this, arguments);
     567  }
     568
     569  TextareaController.prototype.catchQuery = function() {
     570    var caretPos, content, end, isString, query, start, subtext;
     571    content = this.$inputor.val();
     572    caretPos = this.$inputor.caret('pos', {
    323573      iframe: this.app.iframe
    324574    });
    325     subtext = content.slice(0, caret_pos);
    326     query = this.callbacks("matcher").call(this, this.at, subtext, this.get_opt('start_with_space'));
    327     if (typeof query === "string" && query.length <= this.get_opt('max_len', 20)) {
    328       start = caret_pos - query.length;
     575    subtext = content.slice(0, caretPos);
     576    query = this.callbacks("matcher").call(this, this.at, subtext, this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar"));
     577    isString = typeof query === 'string';
     578    if (isString && query.length < this.getOpt('minLen', 0)) {
     579      return;
     580    }
     581    if (isString && query.length <= this.getOpt('maxLen', 20)) {
     582      start = caretPos - query.length;
    329583      end = start + query.length;
    330584      this.pos = start;
    331585      query = {
    332586        'text': query,
    333         'head_pos': start,
    334         'end_pos': end
     587        'headPos': start,
     588        'endPos': end
    335589      };
    336590      this.trigger("matched", [this.at, query.text]);
     
    342596  };
    343597
    344   Controller.prototype.rect = function() {
    345     var c, iframe_offset, scale_bottom;
     598  TextareaController.prototype.rect = function() {
     599    var c, iframeOffset, scaleBottom;
    346600    if (!(c = this.$inputor.caret('offset', this.pos - 1, {
    347601      iframe: this.app.iframe
     
    349603      return;
    350604    }
    351     if (this.app.iframe && !this.app.iframeStandalone) {
    352       iframe_offset = $(this.app.iframe).offset();
    353       c.left += iframe_offset.left;
    354       c.top += iframe_offset.top;
    355     }
    356     if (this.$inputor.is('[contentEditable]')) {
    357       c = this.cur_rect || (this.cur_rect = c);
    358     }
    359     scale_bottom = this.app.document.selection ? 0 : 2;
     605    if (this.app.iframe && !this.app.iframeAsRoot) {
     606      iframeOffset = $(this.app.iframe).offset();
     607      c.left += iframeOffset.left;
     608      c.top += iframeOffset.top;
     609    }
     610    scaleBottom = this.app.document.selection ? 0 : 2;
    360611    return {
    361612      left: c.left,
    362613      top: c.top,
    363       bottom: c.top + c.height + scale_bottom
     614      bottom: c.top + c.height + scaleBottom
    364615    };
    365616  };
    366617
    367   Controller.prototype.reset_rect = function() {
    368     if (this.$inputor.is('[contentEditable]')) {
    369       return this.cur_rect = null;
    370     }
    371   };
    372 
    373   Controller.prototype.mark_range = function() {
    374     var sel;
    375     if (!this.$inputor.is('[contentEditable]')) {
    376       return;
    377     }
    378     if (this.app.window.getSelection && (sel = this.app.window.getSelection()).rangeCount > 0) {
    379       return this.range = sel.getRangeAt(0);
    380     } else if (this.app.document.selection) {
    381       return this.ie8_range = this.app.document.selection.createRange();
    382     }
    383   };
    384 
    385   Controller.prototype.insert_content_for = function($li) {
    386     var data, data_value, tpl;
    387     data_value = $li.data('value');
    388     tpl = this.get_opt('insert_tpl');
    389     if (this.$inputor.is('textarea, input') || !tpl) {
    390       return data_value;
    391     }
    392     data = $.extend({}, $li.data('item-data'), {
    393       'atwho-data-value': data_value,
    394       'atwho-at': this.at
     618  TextareaController.prototype.insert = function(content, $li) {
     619    var $inputor, source, startStr, suffix, text;
     620    $inputor = this.$inputor;
     621    source = $inputor.val();
     622    startStr = source.slice(0, Math.max(this.query.headPos - this.at.length, 0));
     623    suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || " ";
     624    content += suffix;
     625    text = "" + startStr + content + (source.slice(this.query['endPos'] || 0));
     626    $inputor.val(text);
     627    $inputor.caret('pos', startStr.length + content.length, {
     628      iframe: this.app.iframe
    395629    });
    396     return this.callbacks("tpl_eval").call(this, tpl, data);
    397   };
    398 
    399   Controller.prototype.insert = function(content, $li) {
    400     var $inputor, node, pos, range, sel, source, start_str, text, wrapped_contents, _i, _len, _ref;
    401     $inputor = this.$inputor;
    402     wrapped_contents = this.callbacks('inserting_wrapper').call(this, $inputor, content, this.get_opt("suffix"));
    403     if ($inputor.is('textarea, input')) {
    404       source = $inputor.val();
    405       start_str = source.slice(0, Math.max(this.query.head_pos - this.at.length, 0));
    406       text = "" + start_str + wrapped_contents + (source.slice(this.query['end_pos'] || 0));
    407       $inputor.val(text);
    408       $inputor.caret('pos', start_str.length + wrapped_contents.length, {
    409         iframe: this.app.iframe
    410       });
    411     } else if (range = this.range) {
    412       pos = range.startOffset - (this.query.end_pos - this.query.head_pos) - this.at.length;
    413       range.setStart(range.endContainer, Math.max(pos, 0));
    414       range.setEnd(range.endContainer, range.endOffset);
    415       range.deleteContents();
    416       _ref = $(wrapped_contents, this.app.document);
    417       for (_i = 0, _len = _ref.length; _i < _len; _i++) {
    418         node = _ref[_i];
    419         range.insertNode(node);
    420         range.setEndAfter(node);
    421         range.collapse(false);
    422       }
    423       sel = this.app.window.getSelection();
    424       sel.removeAllRanges();
    425       sel.addRange(range);
    426     } else if (range = this.ie8_range) {
    427       range.moveStart('character', this.query.end_pos - this.query.head_pos - this.at.length);
    428       range.pasteHTML(wrapped_contents);
    429       range.collapse(false);
    430       range.select();
    431     }
    432630    if (!$inputor.is(':focus')) {
    433631      $inputor.focus();
     
    436634  };
    437635
    438   Controller.prototype.render_view = function(data) {
    439     var search_key;
    440     search_key = this.get_opt("search_key");
    441     data = this.callbacks("sorter").call(this, this.query.text, data.slice(0, 1001), search_key);
    442     return this.view.render(data.slice(0, this.get_opt('limit')));
    443   };
    444 
    445   Controller.prototype.look_up = function() {
    446     var query, _callback;
    447     if (!(query = this.catch_query())) {
    448       return;
    449     }
    450     _callback = function(data) {
    451       if (data && data.length > 0) {
    452         return this.render_view(data);
    453       } else {
    454         return this.view.hide();
    455       }
    456     };
    457     this.model.query(query.text, $.proxy(_callback, this));
    458     return query;
    459   };
    460 
    461   return Controller;
    462 
    463 })();
     636  return TextareaController;
     637
     638})(Controller);
     639
     640var EditableController,
     641  extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
     642  hasProp = {}.hasOwnProperty;
     643
     644EditableController = (function(superClass) {
     645  extend(EditableController, superClass);
     646
     647  function EditableController() {
     648    return EditableController.__super__.constructor.apply(this, arguments);
     649  }
     650
     651  EditableController.prototype._getRange = function() {
     652    var sel;
     653    sel = this.app.window.getSelection();
     654    if (sel.rangeCount > 0) {
     655      return sel.getRangeAt(0);
     656    }
     657  };
     658
     659  EditableController.prototype._setRange = function(position, node, range) {
     660    if (range == null) {
     661      range = this._getRange();
     662    }
     663    if (!(range && node)) {
     664      return;
     665    }
     666    node = $(node)[0];
     667    if (position === 'after') {
     668      range.setEndAfter(node);
     669      range.setStartAfter(node);
     670    } else {
     671      range.setEndBefore(node);
     672      range.setStartBefore(node);
     673    }
     674    range.collapse(false);
     675    return this._clearRange(range);
     676  };
     677
     678  EditableController.prototype._clearRange = function(range) {
     679    var sel;
     680    if (range == null) {
     681      range = this._getRange();
     682    }
     683    sel = this.app.window.getSelection();
     684    if (this.ctrl_a_pressed == null) {
     685      sel.removeAllRanges();
     686      return sel.addRange(range);
     687    }
     688  };
     689
     690  EditableController.prototype._movingEvent = function(e) {
     691    var ref;
     692    return e.type === 'click' || ((ref = e.which) === KEY_CODE.RIGHT || ref === KEY_CODE.LEFT || ref === KEY_CODE.UP || ref === KEY_CODE.DOWN);
     693  };
     694
     695  EditableController.prototype._unwrap = function(node) {
     696    var next;
     697    node = $(node).unwrap().get(0);
     698    if ((next = node.nextSibling) && next.nodeValue) {
     699      node.nodeValue += next.nodeValue;
     700      $(next).remove();
     701    }
     702    return node;
     703  };
     704
     705  EditableController.prototype.catchQuery = function(e) {
     706    var $inserted, $query, _range, index, inserted, isString, lastNode, matched, offset, query, query_content, range;
     707    if (!(range = this._getRange())) {
     708      return;
     709    }
     710    if (!range.collapsed) {
     711      return;
     712    }
     713    if (e.which === KEY_CODE.ENTER) {
     714      ($query = $(range.startContainer).closest('.atwho-query')).contents().unwrap();
     715      if ($query.is(':empty')) {
     716        $query.remove();
     717      }
     718      ($query = $(".atwho-query", this.app.document)).text($query.text()).contents().last().unwrap();
     719      this._clearRange();
     720      return;
     721    }
     722    if (/firefox/i.test(navigator.userAgent)) {
     723      if ($(range.startContainer).is(this.$inputor)) {
     724        this._clearRange();
     725        return;
     726      }
     727      if (e.which === KEY_CODE.BACKSPACE && range.startContainer.nodeType === document.ELEMENT_NODE && (offset = range.startOffset - 1) >= 0) {
     728        _range = range.cloneRange();
     729        _range.setStart(range.startContainer, offset);
     730        if ($(_range.cloneContents()).contents().last().is('.atwho-inserted')) {
     731          inserted = $(range.startContainer).contents().get(offset);
     732          this._setRange('after', $(inserted).contents().last());
     733        }
     734      } else if (e.which === KEY_CODE.LEFT && range.startContainer.nodeType === document.TEXT_NODE) {
     735        $inserted = $(range.startContainer.previousSibling);
     736        if ($inserted.is('.atwho-inserted') && range.startOffset === 0) {
     737          this._setRange('after', $inserted.contents().last());
     738        }
     739      }
     740    }
     741    $(range.startContainer).closest('.atwho-inserted').addClass('atwho-query').siblings().removeClass('atwho-query');
     742    if (($query = $(".atwho-query", this.app.document)).length > 0 && $query.is(':empty') && $query.text().length === 0) {
     743      $query.remove();
     744    }
     745    if (!this._movingEvent(e)) {
     746      $query.removeClass('atwho-inserted');
     747    }
     748    if ($query.length > 0) {
     749      switch (e.which) {
     750        case KEY_CODE.LEFT:
     751          this._setRange('before', $query.get(0), range);
     752          $query.removeClass('atwho-query');
     753          return;
     754        case KEY_CODE.RIGHT:
     755          this._setRange('after', $query.get(0).nextSibling, range);
     756          $query.removeClass('atwho-query');
     757          return;
     758      }
     759    }
     760    if ($query.length > 0 && (query_content = $query.attr('data-atwho-at-query'))) {
     761      $query.empty().html(query_content).attr('data-atwho-at-query', null);
     762      this._setRange('after', $query.get(0), range);
     763    }
     764    _range = range.cloneRange();
     765    _range.setStart(range.startContainer, 0);
     766    matched = this.callbacks("matcher").call(this, this.at, _range.toString(), this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar"));
     767    isString = typeof matched === 'string';
     768    if ($query.length === 0 && isString && (index = range.startOffset - this.at.length - matched.length) >= 0) {
     769      range.setStart(range.startContainer, index);
     770      $query = $('<span/>', this.app.document).attr(this.getOpt("editableAtwhoQueryAttrs")).addClass('atwho-query');
     771      range.surroundContents($query.get(0));
     772      lastNode = $query.contents().last().get(0);
     773      if (lastNode) {
     774        if (/firefox/i.test(navigator.userAgent)) {
     775          range.setStart(lastNode, lastNode.length);
     776          range.setEnd(lastNode, lastNode.length);
     777          this._clearRange(range);
     778        } else {
     779          this._setRange('after', lastNode, range);
     780        }
     781      }
     782    }
     783    if (isString && matched.length < this.getOpt('minLen', 0)) {
     784      return;
     785    }
     786    if (isString && matched.length <= this.getOpt('maxLen', 20)) {
     787      query = {
     788        text: matched,
     789        el: $query
     790      };
     791      this.trigger("matched", [this.at, query.text]);
     792      return this.query = query;
     793    } else {
     794      this.view.hide();
     795      this.query = {
     796        el: $query
     797      };
     798      if ($query.text().indexOf(this.at) >= 0) {
     799        if (this._movingEvent(e) && $query.hasClass('atwho-inserted')) {
     800          $query.removeClass('atwho-query');
     801        } else if (false !== this.callbacks('afterMatchFailed').call(this, this.at, $query)) {
     802          this._setRange("after", this._unwrap($query.text($query.text()).contents().first()));
     803        }
     804      }
     805      return null;
     806    }
     807  };
     808
     809  EditableController.prototype.rect = function() {
     810    var $iframe, iframeOffset, rect;
     811    rect = this.query.el.offset();
     812    if (!(rect && this.query.el[0].getClientRects().length)) {
     813      return;
     814    }
     815    if (this.app.iframe && !this.app.iframeAsRoot) {
     816      iframeOffset = ($iframe = $(this.app.iframe)).offset();
     817      rect.left += iframeOffset.left - this.$inputor.scrollLeft();
     818      rect.top += iframeOffset.top - this.$inputor.scrollTop();
     819    }
     820    rect.bottom = rect.top + this.query.el.height();
     821    return rect;
     822  };
     823
     824  EditableController.prototype.insert = function(content, $li) {
     825    var data, overrides, range, suffix, suffixNode;
     826    if (!this.$inputor.is(':focus')) {
     827      this.$inputor.focus();
     828    }
     829    overrides = this.getOpt('functionOverrides');
     830    if (overrides.insert) {
     831      return overrides.insert.call(this, content, $li);
     832    }
     833    suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || "\u00A0";
     834    data = $li.data('item-data');
     835    this.query.el.removeClass('atwho-query').addClass('atwho-inserted').html(content).attr('data-atwho-at-query', "" + data['atwho-at'] + this.query.text).attr('contenteditable', "false");
     836    if (range = this._getRange()) {
     837      if (this.query.el.length) {
     838        range.setEndAfter(this.query.el[0]);
     839      }
     840      range.collapse(false);
     841      range.insertNode(suffixNode = this.app.document.createTextNode("" + suffix));
     842      this._setRange('after', suffixNode, range);
     843    }
     844    if (!this.$inputor.is(':focus')) {
     845      this.$inputor.focus();
     846    }
     847    return this.$inputor.change();
     848  };
     849
     850  return EditableController;
     851
     852})(Controller);
     853
     854var Model;
    464855
    465856Model = (function() {
     
    479870
    480871  Model.prototype.query = function(query, callback) {
    481     var data, search_key, _remote_filter;
     872    var _remoteFilter, data, searchKey;
    482873    data = this.fetch();
    483     search_key = this.context.get_opt("search_key");
    484     data = this.context.callbacks('filter').call(this.context, query, data, search_key) || [];
    485     _remote_filter = this.context.callbacks('remote_filter');
    486     if (data.length > 0 || (!_remote_filter && data.length === 0)) {
     874    searchKey = this.context.getOpt("searchKey");
     875    data = this.context.callbacks('filter').call(this.context, query, data, searchKey) || [];
     876    _remoteFilter = this.context.callbacks('remoteFilter');
     877    if (data.length > 0 || (!_remoteFilter && data.length === 0)) {
    487878      return callback(data);
    488879    } else {
    489       return _remote_filter.call(this.context, query, callback);
     880      return _remoteFilter.call(this.context, query, callback);
    490881    }
    491882  };
     
    496887
    497888  Model.prototype.save = function(data) {
    498     return this.storage.data(this.at, this.context.callbacks("before_save").call(this.context, data || []));
     889    return this.storage.data(this.at, this.context.callbacks("beforeSave").call(this.context, data || []));
    499890  };
    500891
     
    527918})();
    528919
     920var View;
     921
    529922View = (function() {
    530923  function View(context) {
    531924    this.context = context;
    532925    this.$el = $("<div class='atwho-view'><ul class='atwho-view-ul'></ul></div>");
    533     this.timeout_id = null;
     926    this.$elUl = this.$el.children();
     927    this.timeoutID = null;
    534928    this.context.$el.append(this.$el);
    535     this.bind_event();
     929    this.bindEvent();
    536930  }
    537931
    538932  View.prototype.init = function() {
    539     var id;
    540     id = this.context.get_opt("alias") || this.context.at.charCodeAt(0);
     933    var header_tpl, id;
     934    id = this.context.getOpt("alias") || this.context.at.charCodeAt(0);
     935    header_tpl = this.context.getOpt("headerTpl");
     936    if (header_tpl && this.$el.children().length === 1) {
     937      this.$el.prepend(header_tpl);
     938    }
    541939    return this.$el.attr({
    542940      'id': "at-view-" + id
     
    548946  };
    549947
    550   View.prototype.bind_event = function() {
    551     var $menu;
     948  View.prototype.bindEvent = function() {
     949    var $menu, lastCoordX, lastCoordY;
    552950    $menu = this.$el.find('ul');
    553     return $menu.on('mouseenter.atwho-view', 'li', function(e) {
    554       $menu.find('.cur').removeClass('cur');
    555       return $(e.currentTarget).addClass('cur');
    556     }).on('click.atwho-view', 'li', (function(_this) {
     951    lastCoordX = 0;
     952    lastCoordY = 0;
     953    return $menu.on('mousemove.atwho-view', 'li', (function(_this) {
     954      return function(e) {
     955        var $cur;
     956        if (lastCoordX === e.clientX && lastCoordY === e.clientY) {
     957          return;
     958        }
     959        lastCoordX = e.clientX;
     960        lastCoordY = e.clientY;
     961        $cur = $(e.currentTarget);
     962        if ($cur.hasClass('cur')) {
     963          return;
     964        }
     965        $menu.find('.cur').removeClass('cur');
     966        return $cur.addClass('cur');
     967      };
     968    })(this)).on('click.atwho-view', 'li', (function(_this) {
    557969      return function(e) {
    558970        $menu.find('.cur').removeClass('cur');
     
    565977
    566978  View.prototype.visible = function() {
    567     return this.$el.is(":visible");
     979    return $.expr.filters.visible(this.$el[0]);
     980  };
     981
     982  View.prototype.highlighted = function() {
     983    return this.$el.find(".cur").length > 0;
    568984  };
    569985
     
    571987    var $li, content;
    572988    if (($li = this.$el.find(".cur")).length) {
    573       content = this.context.insert_content_for($li);
    574       this.context.insert(this.context.callbacks("before_insert").call(this.context, content, $li), $li);
     989      content = this.context.insertContentFor($li);
     990      this.context._stopDelayedCall();
     991      this.context.insert(this.context.callbacks("beforeInsert").call(this.context, content, $li, e), $li);
    575992      this.context.trigger("inserted", [$li, e]);
    576993      this.hide(e);
    577994    }
    578     if (this.context.get_opt("hide_without_suffix")) {
    579       return this.stop_showing = true;
     995    if (this.context.getOpt("hideWithoutSuffix")) {
     996      return this.stopShowing = true;
    580997    }
    581998  };
    582999
    5831000  View.prototype.reposition = function(rect) {
    584     var offset, overflowOffset, _ref, _window;
    585     _window = this.context.app.iframeStandalone ? this.context.app.window : window;
     1001    var _window, offset, overflowOffset, ref;
     1002    _window = this.context.app.iframeAsRoot ? this.context.app.window : window;
    5861003    if (rect.bottom + this.$el.height() - $(_window).scrollTop() > $(_window).height()) {
    5871004      rect.bottom = rect.top - this.$el.height();
     
    5941011      top: rect.bottom
    5951012    };
    596     if ((_ref = this.context.callbacks("before_reposition")) != null) {
    597       _ref.call(this.context, offset);
     1013    if ((ref = this.context.callbacks("beforeReposition")) != null) {
     1014      ref.call(this.context, offset);
    5981015    }
    5991016    this.$el.offset(offset);
     
    6021019
    6031020  View.prototype.next = function() {
    604     var cur, next;
     1021    var cur, next, nextEl, offset;
    6051022    cur = this.$el.find('.cur').removeClass('cur');
    6061023    next = cur.next();
     
    6091026    }
    6101027    next.addClass('cur');
    611     return this.$el.animate({
    612       scrollTop: Math.max(0, cur.innerHeight() * (next.index() + 2) - this.$el.height())
    613     }, 150);
     1028    nextEl = next[0];
     1029    offset = nextEl.offsetTop + nextEl.offsetHeight + (nextEl.nextSibling ? nextEl.nextSibling.offsetHeight : 0);
     1030    return this.scrollTop(Math.max(0, offset - this.$el.height()));
    6141031  };
    6151032
    6161033  View.prototype.prev = function() {
    617     var cur, prev;
     1034    var cur, offset, prev, prevEl;
    6181035    cur = this.$el.find('.cur').removeClass('cur');
    6191036    prev = cur.prev();
     
    6221039    }
    6231040    prev.addClass('cur');
    624     return this.$el.animate({
    625       scrollTop: Math.max(0, cur.innerHeight() * (prev.index() + 2) - this.$el.height())
    626     }, 150);
     1041    prevEl = prev[0];
     1042    offset = prevEl.offsetTop + prevEl.offsetHeight + (prevEl.nextSibling ? prevEl.nextSibling.offsetHeight : 0);
     1043    return this.scrollTop(Math.max(0, offset - this.$el.height()));
     1044  };
     1045
     1046  View.prototype.scrollTop = function(scrollTop) {
     1047    var scrollDuration;
     1048    scrollDuration = this.context.getOpt('scrollDuration');
     1049    if (scrollDuration) {
     1050      return this.$elUl.animate({
     1051        scrollTop: scrollTop
     1052      }, scrollDuration);
     1053    } else {
     1054      return this.$elUl.scrollTop(scrollTop);
     1055    }
    6271056  };
    6281057
    6291058  View.prototype.show = function() {
    6301059    var rect;
    631     if (this.stop_showing) {
    632       this.stop_showing = false;
    633       return;
    634     }
    635     this.context.mark_range();
     1060    if (this.stopShowing) {
     1061      this.stopShowing = false;
     1062      return;
     1063    }
    6361064    if (!this.visible()) {
    6371065      this.$el.show();
     
    6501078    }
    6511079    if (isNaN(time)) {
    652       this.context.reset_rect();
    6531080      this.$el.hide();
    6541081      return this.context.trigger('hidden', [e]);
     
    6591086        };
    6601087      })(this);
    661       clearTimeout(this.timeout_id);
    662       return this.timeout_id = setTimeout(callback, time);
     1088      clearTimeout(this.timeoutID);
     1089      return this.timeoutID = setTimeout(callback, time);
    6631090    }
    6641091  };
    6651092
    6661093  View.prototype.render = function(list) {
    667     var $li, $ul, item, li, tpl, _i, _len;
     1094    var $li, $ul, i, item, len, li, tpl;
    6681095    if (!($.isArray(list) && list.length > 0)) {
    6691096      this.hide();
     
    6721099    this.$el.find('ul').empty();
    6731100    $ul = this.$el.find('ul');
    674     tpl = this.context.get_opt('tpl');
    675     for (_i = 0, _len = list.length; _i < _len; _i++) {
    676       item = list[_i];
     1101    tpl = this.context.getOpt('displayTpl');
     1102    for (i = 0, len = list.length; i < len; i++) {
     1103      item = list[i];
    6771104      item = $.extend({}, item, {
    6781105        'atwho-at': this.context.at
    6791106      });
    680       li = this.context.callbacks("tpl_eval").call(this.context, tpl, item);
     1107      li = this.context.callbacks("tplEval").call(this.context, tpl, item, "onDisplay");
    6811108      $li = $(this.context.callbacks("highlighter").call(this.context, li, this.context.query.text));
    6821109      $li.data("item-data", item);
     
    6841111    }
    6851112    this.show();
    686     if (this.context.get_opt('highlight_first')) {
     1113    if (this.context.getOpt('highlightFirst')) {
    6871114      return $ul.find("li:first").addClass("cur");
    6881115    }
     
    6931120})();
    6941121
    695 KEY_CODE = {
    696   DOWN: 40,
    697   UP: 38,
    698   ESC: 27,
    699   TAB: 9,
    700   ENTER: 13,
    701   CTRL: 17,
    702   P: 80,
    703   N: 78
    704 };
    705 
    706 DEFAULT_CALLBACKS = {
    707   before_save: function(data) {
    708     var item, _i, _len, _results;
    709     if (!$.isArray(data)) {
    710       return data;
    711     }
    712     _results = [];
    713     for (_i = 0, _len = data.length; _i < _len; _i++) {
    714       item = data[_i];
    715       if ($.isPlainObject(item)) {
    716         _results.push(item);
    717       } else {
    718         _results.push({
    719           name: item
    720         });
    721       }
    722     }
    723     return _results;
    724   },
    725   matcher: function(flag, subtext, should_start_with_space) {
    726     var match, regexp, _a, _y;
    727     flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    728     if (should_start_with_space) {
    729       flag = '(?:^|\\s)' + flag;
    730     }
    731     _a = decodeURI("%C3%80");
    732     _y = decodeURI("%C3%BF");
    733     regexp = new RegExp("" + flag + "([A-Za-z" + _a + "-" + _y + "0-9_\+\-]*)$|" + flag + "([^\\x00-\\xff]*)$", 'gi');
    734     match = regexp.exec(subtext);
    735     if (match) {
    736       return match[2] || match[1];
    737     } else {
    738       return null;
    739     }
    740   },
    741   filter: function(query, data, search_key) {
    742     var item, _i, _len, _results;
    743     _results = [];
    744     for (_i = 0, _len = data.length; _i < _len; _i++) {
    745       item = data[_i];
    746       if (~new String(item[search_key]).toLowerCase().indexOf(query.toLowerCase())) {
    747         _results.push(item);
    748       }
    749     }
    750     return _results;
    751   },
    752   remote_filter: null,
    753   sorter: function(query, items, search_key) {
    754     var item, _i, _len, _results;
    755     if (!query) {
    756       return items;
    757     }
    758     _results = [];
    759     for (_i = 0, _len = items.length; _i < _len; _i++) {
    760       item = items[_i];
    761       item.atwho_order = new String(item[search_key]).toLowerCase().indexOf(query.toLowerCase());
    762       if (item.atwho_order > -1) {
    763         _results.push(item);
    764       }
    765     }
    766     return _results.sort(function(a, b) {
    767       return a.atwho_order - b.atwho_order;
    768     });
    769   },
    770   tpl_eval: function(tpl, map) {
    771     var error;
    772     try {
    773       return tpl.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) {
    774         return map[key];
    775       });
    776     } catch (_error) {
    777       error = _error;
    778       return "";
    779     }
    780   },
    781   highlighter: function(li, query) {
    782     var regexp;
    783     if (!query) {
    784       return li;
    785     }
    786     regexp = new RegExp(">\\s*(\\w*?)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig');
    787     return li.replace(regexp, function(str, $1, $2, $3) {
    788       return '> ' + $1 + '<strong>' + $2 + '</strong>' + $3 + ' <';
    789     });
    790   },
    791   before_insert: function(value, $li) {
    792     return value;
    793   },
    794   inserting_wrapper: function($inputor, content, suffix) {
    795     var wrapped_content;
    796     suffix = suffix === "" ? suffix : suffix || " ";
    797     if ($inputor.is('textarea, input')) {
    798       return '' + content + suffix;
    799     } else if ($inputor.attr('contentEditable') === 'true') {
    800       suffix = suffix === " " ? "&nbsp;" : suffix;
    801       if (/firefox/i.test(navigator.userAgent)) {
    802         wrapped_content = "<span>" + content + suffix + "</span>";
    803       } else {
    804         suffix = "<span contenteditable='false'>" + suffix + "</span>";
    805         wrapped_content = "<span contenteditable='false'>" + content + suffix + "</span>";
    806       }
    807       if (this.app.document.selection) {
    808         wrapped_content = "<span contenteditable='true'>" + content + "</span>";
    809       }
    810       return wrapped_content + "<span></span>";
    811     }
    812   }
    813 };
     1122var Api;
    8141123
    8151124Api = {
     
    8201129    }
    8211130  },
    822   setIframe: function(iframe, standalone) {
    823     this.setIframe(iframe, standalone);
     1131  isSelecting: function() {
     1132    var ref;
     1133    return !!((ref = this.controller()) != null ? ref.view.visible() : void 0);
     1134  },
     1135  hide: function() {
     1136    var ref;
     1137    return (ref = this.controller()) != null ? ref.view.hide() : void 0;
     1138  },
     1139  reposition: function() {
     1140    var c;
     1141    if (c = this.controller()) {
     1142      return c.view.reposition(c.rect());
     1143    }
     1144  },
     1145  setIframe: function(iframe, asRoot) {
     1146    this.setupRootElement(iframe, asRoot);
    8241147    return null;
    8251148  },
     
    8341157
    8351158$.fn.atwho = function(method) {
    836   var result, _args;
     1159  var _args, result;
    8371160  _args = arguments;
    8381161  result = null;
     
    8471170      return result = Api[method].apply(app, Array.prototype.slice.call(_args, 1));
    8481171    } else {
    849       return $.error("Method " + method + " does not exist on jQuery.caret");
     1172      return $.error("Method " + method + " does not exist on jQuery.atwho");
    8501173    }
    8511174  });
    852   return result || this;
     1175  if (result != null) {
     1176    return result;
     1177  } else {
     1178    return this;
     1179  }
    8531180};
    8541181
     
    8571184  alias: void 0,
    8581185  data: null,
    859   tpl: "<li data-value='${atwho-at}${name}'>${name}</li>",
    860   insert_tpl: "<span id='${id}'>${atwho-data-value}</span>",
     1186  displayTpl: "<li>${name}</li>",
     1187  insertTpl: "${atwho-at}${name}",
     1188  headerTpl: null,
    8611189  callbacks: DEFAULT_CALLBACKS,
    862   search_key: "name",
     1190  functionOverrides: {},
     1191  searchKey: "name",
    8631192  suffix: void 0,
    864   hide_without_suffix: false,
    865   start_with_space: true,
    866   highlight_first: true,
     1193  hideWithoutSuffix: false,
     1194  startWithSpace: true,
     1195  acceptSpaceBar: false,
     1196  highlightFirst: true,
    8671197  limit: 5,
    868   max_len: 20,
    869   display_timeout: 300,
    870   delay: null
     1198  maxLen: 20,
     1199  minLen: 0,
     1200  displayTimeout: 300,
     1201  delay: null,
     1202  spaceSelectsMatch: false,
     1203  tabSelectsMatch: true,
     1204  editableAtwhoQueryAttrs: {},
     1205  scrollDuration: 150,
     1206  suspendOnComposing: true,
     1207  lookUpOnClick: true
    8711208};
    8721209
    873 
     1210$.fn.atwho.debug = false;
    8741211
    8751212}));
  • trunk/src/bp-core/js/vendor/jquery.caret.js

    • Property svn:executable set to *
    r11009 r11795  
    4141
    4242  EditableCaret.prototype.setPos = function(pos) {
     43    var fn, found, offset, sel;
     44    if (sel = oWindow.getSelection()) {
     45      offset = 0;
     46      found = false;
     47      (fn = function(pos, parent) {
     48        var node, range, _i, _len, _ref, _results;
     49        _ref = parent.childNodes;
     50        _results = [];
     51        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
     52          node = _ref[_i];
     53          if (found) {
     54            break;
     55          }
     56          if (node.nodeType === 3) {
     57            if (offset + node.length >= pos) {
     58              found = true;
     59              range = oDocument.createRange();
     60              range.setStart(node, pos - offset);
     61              sel.removeAllRanges();
     62              sel.addRange(range);
     63              break;
     64            } else {
     65              _results.push(offset += node.length);
     66            }
     67          } else {
     68            _results.push(fn(pos, node));
     69          }
     70        }
     71        return _results;
     72      })(pos, this.domInputor);
     73    }
    4374    return this.domInputor;
    4475  };
     
    95126    var clonedRange, offset, range, rect, shadowCaret;
    96127    if (oWindow.getSelection && (range = this.range())) {
    97       if (range.endOffset - 1 > 0 && range.endContainer === !this.domInputor) {
     128      if (range.endOffset - 1 > 0 && range.endContainer !== this.domInputor) {
    98129        clonedRange = range.cloneRange();
    99130        clonedRange.setStart(range.endContainer, range.endOffset - 1);
Note: See TracChangeset for help on using the changeset viewer.