UNPKG

@universityofwarwick/bootstrap-3-typeahead

Version:

Bootstrap 3 Typeahead: The typeahead autocomplete plugin for Twitter's Bootstrap 2 ready to use with Bootstrap 3.

1 lines 15.3 kB
!function(root,factory){"use strict";"undefined"!=typeof module&&module.exports?module.exports=factory(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],factory):factory(root.jQuery)}(this,function($){"use strict";var idCounter=1e5;function getOrGenId(element){var id=element.getAttribute("id");return id||(id="gen-id-"+idCounter++,element.setAttribute("id",id)),id}var Typeahead=function(element,options){this.$element=$(element),this.$parent=this.$element.parent(),this.options=$.extend({},Typeahead.defaults,options),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.select=this.options.select||this.select,this.autoSelect="boolean"!=typeof this.options.autoSelect||this.options.autoSelect,this.highlighter=this.options.highlighter||this.highlighter,this.render=this.options.render||this.render,this.updater=this.options.updater||this.updater,this.displayText=this.options.displayText||this.displayText,this.itemLink=this.options.itemLink||this.itemLink,this.itemTitle=this.options.itemTitle||this.itemTitle,this.followLinkOnSelect=this.options.followLinkOnSelect||this.followLinkOnSelect,this.source=this.options.source,this.delay=this.options.delay,this.theme=this.options.theme&&this.options.themes&&this.options.themes[this.options.theme]||Typeahead.defaults.themes[Typeahead.defaults.theme],this.$menu=$(this.options.menu||this.theme.menu),this.$appendTo=this.options.appendTo?$(this.options.appendTo):null,this.fitToElement="boolean"==typeof this.options.fitToElement&&this.options.fitToElement,this.shown=!1,this.listen(),this.showHintOnFocus=("boolean"==typeof this.options.showHintOnFocus||"all"===this.options.showHintOnFocus)&&this.options.showHintOnFocus,this.afterSelect=this.options.afterSelect,this.afterEmptySelect=this.options.afterEmptySelect,this.addItem=!1,this.value=this.$element.val()||this.$element.text(),this.keyPressed=!1,this.focused=this.$element.is(":focus"),this.changeInputOnSelect=this.options.changeInputOnSelect||this.changeInputOnSelect,this.changeInputOnMove=this.options.changeInputOnMove||this.changeInputOnMove,this.openLinkInNewTab=this.options.openLinkInNewTab||this.openLinkInNewTab,this.selectOnBlur=this.options.selectOnBlur||this.selectOnBlur,this.selectOnTab=this.options.selectOnTab,this.showCategoryHeader=this.options.showCategoryHeader||this.showCategoryHeader,this.prevItems=[],this.$statusRegion=$("<div></div>").addClass("sr-only").attr({role:"status","aria-live":"polite"}),this.$element.after(this.$statusRegion),this.$parent.attr({role:"combobox","aria-haspopup":"listbox"}),this.$element.attr({"aria-autocomplete":"list"}),this.show(),this.hide()};Typeahead.prototype={constructor:Typeahead,setDefault:function(val){var newVal;return this.$element.data("active",val),(this.autoSelect||val)&&(newVal=(newVal=this.updater(val))||"",this.$element.val(this.displayText(newVal)||newVal).text(this.displayText(newVal)||newVal).change(),this.afterSelect(newVal)),this.hide()},select:function(){var newVal,val=this.$menu.find(".active").data("value");return this.$element.data("active",val),this.autoSelect||val?(newVal=(newVal=this.updater(val))||"",this.changeInputOnSelect&&this.$element.val(this.displayText(newVal)||newVal).text(this.displayText(newVal)||newVal).change(),this.followLinkOnSelect&&this.itemLink(val)?(this.openLinkInNewTab?window.open(this.itemLink(val),"_blank"):document.location=this.itemLink(val),this.afterSelect(newVal)):this.followLinkOnSelect&&!this.itemLink(val)?this.afterEmptySelect(newVal):this.afterSelect(newVal)):this.afterEmptySelect(),this.hide()},updater:function(item){return item},setSource:function(source){this.source=source},show:function(){var element,offset,pos=$.extend({},this.$element.position(),{height:this.$element[0].offsetHeight}),scrollHeight="function"==typeof this.options.scrollHeight?this.options.scrollHeight.call():this.options.scrollHeight;this.shown?element=this.$menu:this.$appendTo?(element=this.$menu.appendTo(this.$appendTo),this.hasSameParent=this.$appendTo.is(this.$element.parent())):(element=this.$menu.insertAfter(this.$element),this.hasSameParent=!0),this.hasSameParent||(element.css("position","fixed"),offset=this.$element.offset(),pos.top=offset.top,pos.left=offset.left);var newTop=$(element).parent().hasClass("dropup")?"auto":pos.top+pos.height+scrollHeight,newLeft=$(element).hasClass("dropdown-menu-right")?"auto":pos.left;return element.css({top:newTop,left:newLeft}).show(),!0===this.options.fitToElement&&element.css("width",this.$element.outerWidth()+"px"),this.shown=!0,this.$parent.attr("aria-expanded","true"),this.$parent.attr("aria-owns",getOrGenId(element[0])),this.$element.attr("aria-controls",getOrGenId(element[0])),this},hide:function(){return this.$menu.hide(),this.prevItems=[],this.shown=!1,this.$parent.attr("aria-expanded","false"),this.$element.attr("aria-activedescendant",null),this},lookup:function(query){if(this.query=null!=query?query:this.$element.val(),this.query.length<this.options.minLength&&!this.options.showHintOnFocus)return this.shown?this.hide():this;var worker=$.proxy(function(){$.isFunction(this.source)&&3===this.source.length?this.source(this.query,$.proxy(this.process,this),$.proxy(this.process,this)):$.isFunction(this.source)?this.source(this.query,$.proxy(this.process,this)):this.source&&this.process(this.source)},this);clearTimeout(this.lookupWorker),this.lookupWorker=setTimeout(worker,this.delay)},process:function(items){var that=this,oldItems=this.prevItems;return this.prevItems=items,this.onItemsChanged(oldItems||[],items),items=$.grep(items,function(item){return that.matcher(item)}),(items=this.sorter(items)).length||this.options.addItem?(0<items.length?this.$element.data("active",items[0]):this.$element.data("active",null),items=this._limitListSize(items),this.options.addItem&&items.push(this.options.addItem),this.render(items).show()):this.shown?this.hide():this},_limitListSize:function(items){return"all"===this.options.items?items:items.slice(0,this.options.items)},matcher:function(item){return~this.displayText(item).toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(items){for(var item,beginswith=[],caseSensitive=[],caseInsensitive=[];item=items.shift();){var it=this.displayText(item);it.toLowerCase().indexOf(this.query.toLowerCase())?~it.indexOf(this.query)?caseSensitive.push(item):caseInsensitive.push(item):beginswith.push(item)}return beginswith.concat(caseSensitive,caseInsensitive)},highlighter:function(item){var text=this.query;if(""===text)return item;var matches=item.match(/(>)([^<]*)(<)/g),first=[],second=[];if(matches&&matches.length)for(i=0;i<matches.length;++i)2<matches[i].length&&first.push(matches[i]);else(first=[]).push(item);text=text.replace(/[\(\)\/\.\*\+\?\[\]]/g,function(mat){return"\\"+mat});for(var m,reg=new RegExp(text,"g"),i=0;i<first.length;++i)(m=first[i].match(reg))&&0<m.length&&second.push(first[i]);for(i=0;i<second.length;++i)item=item.replace(second[i],second[i].replace(reg,"<strong>$&</strong>"));return item},onItemsChanged:function(oldItems,newItems){var oldItemsShown=this._limitListSize(oldItems),newItemsShown=this._limitListSize(newItems);!oldItemsShown.length&&newItemsShown.length?this._setLiveStatus(newItemsShown.length+" results, use arrow keys"):oldItemsShown.length&&!newItemsShown.length&&this._setLiveStatus("No results, try another query")},render:function(items){var that=this,self=this,activeFound=!1,data=[],_category=that.options.separator;return $.each(items,function(key,value){0<key&&value[_category]!==items[key-1][_category]&&data.push({__type:"divider"}),that.showCategoryHeader&&(!value[_category]||0!==key&&value[_category]===items[key-1][_category]||data.push({__type:"category",name:value[_category]})),data.push(value)}),items=$(data).map(function(i,item){if("category"==(item.__type||!1))return $(that.options.headerHtml||that.theme.headerHtml).text(item.name)[0];if("divider"==(item.__type||!1))return $(that.options.headerDivider||that.theme.headerDivider)[0];var htmlString,$html,text=self.displayText(item),itemTitle=self.itemTitle(item),ariaLabel=itemTitle||(htmlString=text,($html=$("<div></div>").html(htmlString)).find("div,p,section,h1,h2,h3,h4,h5,h6").append(" "),$html.text());return(i=$(that.options.item||that.theme.item).data("value",item)).find(that.options.itemContentSelector||that.theme.itemContentSelector).addBack(that.options.itemContentSelector||that.theme.itemContentSelector).attr("aria-label",ariaLabel).html(that.highlighter(text,item)),that.options.followLinkOnSelect&&i.find("a").attr("href",self.itemLink(item)),i.find("a").attr("title",itemTitle),text==self.$element.val()&&(self._markActive(i),self.$element.data("active",item),activeFound=!0),i[0]}),this.autoSelect&&!activeFound&&(this._markActive(items.filter(":not(.dropdown-header)").first()),this.$element.data("active",items.first().data("value"))),this.$menu.html(items),this},displayText:function(item){return void 0!==item&&void 0!==item.name?item.name:item},itemLink:function(item){return null},itemTitle:function(item){return null},_markActive:function($li){$li.addClass("active"),$li.attr("aria-selected","true"),this.$element.attr("aria-activedescendant",getOrGenId($li[0]))},next:function(event){var next=this.$menu.find(".active").removeClass("active").attr("aria-selected","false").next();for(next.length||(next=$(this.$menu.find($(this.options.item||this.theme.item).prop("tagName"))[0]));next.hasClass("divider")||next.hasClass("dropdown-header");)next=next.next();this._markActive(next);var newVal=this.updater(next.data("value"));this.changeInputOnMove&&this.$element.val(this.displayText(newVal)||newVal)},prev:function(event){var prev=this.$menu.find(".active").removeClass("active").attr("aria-selected","false").prev();for(prev.length||(prev=this.$menu.find($(this.options.item||this.theme.item).prop("tagName")).last());prev.hasClass("divider")||prev.hasClass("dropdown-header");)prev=prev.prev();this._markActive(prev);var newVal=this.updater(prev.data("value"));this.changeInputOnMove&&this.$element.val(this.displayText(newVal)||newVal)},listen:function(){this.$element.on("focus.bootstrap3Typeahead",$.proxy(this.focus,this)).on("blur.bootstrap3Typeahead",$.proxy(this.blur,this)).on("keypress.bootstrap3Typeahead",$.proxy(this.keypress,this)).on("propertychange.bootstrap3Typeahead input.bootstrap3Typeahead",$.proxy(this.input,this)).on("keyup.bootstrap3Typeahead",$.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown.bootstrap3Typeahead",$.proxy(this.keydown,this));var eventSelector=$(this.options.item||this.theme.item).prop("tagName")+":not(.divider):not(.dropdown-header)";this.$menu.on("click",eventSelector,$.proxy(this.click,this)).on("mouseenter",eventSelector,$.proxy(this.mouseenter,this)).on("mouseleave",eventSelector,$.proxy(this.mouseleave,this)).on("mousedown",$.proxy(this.mousedown,this))},destroy:function(){this.$element.data("typeahead",null),this.$element.data("active",null),this.$element.unbind("focus.bootstrap3Typeahead").unbind("blur.bootstrap3Typeahead").unbind("keypress.bootstrap3Typeahead").unbind("propertychange.bootstrap3Typeahead input.bootstrap3Typeahead").unbind("keyup.bootstrap3Typeahead"),this.eventSupported("keydown")&&this.$element.unbind("keydown.bootstrap3Typeahead"),this.$menu.remove(),this.destroyed=!0},eventSupported:function(eventName){var isSupported=eventName in this.$element;return isSupported||(this.$element.setAttribute(eventName,"return;"),isSupported="function"==typeof this.$element[eventName]),isSupported},move:function(e){if(this.shown)switch(e.keyCode){case 9:this.selectOnTab?e.preventDefault():this.hide();break;case 13:case 27:e.preventDefault();break;case 38:if(e.shiftKey)return;e.preventDefault(),this.prev();break;case 40:if(e.shiftKey)return;e.preventDefault(),this.next()}},keydown:function(e){17!==e.keyCode&&(this.keyPressed=!0,this.suppressKeyPressRepeat=~$.inArray(e.keyCode,[40,38,9,13,27]),this.shown||40!==e.keyCode?this.move(e):this.lookup())},keypress:function(e){this.suppressKeyPressRepeat||this.move(e)},input:function(e){var currentValue=this.$element.val()||this.$element.text();this.value!==currentValue&&(this.value=currentValue,this.lookup())},keyup:function(e){if(!this.destroyed)switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:if(this.selectOnTab||e.preventDefault(),!this.selectOnTab||!this.shown||this.showHintOnFocus&&!this.keyPressed)return;this.select();break;case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide()}},focus:function(e){this.focused||(this.focused=!0,this.keyPressed=!1,this.options.showHintOnFocus&&!0!==this.skipShowHintOnFocus&&("all"===this.options.showHintOnFocus?this.lookup(""):this.lookup())),this.skipShowHintOnFocus&&(this.skipShowHintOnFocus=!1)},blur:function(e){this.mousedover||this.mouseddown||!this.shown?this.mouseddown&&(this.skipShowHintOnFocus=!0,this.$element.focus(),this.mouseddown=!1):(this.selectOnBlur&&this.select(),this.hide(),this.focused=!1,this.keyPressed=!1)},click:function(e){e.preventDefault(),this.skipShowHintOnFocus=!0,this.select(),this.$element.focus(),this.hide()},mouseenter:function(e){this.mousedover=!0,this.$menu.find(".active").removeClass("active").attr("aria-selected","false"),this._markActive($(e.currentTarget))},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()},mousedown:function(e){this.mouseddown=!0,this.$menu.one("mouseup",function(e){this.mouseddown=!1}.bind(this))},_setLiveStatus:function(text){this.$statusRegion.text(text)}};var old=$.fn.typeahead;$.fn.typeahead=function(option){var arg=arguments;return"string"==typeof option&&"getActive"===option?this.data("active"):this.each(function(){var $this=$(this),data=$this.data("typeahead"),options="object"==typeof option&&option;data||$this.data("typeahead",data=new Typeahead(this,options)),"string"==typeof option&&data[option]&&(1<arg.length?data[option].apply(data,Array.prototype.slice.call(arg,1)):data[option]())})},Typeahead.defaults={source:[],items:8,minLength:1,scrollHeight:0,autoSelect:!0,afterSelect:$.noop,afterEmptySelect:$.noop,addItem:!1,followLinkOnSelect:!1,delay:0,separator:"category",changeInputOnSelect:!0,changeInputOnMove:!0,openLinkInNewTab:!1,selectOnBlur:!0,selectOnTab:!0,showCategoryHeader:!0,theme:"bootstrap3",themes:{bootstrap3:{menu:'<ul class="typeahead dropdown-menu" role="listbox" aria-label="Search results"></ul>',item:'<li role="option"><a class="dropdown-item" href="#"></a></li>',itemContentSelector:"a",headerHtml:'<li class="dropdown-header"></li>',headerDivider:'<li class="divider" role="separator"></li>'},bootstrap4:{menu:'<div class="typeahead dropdown-menu" role="listbox" aria-label="Search results"></div>',item:'<button class="dropdown-item" role="option"></button>',itemContentSelector:".dropdown-item",headerHtml:'<h6 class="dropdown-header"></h6>',headerDivider:'<div class="dropdown-divider"></div>'}}},$.fn.typeahead.Constructor=Typeahead,$.fn.typeahead.noConflict=function(){return $.fn.typeahead=old,this},$(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(e){var $this=$(this);$this.data("typeahead")||$this.typeahead($this.data())})});