[ Index ]

PHP Cross Reference of BuddyPress

title

Body

[close]

/src/bp-core/js/vendor/ -> jquery.atwho.js (source)

   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   */
   7  (function (root, factory) {
   8    if (typeof define === 'function' && define.amd) {
   9      // AMD. Register as an anonymous module unless amdModuleId is set.
  10      define(["jquery"], function (a0) {
  11        return (factory(a0));
  12      });
  13    } else if (typeof exports === 'object') {
  14      // Node. Does not work with strict CommonJS, but
  15      // only CommonJS-like environments that support module.exports,
  16      // like Node.
  17      module.exports = factory(require("jquery"));
  18    } else {
  19      factory(jQuery);
  20    }
  21  }(this, function ($) {
  22  var DEFAULT_CALLBACKS, KEY_CODE;
  23  
  24  KEY_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  
  40  DEFAULT_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  
 124  var App;
 125  
 126  App = (function() {
 127    function App(inputor) {
 128      this.currentFlag = null;
 129      this.controllers = {};
 130      this.aliasMaps = {};
 131      this.$inputor = $(inputor);
 132      this.setupRootElement();
 133      this.listen();
 134    }
 135  
 136    App.prototype.createContainer = function(doc) {
 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;
 148      }
 149      if (iframe) {
 150        this.window = iframe.contentWindow;
 151        this.document = iframe.contentDocument || this.window.document;
 152        this.iframe = iframe;
 153      } else {
 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);
 167    };
 168  
 169    App.prototype.controller = function(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) {
 178            current = c;
 179            break;
 180          }
 181        }
 182      }
 183      if (current) {
 184        return current;
 185      } else {
 186        return this.controllers[this.currentFlag];
 187      }
 188    };
 189  
 190    App.prototype.setContextFor = function(at) {
 191      this.currentFlag = at;
 192      return this;
 193    };
 194  
 195    App.prototype.reg = function(flag, setting) {
 196      var base, controller;
 197      controller = (base = this.controllers)[flag] || (base[flag] = this.$inputor.is('[contentEditable]') ? new EditableController(this, flag) : new TextareaController(this, flag));
 198      if (setting.alias) {
 199        this.aliasMaps[setting.alias] = flag;
 200      }
 201      controller.init(setting);
 202      return this;
 203    };
 204  
 205    App.prototype.listen = function() {
 206      return this.$inputor.on('compositionstart', (function(_this) {
 207        return function(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);
 226        };
 227      })(this)).on('keydown.atwhoInner', (function(_this) {
 228        return function(e) {
 229          return _this.onKeydown(e);
 230        };
 231      })(this)).on('blur.atwhoInner', (function(_this) {
 232        return function(e) {
 233          var c;
 234          if (c = _this.controller()) {
 235            c.expectedQueryCBId = null;
 236            return c.view.hide(e, c.getOpt("displayTimeout"));
 237          }
 238        };
 239      })(this)).on('click.atwhoInner', (function(_this) {
 240        return function(e) {
 241          return _this.dispatch(e);
 242        };
 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)());
 260    };
 261  
 262    App.prototype.shutdown = function() {
 263      var _, c, ref;
 264      ref = this.controllers;
 265      for (_ in ref) {
 266        c = ref[_];
 267        c.destroy();
 268        delete this.controllers[_];
 269      }
 270      this.$inputor.off('.atwhoInner');
 271      return this.$el.remove();
 272    };
 273  
 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;
 287      switch (e.keyCode) {
 288        case KEY_CODE.ESC:
 289          e.preventDefault();
 290          if ((ref = this.controller()) != null) {
 291            ref.view.hide();
 292          }
 293          break;
 294        case KEY_CODE.DOWN:
 295        case KEY_CODE.UP:
 296        case KEY_CODE.CTRL:
 297        case KEY_CODE.ENTER:
 298          $.noop();
 299          break;
 300        case KEY_CODE.P:
 301        case KEY_CODE.N:
 302          if (!e.ctrlKey) {
 303            this.dispatch(e);
 304          }
 305          break;
 306        default:
 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;
 314      if (!(view && view.visible())) {
 315        return;
 316      }
 317      switch (e.keyCode) {
 318        case KEY_CODE.ESC:
 319          e.preventDefault();
 320          view.hide(e);
 321          break;
 322        case KEY_CODE.UP:
 323          e.preventDefault();
 324          view.prev();
 325          break;
 326        case KEY_CODE.DOWN:
 327          e.preventDefault();
 328          view.next();
 329          break;
 330        case KEY_CODE.P:
 331          if (!e.ctrlKey) {
 332            return;
 333          }
 334          e.preventDefault();
 335          view.prev();
 336          break;
 337        case KEY_CODE.N:
 338          if (!e.ctrlKey) {
 339            return;
 340          }
 341          e.preventDefault();
 342          view.next();
 343          break;
 344        case KEY_CODE.TAB:
 345        case KEY_CODE.ENTER:
 346        case KEY_CODE.SPACE:
 347          if (!view.visible()) {
 348            return;
 349          }
 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          }
 362          break;
 363        default:
 364          $.noop();
 365      }
 366    };
 367  
 368    return App;
 369  
 370  })();
 371  
 372  var Controller,
 373    slice = [].slice;
 374  
 375  Controller = (function() {
 376    Controller.prototype.uid = function() {
 377      return (Math.random().toString(16) + "000000000").substr(2, 8) + (new Date().getTime());
 378    };
 379  
 380    function Controller(app, at1) {
 381      this.app = app;
 382      this.at = at1;
 383      this.$inputor = this.app.$inputor;
 384      this.id = this.$inputor[0].id || this.uid();
 385      this.expectedQueryCBId = null;
 386      this.setting = null;
 387      this.query = null;
 388      this.pos = 0;
 389      this.range = null;
 390      if ((this.$el = $("#atwho-ground-" + this.id, this.app.$el)).length === 0) {
 391        this.app.$el.append(this.$el = $("<div id='atwho-ground-" + this.id + "'></div>"));
 392      }
 393      this.model = new Model(this);
 394      this.view = new View(this);
 395    }
 396  
 397    Controller.prototype.init = function(setting) {
 398      this.setting = $.extend({}, this.setting || $.fn.atwho["default"], setting);
 399      this.view.init();
 400      return this.model.reload(this.setting.data);
 401    };
 402  
 403    Controller.prototype.destroy = function() {
 404      this.trigger('beforeDestroy');
 405      this.model.destroy();
 406      this.view.destroy();
 407      return this.$el.remove();
 408    };
 409  
 410    Controller.prototype.callDefault = function() {
 411      var args, error, error1, funcName;
 412      funcName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
 413      try {
 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);
 418      }
 419    };
 420  
 421    Controller.prototype.trigger = function(name, data) {
 422      var alias, eventName;
 423      if (data == null) {
 424        data = [];
 425      }
 426      data.push(this);
 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;
 438      try {
 439        return this.setting[at];
 440      } catch (error1) {
 441        e = error1;
 442        return null;
 443      }
 444    };
 445  
 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 (!Array.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) {
 542          return;
 543        }
 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  
 558  var 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  
 562  TextareaController = (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', {
 573        iframe: this.app.iframe
 574      });
 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;
 583        end = start + query.length;
 584        this.pos = start;
 585        query = {
 586          'text': query,
 587          'headPos': start,
 588          'endPos': end
 589        };
 590        this.trigger("matched", [this.at, query.text]);
 591      } else {
 592        query = null;
 593        this.view.hide();
 594      }
 595      return this.query = query;
 596    };
 597  
 598    TextareaController.prototype.rect = function() {
 599      var c, iframeOffset, scaleBottom;
 600      if (!(c = this.$inputor.caret('offset', this.pos - 1, {
 601        iframe: this.app.iframe
 602      }))) {
 603        return;
 604      }
 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;
 611      return {
 612        left: c.left,
 613        top: c.top,
 614        bottom: c.top + c.height + scaleBottom
 615      };
 616    };
 617  
 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
 629      });
 630      if (!$inputor.is(':focus')) {
 631        $inputor.trigger( 'focus' );
 632      }
 633      return $inputor.trigger( 'change' );
 634    };
 635  
 636    return TextareaController;
 637  
 638  })(Controller);
 639  
 640  var 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  
 644  EditableController = (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  
 854  var Model;
 855  
 856  Model = (function() {
 857    function Model(context) {
 858      this.context = context;
 859      this.at = this.context.at;
 860      this.storage = this.context.$inputor;
 861    }
 862  
 863    Model.prototype.destroy = function() {
 864      return this.storage.data(this.at, null);
 865    };
 866  
 867    Model.prototype.saved = function() {
 868      return this.fetch() > 0;
 869    };
 870  
 871    Model.prototype.query = function(query, callback) {
 872      var _remoteFilter, data, searchKey;
 873      data = this.fetch();
 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)) {
 878        return callback(data);
 879      } else {
 880        return _remoteFilter.call(this.context, query, callback);
 881      }
 882    };
 883  
 884    Model.prototype.fetch = function() {
 885      return this.storage.data(this.at) || [];
 886    };
 887  
 888    Model.prototype.save = function(data) {
 889      return this.storage.data(this.at, this.context.callbacks("beforeSave").call(this.context, data || []));
 890    };
 891  
 892    Model.prototype.load = function(data) {
 893      if (!(this.saved() || !data)) {
 894        return this._load(data);
 895      }
 896    };
 897  
 898    Model.prototype.reload = function(data) {
 899      return this._load(data);
 900    };
 901  
 902    Model.prototype._load = function(data) {
 903      if (typeof data === "string") {
 904        return $.ajax(data, {
 905          dataType: "json"
 906        }).done((function(_this) {
 907          return function(data) {
 908            return _this.save(data);
 909          };
 910        })(this));
 911      } else {
 912        return this.save(data);
 913      }
 914    };
 915  
 916    return Model;
 917  
 918  })();
 919  
 920  var View;
 921  
 922  View = (function() {
 923    function View(context) {
 924      this.context = context;
 925      this.$el = $("<div class='atwho-view'><ul class='atwho-view-ul'></ul></div>");
 926      this.$elUl = this.$el.children();
 927      this.timeoutID = null;
 928      this.context.$el.append(this.$el);
 929      this.bindEvent();
 930    }
 931  
 932    View.prototype.init = function() {
 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      }
 939      return this.$el.attr({
 940        'id': "at-view-" + id
 941      });
 942    };
 943  
 944    View.prototype.destroy = function() {
 945      return this.$el.remove();
 946    };
 947  
 948    View.prototype.bindEvent = function() {
 949      var $menu, lastCoordX, lastCoordY;
 950      $menu = this.$el.find('ul');
 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) {
 969        return function(e) {
 970          $menu.find('.cur').removeClass('cur');
 971          $(e.currentTarget).addClass('cur');
 972          _this.choose(e);
 973          return e.preventDefault();
 974        };
 975      })(this));
 976    };
 977  
 978    View.prototype.visible = function() {
 979      return $.expr.pseudos.visible(this.$el[0]);
 980    };
 981  
 982    View.prototype.highlighted = function() {
 983      return this.$el.find(".cur").length > 0;
 984    };
 985  
 986    View.prototype.choose = function(e) {
 987      var $li, content;
 988      if (($li = this.$el.find(".cur")).length) {
 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);
 992        this.context.trigger("inserted", [$li, e]);
 993        this.hide(e);
 994      }
 995      if (this.context.getOpt("hideWithoutSuffix")) {
 996        return this.stopShowing = true;
 997      }
 998    };
 999  
