1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/js/bootstrap-typeahead.js Fri Jul 04 16:42:41 2014 +0400
1.3 @@ -0,0 +1,335 @@
1.4 +/* =============================================================
1.5 + * bootstrap-typeahead.js v2.3.1
1.6 + * http://twitter.github.com/bootstrap/javascript.html#typeahead
1.7 + * =============================================================
1.8 + * Copyright 2012 Twitter, Inc.
1.9 + *
1.10 + * Licensed under the Apache License, Version 2.0 (the "License");
1.11 + * you may not use this file except in compliance with the License.
1.12 + * You may obtain a copy of the License at
1.13 + *
1.14 + * http://www.apache.org/licenses/LICENSE-2.0
1.15 + *
1.16 + * Unless required by applicable law or agreed to in writing, software
1.17 + * distributed under the License is distributed on an "AS IS" BASIS,
1.18 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1.19 + * See the License for the specific language governing permissions and
1.20 + * limitations under the License.
1.21 + * ============================================================ */
1.22 +
1.23 +
1.24 +!function($){
1.25 +
1.26 + "use strict"; // jshint ;_;
1.27 +
1.28 +
1.29 + /* TYPEAHEAD PUBLIC CLASS DEFINITION
1.30 + * ================================= */
1.31 +
1.32 + var Typeahead = function (element, options) {
1.33 + this.$element = $(element)
1.34 + this.options = $.extend({}, $.fn.typeahead.defaults, options)
1.35 + this.matcher = this.options.matcher || this.matcher
1.36 + this.sorter = this.options.sorter || this.sorter
1.37 + this.highlighter = this.options.highlighter || this.highlighter
1.38 + this.updater = this.options.updater || this.updater
1.39 + this.source = this.options.source
1.40 + this.$menu = $(this.options.menu)
1.41 + this.shown = false
1.42 + this.listen()
1.43 + }
1.44 +
1.45 + Typeahead.prototype = {
1.46 +
1.47 + constructor: Typeahead
1.48 +
1.49 + , select: function () {
1.50 + var val = this.$menu.find('.active').attr('data-value')
1.51 + this.$element
1.52 + .val(this.updater(val))
1.53 + .change()
1.54 + return this.hide()
1.55 + }
1.56 +
1.57 + , updater: function (item) {
1.58 + return item
1.59 + }
1.60 +
1.61 + , show: function () {
1.62 + var pos = $.extend({}, this.$element.position(), {
1.63 + height: this.$element[0].offsetHeight
1.64 + })
1.65 +
1.66 + this.$menu
1.67 + .insertAfter(this.$element)
1.68 + .css({
1.69 + top: pos.top + pos.height
1.70 + , left: pos.left
1.71 + })
1.72 + .show()
1.73 +
1.74 + this.shown = true
1.75 + return this
1.76 + }
1.77 +
1.78 + , hide: function () {
1.79 + this.$menu.hide()
1.80 + this.shown = false
1.81 + return this
1.82 + }
1.83 +
1.84 + , lookup: function (event) {
1.85 + var items
1.86 +
1.87 + this.query = this.$element.val()
1.88 +
1.89 + if (!this.query || this.query.length < this.options.minLength) {
1.90 + return this.shown ? this.hide() : this
1.91 + }
1.92 +
1.93 + items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
1.94 +
1.95 + return items ? this.process(items) : this
1.96 + }
1.97 +
1.98 + , process: function (items) {
1.99 + var that = this
1.100 +
1.101 + items = $.grep(items, function (item) {
1.102 + return that.matcher(item)
1.103 + })
1.104 +
1.105 + items = this.sorter(items)
1.106 +
1.107 + if (!items.length) {
1.108 + return this.shown ? this.hide() : this
1.109 + }
1.110 +
1.111 + return this.render(items.slice(0, this.options.items)).show()
1.112 + }
1.113 +
1.114 + , matcher: function (item) {
1.115 + return ~item.toLowerCase().indexOf(this.query.toLowerCase())
1.116 + }
1.117 +
1.118 + , sorter: function (items) {
1.119 + var beginswith = []
1.120 + , caseSensitive = []
1.121 + , caseInsensitive = []
1.122 + , item
1.123 +
1.124 + while (item = items.shift()) {
1.125 + if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
1.126 + else if (~item.indexOf(this.query)) caseSensitive.push(item)
1.127 + else caseInsensitive.push(item)
1.128 + }
1.129 +
1.130 + return beginswith.concat(caseSensitive, caseInsensitive)
1.131 + }
1.132 +
1.133 + , highlighter: function (item) {
1.134 + var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
1.135 + return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
1.136 + return '<strong>' + match + '</strong>'
1.137 + })
1.138 + }
1.139 +
1.140 + , render: function (items) {
1.141 + var that = this
1.142 +
1.143 + items = $(items).map(function (i, item) {
1.144 + i = $(that.options.item).attr('data-value', item)
1.145 + i.find('a').html(that.highlighter(item))
1.146 + return i[0]
1.147 + })
1.148 +
1.149 + items.first().addClass('active')
1.150 + this.$menu.html(items)
1.151 + return this
1.152 + }
1.153 +
1.154 + , next: function (event) {
1.155 + var active = this.$menu.find('.active').removeClass('active')
1.156 + , next = active.next()
1.157 +
1.158 + if (!next.length) {
1.159 + next = $(this.$menu.find('li')[0])
1.160 + }
1.161 +
1.162 + next.addClass('active')
1.163 + }
1.164 +
1.165 + , prev: function (event) {
1.166 + var active = this.$menu.find('.active').removeClass('active')
1.167 + , prev = active.prev()
1.168 +
1.169 + if (!prev.length) {
1.170 + prev = this.$menu.find('li').last()
1.171 + }
1.172 +
1.173 + prev.addClass('active')
1.174 + }
1.175 +
1.176 + , listen: function () {
1.177 + this.$element
1.178 + .on('focus', $.proxy(this.focus, this))
1.179 + .on('blur', $.proxy(this.blur, this))
1.180 + .on('keypress', $.proxy(this.keypress, this))
1.181 + .on('keyup', $.proxy(this.keyup, this))
1.182 +
1.183 + if (this.eventSupported('keydown')) {
1.184 + this.$element.on('keydown', $.proxy(this.keydown, this))
1.185 + }
1.186 +
1.187 + this.$menu
1.188 + .on('click', $.proxy(this.click, this))
1.189 + .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
1.190 + .on('mouseleave', 'li', $.proxy(this.mouseleave, this))
1.191 + }
1.192 +
1.193 + , eventSupported: function(eventName) {
1.194 + var isSupported = eventName in this.$element
1.195 + if (!isSupported) {
1.196 + this.$element.setAttribute(eventName, 'return;')
1.197 + isSupported = typeof this.$element[eventName] === 'function'
1.198 + }
1.199 + return isSupported
1.200 + }
1.201 +
1.202 + , move: function (e) {
1.203 + if (!this.shown) return
1.204 +
1.205 + switch(e.keyCode) {
1.206 + case 9: // tab
1.207 + case 13: // enter
1.208 + case 27: // escape
1.209 + e.preventDefault()
1.210 + break
1.211 +
1.212 + case 38: // up arrow
1.213 + e.preventDefault()
1.214 + this.prev()
1.215 + break
1.216 +
1.217 + case 40: // down arrow
1.218 + e.preventDefault()
1.219 + this.next()
1.220 + break
1.221 + }
1.222 +
1.223 + e.stopPropagation()
1.224 + }
1.225 +
1.226 + , keydown: function (e) {
1.227 + this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27])
1.228 + this.move(e)
1.229 + }
1.230 +
1.231 + , keypress: function (e) {
1.232 + if (this.suppressKeyPressRepeat) return
1.233 + this.move(e)
1.234 + }
1.235 +
1.236 + , keyup: function (e) {
1.237 + switch(e.keyCode) {
1.238 + case 40: // down arrow
1.239 + case 38: // up arrow
1.240 + case 16: // shift
1.241 + case 17: // ctrl
1.242 + case 18: // alt
1.243 + break
1.244 +
1.245 + case 9: // tab
1.246 + case 13: // enter
1.247 + if (!this.shown) return
1.248 + this.select()
1.249 + break
1.250 +
1.251 + case 27: // escape
1.252 + if (!this.shown) return
1.253 + this.hide()
1.254 + break
1.255 +
1.256 + default:
1.257 + this.lookup()
1.258 + }
1.259 +
1.260 + e.stopPropagation()
1.261 + e.preventDefault()
1.262 + }
1.263 +
1.264 + , focus: function (e) {
1.265 + this.focused = true
1.266 + }
1.267 +
1.268 + , blur: function (e) {
1.269 + this.focused = false
1.270 + if (!this.mousedover && this.shown) this.hide()
1.271 + }
1.272 +
1.273 + , click: function (e) {
1.274 + e.stopPropagation()
1.275 + e.preventDefault()
1.276 + this.select()
1.277 + this.$element.focus()
1.278 + }
1.279 +
1.280 + , mouseenter: function (e) {
1.281 + this.mousedover = true
1.282 + this.$menu.find('.active').removeClass('active')
1.283 + $(e.currentTarget).addClass('active')
1.284 + }
1.285 +
1.286 + , mouseleave: function (e) {
1.287 + this.mousedover = false
1.288 + if (!this.focused && this.shown) this.hide()
1.289 + }
1.290 +
1.291 + }
1.292 +
1.293 +
1.294 + /* TYPEAHEAD PLUGIN DEFINITION
1.295 + * =========================== */
1.296 +
1.297 + var old = $.fn.typeahead
1.298 +
1.299 + $.fn.typeahead = function (option) {
1.300 + return this.each(function () {
1.301 + var $this = $(this)
1.302 + , data = $this.data('typeahead')
1.303 + , options = typeof option == 'object' && option
1.304 + if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
1.305 + if (typeof option == 'string') data[option]()
1.306 + })
1.307 + }
1.308 +
1.309 + $.fn.typeahead.defaults = {
1.310 + source: []
1.311 + , items: 8
1.312 + , menu: '<ul class="typeahead dropdown-menu"></ul>'
1.313 + , item: '<li><a href="#"></a></li>'
1.314 + , minLength: 1
1.315 + }
1.316 +
1.317 + $.fn.typeahead.Constructor = Typeahead
1.318 +
1.319 +
1.320 + /* TYPEAHEAD NO CONFLICT
1.321 + * =================== */
1.322 +
1.323 + $.fn.typeahead.noConflict = function () {
1.324 + $.fn.typeahead = old
1.325 + return this
1.326 + }
1.327 +
1.328 +
1.329 + /* TYPEAHEAD DATA-API
1.330 + * ================== */
1.331 +
1.332 + $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
1.333 + var $this = $(this)
1.334 + if ($this.data('typeahead')) return
1.335 + $this.typeahead($this.data())
1.336 + })
1.337 +
1.338 +}(window.jQuery);