[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
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 }));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Dec 26 01:01:04 2024 | Cross-referenced by PHPXref 0.7.1 |