1000    View.prototype.reposition = function(rect) {
1001      var _window, offset, overflowOffset, ref;
1002      _window = this.context.app.iframeAsRoot ? this.context.app.window : window;
1003      if (rect.bottom + this.$el.height() - $(_window).scrollTop() > $(_window).height()) {
1004        rect.bottom = rect.top - this.$el.height();
1005      }
1006      if (rect.left > (overflowOffset = $(_window).width() - this.$el.width() - 5)) {
1007        rect.left = overflowOffset;
1008      }
1009      offset = {
1010        left: rect.left,
1011        top: rect.bottom
1012      };
1013      if ((ref = this.context.callbacks("beforeReposition")) != null) {
1014        ref.call(this.context, offset);
1015      }
1016      this.$el.offset(offset);
1017      return this.context.trigger("reposition", [offset]);
1018    };
1019  
1020    View.prototype.next = function() {
1021      var cur, next, nextEl, offset;
1022      cur = this.$el.find('.cur').removeClass('cur');
1023      next = cur.next();
1024      if (!next.length) {
1025        next = this.$el.find('li:first');
1026      }
1027      next.addClass('cur');
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()));
1031    };
1032  
1033    View.prototype.prev = function() {
1034      var cur, offset, prev, prevEl;
1035      cur = this.$el.find('.cur').removeClass('cur');
1036      prev = cur.prev();
1037      if (!prev.length) {
1038        prev = this.$el.find('li:last');
1039      }
1040      prev.addClass('cur');
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      }
1056    };
1057  
1058    View.prototype.show = function() {
1059      var rect;
1060      if (this.stopShowing) {
1061        this.stopShowing = false;
1062        return;
1063      }
1064      if (!this.visible()) {
1065        this.$el.show();
1066        this.$el.scrollTop(0);
1067        this.context.trigger('shown');
1068      }
1069      if (rect = this.context.rect()) {
1070        return this.reposition(rect);
1071      }
1072    };
1073  
1074    View.prototype.hide = function(e, time) {
1075      var callback;
1076      if (!this.visible()) {
1077        return;
1078      }
1079      if (isNaN(time)) {
1080        this.$el.hide();
1081        return this.context.trigger('hidden', [e]);
1082      } else {
1083        callback = (function(_this) {
1084          return function() {
1085            return _this.hide();
1086          };
1087        })(this);
1088        clearTimeout(this.timeoutID);
1089        return this.timeoutID = setTimeout(callback, time);
1090      }
1091    };
1092  
1093    View.prototype.render = function(list) {
1094      var $li, $ul, i, item, len, li, tpl;
1095      if (!(Array.isArray(list) && list.length > 0)) {
1096        this.hide();
1097        return;
1098      }
1099      this.$el.find('ul').empty();
1100      $ul = this.$el.find('ul');
1101      tpl = this.context.getOpt('displayTpl');
1102      for (i = 0, len = list.length; i < len; i++) {
1103        item = list[i];
1104        item = $.extend({}, item, {
1105          'atwho-at': this.context.at
1106        });
1107        li = this.context.callbacks("tplEval").call(this.context, tpl, item, "onDisplay");
1108        $li = $(this.context.callbacks("highlighter").call(this.context, li, this.context.query.text));
1109        $li.data("item-data", item);
1110        $ul.append($li);
1111      }
1112      this.show();
1113      if (this.context.getOpt('highlightFirst')) {
1114        return $ul.find("li:first").addClass("cur");
1115      }
1116    };
1117  
1118    return View;
1119  
1120  })();
1121  
1122  var Api;
1123  
1124  Api = {
1125    load: function(at, data) {
1126      var c;
1127      if (c = this.controller(at)) {
1128        return c.model.load(data);
1129      }
1130    },
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);
1147      return null;
1148    },
1149    run: function() {
1150      return this.dispatch();
1151    },
1152    destroy: function() {
1153      this.shutdown();
1154      return this.$inputor.data('atwho', null);
1155    }
1156  };
1157  
1158  $.fn.atwho = function(method) {
1159    var _args, result;
1160    _args = arguments;
1161    result = null;
1162    this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function() {
1163      var $this, app;
1164      if (!(app = ($this = $(this)).data("atwho"))) {
1165        $this.data('atwho', (app = new App(this)));
1166      }
1167      if (typeof method === 'object' || !method) {
1168        return app.reg(method.at, method);
1169      } else if (Api[method] && app) {
1170        return result = Api[method].apply(app, Array.prototype.slice.call(_args, 1));
1171      } else {
1172        return $.error("Method " + method + " does not exist on jQuery.atwho");
1173      }
1174    });
1175    if (result != null) {
1176      return result;
1177    } else {
1178      return this;
1179    }
1180  };
1181  
1182  $.fn.atwho["default"] = {
1183    at: void 0,
1184    alias: void 0,
1185    data: null,
1186    displayTpl: "<li>$name}</li>",
1187    insertTpl: "$atwho-at}$name}",
1188    headerTpl: null,
1189    callbacks: DEFAULT_CALLBACKS,
1190    functionOverrides: {},
1191    searchKey: "name",
1192    suffix: void 0,
1193    hideWithoutSuffix: false,
1194    startWithSpace: true,
1195    acceptSpaceBar: false,
1196    highlightFirst: true,
1197    limit: 5,
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
1208  };
1209  
1210  $.fn.atwho.debug = false;
1211  
1212  }));


Generated: Thu Dec 26 01:01:04 2024 Cross-referenced by PHPXref 0.7.1