vendor: 7,604 bytes, lines 1-303
1/* ============================================================= 2 * bootstrap-typeahead.js v2.2.1 3 * http://twitter.github.com/bootstrap/javascript.html#typeahead 4 * ============================================================= 5 * Copyright 2012 Twitter, Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * ============================================================ */ 19 20 21!function($){ 22 23 "use strict"; // jshint ;_; 24 25 26 /* TYPEAHEAD PUBLIC CLASS DEFINITION 27 * ================================= */ 28 29 window.Typeahead = function (element, options) { 30 this.$element = $(element) 31 this.options = $.extend({}, $.fn.typeahead.defaults, options) 32 this.matcher = this.options.matcher || this.matcher 33 this.sorter = this.options.sorter || this.sorter 34 this.highlighter = this.options.highlighter || this.highlighter 35 this.updater = this.options.updater || this.updater 36 this.$menu = $(this.options.menu).appendTo('body') 37 this.source = this.options.source 38 this.shown = false 39 this.listen() 40 } 41 42 // FIX:JCMS Hook to expose Typeahead prototype 43 Typeahead.prototype = { 44 45 constructor: Typeahead 46 47 , select: function () { 48 var val = this.$menu.find('.active').attr('data-value') 49 this.$element 50 .val(this.updater(val)) 51 .change() 52 return this.hide() 53 } 54 55 , updater: function (item) { 56 return item 57 } 58 59 , show: function () { 60 var pos = $.extend({}, this.$element.offset(), { 61 height: this.$element[0].offsetHeight 62 }) 63 64 this.$menu.css({ 65 top: pos.top + pos.height 66 , left: pos.left 67 }) 68 69 this.$menu.show() 70 this.shown = true 71 return this 72 } 73 74 , hide: function () { 75 this.$menu.hide() 76 this.shown = false 77 return this 78 } 79 80 , lookup: function (event) { 81 var items 82 83 this.query = this.$element.val() 84 85 if (!this.query || this.query.length < this.options.minLength) { 86 return this.shown ? this.hide() : this 87 } 88 89 items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source 90 91 return items ? this.process(items) : this 92 } 93 94 , process: function (items) { 95 var that = this 96 97 items = $.grep(items, function (item) { 98 return that.matcher(item) 99 }) 100 101 items = this.sorter(items) 102 103 if (!items.length) { 104 return this.shown ? this.hide() : this 105 } 106 107 return this.render(items.slice(0, this.options.items)).show() 108 } 109 110 , matcher: function (item) { 111 return ~item.toLowerCase().indexOf(this.query.toLowerCase()) 112 } 113 114 , sorter: function (items) { 115 var beginswith = [] 116 , caseSensitive = [] 117 , caseInsensitive = [] 118 , item 119 120 while (item = items.shift()) { 121 if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) 122 else if (~item.indexOf(this.query)) caseSensitive.push(item) 123 else caseInsensitive.push(item) 124 } 125 126 return beginswith.concat(caseSensitive, caseInsensitive) 127 } 128 129 , highlighter: function (item) { 130 var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&') 131 return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { 132 return '<strong>' + match + '</strong>' 133 }) 134 } 135 136 , render: function (items) { 137 var that = this 138 139 items = $(items).map(function (i, item) { 140 i = $(that.options.item).attr('data-value', item) 141 i.find('a').html(that.highlighter(item)) 142 return i[0] 143 }) 144 145 items.first().addClass('active') 146 this.$menu.html(items) 147 return this 148 } 149 150 , next: function (event) { 151 var active = this.$menu.find('.active').removeClass('active') 152 , next = active.next() 153 154 if (!next.length) { 155 next = $(this.$menu.find('li')[0]) 156 } 157 158 next.addClass('active') 159 } 160 161 , prev: function (event) { 162 var active = this.$menu.find('.active').removeClass('active') 163 , prev = active.prev() 164 165 if (!prev.length) { 166 prev = this.$menu.find('li').last() 167 } 168 169 prev.addClass('active') 170 } 171 172 , listen: function () { 173 this.$element 174 .on('blur', $.proxy(this.blur, this)) 175 .on('keypress', $.proxy(this.keypress, this)) 176 .on('keyup', $.proxy(this.keyup, this)) 177 178 if (this.eventSupported('keydown')) { 179 this.$element.on('keydown', $.proxy(this.keydown, this)) 180 } 181 182 this.$menu 183 .on('click', $.proxy(this.click, this)) 184 .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) 185 } 186 187 , eventSupported: function(eventName) { 188 var isSupported = eventName in this.$element 189 if (!isSupported) { 190 this.$element.setAttribute(eventName, 'return;') 191 isSupported = typeof this.$element[eventName] === 'function' 192 } 193 return isSupported 194 } 195 196 , move: function (e) { 197 if (!this.shown) return 198 199 switch(e.keyCode) { 200 case 9: // tab 201 case 13: // enter 202 case 27: // escape 203 e.preventDefault() 204 break 205 206 case 38: // up arrow 207 e.preventDefault() 208 this.prev() 209 break 210 211 case 40: // down arrow 212 e.preventDefault() 213 this.next() 214 break 215 } 216 217 e.stopPropagation() 218 } 219 220 , keydown: function (e) { 221 this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]) 222 this.move(e) 223 } 224 225 , keypress: function (e) { 226 if (this.suppressKeyPressRepeat) return 227 this.move(e) 228 } 229 230 , keyup: function (e) { 231 switch(e.keyCode) { 232 case 40: // down arrow 233 case 38: // up arrow 234 case 16: // shift 235 case 17: // ctrl 236 case 18: // alt 237 break 238 239 case 9: // tab 240 case 13: // enter 241 if (!this.shown) return 242 this.select() 243 break 244 245 case 27: // escape 246 if (!this.shown) return 247 this.hide() 248 break 249 250 default: 251 this.lookup() 252 } 253 254 e.stopPropagation() 255 e.preventDefault() 256 } 257 258 , blur: function (e) { 259 var that = this 260 setTimeout(function () { that.hide() }, 150) 261 } 262 263 , click: function (e) { 264 e.stopPropagation() 265 e.preventDefault() 266 this.select() 267 } 268 269 , mouseenter: function (e) { 270 this.$menu.find('.active').removeClass('active') 271 $(e.currentTarget).addClass('active') 272 } 273 274 } 275 276 277 /* TYPEAHEAD PLUGIN DEFINITION 278 * =========================== */ 279 280 $.fn.typeahead = function (option) { 281 return this.each(function () { 282 var $this = $(this) 283 , data = $this.data('typeahead') 284 , options = typeof option == 'object' && option 285 if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) 286 if (typeof option == 'string') data[option]() 287 }) 288 } 289 290 $.fn.typeahead.defaults = { 291 source: [] 292 , items: 8 293 , menu: '<ul class="typeahead dropdown-menu"></ul>' 294 , item: '<li><a href="#"></a></li>' 295 , minLength: 1 296 } 297 298 $.fn.typeahead.Constructor = Typeahead 299 300 301 /* TYPEAHEAD DATA-API 302 * ================== */ 303
304 $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { 305 var $this = $(this) 306 if ($this.data('typeahead')) return 307 e.preventDefault() 308 $this.typeahead($this.data()) 309 }) 310 311}(window.jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.