Merge branch 'release/v0.2.1'

This commit is contained in:
2011-03-31 23:44:00 +01:00
10 changed files with 571 additions and 614 deletions

View File

@@ -1,6 +1,6 @@
(The MIT License) (The MIT License)
Copyright (c) 2009 Jim Myhrberg. Copyright (c) 2011 Jim Myhrberg.
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the

View File

@@ -1,4 +1,4 @@
# Suggest Results # Fancy Input / Fancy Suggest
Easily customizable search suggestion plugin for jQuery, which suggests results directly, rather than search terms. Easily customizable search suggestion plugin for jQuery, which suggests results directly, rather than search terms.
@@ -10,18 +10,19 @@ Check out the [Demo][].
First of all you will need [jQuery][], visit their [site][jquery] for more info. First of all you will need [jQuery][], visit their [site][jquery] for more info.
Then include both `jquery.suggest_results.js` and `jquery.suggest_results.css` on your page. Then include both `jquery.fancy_input.js` and `jquery.fancy_input.css` on your page.
<script src="/suggest_results/jquery.suggest_results.js" type="text/javascript"></script> <script src="/fancy_input/jquery.fancy_input.js" type="text/javascript"></script>
<link href="/suggest_results/jquery.suggest_results.css" rel="stylesheet" type="text/css" /> <script src="/fancy_input/jquery.fancy_suggest.js" type="text/javascript"></script>
<link href="/fancy_input/jquery.fancy_input.css" rel="stylesheet" type="text/css" />
## Usage ## Usage
### Local Javascript Array ### Local Javascript Array
To use Suggest Results, simply call it on a targeted text input element. For example if you have a search box for a users friends: To use Fancy Results, simply call it on a targeted text input element. For example if you have a search box for a users friends:
$("#search_friends").suggest_results({ $("#search_friends").fancy_suggest({
data: userFriends data: userFriends
}); });
@@ -38,9 +39,9 @@ The `match` attribute is useful when you need to include extra information like
### Ajax Call ### Ajax Call
To fetch results via an Ajax call, attach Suggest Results like this to your input element: To fetch results via an Ajax call, attach Fancy Results like this to your input element:
$("#search_friends").suggest_results({ $("#search_friends").fancy_suggest({
url: "/search_friends_json.php" url: "/search_friends_json.php"
}); });
@@ -59,16 +60,16 @@ Also, a query cache is used so a specific search term is only requested once per
## Options ## Options
There's a number of options you can pass `$.suggest_results()`. There's a number of options you can pass `$.fancy_suggest()`.
* **data:** Javascript array with available results. * **data:** Javascript array with available results.
* **url:** URL to send ajax request to for results. Either `url` or `data` are required for Suggest Results to work at all. * **url:** URL to send ajax request to for results. Either `url` or `data` are required for Fancy Results to work at all.
* **name:** When used, the value is used as the class for the suggest box. Useful for having a custom styled suggest box one of two or more input fields with suggestion turned on. * **name:** When used, the value is used as the class for the suggest box. Useful for having a custom styled suggest box one of two or more input fields with suggestion turned on.
* **exact_match:** Results much be an exact match to typed input. If disabled any one word typed is a value match. Enabled by default, and has no effect when fetching results via Ajax. * **exact_match:** Results much be an exact match to typed input. If disabled any one word typed is a value match. Enabled by default, and has no effect when fetching results via Ajax.
* **limit:** Limit the number of suggestions shown. When using the Ajax method, an extra `limit` GET/POST var is supplied. * **limit:** Limit the number of suggestions shown. When using the Ajax method, an extra `limit` GET/POST var is supplied.
* **no_results:** When set to true, a "No Results" label is shown if entered text doesn't yield any results. Enabled by default. * **no\_results:** When set to true, a "No Results" label is shown if entered text doesn't yield any results. Enabled by default.
* **no\_results\_label:** Text shown when there are no results if `no_results` is enabled. Default is "No Results". * **no\_results\_label:** Text shown when there are no results if `no_results` is enabled. Default is "No Results".
* **url_method:** URL method used for Ajax call. Set to "get" or "post". Default is "get". * **url\_method:** URL method used for Ajax call. Set to "get" or "post". Default is "get".
## Customization ## Customization
@@ -83,7 +84,7 @@ For example, if we want to display some extra info underneath our friend's names
When we attach the suggestions to our input element, we specify the `tpl_result_body` option: When we attach the suggestions to our input element, we specify the `tpl_result_body` option:
$("#search_friends").suggest_results({ $("#search_friends").fancy_suggest({
url: "/search_friends_json.php", url: "/search_friends_json.php",
name: "search_friends", name: "search_friends",
tpl_result_body: '<span class="title">{{title}}</span><span class="info">{{info}}</span>' tpl_result_body: '<span class="title">{{title}}</span><span class="info">{{info}}</span>'
@@ -94,11 +95,11 @@ In the `tpl_result_body` option, `{{title}}` is replaced with the `title` attrib
Then to prettify it, we add some CSS: Then to prettify it, we add some CSS:
/* Effects all suggestion boxes */ /* Effects all suggestion boxes */
#suggest_results li span.info { #fancy_suggest li span.info {
color: #888; color: #888;
} }
/* Effects only the #search_friends suggestion box */ /* Effects only the #search_friends suggestion box */
#suggest_results.search_friends li { #fancy_suggest.search_friends li {
border-bottom-style: dashed; border-bottom-style: dashed;
} }
@@ -110,6 +111,7 @@ There are some more options available too for customization, so I recommend you
* Handle mouse hovering and keyboard navigation a bit better when used at the same time on a suggest box. * Handle mouse hovering and keyboard navigation a bit better when used at the same time on a suggest box.
* Support suggesting search terms in addition to currently only supporting results. * Support suggesting search terms in addition to currently only supporting results.
* Add callbacks for most things. * Add callbacks for most things.
* Build other "fancy" input methods on top of `$.fancy_text()`.
## Notice ## Notice
@@ -119,7 +121,7 @@ I wrote this plugin in about 6-7 hours, so things could be a bit stupid. But at
(The MIT License) (The MIT License)
Copyright (c) 2009 Jim Myhrberg. Copyright (c) 2011 Jim Myhrberg.
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
@@ -142,5 +144,5 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
[jquery]: http://jquery.com/ [jquery]: http://jquery.com/
[demo]: http://files.jimeh.me/projects/suggest_results/demo/ [demo]: http://files.jimeh.me/projects/fancy_input/demo/

