/**
* flexselect: a jQuery plugin, version: 0.3 (2011-12-17)
* @requires jQuery v1.3 or later
*
* FlexSelect is a jQuery plugin that makes it easy to convert a select box into
* a Quicksilver-style, autocompleting, flex matching selection tool.
*
* For usage and examples, visit:
* http://rmm5t.github.com/jquery-flexselect/
*
* Licensed under the MIT:
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright (c) 2009-2012, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
(function($) {
$.flexselect = function(select, options) { this.init(select, options); };
$.extend($.flexselect.prototype, {
settings: {
allowMismatch: false,
selectedClass: "flexselect_selected",
dropdownClass: "flexselect_dropdown",
defaultmessage: "No results",
inputIdTransform: function(id) { return id + "_flexselect"; },
inputNameTransform: function(name) { return; },
dropdownIdTransform: function(id) { return id + "_flexselect_dropdown"; }
},
select: null,
input: null,
hidden: null,
dropdown: null,
dropdownList: null,
cache: [],
results: [],
lastAbbreviation: null,
abbreviationBeforeFocus: null,
selectedIndex: 0,
picked: false,
dropdownMouseover: false, // Workaround for poor IE behaviors
init: function(select, options) {
this.settings = $.extend({}, this.settings, options);
this.select = $(select);
this.preloadCache();
this.renderControls();
this.wire();
},
//preloadCache: function() {
// this.cache = this.select.children("option").map(function() {
// return { name: $.trim($(this).text()), value: $(this).val(), score: 0.0 };
// });
//},
preloadCache: function() {
this.cache = this.select.children("option").map(function() {
return { name: ($(this).html()), value: $(this).val(), score: 0.0 };
});
},
renderControls: function() {
var selected = this.select.children("option:selected");
this.hidden = $("").attr({
id: this.select.attr("id"),
name: this.select.attr("name")
}).val(selected.val());
this.input = $("").attr({
id: this.settings.inputIdTransform(this.select.attr("id")),
name: this.settings.inputNameTransform(this.select.attr("name")),
accesskey: this.select.attr("accesskey"),
tabindex: this.select.attr("tabindex"),
placeholder: this.select.attr("placeholder"),
style: this.select.attr("style")
}).addClass(this.select.attr("class")).val($.trim(selected.text()));
this.dropdown = $("
").attr({
id: this.settings.dropdownIdTransform(this.select.attr("id"))
}).addClass(this.settings.dropdownClass);
this.dropdownList = $("");
this.dropdown.append(this.dropdownList);
this.select.after(this.input).after(this.hidden).remove();
$("body").append(this.dropdown);
},
wire: function() {
var self = this;
this.input.click(function() {
self.lastAbbreviation = null;
self.focus();
if (!self.picked) self.filterResults();
});
this.input.mouseup(function(event) {
// This is so Safari selection actually occurs.
event.preventDefault();
});
this.input.focus(function() {
self.abbreviationBeforeFocus = self.input.val();
self.input.select();
//if (!self.picked) self.filterResults();
});
this.input.blur(function() {
if (!self.dropdownMouseover) {
self.hide();
if (!self.settings.allowMismatch && !self.picked) self.reset();
}
});
this.dropdownList.mouseover(function (event) {
if (event.target.tagName == "LI") {
var rows = self.dropdown.find("li");
self.markSelected(rows.index($(event.target)));
}
});
this.dropdownList.mouseleave(function () {
self.markSelected(-1);
});
this.dropdownList.mouseup(function (event) {
self.pickSelected();
self.focusAndHide();
});
this.dropdown.mouseover(function (event) {
self.dropdownMouseover = true;
});
this.dropdown.mouseleave(function (event) {
self.dropdownMouseover = false;
});
this.dropdown.mousedown(function (event) {
event.preventDefault();
});
this.input.keyup(function(event) {
switch (event.keyCode) {
case 13: // return
event.preventDefault();
self.pickSelected();
self.focusAndHide();
break;
case 27: // esc
event.preventDefault();
self.reset();
self.focusAndHide();
break;
default:
self.filterResults();
break;
}
});
this.input.keydown(function(event) {
switch (event.keyCode) {
case 9: // tab
self.pickSelected();
self.hide();
break;
case 33: // pgup
event.preventDefault();
self.markFirst();
break;
case 34: // pgedown
event.preventDefault();
self.markLast();
break;
case 38: // up
event.preventDefault();
self.moveSelected(-1);
break;
case 40: // down
event.preventDefault();
self.moveSelected(1);
break;
case 13: // return
case 27: // esc
event.preventDefault();
event.stopPropagation();
break;
}
});
},
filterResults: function() {
var abbreviation = this.input.val();
if (abbreviation == this.lastAbbreviation) return;
var results = [];
$.each(this.cache, function() {
this.score = LiquidMetal.score(this.name, abbreviation);
if (this.score > 0.0) results.push(this);
});
if (results.length==0){
var defaultOption = { name: this.settings.defaultmessage, value: "ZERO_CONTACTS", score: 9.9 };
results.push(defaultOption);
}
this.results = results;
this.sortResults();
this.renderDropdown();
this.markFirst();
this.lastAbbreviation = abbreviation;
this.picked = false;
},
sortResults: function() {
this.results.sort(function(a, b) { return b.score - a.score; });
},
renderDropdown: function() {
var dropdownBorderWidth = this.dropdown.outerWidth() - this.dropdown.innerWidth();
var inputOffset = this.input.offset();
this.dropdown.css({
width: (this.input.outerWidth() - dropdownBorderWidth) + "px",
top: (inputOffset.top + this.input.outerHeight()) + "px",
left: inputOffset.left + "px"
});
var list = this.dropdownList.html("");
if (this.results.length > 0) {
$.each(this.results, function() {
list.append($("").html(this.name));
});
}
this.dropdown.show();
},
markSelected: function(n) {
if (n > this.results.length) return;
var rows = this.dropdown.find("li");
rows.removeClass(this.settings.selectedClass);
this.selectedIndex = n;
if (n >= 0) $(rows[n]).addClass(this.settings.selectedClass);
},
pickSelected: function() {
var selected = this.results[this.selectedIndex];
if (selected) {
//this.input.val(selected.name);
//this.picked = true;
this.hidden.val(selected.value);
this.input.val("");
if(typeof changeSelectContactValue == "function"){
return changeSelectContactValue(selected.name,selected.value);
}
} else if (this.settings.allowMismatch) {
this.hidden.val("");
} else {
this.reset();
}
},
hide: function() {
this.dropdown.hide();
this.lastAbbreviation = null;
},
moveSelected: function(n) { this.markSelected(this.selectedIndex+n); },
markFirst: function() { this.markSelected(0); },
markLast: function() { this.markSelected(this.results.length - 1); },
reset: function() { this.input.val(this.abbreviationBeforeFocus); },
focus: function() { this.input.focus(); },
focusAndHide: function() { this.hide(); //this.focus();
}
});
$.fn.flexselect = function(options) {
this.each(function() {
if (this.tagName == "SELECT") new $.flexselect(this, options);
});
return this;
};
})(jQuery);