/* ============================================================= * bootstrap-combobox.js v1.0.0 * ============================================================= * 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" var Combobox = function (element, options) { this.options = $.extend({}, $.fn.combobox.defaults, options) this.$container = this.setup(element) this.$element = this.$container.find('input') this.$button = this.$container.find('.dropdown-toggle') this.$target = this.$container.find('select') this.matcher = this.options.matcher || this.matcher this.sorter = this.options.sorter || this.sorter this.highlighter = this.options.highlighter || this.highlighter this.$menu = $(this.options.menu).appendTo('body') this.placeholder = this.options.placeholder || this.$target.attr('data-placeholder') this.$element.attr('placeholder', this.placeholder) this.shown = false this.selected = false this.refresh() this.listen() } /* NOTE: COMBOBOX EXTENDS BOOTSTRAP-TYPEAHEAD.js ========================================== */ Combobox.prototype = $.extend({}, $.fn.typeahead.Constructor.prototype, { constructor:Combobox, setup:function (element) { var select = $(element) , combobox = $(this.options.template) select.before(combobox) select.detach() combobox.append(select) return combobox }, parse:function () { var map = {} , source = [] , selected = false this.$target.find('option').each(function () { var option = $(this) map[option.text()] = option.val() source.push(option.text()) if (option.attr('selected')) selected = option.html() }) this.map = map if (selected) { this.$element.val(selected) this.$container.addClass('combobox-selected') this.selected = true } return source }, toggle:function () { if (this.$container.hasClass('combobox-selected')) { this.clearTarget() this.$element.val('').focus() } else { if (this.shown) { this.hide() } else { this.lookup() } } }, clearTarget:function () { this.$target.val('') this.$container.removeClass('combobox-selected') this.selected = false this.$target.trigger('change') }, refresh:function () { this.source = this.parse() this.options.items = this.source.length } // modified typeahead function adding container and target handling , select:function () { var val = this.$menu.find('.active').attr('data-value') this.$element.val(val) this.$container.addClass('combobox-selected') this.$target.val(this.map[val]) this.$target.trigger('change') this.selected = true return this.hide() } // modified typeahead function removing the blank handling , lookup:function (event) { var that = this , items , q this.query = this.$element.val() items = $.grep(this.source, function (item) { if (that.matcher(item)) return item }) items = this.sorter(items) if (!items.length) { return this.shown ? this.hide() : this } return this.render(items.slice(0, this.options.items)).show() } // modified typeahead function adding button handling , listen:function () { this.$element .on('blur', $.proxy(this.blur, this)) .on('keypress', $.proxy(this.keypress, this)) .on('keyup', $.proxy(this.keyup, this)) if ($.browser.webkit || $.browser.msie) { this.$element.on('keydown', $.proxy(this.keypress, this)) } // hide menu hack this.$button.on('mouseenter', $.proxy(this.addClassOnMouseEnter, this.$button)) .on('mouseleave', $.proxy(this.addClassOnMouseLeave, this.$button)); $(window).on('click', $.proxy(this.hideList, this)); // hide menu hack end this.$menu .on('click', $.proxy(this.click, this)) .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) this.$button .on('click', $.proxy(this.toggle, this)) } // modified typeahead function to clear on type and prevent on moving around , keyup:function (e) { switch (e.keyCode) { case 40: // down arrow case 39: // right arrow case 38: // up arrow case 37: // left arrow case 36: // home case 35: // end case 16: // shift 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() }, addClassOnMouseEnter:function (e) { console.warn("Enter"); this.addClass('hover'); }, addClassOnMouseLeave:function (e) { console.warn("Leave"); this.removeClass('hover'); }, // modified typeahead function to only hide menu if it is visible blur:function (e) { var that = this e.stopPropagation() e.preventDefault() var val = this.$element.val() if (!this.selected && val != "") { this.$element.val("") this.$target.val("").trigger('change') } if (this.shown) { setTimeout(function () { that.hide() }, 150) } }, /** * hide list * @param e */ hideList:function (e) { if (!this.$button.is(".hover")) { var that = this; if (this.shown) { setTimeout(function () { that.hide() }, 150) } } } }) /* 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 = { template:'
', menu:'', item:'
  • ', placeholder:null } $.fn.combobox.Constructor = Combobox }(window.jQuery);