Revisions
-
Jason Rust revised this gist
Mar 13, 2012 . 1 changed file with 188 additions and 111 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,111 +1,188 @@ --- bootstrap-typeahead.js.1 2012-03-12 14:13:12.000000000 -0700 +++ bootstrap-typeahead.js 2012-03-13 12:05:09.000000000 -0700 @@ -1,5 +1,5 @@ /* ============================================================= - * bootstrap-typeahead.js v2.0.2 + * bootstrap-typeahead.js v2.0.0 * http://twitter.github.com/bootstrap/javascript.html#typeahead * ============================================================= * Copyright 2012 Twitter, Inc. @@ -29,6 +29,10 @@ this.highlighter = this.options.highlighter || this.highlighter this.$menu = $(this.options.menu).appendTo('body') this.source = this.options.source + this.onselect = this.options.onselect + this.autoselect = this.options.autoselect + this.autowidth = this.options.autowidth + this.strings = true this.shown = false this.listen() } @@ -38,9 +42,23 @@ constructor: Typeahead , select: function () { - var val = this.$menu.find('.active').attr('data-value') - this.$element.val(val) - this.$element.change(); + var text, original_text; + if (this.$menu.find('.active').length == 0) { + var val = this.$element.val(); + } + else { + var val = JSON.parse(this.$menu.find('.active').attr('data-value')); + } + + if (!this.strings) text = val[this.options.property] + else text = val + + original_text = this.$element.val(); + this.$element.val(text) + + if (typeof this.onselect == "function") + this.onselect(text, original_text) + return this.hide() } @@ -69,6 +87,25 @@ var that = this , items , q + , value + + this.query = this.$element.val() + + if (typeof this.source == "function") { + value = this.source(this, this.query) + if (value) this.process(value) + } else { + this.process(this.source) + } + } + + , process: function (results) { + var that = this + , items + , q + + if (results.length && typeof results[0] != "string") + this.strings = false this.query = this.$element.val() @@ -76,7 +113,9 @@ return this.shown ? this.hide() : this } - items = $.grep(this.source, function (item) { + items = $.grep(results, function (item) { + if (!that.strings) + item = item[that.options.property] if (that.matcher(item)) return item }) @@ -98,10 +137,14 @@ , caseSensitive = [] , caseInsensitive = [] , item + , sortby while (item = items.shift()) { - if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) - else if (~item.indexOf(this.query)) caseSensitive.push(item) + if (this.strings) sortby = item + else sortby = item[this.options.property] + + if (!sortby.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) + else if (~sortby.indexOf(this.query)) caseSensitive.push(item) else caseInsensitive.push(item) } @@ -118,12 +161,15 @@ var that = this items = $(items).map(function (i, item) { - i = $(that.options.item).attr('data-value', item) + i = $(that.options.item).attr('data-value', JSON.stringify(item)) + if (!that.strings) + item = item[that.options.property] i.find('a').html(that.highlighter(item)) return i[0] }) - items.first().addClass('active') + if (that.autoselect) items.first().addClass('active') + if (that.autowidth) this.$menu.width(this.$element.width()); this.$menu.html(items) return this } @@ -166,19 +212,27 @@ } , keyup: function (e) { + e.stopPropagation() + e.preventDefault() + switch(e.keyCode) { case 40: // down arrow case 38: // up arrow break - case 9: // tab case 13: // enter if (!this.shown) return this.select() break + case 9: // tab + var that = this + e.stopPropagation() + e.preventDefault() + setTimeout(function () { that.hide() }, 150) + break + case 27: // escape - if (!this.shown) return this.hide() break @@ -186,11 +240,10 @@ this.lookup() } - e.stopPropagation() - e.preventDefault() } , keypress: function (e) { + e.stopPropagation() if (!this.shown) return switch(e.keyCode) { @@ -210,12 +263,12 @@ this.next() break } - - e.stopPropagation() } , blur: function (e) { var that = this + e.stopPropagation() + e.preventDefault() setTimeout(function () { that.hide() }, 150) } @@ -251,6 +304,10 @@ , items: 8 , menu: '<ul class="typeahead dropdown-menu"></ul>' , item: '<li><a href="#"></a></li>' + , onselect: null + , autoselect: true + , autowidth: true + , property: 'value' } $.fn.typeahead.Constructor = Typeahead -
Jason Rust revised this gist
Mar 13, 2012 . 3 changed files with 154 additions and 374 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,59 +1,35 @@ # This is a fork of a fork of Bootstrap Typeahead that adds minimal but powerful extensions. * Ability to disable autoselect of first matched element. * Ability to automatically set the width of the dropdown to that of the text input. * Ability to fetch source element via AJAX * Ability to have a comma separated list of tags. For the proper source, and other examples, please see [the original gist](https://gist.github.com/1866577). ### Example showing off all the above features ```javascript // This example is in Javascript, fetches a tag via AJAX and appends it to the comma separated list of tags $('#tags').typeahead({ source: function(typeahead, query) { var term = $.trim(query.split(',').pop()); if (term == '') return []; $.getJSON('/tags/typeahead.json' + '?', { term: term }, function(data) { typeahead.process(data); }); } , onselect: function(item, previous_items) { terms = previous_items.split(','); terms.pop(); terms.push(item); terms.push(''); $.each(terms, function(idx, val) { terms[idx] = $.trim(val); }); $('#tags').val(terms.join(', ')); } // Matcher always returns true since there are multiple comma-seperated terms in the input box and the server ensures only matching terms are returned , matcher: function() { return true; } // Autoselect is disabled so that users can enter new tags , autoselect: false }); ``` This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -30,6 +30,8 @@ this.$menu = $(this.options.menu).appendTo('body') this.source = this.options.source this.onselect = this.options.onselect this.autoselect = this.options.autoselect this.autowidth = this.options.autowidth this.strings = true this.shown = false this.listen() @@ -40,16 +42,22 @@ constructor: Typeahead , select: function () { var text, original_text; if (this.$menu.find('.active').length == 0) { var val = this.$element.val(); } else { var val = JSON.parse(this.$menu.find('.active').attr('data-value')); } if (!this.strings) text = val[this.options.property] else text = val original_text = this.$element.val(); this.$element.val(text) if (typeof this.onselect == "function") this.onselect(text, original_text) return this.hide() } @@ -160,7 +168,8 @@ return i[0] }) if (that.autoselect) items.first().addClass('active') if (that.autowidth) this.$menu.width(this.$element.width()); this.$menu.html(items) return this } @@ -296,6 +305,8 @@ , menu: '<ul class="typeahead dropdown-menu"></ul>' , item: '<li><a href="#"></a></li>' , onselect: null , autoselect: true , autowidth: true , property: 'value' } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,318 +1,111 @@ 2c2 < * bootstrap-typeahead.js v2.0.2 --- > * bootstrap-typeahead.js v2.0.0 31a32,35 > this.onselect = this.options.onselect > this.autoselect = this.options.autoselect > this.autowidth = this.options.autowidth > this.strings = true 41,43c45,61 < var val = this.$menu.find('.active').attr('data-value') < this.$element.val(val) < this.$element.change(); --- > var text, original_text; > if (this.$menu.find('.active').length == 0) { > var val = this.$element.val(); > } > else { > var val = JSON.parse(this.$menu.find('.active').attr('data-value')); > } > > if (!this.strings) text = val[this.options.property] > else text = val > > original_text = this.$element.val(); > this.$element.val(text) > > if (typeof this.onselect == "function") > this.onselect(text, original_text) > 71a90,108 > , value > > this.query = this.$element.val() > > if (typeof this.source == "function") { > value = this.source(this, this.query) > if (value) this.process(value) > } else { > this.process(this.source) > } > } > > , process: function (results) { > var that = this > , items > , q > > if (results.length && typeof results[0] != "string") > this.strings = false 79c116,118 < items = $.grep(this.source, function (item) { --- > items = $.grep(results, function (item) { > if (!that.strings) > item = item[that.options.property] 100a140 > , sortby 103,104c143,147 < if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) < else if (~item.indexOf(this.query)) caseSensitive.push(item) --- > if (this.strings) sortby = item > else sortby = item[this.options.property] > > if (!sortby.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) > else if (~sortby.indexOf(this.query)) caseSensitive.push(item) 121c164,166 < i = $(that.options.item).attr('data-value', item) --- > i = $(that.options.item).attr('data-value', JSON.stringify(item)) > if (!that.strings) > item = item[that.options.property] 126c171,172 < items.first().addClass('active') --- > if (that.autoselect) items.first().addClass('active') > if (that.autowidth) this.$menu.width(this.$element.width()); 168a215,217 > e.stopPropagation() > e.preventDefault() > 174d222 < case 9: // tab 179a228,234 > case 9: // tab > var that = this > e.stopPropagation() > e.preventDefault() > setTimeout(function () { that.hide() }, 150) > break > 181d235 < if (!this.shown) return 189,190d242 < e.stopPropagation() < e.preventDefault() 193a246 > e.stopPropagation() 213,214d265 < < e.stopPropagation() 218a270,271 > e.stopPropagation() > e.preventDefault() 253a307,310 > , onselect: null > , autoselect: true > , autowidth: true > , property: 'value' -
pezholio revised this gist
Mar 5, 2012 . 1 changed file with 1 addition and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,8 +1,6 @@ # This is a fork of a fork of Bootstrap Typeahead that adds minimal but powerful extensions. I've added a couple of lines to the original fork to stop the default behaviour when tabbing. For the proper source, please see [the original gist](https://gist.github.com/1866577). ### For example, process typeahead list asynchronously and return objects -
pezholio revised this gist
Mar 5, 2012 . 2 changed files with 323 additions and 113 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,8 @@ # This is a fork of a fork of Bootstrap Typeahead that adds minimal but powerful extensions. I've added a couple of lines to the original fork to stop the default behaviour when tabbing. For the proper source, please see [the original gist][1]. [1] https://gist.github.com/1866577 ### For example, process typeahead list asynchronously and return objects @@ -54,8 +58,4 @@ }) ``` Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I tried to strike a balance between modifying the core source too much and adding functionality, so until further improvements on the original Typeahead source I think these additions are very helpful. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,108 +1,318 @@ /* ============================================================= * bootstrap-typeahead.js v2.0.0 * http://twitter.github.com/bootstrap/javascript.html#typeahead * ============================================================= * Copyright 2012 Twitter, Inc. * * 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 Typeahead = function ( element, options ) { this.$element = $(element) this.options = $.extend({}, $.fn.typeahead.defaults, options) 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.source = this.options.source this.onselect = this.options.onselect this.strings = true this.shown = false this.listen() } Typeahead.prototype = { constructor: Typeahead , select: function () { var val = JSON.parse(this.$menu.find('.active').attr('data-value')) , text if (!this.strings) text = val[this.options.property] else text = val this.$element.val(text) if (typeof this.onselect == "function") this.onselect(val) return this.hide() } , show: function () { var pos = $.extend({}, this.$element.offset(), { height: this.$element[0].offsetHeight }) this.$menu.css({ top: pos.top + pos.height , left: pos.left }) this.$menu.show() this.shown = true return this } , hide: function () { this.$menu.hide() this.shown = false return this } , lookup: function (event) { var that = this , items , q , value this.query = this.$element.val() if (typeof this.source == "function") { value = this.source(this, this.query) if (value) this.process(value) } else { this.process(this.source) } } , process: function (results) { var that = this , items , q if (results.length && typeof results[0] != "string") this.strings = false this.query = this.$element.val() if (!this.query) { return this.shown ? this.hide() : this } items = $.grep(results, function (item) { if (!that.strings) item = item[that.options.property] 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() } , matcher: function (item) { return ~item.toLowerCase().indexOf(this.query.toLowerCase()) } , sorter: function (items) { var beginswith = [] , caseSensitive = [] , caseInsensitive = [] , item , sortby while (item = items.shift()) { if (this.strings) sortby = item else sortby = item[this.options.property] if (!sortby.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) else if (~sortby.indexOf(this.query)) caseSensitive.push(item) else caseInsensitive.push(item) } return beginswith.concat(caseSensitive, caseInsensitive) } , highlighter: function (item) { return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) { return '<strong>' + match + '</strong>' }) } , render: function (items) { var that = this items = $(items).map(function (i, item) { i = $(that.options.item).attr('data-value', JSON.stringify(item)) if (!that.strings) item = item[that.options.property] i.find('a').html(that.highlighter(item)) return i[0] }) items.first().addClass('active') this.$menu.html(items) return this } , next: function (event) { var active = this.$menu.find('.active').removeClass('active') , next = active.next() if (!next.length) { next = $(this.$menu.find('li')[0]) } next.addClass('active') } , prev: function (event) { var active = this.$menu.find('.active').removeClass('active') , prev = active.prev() if (!prev.length) { prev = this.$menu.find('li').last() } prev.addClass('active') } , 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)) } this.$menu .on('click', $.proxy(this.click, this)) .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) } , keyup: function (e) { e.stopPropagation() e.preventDefault() switch(e.keyCode) { case 40: // down arrow case 38: // up arrow break - case 9: // tab case 13: // enter if (!this.shown) return this.select() break + case 9: // tab + var that = this + e.stopPropagation() + e.preventDefault() + setTimeout(function () { that.hide() }, 150) + break + case 27: // escape this.hide() break default: this.lookup() } } , keypress: function (e) { e.stopPropagation() if (!this.shown) return switch(e.keyCode) { case 9: // tab case 13: // enter case 27: // escape e.preventDefault() break case 38: // up arrow e.preventDefault() this.prev() break case 40: // down arrow e.preventDefault() this.next() break } } , blur: function (e) { var that = this e.stopPropagation() e.preventDefault() setTimeout(function () { that.hide() }, 150) } , click: function (e) { e.stopPropagation() e.preventDefault() this.select() } , mouseenter: function (e) { this.$menu.find('.active').removeClass('active') $(e.currentTarget).addClass('active') } } /* TYPEAHEAD PLUGIN DEFINITION * =========================== */ $.fn.typeahead = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('typeahead') , options = typeof option == 'object' && option if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.typeahead.defaults = { source: [] , items: 8 , menu: '<ul class="typeahead dropdown-menu"></ul>' , item: '<li><a href="#"></a></li>' , onselect: null , property: 'value' } $.fn.typeahead.Constructor = Typeahead /* TYPEAHEAD DATA-API * ================== */ $(function () { $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { var $this = $(this) if ($this.data('typeahead')) return e.preventDefault() $this.typeahead($this.data()) }) }) }( window.jQuery ); -
pezholio revised this gist
Mar 5, 2012 . 1 changed file with 8 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -211,12 +211,18 @@ case 38: // up arrow break case 13: // enter if (!this.shown) return this.select() break case 9: // tab var that = this e.stopPropagation() e.preventDefault() setTimeout(function () { that.hide() }, 150) break case 27: // escape this.hide() break @@ -308,4 +314,4 @@ }) }) }( window.jQuery ); -
gudber revised this gist
Feb 23, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ # This is a fork of Bootstrap Typeahead that adds minimal but powerful extensions. ### For example, process typeahead list asynchronously and return objects -
gudber revised this gist
Feb 23, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -56,6 +56,6 @@ Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I tried to strike a balance between modifying the core source too much and adding functionality, so until further improvements on the original Typeahead source I think these additions are very helpful. **Update 02/23/2012: Fixed a bug** ### Gudbergur Erlendsson, reach me here or gudbergur at gmail -
gudber revised this gist
Feb 23, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -56,6 +56,6 @@ Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I tried to strike a balance between modifying the core source too much and adding functionality, so until further improvements on the original Typeahead source I think these additions are very helpful. Update 02/23/2012: Fixed a bug ### Gudbergur Erlendsson, reach me here or gudbergur at gmail -
gudber revised this gist
Feb 23, 2012 . 2 changed files with 6 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -56,4 +56,6 @@ Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I tried to strike a balance between modifying the core source too much and adding functionality, so until further improvements on the original Typeahead source I think these additions are very helpful. 02/23/2012: Fixed a bug ### Gudbergur Erlendsson, reach me here or gudbergur at gmail This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -83,12 +83,12 @@ this.query = this.$element.val() if (typeof this.source == "function") { value = this.source(this, this.query) if (value) this.process(value) } else { this.process(this.source) } } , process: function (results) { -
gudber revised this gist
Feb 20, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -56,4 +56,4 @@ Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I tried to strike a balance between modifying the core source too much and adding functionality, so until further improvements on the original Typeahead source I think these additions are very helpful. ### Gudbergur Erlendsson, reach me here or gudbergur at gmail -
gudber revised this gist
Feb 20, 2012 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -55,3 +55,5 @@ ``` Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I tried to strike a balance between modifying the core source too much and adding functionality, so until further improvements on the original Typeahead source I think these additions are very helpful. - Gudbergur Erlendsson -
gudber revised this gist
Feb 20, 2012 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ # This is an extension to Bootstrap Typeahead that adds minimal but powerful extensions. ### For example, process typeahead list asynchronously and return objects ```coffeescript # This example does an AJAX lookup and is in CoffeeScript @@ -23,7 +23,7 @@ ) ``` ### For example, process typeahead list synchronously and fire a callback on selection ```javascript // This example is in Javascript, collects html in some li's and returns it -
gudber revised this gist
Feb 20, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -54,4 +54,4 @@ }) ``` Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I tried to strike a balance between modifying the core source too much and adding functionality, so until further improvements on the original Typeahead source I think these additions are very helpful. -
gudber revised this gist
Feb 20, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ # This is an extension to Bootstrap Typeahead that adds minimal but powerful extensions. ### For example, process typeahead list asynchronously, return objects and then fire a callback when one is selected -
gudber revised this gist
Feb 19, 2012 . 1 changed file with 9 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -45,4 +45,13 @@ }) ``` ### and a very simple example, showing you can pass list of objects as source, and get that object via onselect ```javascript $('.typeahead').typeahead({ // note that "value" is the default setting for the property option source: [{value: 'Charlie'}, {value: 'Gudbergur'}, ...], onselect: function(obj) { console.log(obj) } }) ``` Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I think these additions are very helpful. -
gudber created this gist
Feb 19, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,48 @@ # This is an extension to Bootstrap Typeahead that adds three minimal but powerful extensions. ### For example, process typeahead list asynchronously, return objects and then fire a callback when one is selected ```coffeescript # This example does an AJAX lookup and is in CoffeeScript $('.typeahead').typeahead( # source can be a function source: (typeahead, query) -> # this function receives the typeahead object and the query string $.ajax( url: "/lookup/?q="+query # i'm binding the function here using CoffeeScript syntactic sugar, # you can use for example Underscore's bind function instead. success: (data) => # data must be a list of either strings or objects # data = [{'name': 'Joe', }, {'name': 'Henry'}, ...] typeahead.process(data) ) # if we return objects to typeahead.process we must specify the property # that typeahead uses to look up the display value property: "name" ) ``` ### For example, process typeahead list synchronously and call a function on selection ```javascript // This example is in Javascript, collects html in some li's and returns it $('.typeahead').typeahead({ source: function (typeahead, query) { var return_list = [] $("li").each(function(i,v){ return_list.push($(v).html()) }) // here I'm just returning a list of strings return return_list }, // typeahead calls this function when a object is selected, and // passes an object or string depending on what you processed, in this case a string onselect: function (obj) { alert('Selected '+obj) } }) ``` Note that onselect works without source as a function and vice versa. Events may be a cleaner solution to passing callbacks and using bind all over the place, but I think these additions are very helpful. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,311 @@ /* ============================================================= * bootstrap-typeahead.js v2.0.0 * http://twitter.github.com/bootstrap/javascript.html#typeahead * ============================================================= * Copyright 2012 Twitter, Inc. * * 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 Typeahead = function ( element, options ) { this.$element = $(element) this.options = $.extend({}, $.fn.typeahead.defaults, options) 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.source = this.options.source this.onselect = this.options.onselect this.strings = true this.shown = false this.listen() } Typeahead.prototype = { constructor: Typeahead , select: function () { var val = JSON.parse(this.$menu.find('.active').attr('data-value')) , text if (!this.strings) text = val[this.options.property] else text = val this.$element.val(text) if (typeof this.onselect == "function") this.onselect(val) return this.hide() } , show: function () { var pos = $.extend({}, this.$element.offset(), { height: this.$element[0].offsetHeight }) this.$menu.css({ top: pos.top + pos.height , left: pos.left }) this.$menu.show() this.shown = true return this } , hide: function () { this.$menu.hide() this.shown = false return this } , lookup: function (event) { var that = this , items , q , value this.query = this.$element.val() if (typeof this.source == "function") value = this.source(this, this.query) if (value) this.process(value) else this.process(this.source) } , process: function (results) { var that = this , items , q if (results.length && typeof results[0] != "string") this.strings = false this.query = this.$element.val() if (!this.query) { return this.shown ? this.hide() : this } items = $.grep(results, function (item) { if (!that.strings) item = item[that.options.property] 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() } , matcher: function (item) { return ~item.toLowerCase().indexOf(this.query.toLowerCase()) } , sorter: function (items) { var beginswith = [] , caseSensitive = [] , caseInsensitive = [] , item , sortby while (item = items.shift()) { if (this.strings) sortby = item else sortby = item[this.options.property] if (!sortby.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) else if (~sortby.indexOf(this.query)) caseSensitive.push(item) else caseInsensitive.push(item) } return beginswith.concat(caseSensitive, caseInsensitive) } , highlighter: function (item) { return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) { return '<strong>' + match + '</strong>' }) } , render: function (items) { var that = this items = $(items).map(function (i, item) { i = $(that.options.item).attr('data-value', JSON.stringify(item)) if (!that.strings) item = item[that.options.property] i.find('a').html(that.highlighter(item)) return i[0] }) items.first().addClass('active') this.$menu.html(items) return this } , next: function (event) { var active = this.$menu.find('.active').removeClass('active') , next = active.next() if (!next.length) { next = $(this.$menu.find('li')[0]) } next.addClass('active') } , prev: function (event) { var active = this.$menu.find('.active').removeClass('active') , prev = active.prev() if (!prev.length) { prev = this.$menu.find('li').last() } prev.addClass('active') } , 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)) } this.$menu .on('click', $.proxy(this.click, this)) .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) } , keyup: function (e) { e.stopPropagation() e.preventDefault() switch(e.keyCode) { case 40: // down arrow case 38: // up arrow break case 9: // tab case 13: // enter if (!this.shown) return this.select() break case 27: // escape this.hide() break default: this.lookup() } } , keypress: function (e) { e.stopPropagation() if (!this.shown) return switch(e.keyCode) { case 9: // tab case 13: // enter case 27: // escape e.preventDefault() break case 38: // up arrow e.preventDefault() this.prev() break case 40: // down arrow e.preventDefault() this.next() break } } , blur: function (e) { var that = this e.stopPropagation() e.preventDefault() setTimeout(function () { that.hide() }, 150) } , click: function (e) { e.stopPropagation() e.preventDefault() this.select() } , mouseenter: function (e) { this.$menu.find('.active').removeClass('active') $(e.currentTarget).addClass('active') } } /* TYPEAHEAD PLUGIN DEFINITION * =========================== */ $.fn.typeahead = function ( option ) { return this.each(function () { var $this = $(this) , data = $this.data('typeahead') , options = typeof option == 'object' && option if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) if (typeof option == 'string') data[option]() }) } $.fn.typeahead.defaults = { source: [] , items: 8 , menu: '<ul class="typeahead dropdown-menu"></ul>' , item: '<li><a href="#"></a></li>' , onselect: null , property: 'value' } $.fn.typeahead.Constructor = Typeahead /* TYPEAHEAD DATA-API * ================== */ $(function () { $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { var $this = $(this) if ($this.data('typeahead')) return e.preventDefault() $this.typeahead($this.data()) }) }) }( window.jQuery ); This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,108 @@ /* ============================================================= * bootstrap-typeahead.js v2.0.0 * http://twitter.github.com/bootstrap/javascript.html#typeahead * ============================================================= * Copyright 2012 Twitter, Inc. @@ -29,6 +29,8 @@ this.highlighter = this.options.highlighter || this.highlighter this.$menu = $(this.options.menu).appendTo('body') this.source = this.options.source + this.onselect = this.options.onselect + this.strings = true this.shown = false this.listen() } @@ -38,8 +40,17 @@ constructor: Typeahead , select: function () { - var val = this.$menu.find('.active').attr('data-value') - this.$element.val(val) + var val = JSON.parse(this.$menu.find('.active').attr('data-value')) + , text + + if (!this.strings) text = val[this.options.property] + else text = val + + this.$element.val(text) + + if (typeof this.onselect == "function") + this.onselect(val) + return this.hide() } @@ -68,6 +79,25 @@ var that = this , items , q + , value + + this.query = this.$element.val() + + if (typeof this.source == "function") + value = this.source(this, this.query) + if (value) + this.process(value) + else + this.process(this.source) + } + + , process: function (results) { + var that = this + , items + , q + + if (results.length && typeof results[0] != "string") + this.strings = false this.query = this.$element.val() @@ -75,7 +105,9 @@ return this.shown ? this.hide() : this } - items = $.grep(this.source, function (item) { + items = $.grep(results, function (item) { + if (!that.strings) + item = item[that.options.property] if (that.matcher(item)) return item }) @@ -97,10 +129,14 @@ , caseSensitive = [] , caseInsensitive = [] , item + , sortby while (item = items.shift()) { - if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) - else if (~item.indexOf(this.query)) caseSensitive.push(item) + if (this.strings) sortby = item + else sortby = item[this.options.property] + + if (!sortby.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item) + else if (~sortby.indexOf(this.query)) caseSensitive.push(item) else caseInsensitive.push(item) } @@ -117,7 +153,9 @@ var that = this items = $(items).map(function (i, item) { - i = $(that.options.item).attr('data-value', item) + i = $(that.options.item).attr('data-value', JSON.stringify(item)) + if (!that.strings) + item = item[that.options.property] i.find('a').html(that.highlighter(item)) return i[0] }) @@ -251,6 +289,8 @@ , items: 8 , menu: '<ul class="typeahead dropdown-menu"></ul>' , item: '<li><a href="#"></a></li>' + , onselect: null + , property: 'value' } $.fn.typeahead.Constructor = Typeahead