266 lines
7.6 KiB
JavaScript
266 lines
7.6 KiB
JavaScript
/* =============================================================
|
|
* bootstrap-combobox.js v1.1.1
|
|
* =============================================================
|
|
* 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.$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()
|
|
}
|
|
|
|
/* NOTE: COMBOBOX EXTENDS BOOTSTRAP-TYPEAHEAD.js
|
|
========================================== */
|
|
|
|
Combobox.prototype = $.extend({}, $.fn.typeahead.Constructor.prototype, {
|
|
|
|
constructor: Combobox,
|
|
|
|
setup: function() {
|
|
var combobox = $(this.options.template)
|
|
this.$source.before(combobox)
|
|
this.$source.hide()
|
|
return combobox
|
|
},
|
|
|
|
parse: function() {
|
|
var that = this, map = {}, source = [], selected = false
|
|
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.attr('selected'))
|
|
selected = option.html()
|
|
})
|
|
this.map = map
|
|
if (selected) {
|
|
this.$element.val(selected)
|
|
this.$container.addClass('combobox-selected')
|
|
this.selected = true
|
|
}
|
|
return source
|
|
},
|
|
|
|
transferAttributes: function() {
|
|
this.options.placeholder = this.$source.attr('data-placeholder')
|
|
|| this.options.placeholder
|
|
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'))
|
|
},
|
|
|
|
toggle: function(e) {
|
|
if (this.shown) {
|
|
this.hide()
|
|
} else {
|
|
// don't clear the textbox when the arrow is clicked and keep the focus
|
|
// inside the textbox to make sure that when the focus leaves (e.g. user
|
|
// clicks outside of it) that the dropdown closes as expected
|
|
this.lookup(e, '') // pass empty query to show all options (this seems more intuitive to me?)
|
|
this.$element.focus()
|
|
}
|
|
},
|
|
|
|
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
|
|
},
|
|
|
|
// modified typeahead function adding container and target handling
|
|
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()
|
|
},
|
|
|
|
// modified typeahead function removing the blank handling and source function handling
|
|
lookup: function(event, existingVal) {
|
|
if (existingVal != undefined)
|
|
this.query = existingVal
|
|
else
|
|
this.query = this.$element.val()
|
|
return this.process(this.source)
|
|
},
|
|
|
|
// modified typeahead function adding button handling and remove mouseleave
|
|
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))
|
|
},
|
|
|
|
// 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
|
|
case 17: // ctrl
|
|
case 18: // alt
|
|
break
|
|
|
|
case 9: // tab
|
|
case 13: // enter
|
|
if (!this.shown) {
|
|
if (this.options.enter_triggers_change === true)
|
|
this.select()
|
|
else
|
|
return
|
|
}
|
|
this.select()
|
|
break
|
|
|
|
case 27: // escape
|
|
if (!this.shown)
|
|
return
|
|
|
|
this.hide()
|
|
break
|
|
|
|
default:
|
|
this.clearTarget()
|
|
this.lookup()
|
|
}
|
|
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
},
|
|
|
|
// modified typeahead function to force a match and add a delay on hide
|
|
blur: function(e) {
|
|
var that = this
|
|
this.focused = false
|
|
var val = this.$element.val()
|
|
if (!!this.options.force_match) {
|
|
if (!this.selected && val !== '') {
|
|
this.$element.val('')
|
|
this.$target.val('').trigger('change')
|
|
this.$source.val('').trigger('change')
|
|
}
|
|
} else {
|
|
this.$target.val(val).trigger('change')
|
|
this.$source.val(val).trigger('change')
|
|
}
|
|
if (!this.mousedover && this.shown)
|
|
setTimeout(function() {
|
|
that.hide()
|
|
}, 200)
|
|
},
|
|
|
|
// modified typeahead function to not hide
|
|
mouseleave: function(e) {
|
|
this.mousedover = false
|
|
},
|
|
|
|
val: function(val) {
|
|
if (val != undefined) {
|
|
this.$element.val(val)
|
|
this.$target.val(val).trigger('change')
|
|
this.$source.val(val).trigger('change')
|
|
return val;
|
|
} else
|
|
return this.$target.val()
|
|
}
|
|
})
|
|
|
|
/* 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: '<div class="combobox-container"><input type="hidden" /><input type="text" autocomplete="off" /><span class="add-on btn dropdown-toggle" data-dropdown="dropdown"><span class="caret"/><span class="combobox-clear"><i class="icon-remove"/></span></span></div>',
|
|
menu: '<ul class="typeahead typeahead-long dropdown-menu"></ul>',
|
|
item: '<li><a href="#"></a></li>',
|
|
force_match: true,
|
|
enter_triggers_change: false
|
|
}
|
|
|
|
$.fn.combobox.Constructor = Combobox
|
|
|
|
}(window.jQuery);
|