Guest User

Untitled

a guest
Jul 15th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.41 KB | None | 0 0
  1. (function($) {
  2. function stopEvent(e) {
  3. e.preventDefault();
  4. e.stopPropagation();
  5. e.stopped = true;
  6. }
  7.  
  8. function getFirstDifferencePos(newS, oldS) {
  9. var boundary = Math.min(newS.length, oldS.length);
  10. for (var index = 0; index < boundary; ++index)
  11. if (newS[index] != oldS[index]) return index;
  12. return boundary;
  13. }
  14.  
  15. var AutoComplete = function(element, update, url, options) {
  16. var autocomplete = this;
  17.  
  18. this.element = element;
  19. this.url = url;
  20. this.update = update;
  21. this.hasFocus = false;
  22. this.changed = false;
  23. this.active = false;
  24. this.index = 0;
  25. this.entryCount = 0;
  26. this.oldElementValue = this.element.value;
  27. this.observer = null;
  28. this.options = $.extend({
  29. paramName: this.element.name,
  30. type: 'GET',
  31. tokens: [],
  32. frequency: 0.4,
  33. minChars: 1,
  34. onShow: function(element, update) {
  35. if (!update.style.position || update.style.position == 'absolute') {
  36. var position = $(element).position();
  37. $(update).css({
  38. position: 'absolute',
  39. left: position.left + 'px',
  40. top: $(element).outerHeight() + position.top + 'px',
  41. width: $(element).outerWidth() + 'px'
  42. });
  43. }
  44. $(update).fadeIn();
  45. },
  46. onHide: function(element, update) {
  47. $(update).fadeOut();
  48. }
  49. }, options);
  50.  
  51. if (typeof(this.options.tokens) == 'string') {
  52. this.options.tokens = new Array(this.options.tokens);
  53. }
  54. if (!$.inArray("\n", this.options.tokens)) {
  55. this.options.tokens.push("\n");
  56. }
  57.  
  58. $(this.update).hide();
  59. $(this.element).attr('autocomplete', 'off')
  60. .blur(function(e) { autocomplete.onBlur(e); })
  61. .keypress(function(e) { autocomplete.onKeyPress(e); });
  62. }
  63. $.extend(AutoComplete.prototype, {
  64. show: function() {
  65. if ($(this.update).not(':visible')) this.options.onShow(this.element, this.update);
  66. },
  67. hide: function() {
  68. this.stopIndicator();
  69. if ($(this.update).is(':visible')) this.options.onHide(this.element, this.update);
  70. },
  71. startIndicator: function() {
  72. if (this.options.indicator) $('#' + this.options.indicator).show();
  73. },
  74. stopIndicator: function() {
  75. if (this.options.indicator) $('#' + this.options.indicator).hide();
  76. },
  77. onKeyPress: function(e) {
  78. var autocomplete = this;
  79.  
  80. if (this.active) {
  81. switch (e.keyCode) {
  82. case 9: // tab
  83. case 13: // return
  84. this.selectEntry();
  85. stopEvent(e);
  86. case 27: // esc
  87. this.hide();
  88. this.active = false;
  89. stopEvent(e);
  90. case 37: // left
  91. case 39: // right
  92. return;
  93. case 38: // up
  94. this.markPrevious();
  95. this.render();
  96. stopEvent(e);
  97. return;
  98. case 40: // down
  99. this.markNext();
  100. this.render();
  101. stopEvent(e);
  102. return;
  103. }
  104. }
  105. else if (e.keyCode == 9 || e.keyCode == 13) return;
  106.  
  107. this.changed = this.hasFocus = true;
  108. if (this.observer) clearTimeout(this.observer);
  109. this.observer = setTimeout(function() { autocomplete.onObserverEvent(); }, this.frequency * 1000);
  110. },
  111. activate: function() {
  112. this.changed = false;
  113. this.hasFocus = true;
  114. this.getUpdatedChoices();
  115. },
  116. onHover: function(e) {
  117. if (this.index != e.target.autocompleteIndex) {
  118. this.index = e.target.autocompleteIndex;
  119. this.render();
  120. }
  121. stopEvent(e);
  122. },
  123. onClick: function(e) {
  124. this.index = e.target.autocompleteIndex;
  125. this.selectEntry();
  126. this.hide();
  127. },
  128. onBlur: function(e) {
  129. var autocomplete = this;
  130. setTimeout(function() { autocomplete.hide(); }, 250);
  131. this.active = this.hasFocus = false;
  132. },
  133. render: function() {
  134. if (this.entryCount > 0) {
  135. for (var i = 0; i < this.entryCount; ++i) {
  136. $(this.getEntry(i))[this.index == i ? 'addClass' : 'removeClass']('selected');
  137. }
  138. if (this.hasFocus) {
  139. this.show();
  140. this.active = true;
  141. }
  142. }
  143. else {
  144. this.active = false;
  145. this.hide();
  146. }
  147. },
  148. markPrevious: function() {
  149. if (this.index > 0) --this.index;
  150. else this.index = this.entryCount - 1;
  151. },
  152. markNext: function() {
  153. if (this.index < this.entryCount - 1) ++this.index;
  154. else this.index = 0;
  155. },
  156. getEntry: function(i) {
  157. return $(this.update.firstChild).children('li').get(i);
  158. },
  159. getCurrentEntry: function() {
  160. return this.getEntry(this.index);
  161. },
  162. selectEntry: function() {
  163. this.active = false;
  164. this.updateElement(this.getCurrentEntry());
  165. },
  166. updateElement: function(element) {
  167. if (this.options.updateElement) {
  168. this.options.updateElement(element);
  169. return;
  170. }
  171.  
  172. var value = $.trim(this.options.select ?
  173. $('.' + this.options.select, element).text() :
  174. $(element).text());
  175.  
  176. var bounds = this.getTokenBounds();
  177. if (bounds[0] != -1) {
  178. var newValue = this.element.value.substr(0, bounds[0]);
  179. var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/);
  180. if (whitespace) newValue += whitespace[0];
  181. this.element.value = newValue + value + this.element.value.substr(bounds[1]);
  182. }
  183. else {
  184. this.element.value = value;
  185. }
  186.  
  187. this.oldElementValue = $(this.element).focus().val();
  188.  
  189. if (this.options.afterUpdateElement) this.options.afterUpdateElement(this.element, element);
  190. },
  191. updateChoices: function(choices) {
  192. if (!this.changed && this.hasFocus) {
  193. $(this.update).html($.trim(choices));
  194. var i = 0, autocomplete = this;
  195. this.entryCount = $(this.update.firstChild).children('li').each(function() {
  196. this.autocompleteIndex = i++;
  197. autocomplete.addObservers(this);
  198. }).length;
  199. }
  200.  
  201. this.stopIndicator();
  202. this.index = 0;
  203.  
  204. if (this.entryCount == 1 && this.options.autoSelect) {
  205. this.selectEntry();
  206. this.hide();
  207. }
  208. else {
  209. this.render();
  210. }
  211. },
  212. addObservers: function(element) {
  213. var autocomplete = this;
  214. $(element)
  215. .mouseover(function(e) { autocomplete.onHover(e); })
  216. .click(function(e) { autocomplete.onClick(e); });
  217. },
  218. onObserverEvent: function() {
  219. this.changed = false;
  220. this.tokenBounds = null;
  221. if (this.getToken().length >= this.options.minChars) {
  222. this.getUpdatedChoices();
  223. }
  224. else {
  225. this.active = false;
  226. this.hide();
  227. }
  228. this.oldElementValue = this.element.value;
  229. },
  230. getToken: function() {
  231. var bounds = this.getTokenBounds();
  232. return $.trim(this.element.value.substring(bounds[0], bounds[1]));
  233. },
  234. getTokenBounds: function() {
  235. if (null != this.tokenBounds) return this.tokenBounds;
  236. var value = $.trim(this.element.value);
  237. if (!value.length) return [-1, 0];
  238. var diff = getFirstDifferencePos(value, this.oldElementValue);
  239. var offset = (diff == this.oldElementValue.length ? 1 : 0);
  240. var prevTokenPos = -1, nextTokenPos = value.length;
  241. for (var tp = null, index = 0, l = this.options.tokens.length; index < l; ++index) {
  242. tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
  243. if (tp > prevTokenPos) prevTokenPos = tp;
  244. tp = value.indexOf(this.options.tokens[index], diff + offset);
  245. if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
  246. }
  247. return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
  248. },
  249. getUpdatedChoices: function() {
  250. this.startIndicator();
  251.  
  252. var autocomplete = this, entry = encodeURIComponent(this.options.paramName) + '=' + encodeURIComponent(this.getToken());
  253. this.options.data = this.options.callback ? this.options.callback(this.element, entry) : entry;
  254.  
  255. if (this.options.defaultParams) this.options.data += '&' + this.options.defaultParams;
  256. var ajaxOptions = $.extend({}, this.options, {
  257. url: this.url,
  258. success: function(data, status) {
  259. autocomplete.updateChoices(data);
  260. }
  261. });
  262. $.ajax(ajaxOptions);
  263. }
  264. });
  265.  
  266. $.fn.autocomplete = function(options) {
  267. var update = $('#' + options.update).get(0), url = options.url;
  268. options.update = options.url = undefined;
  269. this.filter(':text').each(function() {
  270. new AutoComplete(this, update, url, options);
  271. });
  272. return this;
  273. }
  274. })(jQuery);
Add Comment
Please, Sign In to add comment