View File

@@ -2,16 +2,16 @@ require 'fileutils'
RLS_PATH = "_releases" RLS_PATH = "_releases"
RLS_IGNORE = ["#{RLS_PATH}/*", ".git*", "*.DS_Store", "Rakefile"] RLS_IGNORE = ["#{RLS_PATH}/*", ".git*", "*.DS_Store", "Rakefile", "tmp/*"]
desc "Build a release package" desc "Build a release package"
task :release do task :release do
FileUtils.mkdir_p(RLS_PATH) FileUtils.mkdir_p(RLS_PATH)
file = File.read("suggest_results/jquery.suggest_results.js") file = File.read("fancy_input/jquery.fancy_input.js")
if file =~ /\* Suggest Results v([0-9\.]+)\n/ if file =~ /\* Fancy Input v([0-9\.]+)\n/
version = $1 version = $1
target = "#{RLS_PATH}/jquery.suggest_results-#{version}.zip" target = "#{RLS_PATH}/jquery.fancy_input-#{version}.zip"
if File.exist?(target) if File.exist?(target)
puts "ERROR: #{target} already exists." puts "ERROR: #{target} already exists."
else else
@@ -24,7 +24,9 @@ end
desc "Update demo page." desc "Update demo page."
task :demo do task :demo do
rsync(".", "jimeh@jimeh.me:jimeh.me/files/projects/suggest_results", ["--exclude='#{RLS_PATH}'", "--delete"]) rsync(".", "jimeh@jimeh.me:jimeh.me/files/projects/fancy_input", ["--exclude='#{RLS_PATH}'",
"--exclude='tmp'",
"--delete"])
end end

View File

