Skip to content

Instantly share code, notes, and snippets.

@fat
Created April 18, 2012 04:01
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save fat/2411033 to your computer and use it in GitHub Desktop.
Save fat/2411033 to your computer and use it in GitHub Desktop.
Tokenahead - ghetto typeahead with facebook-like tokens 4 @couch <3
!function ($) {
"use strict"; // jshint ;_;
/* TOKENAHEAD PUBLIC CLASS DEFINITION
* ================================== */
var Tokenahead = function (element, options) {
this.$wrapper = $(element)
this.$measurer = $('.measurer', this.$wrapper)
this.$tokens = $('.tokens', this.$wrapper)
$.fn.typeahead.Constructor.call(this, $('input', this.$wrapper), options)
}
Tokenahead.prototype = $.extend({}, $.fn.typeahead.Constructor.prototype, {
constructor: Tokenahead
, updater: function (item) {
this.addToken(item)
return ''
}
, addToken: function (item) {
var token = $(this.options.token)
, text = $('<span></span>').text(item).appendTo(token)
token.appendTo(this.$tokens)
}
, listen: function () {
var that = this
$.fn.typeahead.Constructor.prototype.listen.call(this)
this.$wrapper
.on('click', 'a', function (e) {
e.stopPropagation()
})
.on('click', '.close', function (e) {
$(this).parent().remove()
})
.on('click', function () {
that.$element.focus()
})
this.$element
.on('focus', function (e) {
if (!that.$element.val()) return that.isEmpty = true
})
.on('keyup', function (e) {
var tokens
, value
if (e.keyCode == 13 && !that.shown && (value = that.$element.val())) { //enter with no menu and val
that.$element
.val('')
.change()
that.addToken(value)
return that.$element.focus()
}
if (e.keyCode != 8 || that.$element.val()) return that.isEmpty = false//backspace
if (!that.isEmpty) return that.isEmpty = true
tokens = $('a', that.$wrapper)
if (!tokens.length) return
tokens.last().remove()
})
.on('keypress keydown paste', function () {
var value = that.$element.val()
that.$measurer.text(value)
that.$element.css('width', that.$measurer.width() + 30)
})
}
})
/* TOKENAHEAD PLUGIN DEFINITION
* ============================ */
$.fn.tokenahead = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('tokenahead')
, options = typeof option == 'object' && option
if (!data) $this.data('tokenahead', (data = new Tokenahead(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.tokenahead.Constructor = Tokenahead
$.fn.tokenahead.defaults = $.extend({} , $.fn.typeahead.defaults, {
token: '<a><button class="close">&times;</button></a>'
})
}(window.jQuery)
<!-- markup -->
<div class="input-xlarge uneditable-input tokenahead">
<div class="measurer"></div>
<div class="tokens"></div>
<input type="text">
</div>
<script>
$(function () {
$('.tokenahead').tokenahead({
items: 4
, source: ["fat","mdo","dhg"]
})
})
</script>
// Tokenahead.less
// ---------------
.tokenahead {
cursor: text;
overflow: hidden;
height: auto;
padding-bottom: 0;
border-color: @inputBorder;
}
.tokenahead a {
cursor: default;
float: left;
display: inline-block;
border: 1px solid @inputBorder;
text-decoration: none;
padding: 0 4px;
margin: 0 3px 3px 0;
.border-radius(@inputBorderRadius);
}
.tokenahead a:hover {
color: @linkColor;
}
.tokenahead button.close {
font-size: 14px;
line-height: 14px;
margin-left: 4px;
}
.tokenahead .measurer {
position: absolute;
top: -1000px;
}
.tokenahead input {
border: none;
box-shadow: none;
float: left;
margin: 0 0 5px;
padding: 0;
width: 30px;
}
@msurguy
Copy link

msurguy commented Sep 5, 2012

Somehow I can't get this to work with Bootstrap 2.1 and can't figure out where the data gets lost, the token fields don't get updated upon selection. I guess this typeahead plugin doesn't work nicely with the updated typeahead?

@dantuck
Copy link

dantuck commented Sep 11, 2012

I am trying to create a subclass to add in custom updater functions but like you are adding token to the defaults I am trying to add something similar. I am not seeing where you are adding the new defaults to the plugin. I see you extended $.fn.tokenahead.defaults but from your code I don't see how you could access it with this.options.token. It has not been added to the object.

@dantuck
Copy link

dantuck commented Sep 11, 2012

I was modeling off of your code here but then noticed the {} was preventing the extending of the the $.fn.typeahead.defaults so I removed that and all worked.

$.fn.tokenahead.defaults = $.extend({} , $.fn.typeahead.defaults, {

@fadomire
Copy link

Thanks @fat for this code
Thanks @dantuck for your comment about removing {}

$.fn.tokenahead.defaults = $.extend({} , $.fn.typeahead.defaults, { token: '<a><button class="close">&times;</button></a>' })

becoming

$.fn.tokenahead.defaults = $.extend($.fn.typeahead.defaults, { token: '<a><button class="close">&times;</button></a>' })

I made a fork with following additions :

  • a cloned input is created so that original input can store and keep up with tags values
  • a comma trigger a new tag while typing
  • some css changes

https://gist.github.com/4354488

it was for my own use, but if it can be usefull to anyone...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment