|
1 | 1 | /* ============================================================= |
2 | | - * bootstrap-combobox.js v1.1.4 |
| 2 | + * bootstrap-combobox.js v1.1.5 |
3 | 3 | * ============================================================= |
4 | 4 | * Copyright 2012 Daniel Farrell |
5 | 5 | * |
|
20 | 20 |
|
21 | 21 | "use strict"; |
22 | 22 |
|
| 23 | + /* COMBOBOX PUBLIC CLASS DEFINITION |
| 24 | + * ================================ */ |
| 25 | + |
23 | 26 | var Combobox = function ( element, options ) { |
24 | 27 | this.options = $.extend({}, $.fn.combobox.defaults, options); |
25 | 28 | this.$source = $(element); |
|
38 | 41 | this.listen(); |
39 | 42 | }; |
40 | 43 |
|
41 | | - /* NOTE: COMBOBOX EXTENDS BOOTSTRAP-TYPEAHEAD.js |
42 | | - ========================================== */ |
43 | | - |
44 | | - Combobox.prototype = $.extend({}, $.fn.typeahead.Constructor.prototype, { |
| 44 | + Combobox.prototype = { |
45 | 45 |
|
46 | 46 | constructor: Combobox |
47 | 47 |
|
|
95 | 95 | this.$source.removeAttr('tabindex'); |
96 | 96 | } |
97 | 97 |
|
| 98 | + , select: function () { |
| 99 | + var val = this.$menu.find('.active').attr('data-value'); |
| 100 | + this.$element.val(this.updater(val)).trigger('change'); |
| 101 | + this.$source.val(this.map[val]).trigger('change'); |
| 102 | + this.$target.val(this.map[val]).trigger('change'); |
| 103 | + this.$container.addClass('combobox-selected'); |
| 104 | + this.selected = true; |
| 105 | + return this.hide(); |
| 106 | + } |
| 107 | + |
| 108 | + , updater: function (item) { |
| 109 | + return item; |
| 110 | + } |
| 111 | + |
| 112 | + , show: function () { |
| 113 | + var pos = $.extend({}, this.$element.position(), { |
| 114 | + height: this.$element[0].offsetHeight |
| 115 | + }); |
| 116 | + |
| 117 | + this.$menu |
| 118 | + .insertAfter(this.$element) |
| 119 | + .css({ |
| 120 | + top: pos.top + pos.height |
| 121 | + , left: pos.left |
| 122 | + }) |
| 123 | + .show(); |
| 124 | + |
| 125 | + this.shown = true; |
| 126 | + return this; |
| 127 | + } |
| 128 | + |
| 129 | + , hide: function () { |
| 130 | + this.$menu.hide(); |
| 131 | + this.shown = false; |
| 132 | + return this; |
| 133 | + } |
| 134 | + |
| 135 | + , lookup: function (event) { |
| 136 | + this.query = this.$element.val(); |
| 137 | + return this.process(this.source); |
| 138 | + } |
| 139 | + |
| 140 | + , process: function (items) { |
| 141 | + var that = this; |
| 142 | + |
| 143 | + items = $.grep(items, function (item) { |
| 144 | + return that.matcher(item); |
| 145 | + }) |
| 146 | + |
| 147 | + items = this.sorter(items); |
| 148 | + |
| 149 | + if (!items.length) { |
| 150 | + return this.shown ? this.hide() : this; |
| 151 | + } |
| 152 | + |
| 153 | + return this.render(items.slice(0, this.options.items)).show(); |
| 154 | + } |
| 155 | + |
| 156 | + , matcher: function (item) { |
| 157 | + return ~item.toLowerCase().indexOf(this.query.toLowerCase()); |
| 158 | + } |
| 159 | + |
| 160 | + , sorter: function (items) { |
| 161 | + var beginswith = [] |
| 162 | + , caseSensitive = [] |
| 163 | + , caseInsensitive = [] |
| 164 | + , item; |
| 165 | + |
| 166 | + while (item = items.shift()) { |
| 167 | + if (!item.toLowerCase().indexOf(this.query.toLowerCase())) {beginswith.push(item);} |
| 168 | + else if (~item.indexOf(this.query)) {caseSensitive.push(item);} |
| 169 | + else {caseInsensitive.push(item);} |
| 170 | + } |
| 171 | + |
| 172 | + return beginswith.concat(caseSensitive, caseInsensitive); |
| 173 | + } |
| 174 | + |
| 175 | + , highlighter: function (item) { |
| 176 | + var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); |
| 177 | + return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { |
| 178 | + return '<strong>' + match + '</strong>'; |
| 179 | + }) |
| 180 | + } |
| 181 | + |
| 182 | + , render: function (items) { |
| 183 | + var that = this; |
| 184 | + |
| 185 | + items = $(items).map(function (i, item) { |
| 186 | + i = $(that.options.item).attr('data-value', item); |
| 187 | + i.find('a').html(that.highlighter(item)); |
| 188 | + return i[0]; |
| 189 | + }) |
| 190 | + |
| 191 | + items.first().addClass('active'); |
| 192 | + this.$menu.html(items); |
| 193 | + return this; |
| 194 | + } |
| 195 | + |
| 196 | + , next: function (event) { |
| 197 | + var active = this.$menu.find('.active').removeClass('active') |
| 198 | + , next = active.next(); |
| 199 | + |
| 200 | + if (!next.length) { |
| 201 | + next = $(this.$menu.find('li')[0]); |
| 202 | + } |
| 203 | + |
| 204 | + next.addClass('active'); |
| 205 | + } |
| 206 | + |
| 207 | + , prev: function (event) { |
| 208 | + var active = this.$menu.find('.active').removeClass('active') |
| 209 | + , prev = active.prev(); |
| 210 | + |
| 211 | + if (!prev.length) { |
| 212 | + prev = this.$menu.find('li').last(); |
| 213 | + } |
| 214 | + |
| 215 | + prev.addClass('active'); |
| 216 | + } |
| 217 | + |
98 | 218 | , toggle: function () { |
99 | 219 | if (this.$container.hasClass('combobox-selected')) { |
100 | 220 | this.clearTarget(); |
|
130 | 250 | this.options.items = this.source.length; |
131 | 251 | } |
132 | 252 |
|
133 | | - // modified typeahead function adding container and target handling |
134 | | - , select: function () { |
135 | | - var val = this.$menu.find('.active').attr('data-value'); |
136 | | - this.$element.val(this.updater(val)).trigger('change'); |
137 | | - this.$source.val(this.map[val]).trigger('change'); |
138 | | - this.$target.val(this.map[val]).trigger('change'); |
139 | | - this.$container.addClass('combobox-selected'); |
140 | | - this.selected = true; |
141 | | - return this.hide(); |
142 | | - } |
143 | | - |
144 | | - // modified typeahead function removing the blank handling and source function handling |
145 | | - , lookup: function (event) { |
146 | | - this.query = this.$element.val(); |
147 | | - return this.process(this.source); |
148 | | - } |
149 | | - |
150 | | - // modified typeahead function adding button handling and remove mouseleave |
151 | 253 | , listen: function () { |
152 | 254 | this.$element |
153 | 255 | .on('focus', $.proxy(this.focus, this)) |
|
168 | 270 | .on('click', $.proxy(this.toggle, this)); |
169 | 271 | } |
170 | 272 |
|
171 | | - // modified typeahead function to clear on type and prevent on moving around |
| 273 | + , eventSupported: function(eventName) { |
| 274 | + var isSupported = eventName in this.$element; |
| 275 | + if (!isSupported) { |
| 276 | + this.$element.setAttribute(eventName, 'return;'); |
| 277 | + isSupported = typeof this.$element[eventName] === 'function'; |
| 278 | + } |
| 279 | + return isSupported; |
| 280 | + } |
| 281 | + |
| 282 | + , move: function (e) { |
| 283 | + if (!this.shown) {return;} |
| 284 | + |
| 285 | + switch(e.keyCode) { |
| 286 | + case 9: // tab |
| 287 | + case 13: // enter |
| 288 | + case 27: // escape |
| 289 | + e.preventDefault(); |
| 290 | + break; |
| 291 | + |
| 292 | + case 38: // up arrow |
| 293 | + e.preventDefault(); |
| 294 | + this.prev(); |
| 295 | + break; |
| 296 | + |
| 297 | + case 40: // down arrow |
| 298 | + e.preventDefault(); |
| 299 | + this.next(); |
| 300 | + break; |
| 301 | + } |
| 302 | + |
| 303 | + e.stopPropagation(); |
| 304 | + } |
| 305 | + |
| 306 | + , keydown: function (e) { |
| 307 | + this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]); |
| 308 | + this.move(e); |
| 309 | + } |
| 310 | + |
| 311 | + , keypress: function (e) { |
| 312 | + if (this.suppressKeyPressRepeat) {return;} |
| 313 | + this.move(e); |
| 314 | + } |
| 315 | + |
172 | 316 | , keyup: function (e) { |
173 | 317 | switch(e.keyCode) { |
174 | 318 | case 40: // down arrow |
|
183 | 327 | break; |
184 | 328 |
|
185 | 329 | case 9: // tab |
186 | | - case 13: // enter |
187 | | - if (!this.shown) return; |
| 330 | + case 13: // enter |
| 331 | + if (!this.shown) {return;} |
188 | 332 | this.select(); |
189 | 333 | break; |
190 | 334 |
|
191 | | - case 27: // escape |
192 | | - if (!this.shown) return; |
| 335 | + case 27: // escape |
| 336 | + if (!this.shown) {return;} |
193 | 337 | this.hide(); |
194 | 338 | break; |
195 | 339 |
|
|
202 | 346 | e.preventDefault(); |
203 | 347 | } |
204 | 348 |
|
205 | | - // modified typeahead function to force a match and add a delay on hide |
| 349 | + , focus: function (e) { |
| 350 | + this.focused = true; |
| 351 | + } |
| 352 | + |
206 | 353 | , blur: function (e) { |
207 | 354 | var that = this; |
208 | 355 | this.focused = false; |
|
215 | 362 | if (!this.mousedover && this.shown) {setTimeout(function () { that.hide(); }, 200);} |
216 | 363 | } |
217 | 364 |
|
218 | | - // modified typeahead function to not hide |
| 365 | + , click: function (e) { |
| 366 | + e.stopPropagation(); |
| 367 | + e.preventDefault(); |
| 368 | + this.select(); |
| 369 | + this.$element.focus(); |
| 370 | + } |
| 371 | + |
| 372 | + , mouseenter: function (e) { |
| 373 | + this.mousedover = true; |
| 374 | + this.$menu.find('.active').removeClass('active'); |
| 375 | + $(e.currentTarget).addClass('active'); |
| 376 | + } |
| 377 | + |
219 | 378 | , mouseleave: function (e) { |
220 | 379 | this.mousedover = false; |
221 | 380 | } |
222 | | - }); |
| 381 | + }; |
223 | 382 |
|
224 | 383 | /* COMBOBOX PLUGIN DEFINITION |
225 | 384 | * =========================== */ |
|
0 commit comments