@@ -5,28 +5,29 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Suggest Results Demo</title> <title>Fancy Suggest Demo</title>
<link rel="stylesheet" href="demo.css" type="text/css" media="screen" title="no title" charset="utf-8"> <link rel="stylesheet" href="demo.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script src="../javascripts/jquery.js" type="text/javascript" charset="utf-8"></script> <script src="../javascripts/jquery.js" type="text/javascript" charset="utf-8"></script>
<script src="../suggest_results/jquery.suggest_results.js" type="text/javascript" charset="utf-8"></script> <script src="../fancy_input/jquery.fancy_input.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" href="../suggest_results/jquery.suggest_results.css" type="text/css" media="screen" title="no title" charset="utf-8"> <script src="../fancy_input/jquery.fancy_suggest.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" href="../fancy_input/jquery.fancy_suggest.css" type="text/css" media="screen" title="no title" charset="utf-8">
<script src="demo.js" type="text/javascript" charset="utf-8"></script> <script src="demo.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8"> <script type="text/javascript" charset="utf-8">
$(document).ready(function(){ $(document).ready(function(){
$("#example1").suggest_results({ $("#example1").fancy_suggest({
data: exampleData data: exampleData
}); });
$("#example2").suggest_results({ $("#example2").fancy_suggest({
url: "server-side.php", url: "server-side.php",
}); });
$("#example3").suggest_results({ $("#example3").fancy_suggest({
url: "server-side.php", url: "server-side.php",
name: "example3", name: "example3",
no_results: false, no_results: false,
@@ -34,7 +35,7 @@
tpl_result_body: '<span class="title">{{title}}</span><span class="info">{{ info }}</span>' tpl_result_body: '<span class="title">{{title}}</span><span class="info">{{ info }}</span>'
}); });
$("#example4").suggest_results({ $("#example4").fancy_suggest({
data: exampleData, data: exampleData,
pos_top: 0, pos_top: 0,
pos_left: 20, pos_left: 20,
@@ -47,10 +48,10 @@
<style type="text/css" media="screen"> <style type="text/css" media="screen">
/* Example 3 */ /* Example 3 */
#suggest_results li span.info { #fancy_suggest li span.info {
color: #888; color: #888;
} }
#suggest_results.example3 li { #fancy_suggest.example3 li {
border-bottom-style: dashed; border-bottom-style: dashed;
} }
@@ -62,7 +63,7 @@
<div id="container"> <div id="container">
<p></p> <p></p>
<h1>Suggest Results Demo</h1> <h1>Fancy Suggest Demo</h1>
<p> <p>
<strong>Results from local array:</strong><br /> <strong>Results from local array:</strong><br />
<input type="text" name="example1" value="" id="example1" /> <input type="text" name="example1" value="" id="example1" />
@@ -79,9 +80,6 @@
<strong>Customized position with results from local array:</strong><br /> <strong>Customized position with results from local array:</strong><br />
<input type="text" name="example4" value="" id="example4" /> <input type="text" name="example4" value="" id="example4" />
</p> </p>
<p>
<a href="http://github.com/jimeh/suggest_results">GitHub Project Page</a>
</p>
</div> </div>
</body> </body>

View File

@@ -0,0 +1,126 @@
/*!
* Fancy Input v0.2.1
*
* Copyright (c) 2011 Jim Myhrberg.
* Released under the MIT license.
*/
(function($){
$.fn.fancy_input = {
timeout: null,
default_options: {},
keys: {
BACKSPACE: 8,
TAB: 9,
RETURN: 13,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
PAUSE: 19,
BREAK: 19,
CAPSLOCK: 20,
ESC: 27,
PAGEUP: 33,
PAGEDOWN: 34,
END: 35,
HOME: 36,
ARROW_LEFT: 37,
ARROW_UP: 38,
ARROW_RIGHT: 39,
ARROW_DOWN: 40,
INSERT: 45,
DELETE: 46,
SPECIALS_END: 47
},
elm_uid: function(elm){
if (elm.attr("id") !== "") {
return "ID_" + elm.attr("id");
} else if (elm.attr("class") !== "") {
return "CL_" + elm.attr("class");
} else if (elm.attr("name") !== "") {
return "NA_" + elm.attr("name");
};
return "";
},
setTimeout: function(callback, delay){
this.clearTimeout();
this.timeout = setTimeout(callback, delay);
},
clearTimeout: function(){
if (this.timeout !== null) {
clearTimeout(this.timeout);
this.timeout = null;
};
},
mustache: function(string, data){
if (typeof(string) === "string" && typeof(data) === "object") {
for (var key in data) {
string = string.replace(new RegExp("{{\\s*" + key + "\\s*}}", "g"), data[key]);
}
};
return string;
},
replace_elm: function(target, replacement){
if (typeof(target.attr("id")) !== "undefined" && target.attr("id") !== "") {
replacement = replacement.attr("id", target.attr("id"));
};
if (typeof(target.attr("class")) !== "undefined" && target.attr("class") !== "") {
replacement = replacement.attr("class", target.attr("class"));
};
target.replaceWith(replacement);
return replacement;
},
/*
redirect_to method from: http://gist.github.com/327227
*/
redirect_to: function(url, location){
var redirect_to = "";
if (typeof(location) == "undefined") location = window.location;
if (url.match(/^[a-zA-Z]+\:\/\/.+/) === null) {
redirect_to += location.protocol + "//" + location.hostname;
if (location.port != "") redirect_to += ":" + location.port;
if (url.charAt(0) !== "/") redirect_to += location.pathname.substr(0, location.pathname.lastIndexOf("/")+1);
window.location.href = redirect_to + url;
} else {
window.location.href = url;
};
},
// "borrowed" from PutCursorAtEnd plugin: http://plugins.jquery.com/project/PutCursorAtEnd
putCursorAtEnd: function(){
return this.each(function(){
$(this).focus();
if (this.setSelectionRange) {
var len = $(this).val().length * 2;
this.setSelectionRange(len, len);
} else {
$(this).val($(this).val());
}
this.scrollTop = 999999;
});
}
};
})(jQuery);
/*
Crossbrowser hasOwnProperty solution, based on answers from:
http://stackoverflow.com/questions/135448/how-do-i-check-to-see-if-an-object-has-an-attribute-in-javascript
*/
if ( !Object.prototype.hasOwnProperty ) {
Object.prototype.hasOwnProperty = function(prop){
var proto = obj.__proto__ || obj.constructor.prototype;
return (prop in this) && (!(prop in proto) || proto[prop] !== this[prop]);
};
}

View File

@@ -0,0 +1,61 @@
.fancy_suggest {
border-bottom: 1px solid rgba(187,187,187,0.4);
display: none;
position: absolute;
z-index: 1000;
}
.fancy_suggest ol {
background: #fbfbfb;
border: 1px solid #bbb;
border-top-style: none;
margin: 0px;
padding: 0px;
list-style: none;
}
.fancy_suggest li {
margin: 0px;
border-bottom: 1px solid #ddd;
}
.fancy_suggest li.result {
}
.fancy_suggest li.label {
padding: 3px 5px;
color: #888;
}
.fancy_suggest li.first {
}
.fancy_suggest li.last {
border-bottom: none !important;
}
.fancy_suggest li.result a {
color: #000;
display: block;
padding: 3px 5px;
text-decoration: none;
}
.fancy_suggest li.result a span {
display: block;
}
.fancy_suggest li.result.selected a {
background: #698DE5;
color: #fff;
}
.fancy_suggest li.result .highlight {
background: #ddd;
font-weight: bold;
}
.fancy_suggest li.result.selected .highlight {
background: #7893E5;
color: #fff;
}

View File

@@ -0,0 +1,330 @@
/*!
* Fancy Suggest
*
* Copyright (c) 2011 Jim Myhrberg.
* Released under the MIT license.
*/
(function($){
var Super = $.fn.fancy_input;
var Self = $.fn.fancy_suggest = function(options){
var $options = $.extend({}, Self.default_options, options);
return this.each(function(){
var $e = $(this);
Self.init_suggest($e, $options);
$e.focus(function(){
Self.attach_suggest_box($e, $options);
if ($e.val().length > 0) {
Self.setTimeout(function(){
Self.suggest($e, $options);
}, $options.delay);
};
}).blur(function(){
Self.hide();
}).keydown(function(e){
switch(e.keyCode) {
case Self.keys.ARROW_UP:
Self.select_prev($e, $options);
return false;
case Self.keys.ARROW_DOWN:
Self.select_next($e, $options);
return false;
case Self.keys.ESC:
Self.clear($e, $options);
break;
case Self.keys.RETURN:
if (Self.selected_result !== null) {
Self.activate_selected($options);
return false;
}
break;
}
}).keyup(function(e){
var key = e.keyCode;
Self.align_suggest_box($e, $options);
if (key > Self.keys.SPECIALS_END || key == Self.keys.BACKSPACE || key == Self.keys.DELETE) {
Self.clearTimeout();
Self.suggest($e, $options);
};
});
});
};
$.extend(Self, Super, {
box: null,
list: null,
attached_to: null,
current_results: [],
selected_result: null,
query_cache: [],
default_options: $.extend({}, Super.default_options, {
name: "",
exact_match: true,
limit: 6,
no_results: true,
no_results_label: "No Results",
url: null,
url_method: "get",
url_query_var: "search",
pos_top: 0,
pos_left: 0,
hide_delay: 0,
data: null,
tpl_container_id: "fancy_suggest",
tpl_container_class: "fancy_suggest",
tpl_container: '<div id="{{id}}"><ol></ol></div>',
tpl_result_begin: '<li class="result {{class}}" id="{{id}}" result_id="{{result_id}}"><a href="{{href}}">',
tpl_result_body: '<span class="title">{{title}}</span>',
tpl_result_end: '</a></li>',
tpl_label: '<li class="label {{class}}">{{label}}</li>',
tpl_highlight: '<b class="highlight">$1</b>'
}),
init_suggest: function(elm, options){
this.box = $("#" + options.tpl_container_id);
if (this.box.length == 0) {
$("body").append($(options.tpl_container).attr("id", options.tpl_container_id).attr("class", options.tpl_container_class));
this.box = $("#" + options.tpl_container_id);
};
this.list = this.box.children("ol");
},
attach_suggest_box: function(elm, options){
var elm_uid = this.elm_uid(elm);
this.align_suggest_box(elm, options);
if (elm_uid !== this.attached_to) {
if (typeof(options.name) == "string" && options.name != "") {
this.box.hide().addClass(options.name);
};
this.attached_to = elm_uid;
};
},
align_suggest_box: function(elm, options){
var offset = elm.offset();
// left
this.box.css("left", (offset.left + options.pos_left));
// top
var top = offset.top + elm.innerHeight();
top += parseInt(elm.css("border-top-width"), 10) + parseInt(elm.css("border-bottom-width"), 10);
top += options.pos_top;
this.box.css("top", top);
// width
if (typeof(options.width) === "number" || (typeof(options.width) === "string" && options.width != "")) {
this.box.css("width", options.width);
} else {
var width = elm.innerWidth();
width += parseInt(elm.css("border-left-width"), 10) + parseInt(elm.css("border-right-width"), 10);
width -= parseInt(this.box.css("border-left-width"), 10) + parseInt(this.box.css("border-right-width"), 10);
this.box.css("width", width);
};
},
suggest: function(elm, options){
var terms = $.trim(this.get_value(elm, options));
if (options.exact_match) terms = terms.split(/\s/);
if ((typeof(terms) == "string" && terms != "") || (typeof(terms) == "object" && terms.length > 0)) {
this.selected_result = null;
if (typeof(options.url) === "string" && options.url !== "") {
this.query_for_data(elm, options);
} else {
this.current_results = this.filter_data(terms, options.data, options);
this.prerender(elm, this.current_results, options);
};
};
},
filter_data: function(terms, data, options){
if (typeof(terms) === "string") { terms = [terms]; };
var matched = "";
var results = [];
var terms_length = terms.length;
for (var i=0; i < terms_length; i++) {
var term = terms[i];
term = term.toLowerCase();
if (data !== null && typeof(term) !== "undefined" && term !== "") {
var data_length = data.length;
for (var n=0; n < data_length; n++) {
var title = data[n].title.toLowerCase();
var match = (typeof(data[n].match) !== "undefined") ? data[n].match.toLowerCase() : "" ;
if (title.indexOf(term) !== -1 || match.indexOf(term) !== -1) {
if (matched.indexOf(":" + n + ":") == -1) {
results.push(data[n]);
matched += ":" + n + ":";
if (results.length >= options.limit) {
return results;
};
};
};
};
};
};
return results;
},
query_for_data: function(elm, options){
var term = this.get_value(elm, options);
var uid = options.url + "?" + term + ":" + options.limit;
if (term !== "") {
if (this.query_cache.hasOwnProperty(uid)) {
this.current_results = this.query_cache[uid];
this.prerender(elm, this.current_results, options);
} else {
var data = { limit: options.limit };
data[options.url_query_var] = term;
var Self = this;
$.ajax({
type: options.url_method,
url: options.url,
data: data,
dataType: "json",
success: function(response){
Self.current_results = response.results;
Self.query_cache[uid] = Self.current_results;
Self.prerender(elm, Self.current_results, options);
}
});
};
} else {
this.no_results(elm, options);
};
},
clear: function(elm, options){
this.set_value(elm, "");
this.hide();
this.selected_result = null;
},
no_results: function(elm, options){
if (options.no_results && this.get_value(elm, options) !== "") {
var meta = {label: options.no_results_label, "class": "last"};
this.list.html(this.mustache(options.tpl_label, meta));
this.show();
} else {
this.hide(0);
};
},
prerender: function(elm, results, options){
if (results.length > 0) {
this.render(elm, results, options);
this.show();
if (results.length == 1) {
this.select_next(elm, options);
};
} else {
this.no_results(elm, options);
};
},
render: function(elm, results, options){
var results_length = results.length;
var html = "";
for (var i=0; i < results_length; i++) {
var elm_id = "fancy_suggest_result_" + i;
var meta = $.extend({}, results[i], {id: elm_id, "class": "", result_id: i});
if (i == 0) { $.extend(meta, {"class": "first"}); };
if (i == results_length - 1) { $.extend(meta, {"class": "last"}); };
meta["title"] = meta["title"].replace(new RegExp("(" + this.get_value(elm, options) + ")", "ig"), options.tpl_highlight);
html += this.mustache(options.tpl_result_begin, meta);
html += this.mustache(options.tpl_result_body, meta);
html += this.mustache(options.tpl_result_end, meta);
};
this.list.html(html);
var Self = this;
$(".result a", this.list).mousedown(function(){
Self.selected_result = parseInt($(this).parent().attr("result_id"), 10);
Self.activate_selected(elm, options);
}).click(function(){
return false;
});
$(".result", this.list).hover(function(){
$(".selected", Self.list).removeClass("selected");
Self.selected_result = $(this).addClass("selected").attr("result_id");
},function(){
$(this).removeClass("selected");
Self.selected_result = null;
});
},
show: function(){
this.box.show();
},
hide: function(delay){
if (typeof(delay) !== "number") { delay = this.default_options.hide_delay; };
this.selected_result = null;
var Self = this;
this.setTimeout(function(){
Self.selected_result = null;
$(".selected", this.list).removeClass("selected");
Self.box.hide();
}, delay);
},
select_next: function(elm, options){
var limit = this.current_results.length;
var result_id = "fancy_suggest_result_";
if (limit > 0) {
if (this.selected_result === null) {
$(".selected", this.list).removeClass("selected");
this.selected_result = 0;
$("#" + result_id + this.selected_result).addClass("selected");
} else if (this.selected_result + 1 < limit) {
$(".selected", this.list).removeClass("selected");
this.selected_result++;
$("#" + result_id + this.selected_result).addClass("selected");
} else {
$(".selected", this.list).removeClass("selected");
this.selected_result = null;
elm.putCursorAtEnd();
};
};
return false;
},
select_prev: function(elm, options){
var limit = this.current_results.length;
var result_id = "fancy_suggest_result_";
if (limit > 0) {
if (this.selected_result === null) {
$(".selected", this.list).removeClass("selected");
this.selected_result = limit - 1;
$("#" + result_id + this.selected_result).addClass("selected");
} else if (this.selected_result > 0) {
$(".selected", this.list).removeClass("selected");
this.selected_result--;
$("#" + result_id + this.selected_result).addClass("selected");
} else {
$(".selected", this.list).removeClass("selected");
this.selected_result = null;
elm.putCursorAtEnd();
};
};
return false;
},
activate_selected: function(elm, options){
if (this.selected_result !== null) {
this.redirect_to(this.current_results[this.selected_result].href);
};
},
get_value: function(elm, options) {
return elm.val();
},
set_value: function(elm, value, options) {
elm.val(value);
}
});
})(jQuery);

155
javascripts/jquery.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,53 +0,0 @@
#suggest_results {
border-bottom: 1px solid rgba(187,187,187,0.4);
display: none;
position: absolute;
z-index: 1000;
}
#suggest_results ol {
background: #fbfbfb;
border: 1px solid #bbb;
border-top-style: none;
margin: 0px;
padding: 0px;
list-style: none;
}
#suggest_results li {
margin: 0px;
border-bottom: 1px solid #ddd;
}
#suggest_results li.result {
}
#suggest_results li.label {
padding: 3px 5px;
color: #888;
}
#suggest_results li.first {
}
#suggest_results li.last {
border-bottom: none !important;
}
#suggest_results li.result a {
color: #000;
display: block;
padding: 3px 5px;
text-decoration: none;
}
#suggest_results li.result a span {
display: block;
}
#suggest_results li.result.selected a {
background: #698DE5;
color: #fff;
}

View File

@@ -1,386 +0,0 @@
/*!
* Suggest Results v0.1.3
* http://github.com/jimeh/suggest_results
*
* Copyright (c) 2010 Jim Myhrberg.
* Released under the MIT license.
*/
(function($){
$.fn.suggest_results = function(options){
var self = $.fn.suggest_results;
var $options = $.extend({}, self.defaults, options);
self.init($options);
var BACKSPACE = 8;
var RETURN = 13;
var ESC = 27;
var ARRUP = 38;
var ARRDN = 40;
var SPECIALS_END = 45;
return this.each(function(){
var $e = $(this);
$e.focus(function(){
self.attach($e, $options);
if ($e.val().length > 0) {
self.setTimeout(function(){
self.search($e, $options);
}, $options.delay);
};
}).blur(function(){
self.hide();
}).keydown(function(e){
switch(e.keyCode) {
case ARRUP:
self.select_prev($e, $options);
return false;
case ARRDN:
self.select_next($e, $options);
return false;
case ESC:
self.clear($e, $options);
break;
case RETURN:
if (self.selected_result !== null) {
self.activate_selected($options);
return false;
}
break;
}
}).keyup(function(e){
if (e.keyCode > SPECIALS_END || e.keyCode == BACKSPACE) {
self.clearTimeout();
self.search($e, $options);
};
});
});
};
$.fn.suggest_results.box = null;
$.fn.suggest_results.list = null;
$.fn.suggest_results.attached_to = null;
$.fn.suggest_results.current_results = [];
$.fn.suggest_results.selected_result = null;
$.fn.suggest_results.timeout = null;
$.fn.suggest_results.query_cache = [];
$.fn.suggest_results.init = function(options){
var self = $.fn.suggest_results;
self.box = $("#" + options.tpl_container_id);
if (self.box.length == 0) {
$("body").append(self.mustache(options.tpl_container, {id: options.tpl_container_id}));
self.box = $("#" + options.tpl_container_id);
self.list = self.box.children("ol");
};
};
$.fn.suggest_results.search = function(elm, options){
var self = $.fn.suggest_results;
var terms = (options.exact_match) ? $.trim(elm.val()) : $.trim(elm.val()).split(/\s+/);
if (typeof(options.url) === "string" && options.url !== "") {
self.query_for_data(elm, options);
} else {
self.current_results = self.filter_data(terms, options.data, options);
self.prerender(elm, self.current_results, options);
};
};
$.fn.suggest_results.clear = function(elm, options){
var self = $.fn.suggest_results;
elm.val("");
self.hide(0);
self.selected_result = null;
};
$.fn.suggest_results.no_results = function(elm, options){
var self = $.fn.suggest_results;
if (options.no_results && elm.val() !== "") {
var meta = {label: options.no_results_label, "class": "last"};
self.list.html(self.mustache(options.tpl_label, meta));
self.show();
} else {
self.hide(0);
};
};
$.fn.suggest_results.prerender = function(elm, results, options){
var self = $.fn.suggest_results;
if (results.length > 0) {
self.render(results, options);
self.show();
} else {
self.no_results(elm, options);
};
};
$.fn.suggest_results.render = function(results, options){
var self = $.fn.suggest_results;
var results_length = results.length;
var html = "";
for (var i=0; i < results_length; i++) {
var meta = $.extend({}, results[i], {id: "suggested_result_" + i, "class": ""});
if (i == 0) { $.extend(meta, {"class": "first"}); };
if (i == results_length - 1) { $.extend(meta, {"class": "last"}); };
html += self.mustache(options.tpl_result_begin, meta);
html += self.mustache(options.tpl_result_body, meta);
html += self.mustache(options.tpl_result_end, meta);
};
self.list.html(html);
$(".result", self.list).click(function(){
window.redirect_to($("a", $(this)).attr("href"));
}).hover(function(){
$(".selected", self.list).removeClass("selected");
$(this).addClass("selected");
},function(){
$(this).removeClass("selected");
});
};
$.fn.suggest_results.attach = function(elm, options){
var self = $.fn.suggest_results;
var elm_uid = self.elm_uid(elm);
if (elm_uid !== self.attached_to) {
self.box.hide().attr("class", options.name);
var offset = elm.offset();
// left offset
self.box.css("left", (offset.left + options.pos_left));
// top offset
var top = offset.top + elm.innerHeight();
top += parseInt(elm.css("border-top-width"), 10) + parseInt(elm.css("border-bottom-width"), 10);
top += options.pos_top;
self.box.css("top", top);
// width
if (typeof(options.width) === "number" || (typeof(options.width) === "string" && options.width != "")) {
self.box.css("width", options.width);
} else {
var width = elm.innerWidth();
width += parseInt(elm.css("border-left-width"), 10) + parseInt(elm.css("border-right-width"), 10);
width -= parseInt(self.box.css("border-left-width"), 10) + parseInt(self.box.css("border-right-width"), 10);
self.box.css("width", width);
};
self.attached_to = elm_uid;
};
};
$.fn.suggest_results.show = function(){
$.fn.suggest_results.box.show();
};
$.fn.suggest_results.hide = function(delay){
var self = $.fn.suggest_results;
if (typeof(delay) !== "number") { delay = 250; };
self.selected_result = null;
self.setTimeout(function(){
self.selected_result = null;
self.box.hide();
}, delay);
};
$.fn.suggest_results.select_next = function(elm, options){
var self = $.fn.suggest_results;
var limit = self.current_results.length;
if (limit > 0) {
if (self.selected_result === null) {
$(".selected", self.list).removeClass("selected");
self.selected_result = 0;
$("#suggested_result_" + self.selected_result, self.box).addClass("selected");
} else if (self.selected_result + 1 < limit) {
$(".selected", self.list).removeClass("selected");
self.selected_result++;
$("#suggested_result_" + self.selected_result, self.box).addClass("selected");
} else {
$(".selected", self.list).removeClass("selected");
self.selected_result = null;
elm.putCursorAtEnd();
};
};
return false;
};
$.fn.suggest_results.select_prev = function(elm, options){
var self = $.fn.suggest_results;
var limit = self.current_results.length;
if (limit > 0) {
if (self.selected_result === null) {
$(".selected", self.list).removeClass("selected");
self.selected_result = limit - 1;
$("#suggested_result_" + self.selected_result, self.box).addClass("selected");
} else if (self.selected_result > 0) {
$(".selected", self.list).removeClass("selected");
self.selected_result--;
$("#suggested_result_" + self.selected_result, self.box).addClass("selected");
} else {
$(".selected", self.list).removeClass("selected");
self.selected_result = null;
elm.putCursorAtEnd();
};
};
return false;
};
$.fn.suggest_results.activate_selected = function(options){
var self = $.fn.suggest_results;
if (self.selected_result !== null) {
window.redirect_to(self.current_results[self.selected_result].href);
};
};
$.fn.suggest_results.filter_data = function(terms, data, options){
if (typeof(terms) === "string") { terms = [terms]; };
var matched = "";
var results = [];
var terms_length = terms.length;
for (var i=0; i < terms_length; i++) {
var term = terms[i];
term = term.toLowerCase();
if (data !== null && typeof(term) !== "undefined" && term !== "") {
var data_length = data.length;
for (var n=0; n < data_length; n++) {
var title = data[n].title.toLowerCase();
var match = (typeof(data[n].match) !== "undefined") ? data[n].match.toLowerCase() : "" ;
if (title.indexOf(term) !== -1 || match.indexOf(term) !== -1) {
if (matched.indexOf(":" + n + ":") == -1) {
results.push(data[n]);
matched += ":" + n + ":";
if (results.length >= options.limit) {
return results;
};
};
};
};
};
};
return results;
};
$.fn.suggest_results.query_for_data = function(elm, options){
var self = $.fn.suggest_results;
var term = elm.val();
var uid = options.url + "?" + term + ":" + options.limit;
if (term !== "") {
if (self.query_cache.hasOwnProperty(uid)) {
self.current_results = self.query_cache[uid];
self.prerender(elm, self.current_results, options);
} else {
var data = { limit: options.limit };
data[options.url_query_var] = term;
$.ajax({
type: options.url_method,
url: options.url,
data: data,
dataType: "json",
success: function(response){
self.current_results = response.results;
self.query_cache[uid] = self.current_results;
self.prerender(elm, self.current_results, options);
}
});
};
} else {
self.no_results(elm, options);
};
};
$.fn.suggest_results.elm_uid = function(elm){
if (elm.attr("id") !== "") {
return "#" + elm.attr("id");
} else if (elm.attr("class") !== "") {
return "." + elm.attr("class");
} else if (elm.attr("name") !== "") {
return "!" + elm.attr("name");
};
return "";
};
$.fn.suggest_results.mustache = function(string, data){
if (typeof(string) === "string" && typeof(data) === "object") {
for (var key in data) {
string = string.replace(new RegExp("{{\\s*" + key + "\\s*}}", "g"), data[key]);
}
};
return string;
};
$.fn.suggest_results.setTimeout = function(callback, delay){
var self = $.fn.suggest_results;
self.clearTimeout();
self.timeout = setTimeout(callback, delay);
};
$.fn.suggest_results.clearTimeout = function(){
var self = $.fn.suggest_results;
if (self.timeout !== null) {
clearTimeout(self.timeout);
self.timeout = null;
};
};
// "borrowed" from PutCursorAtEnd plugin: http://plugins.jquery.com/project/PutCursorAtEnd
$.fn.putCursorAtEnd = function(){
return this.each(function(){
$(this).focus();
if (this.setSelectionRange) {
var len = $(this).val().length * 2;
this.setSelectionRange(len, len);
} else {
$(this).val($(this).val());
}
this.scrollTop = 999999;
});
};
$.fn.suggest_results.defaults = {
name: "",
exact_match: true,
limit: 6,
no_results: true,
no_results_label: "No Results",
url: null,
url_method: "get",
url_query_var: "search",
pos_top: 0,
pos_left: 0,
delay: 100,
data: null,
tpl_container_id: "suggest_results",
tpl_container: '<div id="{{id}}"><ol></ol></div>',
tpl_result_begin: '<li class="result {{class}}" id="{{id}}"><a href="{{href}}">',
tpl_result_body: '<span class="title">{{title}}</span>',
tpl_result_end: '</a></li>',
tpl_label: '<li class="label {{class}}">{{label}}</li>'
};
})(jQuery);
/*
redirect_to method from: http://gist.github.com/327227
*/
window.redirect_to = function(url, location){
var redirect_to = "";
if (typeof(location) == "undefined") location = window.location;
if (url.match(/^[a-zA-Z]+\:\/\/.+/) === null) {
redirect_to += location.protocol + "//" + location.hostname;
if (location.port != "") redirect_to += ":" + location.port;
if (url.charAt(0) !== "/") redirect_to += location.pathname.substr(0, location.pathname.lastIndexOf("/")+1);
window.location.href = redirect_to + url;
} else {
window.location.href = url;
};
};
/*
Crossbrowser hasOwnProperty solution, based on answers from:
http://stackoverflow.com/questions/135448/how-do-i-check-to-see-if-an-object-has-an-attribute-in-javascript
*/
if ( !Object.prototype.hasOwnProperty ) {
Object.prototype.hasOwnProperty = function(prop) {
var proto = obj.__proto__ || obj.constructor.prototype;
return (prop in this) && (!(prop in proto) || proto[prop] !== this[prop]);
};
}