Extend TextboxList to add closing functionality via a link added to each box.
Here We will explained how to extend TextboxList to add closing functionality via a link added to each box. But it was missing an important ingredient: autocompletion!
Again, all we have to do is extend the TextboxList class, override some methods, some events, and create some new ones (all prefixed by auto)
var FacebookList = new Class({
Extends: TextboxList,
data: [],
options: {
onInputFocus: function() { this.autoShow(); },
onInputBlur: function(el) {
el.value = '';
this.autoHide();
},
onBoxDispose: function(item) {
this.autoFeed(item.$attributes.$text);
},
autocomplete: {
'opacity': 0.8,
'maxresults': 10,
'minchars': 1
}
},
initialize: function(element, autoholder, options) {
arguments.callee.parent(element, options);
this.autoholder = $(autoholder).set('opacity', this.options.autocomplete.opacity);
this.autoresults = this.autoholder.getElement('ul');
var children = this.autoresults.getElements('li');
children.each(function(el) { this.add(el.innerHTML); }, this);
},
autoShow: function(search) {
this.autoholder.setStyle('display', 'block');
this.autoholder.getElements('*').setStyle('display', 'none');
if(! search || ! search.trim() || (! search.length || search.length < this.options.autocomplete.minchars ))
{
this.autoholder.getElement('.default').setStyle('display', 'block');
this.resultsshown = false;
} else {
this.resultsshown = true;
this.autoresults.setStyle('display', 'block').empty();
this.data.filter(function(str) { return str ? str.test(search, 'i') : false; }).each(function(result, ti) {
if(ti >= this.options.autocomplete.maxresults) return;
var el = new Element('li').set('html', this.autoHighlight(result, search)).inject(this.autoresults);
el.$attributes.$result = result;
if(ti == 0) this.autoFocus(el);
}, this);
}
},
autoHighlight: function(html, highlight) {
return html.replace(new RegExp(highlight, 'gi'), function(match) {
return '<em>' + match + '</em>';
});
},
autoHide: function() {
this.resultsshown = false;
this.autoholder.setStyle('display', 'none');
},
autoFocus: function(el) {
if(! el) return;
if(this.autocurrent) this.autocurrent.removeClass('auto-focus');
this.autocurrent = el.addClass('auto-focus');
},
autoMove: function(direction) {
if(!this.resultsshown) return;
this.autoFocus(this.autocurrent['get' + (direction == 'up' ? 'Previous' : 'Next')]());
},
autoFeed: function(text) {
if(this.data.indexOf(text) == -1)
this.data.push(text);
},
autoAdd: function(el) {
if(!el || ! el.$attributes.$result) return;
this.add(el.$attributes.$result);
delete this.data[this.data.indexOf(el.$attributes.$result)];
this.autoHide();
this.current.$attributes.$input.value = '';
},
createInput: function(options) {
var li = arguments.callee.parent(options);
var input = li.$attributes.$input;
input.addEvents({
'keydown': function(e) {
e = new Event(e);
this.dosearch = false;
switch(e.code) {
case Event.Keys.up: return this.autoMove('up');
case Event.Keys.down: return this.autoMove('down');
case Event.Keys.enter:
this.autoAdd(this.autocurrent);
this.autocurrent = false;
this.autoenter = true;
break;
default: this.dosearch = true;
}
}.bind(this),
'keyup': function() {
if(this.dosearch) this.autoShow(input.value);
}.bind(this)
});
input.addEvent(Browser.Engine.trident ? 'keydown' : 'keypress', function(e) {
if(this.autoenter) new Event(e).stop();
this.autoenter = false;
}.bind(this));
return li;
},
createBox: function(text, options) {
var li = arguments.callee.parent(text, options);
li.addEvents({
'mouseenter': function() { this.addClass('bit-hover') },
'mouseleave': function() { this.removeClass('bit-hover') }
});
li.adopt(new Element('a', {
'href': '#',
'class': 'closebutton',
'events': {
'click': function(e) {
new Event(e).stop();
if(! this.current) this.focus(this.maininput);
this.dispose(li);
}.bind(this)
}
}));
li.$attributes.$text = text;
return li;
}
});
window.addEvent('domready', function() {
// init
var tlist2 = new FacebookList('facebook-demo', 'facebook-auto');
// fetch and feed
new Request.JSON({'url': 'json.html', 'onComplete': function(j) {
j.each(tlist2.autoFeed, tlist2);
}}).send();
});
It works by caching all the results from a JSON Request and feeding them to the autocompleter object. When a item is added as a box, it’ removed from the feed array, and when the box is disposed it’s added back, so that it becomes available in the list when the user types.
Another new feature is that you’ll be able to let it add boxes from the HTML directly:
<label>FacebookList input</label> <input type="text" value="" id="facebook-demo" /> <div id="facebook-auto"> <div class="default">Type the name of an argentine writer you like</div> <ul class="feed"> <li>Jorge Luis Borges</li> <li>Julio Cortazar</li> </ul> </div>
The constructor now takes new parameters to configure the autocompletion, like the minimum number of characters to trigger the dropdown, and more.
Demo: http://devthought.com/wp-content/articles/autocompletelist/test.html
Download: http://devthought.com/wp-content/articles/autocompletelist/AutocompleteList.zip
Source: http://devthought.com/blog/projects-news/2008/01/textboxlist-meets-autocompletion/

Related Listings:
No comments yet.
RSS feed for comments on this post. TrackBack URL