jquery.searchableSelect.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. (function($){
  2. // a case insensitive jQuery :contains selector
  3. $.expr[":"].searchableSelectContains = $.expr.createPseudo(function(arg) {
  4. return function( elem ) {
  5. return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
  6. };
  7. });
  8. $.searchableSelect = function(element, options) {
  9. this.element = element;
  10. this.options = options || {};
  11. this.init();
  12. var _this = this;
  13. this.searchableElement.click(function(event){
  14. // event.stopPropagation();
  15. _this.show();
  16. }).on('keydown', function(event){
  17. if (event.which === 13 || event.which === 40 || event.which == 38){
  18. event.preventDefault();
  19. _this.show();
  20. }
  21. });
  22. $(document).on('click', null, function(event){
  23. if(_this.searchableElement.has($(event.target)).length === 0)
  24. _this.hide();
  25. });
  26. this.input.on('keydown', function(event){
  27. event.stopPropagation();
  28. if(event.which === 13){ //enter
  29. event.preventDefault();
  30. _this.selectCurrentHoverItem();
  31. _this.hide();
  32. } else if (event.which == 27) { //ese
  33. _this.hide();
  34. } else if (event.which == 40) { //down
  35. _this.hoverNextItem();
  36. } else if (event.which == 38) { //up
  37. _this.hoverPreviousItem();
  38. }
  39. }).on('keyup', function(event){
  40. if(event.which != 13 && event.which != 27 && event.which != 38 && event.which != 40)
  41. _this.filter();
  42. })
  43. }
  44. var $sS = $.searchableSelect;
  45. $sS.fn = $sS.prototype = {
  46. version: '0.0.1'
  47. };
  48. $sS.fn.extend = $sS.extend = $.extend;
  49. $sS.fn.extend({
  50. init: function(){
  51. var _this = this;
  52. this.element.hide();
  53. this.searchableElement = $('<div tabindex="0" class="searchable-select" style="position: absolute;"></div>');
  54. this.holder = $('<div class="searchable-select-holder"></div>');
  55. this.dropdown = $('<div class="searchable-select-dropdown searchable-select-hide"></div>');
  56. this.input = $('<input type="text" class="searchable-select-input" />');
  57. this.items = $('<div class="searchable-select-items"></div>');
  58. this.caret = $('<span class="searchable-select-caret"></span>');
  59. this.scrollPart = $('<div class="searchable-scroll"></div>');
  60. this.hasPrivious = $('<div class="searchable-has-privious">...</div>');
  61. this.hasNext = $('<div class="searchable-has-next">...</div>');
  62. this.hasNext.on('mouseenter', function(){
  63. _this.hasNextTimer = null;
  64. var f = function(){
  65. var scrollTop = _this.items.scrollTop();
  66. _this.items.scrollTop(scrollTop + 20);
  67. _this.hasNextTimer = setTimeout(f, 50);
  68. }
  69. f();
  70. }).on('mouseleave', function(event) {
  71. clearTimeout(_this.hasNextTimer);
  72. });
  73. this.hasPrivious.on('mouseenter', function(){
  74. _this.hasPriviousTimer = null;
  75. var f = function(){
  76. var scrollTop = _this.items.scrollTop();
  77. _this.items.scrollTop(scrollTop - 20);
  78. _this.hasPriviousTimer = setTimeout(f, 50);
  79. }
  80. f();
  81. }).on('mouseleave', function(event) {
  82. clearTimeout(_this.hasPriviousTimer);
  83. });
  84. this.dropdown.append(this.input);
  85. this.dropdown.append(this.scrollPart);
  86. this.scrollPart.append(this.hasPrivious);
  87. this.scrollPart.append(this.items);
  88. this.scrollPart.append(this.hasNext);
  89. this.searchableElement.append(this.caret);
  90. this.searchableElement.append(this.holder);
  91. this.searchableElement.append(this.dropdown);
  92. this.element.after(this.searchableElement);
  93. this.buildItems();
  94. this.setPriviousAndNextVisibility();
  95. },
  96. filter: function(){
  97. var text = this.input.val();
  98. this.items.find('.searchable-select-item').addClass('searchable-select-hide');
  99. this.items.find('.searchable-select-item:searchableSelectContains('+text+')').removeClass('searchable-select-hide');
  100. if(this.currentSelectedItem.hasClass('searchable-select-hide') && this.items.find('.searchable-select-item:not(.searchable-select-hide)').length > 0){
  101. this.hoverFirstNotHideItem();
  102. }
  103. this.setPriviousAndNextVisibility();
  104. },
  105. hoverFirstNotHideItem: function(){
  106. this.hoverItem(this.items.find('.searchable-select-item:not(.searchable-select-hide)').first());
  107. },
  108. selectCurrentHoverItem: function(){
  109. if(!this.currentHoverItem.hasClass('searchable-select-hide'))
  110. this.selectItem(this.currentHoverItem);
  111. },
  112. hoverPreviousItem: function(){
  113. if(!this.hasCurrentHoverItem())
  114. this.hoverFirstNotHideItem();
  115. else{
  116. var prevItem = this.currentHoverItem.prevAll('.searchable-select-item:not(.searchable-select-hide):first')
  117. if(prevItem.length > 0)
  118. this.hoverItem(prevItem);
  119. }
  120. },
  121. hoverNextItem: function(){
  122. if(!this.hasCurrentHoverItem())
  123. this.hoverFirstNotHideItem();
  124. else{
  125. var nextItem = this.currentHoverItem.nextAll('.searchable-select-item:not(.searchable-select-hide):first')
  126. if(nextItem.length > 0)
  127. this.hoverItem(nextItem);
  128. }
  129. },
  130. buildItems: function(){
  131. var _this = this;
  132. this.element.find('option').each(function(){
  133. var item = $('<div class="searchable-select-item" data-value="'+$(this).attr('value')+'">'+$(this).text()+'</div>');
  134. if(this.selected){
  135. _this.selectItem(item);
  136. _this.hoverItem(item);
  137. }
  138. item.on('mouseenter', function(){
  139. $(this).addClass('hover');
  140. }).on('mouseleave', function(){
  141. $(this).removeClass('hover');
  142. }).click(function(event){
  143. event.stopPropagation();
  144. _this.selectItem($(this));
  145. _this.hide();
  146. });
  147. _this.items.append(item);
  148. });
  149. this.items.on('scroll', function(){
  150. _this.setPriviousAndNextVisibility();
  151. })
  152. },
  153. show: function(){
  154. this.dropdown.removeClass('searchable-select-hide');
  155. this.input.focus();
  156. this.status = 'show';
  157. this.setPriviousAndNextVisibility();
  158. closeScroll();
  159. console.log(132);
  160. },
  161. hide: function(){
  162. if(!(this.status === 'show'))
  163. return;
  164. if(this.items.find(':not(.searchable-select-hide)').length === 0)
  165. this.input.val('');
  166. this.dropdown.addClass('searchable-select-hide');
  167. this.searchableElement.trigger('focus');
  168. this.status = 'hide';
  169. openScroll();
  170. },
  171. hasCurrentSelectedItem: function(){
  172. return this.currentSelectedItem && this.currentSelectedItem.length > 0;
  173. },
  174. selectItem: function(item){
  175. if(this.hasCurrentSelectedItem())
  176. this.currentSelectedItem.removeClass('selected');
  177. this.currentSelectedItem = item;
  178. item.addClass('selected');
  179. this.hoverItem(item);
  180. this.holder.text(item.text());
  181. var value = item.data('value');
  182. this.holder.data('value', value);
  183. this.element.val(value);
  184. if(this.options.afterSelectItem){
  185. this.options.afterSelectItem.apply(this);
  186. }
  187. setselect();
  188. },
  189. hasCurrentHoverItem: function(){
  190. return this.currentHoverItem && this.currentHoverItem.length > 0;
  191. },
  192. hoverItem: function(item){
  193. if(this.hasCurrentHoverItem())
  194. this.currentHoverItem.removeClass('hover');
  195. if(item.outerHeight() + item.position().top > this.items.height())
  196. this.items.scrollTop(this.items.scrollTop() + item.outerHeight() + item.position().top - this.items.height());
  197. else if(item.position().top < 0)
  198. this.items.scrollTop(this.items.scrollTop() + item.position().top);
  199. this.currentHoverItem = item;
  200. item.addClass('hover');
  201. },
  202. setPriviousAndNextVisibility: function(){
  203. if(this.items.scrollTop() === 0){
  204. this.hasPrivious.addClass('searchable-select-hide');
  205. this.scrollPart.removeClass('has-privious');
  206. } else {
  207. this.hasPrivious.removeClass('searchable-select-hide');
  208. this.scrollPart.addClass('has-privious');
  209. }
  210. if(this.items.scrollTop() + this.items.innerHeight() >= this.items[0].scrollHeight){
  211. this.hasNext.addClass('searchable-select-hide');
  212. this.scrollPart.removeClass('has-next');
  213. } else {
  214. this.hasNext.removeClass('searchable-select-hide');
  215. this.scrollPart.addClass('has-next');
  216. }
  217. }
  218. });
  219. $.fn.searchableSelect = function(options){
  220. this.each(function(){
  221. var sS = new $sS($(this), options);
  222. });
  223. return this;
  224. };
  225. })(jQuery);