+function ($) { 'use strict'; var now = Date.now || function () { return new Date().getTime(); }; // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // `wait` msec. // // This utility function was originally implemented at Underscore.js. var debounce = function (func, wait) { var timeout, args, context, timestamp, result; var later = function () { var last = now() - timestamp; if (last < wait) { timeout = setTimeout(later, wait - last); } else { timeout = null; result = func.apply(context, args); context = args = null; } }; return function () { context = this; args = arguments; timestamp = now(); if (!timeout) { timeout = setTimeout(later, wait); } return result; }; }; function Adapter () {} $.extend(Adapter.prototype, { // Public properties // ----------------- id: null, // Identity. completer: null, // Completer object which creates it. el: null, // Textarea element. $el: null, // jQuery object of the textarea. option: null, // Public methods // -------------- initialize: function (element, completer, option) { this.el = element; this.$el = $(element); this.id = completer.id + this.constructor.name; this.completer = completer; this.option = option; if (this.option.debounce) { this._onKeyup = debounce(this._onKeyup, this.option.debounce); } this._bindEvents(); }, destroy: function () { this.$el.off('.' + this.id); // Remove all event handlers. this.$el = this.el = this.completer = null; }, // Update the element with the given value and strategy. // // value - The selected object. It is one of the item of the array // which was callbacked from the search function. // strategy - The Strategy associated with the selected value. select: function (/* value, strategy */) { throw new Error('Not implemented'); }, // Returns the caret's relative coordinates from body's left top corner. getCaretPosition: function () { var position = this._getCaretRelativePosition(); var offset = this.$el.offset(); // Calculate the left top corner of `this.option.appendTo` element. var $parent = this.option.appendTo; if ($parent) { if (!($parent instanceof $)) { $parent = $($parent); } var parentOffset = $parent.offsetParent().offset(); offset.top -= parentOffset.top; offset.left -= parentOffset.left; } position.top += offset.top; position.left += offset.left; return position; }, // Focus on the element. focus: function () { this.$el.focus(); }, // Private methods // --------------- _bindEvents: function () { this.$el.on('keyup.' + this.id, $.proxy(this._onKeyup, this)); }, _onKeyup: function (e) { if (this._skipSearch(e)) { return; } this.completer.trigger(this.getTextFromHeadToCaret(), true); }, // Suppress searching if it returns true. _skipSearch: function (clickEvent) { switch (clickEvent.keyCode) { case 9: // TAB case 13: // ENTER case 40: // DOWN case 38: // UP return true; } if (clickEvent.ctrlKey) switch (clickEvent.keyCode) { case 78: // Ctrl-N case 80: // Ctrl-P return true; } } }); $.fn.textcomplete.Adapter = Adapter; }(jQuery);