<!DOCTYPE html>
<html>

<head>
  <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" data-require="bootstrap@3.3.7" data-semver="3.3.7" />
  <link href="bootstrap-combobox.css" rel="stylesheet" />
  <link href="style.css" rel="stylesheet" />

</head>

<body>
  <h1>Hello Plunker!</h1>
  <select id="combobox1" class="combobox">
    <option></option>
    <option value="PA">Pennsylvania</option>
    <option value="CT">Connecticut</option>
    <option value="NY">New York</option>
    <option value="MD">Maryland</option>
    <option value="VA">Virginia</option>
  </select>
  <br />
  <select id="combobox2"></select>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js" data-require="jquery@3.0.0" data-semver="3.0.0"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" data-require="bootstrap@3.3.7" data-semver="3.3.7"></script>
  <script src="bootstrap-combobox.js"></script>
  <script src="script.js"></script>
</body>

</html>
$(document).ready(function() {
  var s = '';
  for (var i = 0; i < 1000; i++) {
    s += '<option>option ' + i + '</option>';
  }

  $('#combobox1').combobox();

  $('#combobox2').html(s);
  $('#combobox2').combobox();
});
/* Styles go here */

/* =============================================================

 * bootstrap-combobox.js v1.1.8

 * =============================================================

 * Copyright 2012 Daniel Farrell

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 * http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 * ============================================================ */



(function( $ ) {



 "use strict";



 /* COMBOBOX PUBLIC CLASS DEFINITION

  * ================================ */



  var Combobox = function ( element, options ) {

    this.options = $.extend({}, $.fn.combobox.defaults, options);

    this.template = this.options.template || this.template

    this.$source = $(element);

    this.$container = this.setup();

    this.$element = this.$container.find('input[type=text]');

    this.$target = this.$container.find('input[type=hidden]');

    this.$button = this.$container.find('.dropdown-toggle');

    this.$menu = $(this.options.menu).appendTo('body');

    this.matcher = this.options.matcher || this.matcher;

    this.sorter = this.options.sorter || this.sorter;

    this.highlighter = this.options.highlighter || this.highlighter;

    this.shown = false;

    this.selected = false;

    this.refresh();

    this.transferAttributes();

    this.listen();

  };



  Combobox.prototype = {



    constructor: Combobox



  , setup: function () {

      var combobox = $(this.template());

      this.$source.before(combobox);

      this.$source.hide();

      return combobox;

    }



  , disable: function() {

      this.$element.prop('disabled', true);

      this.$button.attr('disabled', true);

      this.disabled = true;

      this.$container.addClass('combobox-disabled');

    }



  , enable: function() {

      this.$element.prop('disabled', false);

      this.$button.attr('disabled', false);

      this.disabled = false;

      this.$container.removeClass('combobox-disabled');

    }

  , parse: function () {

      var that = this

        , map = {}

        , source = []

        , selected = false

        , selectedValue = '';

      this.$source.find('option').each(function() {

        var option = $(this);

        if (option.val() === '') {

          that.options.placeholder = option.text();

          return;

        }

        map[option.text()] = option.val();

        source.push(option.text());

        if (option.prop('selected')) {

          selected = option.text();

          selectedValue = option.val();

        }

      })

      this.map = map;

      if (selected) {

        this.$element.val(selected);

        this.$target.val(selectedValue);

        this.$container.addClass('combobox-selected');

        this.selected = true;

      }

      return source;

    }



  , transferAttributes: function() {

    this.options.placeholder = this.$source.attr('data-placeholder') || this.options.placeholder

    if(this.options.appendId !== "undefined") {

    	this.$element.attr('id', this.$source.attr('id') + this.options.appendId);

    }

    this.$element.attr('placeholder', this.options.placeholder)

    this.$target.prop('name', this.$source.prop('name'))

    this.$target.val(this.$source.val())

    this.$source.removeAttr('name')  // Remove from source otherwise form will pass parameter twice.

    this.$element.attr('required', this.$source.attr('required'))

    this.$element.attr('rel', this.$source.attr('rel'))

    this.$element.attr('title', this.$source.attr('title'))

    this.$element.attr('class', this.$source.attr('class'))

    this.$element.attr('tabindex', this.$source.attr('tabindex'))

    this.$source.removeAttr('tabindex')

    if (this.$source.attr('disabled')!==undefined)

      this.disable();

  }



  , select: function () {

      var val = this.$menu.find('.active').attr('data-value');

      this.$element.val(this.updater(val)).trigger('change');

      this.$target.val(this.map[val]).trigger('change');

      this.$source.val(this.map[val]).trigger('change');

      this.$container.addClass('combobox-selected');

      this.selected = true;

      return this.hide();

    }



  , updater: function (item) {

      return item;

    }



  , show: function () {

      var pos = $.extend({}, this.$element.position(), {

        height: this.$element[0].offsetHeight

      });



      this.$menu

        .insertAfter(this.$element)

        .css({

          top: pos.top + pos.height

        , left: pos.left

        })

        .show();



      $('.dropdown-menu').on('mousedown', $.proxy(this.scrollSafety, this));



      this.shown = true;

      return this;

    }



  , hide: function () {

      this.$menu.hide();

      $('.dropdown-menu').off('mousedown', $.proxy(this.scrollSafety, this));

      this.$element.on('blur', $.proxy(this.blur, this));

      this.shown = false;

      return this;

    }



  , lookup: function (event) {

      this.query = this.$element.val();

      return this.process(this.source);

    }



  , process: function (items) {

      var that = this;



      items = $.grep(items, function (item) {

        return that.matcher(item);

      })



      items = this.sorter(items);



      if (!items.length) {

        return this.shown ? this.hide() : this;

      }



      return this.render(items.slice(0, this.options.items)).show();

    }



  , template: function() {

      if (this.options.bsVersion == '2') {

        return '<div class="combobox-container"><input type="hidden" /> <div class="input-append"> <input type="text" autocomplete="off" /> <span class="add-on dropdown-toggle" data-dropdown="dropdown"> <span class="caret"/> <i class="icon-remove"/> </span> </div> </div>'

      } else {

        return '<div class="combobox-container"> <input type="hidden" /> <div class="input-group"> <input type="text" autocomplete="off" /> <span class="input-group-addon dropdown-toggle" data-dropdown="dropdown"> <span class="caret" /> <span class="glyphicon glyphicon-remove" /> </span> </div> </div>'

      }

    }



  , matcher: function (item) {

      return ~item.toLowerCase().indexOf(this.query.toLowerCase());

    }



  , sorter: function (items) {

      var beginswith = []

        , caseSensitive = []

        , caseInsensitive = []

        , item;



      while (item = items.shift()) {

        if (!item.toLowerCase().indexOf(this.query.toLowerCase())) {beginswith.push(item);}

        else if (~item.indexOf(this.query)) {caseSensitive.push(item);}

        else {caseInsensitive.push(item);}

      }



      return beginswith.concat(caseSensitive, caseInsensitive);

    }



  , highlighter: function (item) {

      var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');

      return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {

        return '<strong>' + match + '</strong>';

      })

    }



  , render: function (items) {

      var that = this;



      items = $(items).map(function (i, item) {

        i = $(that.options.item).attr('data-value', item);

        i.find('a').html(that.highlighter(item));

        return i[0];

      })



      items.first().addClass('active');

      this.$menu.html(items);

      return this;

    }



  , next: function (event) {

      var active = this.$menu.find('.active').removeClass('active')

        , next = active.next();



      if (!next.length) {

        next = $(this.$menu.find('li')[0]);

      }



      next.addClass('active');

    }



  , prev: function (event) {

      var active = this.$menu.find('.active').removeClass('active')

        , prev = active.prev();



      if (!prev.length) {

        prev = this.$menu.find('li').last();

      }



      prev.addClass('active');

    }



  , toggle: function () {

    if (!this.disabled) {

      if (this.$container.hasClass('combobox-selected')) {

        this.clearTarget();

        this.triggerChange();

        this.clearElement();

      } else {

        if (this.shown) {

          this.hide();

        } else {

          this.clearElement();

          this.lookup();

        }

      }

    }

  }



  , scrollSafety: function(e) {

      if (e.target.tagName == 'UL') {

          this.$element.off('blur');

      }

  }

  , clearElement: function () {

    this.$element.val('').focus();

  }



  , clearTarget: function () {

    this.$source.val('');

    this.$target.val('');

    this.$container.removeClass('combobox-selected');

    this.selected = false;

  }



  , triggerChange: function () {

    this.$source.trigger('change');

  }



  , refresh: function () {

    this.source = this.parse();

    this.options.items = this.source.length;

  }



  , listen: function () {

      this.$element

        .on('focus',    $.proxy(this.focus, this))

        .on('blur',     $.proxy(this.blur, this))

        .on('keypress', $.proxy(this.keypress, this))

        .on('keyup',    $.proxy(this.keyup, this));



      if (this.eventSupported('keydown')) {

        this.$element.on('keydown', $.proxy(this.keydown, this));

      }



      this.$menu

        .on('click', $.proxy(this.click, this))

        .on('mouseenter', 'li', $.proxy(this.mouseenter, this))

        .on('mouseleave', 'li', $.proxy(this.mouseleave, this));



      this.$button

        .on('click', $.proxy(this.toggle, this));

    }



  , eventSupported: function(eventName) {

      var isSupported = eventName in this.$element;

      if (!isSupported) {

        this.$element.setAttribute(eventName, 'return;');

        isSupported = typeof this.$element[eventName] === 'function';

      }

      return isSupported;

    }



  , move: function (e) {

      if (!this.shown) {return;}



      switch(e.keyCode) {

        case 9: // tab

        case 13: // enter

        case 27: // escape

          e.preventDefault();

          break;



        case 38: // up arrow

          e.preventDefault();

          this.prev();

          this.fixMenuScroll();

          break;



        case 40: // down arrow

          e.preventDefault();

          this.next();

          this.fixMenuScroll();

          break;

      }



      e.stopPropagation();

    }



  , fixMenuScroll: function(){

      var active = this.$menu.find('.active');

      if(active.length){

          var top = active.position().top;

          var bottom = top + active.height();

          var scrollTop = this.$menu.scrollTop();

          var menuHeight = this.$menu.height();

          if(bottom > menuHeight){

              this.$menu.scrollTop(scrollTop + bottom - menuHeight);

          } else if(top < 0){

              this.$menu.scrollTop(scrollTop + top);

          }

      }

  }



  , keydown: function (e) {

      this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);

      this.move(e);

    }



  , keypress: function (e) {

      if (this.suppressKeyPressRepeat) {return;}

      this.move(e);

    }



  , keyup: function (e) {

      switch(e.keyCode) {

        case 40: // down arrow

         if (!this.shown){

           this.toggle();

         }

         break;

        case 39: // right arrow

        case 38: // up arrow

        case 37: // left arrow

        case 36: // home

        case 35: // end

        case 16: // shift

        case 17: // ctrl

        case 18: // alt

          break;



        case 9: // tab

        case 13: // enter

          if (!this.shown) {return;}

          this.select();

          break;



        case 27: // escape

          if (!this.shown) {return;}

          this.hide();

          break;



        default:

          this.clearTarget();

          this.lookup();

      }



      e.stopPropagation();

      e.preventDefault();

  }



  , focus: function (e) {

      this.focused = true;

    }



  , blur: function (e) {

      var that = this;

      this.focused = false;

      var val = this.$element.val();

      if (!this.selected && val !== '' ) {

        this.$element.val('');

        this.$source.val('').trigger('change');

        this.$target.val('').trigger('change');

      }

      if (!this.mousedover && this.shown) {setTimeout(function () { that.hide(); }, 200);}

    }



  , click: function (e) {

      e.stopPropagation();

      e.preventDefault();

      this.select();

      this.$element.focus();

    }



  , mouseenter: function (e) {

      this.mousedover = true;

      this.$menu.find('.active').removeClass('active');

      $(e.currentTarget).addClass('active');

    }



  , mouseleave: function (e) {

      this.mousedover = false;

    }

  };



  /* COMBOBOX PLUGIN DEFINITION

   * =========================== */

  $.fn.combobox = function ( option ) {

    return this.each(function () {

      var $this = $(this)

        , data = $this.data('combobox')

        , options = typeof option == 'object' && option;

      if(!data) {$this.data('combobox', (data = new Combobox(this, options)));}

      if (typeof option == 'string') {data[option]();}

    });

  };



  $.fn.combobox.defaults = {

    bsVersion: '4'

  , menu: '<ul class="typeahead typeahead-long dropdown-menu"></ul>'

  , item: '<li><a href="#" class="dropdown-item"></a></li>'

  };



  $.fn.combobox.Constructor = Combobox;



}( window.jQuery ));
@media (min-width: 768px) {

  .form-search .combobox-container,

  .form-inline .combobox-container {

    display: inline-block;

    margin-bottom: 0;

    vertical-align: top;

  }

  .form-search .combobox-container .input-group-addon,

  .form-inline .combobox-container .input-group-addon {

    width: auto;

  }

}

.combobox-selected .caret {

  display: none;

}

/* :not doesn't work in IE8 */

.combobox-container:not(.combobox-selected) .glyphicon-remove {

  display: none;

}

.typeahead-long {

  max-height: 300px;

  overflow-y: auto;

}

.control-group.error .combobox-container .add-on {

  color: #B94A48;

  border-color: #B94A48;

}

.control-group.error .combobox-container .caret {

  border-top-color: #B94A48;

}

.control-group.warning .combobox-container .add-on {

  color: #C09853;

  border-color: #C09853;

}

.control-group.warning .combobox-container .caret {

  border-top-color: #C09853;

}

.control-group.success .combobox-container .add-on {

  color: #468847;

  border-color: #468847;

}

.control-group.success .combobox-container .caret {

  border-top-color: #468847;

}