From 933cbc8ab92f7add44177d00904b75b3549b76ef Mon Sep 17 00:00:00 2001 From: Jim Myhrberg Date: Wed, 10 Mar 2010 17:25:12 +0200 Subject: [PATCH] things all work, about time for public release --- demo/demo.css | 21 +++ demo/demo.html | 60 -------- demo/demo.js | 102 +++++++++++++ demo/demo.json | 11 -- demo/index.html | 71 +++++++++ demo/server-side.php | 135 ++++++++++++++++ suggest_results/jquery.suggest_results.css | 65 +++++--- suggest_results/jquery.suggest_results.js | 169 +++++++++++++++------ 8 files changed, 494 insertions(+), 140 deletions(-) delete mode 100644 demo/demo.html create mode 100644 demo/demo.js delete mode 100644 demo/demo.json create mode 100644 demo/index.html create mode 100644 demo/server-side.php diff --git a/demo/demo.css b/demo/demo.css index 03c0cd6..5efc209 100644 --- a/demo/demo.css +++ b/demo/demo.css @@ -4,11 +4,32 @@ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abb /* @end */ +body { + background: #fff; + font: 12px/1.5 'Helvetica Neue', Arial, 'Liberation Sans', FreeSans, sans-serif; +} + +p, dl, hr, h1, h2, h3, h4, h5, h6, ol, +ul, pre, table, address, fieldset { + margin-bottom: 20px; +} + +h1 { font-size: 25px; } +h2 { font-size: 23px; } +h3 { font-size: 21px; } +h4 { font-size: 19px; } +h5 { font-size: 17px; } +h6 { font-size: 13px; } + input { border: 1px solid #999; + width: 200px; + padding: 3px 3px; + font-size: 12px; } #container { width: 960px; margin: 0px auto; + text-align: center; } \ No newline at end of file diff --git a/demo/demo.html b/demo/demo.html deleted file mode 100644 index f79bbc8..0000000 --- a/demo/demo.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - examples - - - - - - - - - - - - - - -
- -
-
- - -
-
- - -
-
- - -
- - - diff --git a/demo/demo.js b/demo/demo.js new file mode 100644 index 0000000..de57dea --- /dev/null +++ b/demo/demo.js @@ -0,0 +1,102 @@ +var data = [ + {"title": "Ädams, Egbert", "info": "Bedfordshire", "href": "/demo/user/1"}, + {"title": "Altman, Alisha", "info": "Buckinghamshire", "href": "/demo/user/2"}, + {"title": "Archibald, Janna", "info": "Cambridgeshire", "href": "/demo/user/3"}, + {"title": "Auman, Cody", "info": "Cheshire", "href": "/demo/user/4"}, + {"title": "Bagley, Sheree", "info": "Cornwall", "href": "/demo/user/5"}, + {"title": "Ballou, Wilmot", "info": "Cumbria", "href": "/demo/user/6"}, + {"title": "Bard, Cassian", "info": "Derbyshire", "href": "/demo/user/1"}, + {"title": "Bash, Latanya", "info": "Devon", "href": "/demo/user/2"}, + {"title": "Beail, May", "info": "Dorset", "href": "/demo/user/3"}, + {"title": "Black, Lux", "info": "Durham", "href": "/demo/user/4"}, + {"title": "Bloise, India", "info": "East Sussex", "href": "/demo/user/5"}, + {"title": "Blyant, Nora", "info": "Essex", "href": "/demo/user/6"}, + {"title": "Bollinger, Carter", "info": "Gloucestershire", "href": "/demo/user/1"}, + {"title": "Burns, Jaycob", "info": "Hampshire", "href": "/demo/user/2"}, + {"title": "Carden, Preston", "info": "Hertfordshire", "href": "/demo/user/3"}, + {"title": "Carter, Merrilyn", "info": "Kent", "href": "/demo/user/4"}, + {"title": "Christner, Addie", "info": "Lancashire", "href": "/demo/user/5"}, + {"title": "Churchill, Mirabelle", "info": "Leicestershire", "href": "/demo/user/6"}, + {"title": "Conkle, Erin", "info": "Lincolnshire", "href": "/demo/user/1"}, + {"title": "Countryman, Abner", "info": "Norfolk", "href": "/demo/user/2"}, + {"title": "Courtney, Edgar", "info": "Northamptonshire", "href": "/demo/user/3"}, + {"title": "Cowher, Antony", "info": "Northumberland", "href": "/demo/user/4"}, + {"title": "Craig, Charlie", "info": "North Yorkshire", "href": "/demo/user/5"}, + {"title": "Cram, Zacharias", "info": "Nottinghamshire", "href": "/demo/user/6"}, + {"title": "Cressman, Ted", "info": "Oxfordshire", "href": "/demo/user/1"}, + {"title": "Crissman, Annie", "info": "Shropshire", "href": "/demo/user/2"}, + {"title": "Davis, Palmer", "info": "Somerset", "href": "/demo/user/3"}, + {"title": "Downing, Casimir", "info": "Staffordshire", "href": "/demo/user/4"}, + {"title": "Earl, Missie", "info": "Suffolk", "href": "/demo/user/5"}, + {"title": "Eckert, Janele", "info": "Surrey", "href": "/demo/user/6"}, + {"title": "Eisenman, Briar", "info": "Warwickshire", "href": "/demo/user/1"}, + {"title": "Fitzgerald, Love", "info": "West Sussex", "href": "/demo/user/2"}, + {"title": "Fleming, Sidney", "info": "Wiltshire", "href": "/demo/user/3"}, + {"title": "Fuchs, Bridger", "info": "Worcestershire", "href": "/demo/user/4"}, + {"title": "Fulton, Rosalynne", "info": "Durham", "href": "/demo/user/5"}, + {"title": "Fye, Webster", "info": "East Sussex", "href": "/demo/user/6"}, + {"title": "Geyer, Rylan", "info": "Essex", "href": "/demo/user/1"}, + {"title": "Greene, Charis", "info": "Gloucestershire", "href": "/demo/user/2"}, + {"title": "Greif, Jem", "info": "Hampshire", "href": "/demo/user/3"}, + {"title": "Guest, Sarahjeanne", "info": "Hertfordshire", "href": "/demo/user/4"}, + {"title": "Harper, Phyllida", "info": "Kent", "href": "/demo/user/5"}, + {"title": "Hildyard, Erskine", "info": "Lancashire", "href": "/demo/user/6"}, + {"title": "Hoenshell, Eulalia", "info": "Leicestershire", "href": "/demo/user/1"}, + {"title": "Isaman, Lalo", "info": "Lincolnshire", "href": "/demo/user/2"}, + {"title": "James, Diamond", "info": "Norfolk", "href": "/demo/user/3"}, + {"title": "Jenkins, Merrill", "info": "Northamptonshire", "href": "/demo/user/4"}, + {"title": "Jube, Bennett", "info": "Northumberland", "href": "/demo/user/5"}, + {"title": "Kava, Marianne", "info": "North Yorkshire", "href": "/demo/user/6"}, + {"title": "Kern, Linda", "info": "Nottinghamshire", "href": "/demo/user/1"}, + {"title": "Klockman, Jenifer", "info": "Oxfordshire", "href": "/demo/user/2"}, + {"title": "Lacon, Quincy", "info": "Shropshire", "href": "/demo/user/3"}, + {"title": "Laurenzi, Leland", "info": "Somerset", "href": "/demo/user/4"}, + {"title": "Leichter, Jeane", "info": "Staffordshire", "href": "/demo/user/5"}, + {"title": "Leslie, Kerrie", "info": "Suffolk", "href": "/demo/user/6"}, + {"title": "Lester, Noah", "info": "Surrey", "href": "/demo/user/1"}, + {"title": "Llora, Roxana", "info": "Warwickshire", "href": "/demo/user/2"}, + {"title": "Lombardi, Polly", "info": "West Sussex", "href": "/demo/user/3"}, + {"title": "Lowstetter, Louisa", "info": "Wiltshire", "href": "/demo/user/4"}, + {"title": "Mays, Emery", "info": "Worcestershire", "href": "/demo/user/5"}, + {"title": "Mccullough, Bernadine", "info": "Durham", "href": "/demo/user/6"}, + {"title": "Mckinnon, Kristie", "info": "East Sussex", "href": "/demo/user/1"}, + {"title": "Meyers, Hector", "info": "Essex", "href": "/demo/user/2"}, + {"title": "Monahan, Penelope", "info": "Gloucestershire", "href": "/demo/user/3"}, + {"title": "Mull, Kaelea", "info": "Hampshire", "href": "/demo/user/4"}, + {"title": "Newbiggin, Osmond", "info": "Hertfordshire", "href": "/demo/user/5"}, + {"title": "Nickolson, Alfreda", "info": "Kent", "href": "/demo/user/6"}, + {"title": "Pawle, Jacki", "info": "Lancashire", "href": "/demo/user/1"}, + {"title": "Paynter, Nerissa", "info": "Leicestershire", "href": "/demo/user/2"}, + {"title": "Pinney, Wilkie", "info": "Lincolnshire", "href": "/demo/user/3"}, + {"title": "Pratt, Ricky", "info": "Norfolk", "href": "/demo/user/4"}, + {"title": "Putnam, Stephanie", "info": "Northamptonshire", "href": "/demo/user/5"}, + {"title": "Ream, Terrence", "info": "Northumberland", "href": "/demo/user/6"}, + {"title": "Rumbaugh, Noelle", "info": "North Yorkshire", "href": "/demo/user/1"}, + {"title": "Ryals, Titania", "info": "Nottinghamshire", "href": "/demo/user/2"}, + {"title": "Saylor, Lenora", "info": "Oxfordshire", "href": "/demo/user/3"}, + {"title": "Schofield, Denice", "info": "Shropshire", "href": "/demo/user/4"}, + {"title": "Schuck, John", "info": "Somerset", "href": "/demo/user/5"}, + {"title": "Scott, Clover", "info": "Staffordshire", "href": "/demo/user/6"}, + {"title": "Smith, Estella", "info": "Suffolk", "href": "/demo/user/1"}, + {"title": "Smothers, Matthew", "info": "Surrey", "href": "/demo/user/2"}, + {"title": "Stainforth, Maurene", "info": "Warwickshire", "href": "/demo/user/3"}, + {"title": "Stephenson, Phillipa", "info": "West Sussex", "href": "/demo/user/4"}, + {"title": "Stewart, Hyram", "info": "Wiltshire", "href": "/demo/user/5"}, + {"title": "Stough, Gussie", "info": "Worcestershire", "href": "/demo/user/6"}, + {"title": "Strickland, Temple", "info": "Durham", "href": "/demo/user/1"}, + {"title": "Sullivan, Gertie", "info": "East Sussex", "href": "/demo/user/2"}, + {"title": "Swink, Stefanie", "info": "Essex", "href": "/demo/user/3"}, + {"title": "Tavoularis, Terance", "info": "Gloucestershire", "href": "/demo/user/4"}, + {"title": "Taylor, Kizzy", "info": "Hampshire", "href": "/demo/user/5"}, + {"title": "Thigpen, Alwyn", "info": "Hertfordshire", "href": "/demo/user/6"}, + {"title": "Treeby, Jim", "info": "Kent", "href": "/demo/user/1"}, + {"title": "Trevithick, Jayme", "info": "Lancashire", "href": "/demo/user/2"}, + {"title": "Waldron, Ashley", "info": "Leicestershire", "href": "/demo/user/3"}, + {"title": "Wheeler, Bysshe", "info": "Lincolnshire", "href": "/demo/user/4"}, + {"title": "Whishaw, Dodie", "info": "Norfolk", "href": "/demo/user/5"}, + {"title": "Whitehead, Jericho", "info": "Northamptonshire", "href": "/demo/user/6"}, + {"title": "Wilks, Debby", "info": "Northumberland", "href": "/demo/user/1"}, + {"title": "Wire, Tallulah", "info": "North Yorkshire", "href": "/demo/user/2"}, + {"title": "Woodworth, Alexandria", "info": "Nottinghamshire", "href": "/demo/user/3"}, + {"title": "Zaun, Jillie", "info": "", "href": ""} +]; \ No newline at end of file diff --git a/demo/demo.json b/demo/demo.json deleted file mode 100644 index 44576b5..0000000 --- a/demo/demo.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - {title: "head", href: "/head", match: "head zzz"}, - {title: "headache", href: "/headache", match: "headache zzz"}, - {title: "health", href: "/health", match: "health zzz"}, - {title: "healthcare", href: "/healthcare", match: "healthcare zzz"}, - {title: "healthier", href: "/healthier", match: "healthier zzz"}, - {title: "heck", href: "/heck", match: "heck zzz"}, - {title: "hectic", href: "/hectic", match: "hectic zzz"}, - {title: "held", href: "/held", match: "held zzz"}, - {title: "hell", href: "/hell", match: "hell zzz"}, -]; \ No newline at end of file diff --git a/demo/index.html b/demo/index.html new file mode 100644 index 0000000..2836de1 --- /dev/null +++ b/demo/index.html @@ -0,0 +1,71 @@ + + + + + + + Suggest Results Demo + + + + + + + + + + + + + + + + + +
+

+

Suggest Results Demo

+

+ Results from local array:
+ +

+

+ Results from ajax call:
+ +

+

+ Customized results from ajax call:
+ +

+
+ + + diff --git a/demo/server-side.php b/demo/server-side.php new file mode 100644 index 0000000..ea0fde1 --- /dev/null +++ b/demo/server-side.php @@ -0,0 +1,135 @@ +($i+1), + "title"=>htmlspecialchars($aUsers[$i]), + "info"=>htmlspecialchars($aInfo[$i]), + "href"=>$aImg[$i], + ); + } + + if ($limit && $count==$limit) + break; + } + } + + header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past + header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified + header ("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1 + header ("Pragma: no-cache"); // HTTP/1.0 + + header("Content-Type: application/json"); + + echo "{\"results\": [\n\t"; + $arr = array(); + for ($i=0;$i \ No newline at end of file diff --git a/suggest_results/jquery.suggest_results.css b/suggest_results/jquery.suggest_results.css index 5e57070..e6dc6ed 100644 --- a/suggest_results/jquery.suggest_results.css +++ b/suggest_results/jquery.suggest_results.css @@ -1,33 +1,48 @@ #suggest_results { - background: #fbfbfb; - border: 1px solid #ccc; - border-top: none; + border-bottom: 1px solid #efefef; display: none; position: absolute; z-index: 1000; +} + +#suggest_results ol { + background: #fbfbfb; + border: 1px solid #bbb; + border-top: none; margin: 0px; padding: 0px; + list-style: none; } - #suggest_results li { - margin: 0px; - border-bottom: 1px solid #ddd; - } - #suggest_results li.first { - - } - #suggest_results li.last { - border-bottom: none; - } - #suggest_results li.result { - display: block; - } - #suggest_results li.result a { - display: block; - padding: 3px 5px; - } - #suggest_results li.result a:hover, - #suggest_results li.result.selected a { - background: #698DE5; - color: #fff; - } \ No newline at end of file + +#suggest_results li { + margin: 0px; + border-bottom: 1px solid #ddd; +} + +#suggest_results li.result { + display: block; +} + +#suggest_results li.first { + +} + +#suggest_results li.last { + border-bottom: none; +} + +#suggest_results li.result a { + display: block; + padding: 3px 5px; + text-decoration: none; +} +#suggest_results li.result a span { + display: block; +} + +#suggest_results li.result a:hover, +#suggest_results li.result.selected a { + background: #698DE5; + color: #fff; +} \ No newline at end of file diff --git a/suggest_results/jquery.suggest_results.js b/suggest_results/jquery.suggest_results.js index 561f188..5d0414e 100644 --- a/suggest_results/jquery.suggest_results.js +++ b/suggest_results/jquery.suggest_results.js @@ -5,10 +5,17 @@ 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); + self.attach($e, $options); if ($e.val().length > 0) { self.search_timeout = self.setTimeout(function(){ self.search($e, $options); @@ -17,59 +24,75 @@ }).blur(function(){ self.hide(); }).keydown(function(e){ - var RETURN = 13; - var ESC = 27; - var ARRUP = 38; - var ARRDN = 40; 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: self.activate_selected($options); return false; - default: - self.clearTimeout(); - self.search($e, $options); + default: self.clearTimeout(); self.search($e, $options); } + }).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.template.container_id); + self.box = $("#" + options.tpl_container_id); if (self.box.length == 0) { - $("body").append(self.mustache(options.template.container, {id: options.template.container_id})); - self.box = $("#" + options.template.container_id); + $("body").append(self.mustache(options.tpl_container, {id: options.tpl_container_id})); + self.box = $("#" + options.tpl_container_id); + self.list = $("ol", self.box); }; }; $.fn.suggest_results.search = function(elm, options){ var self = $.fn.suggest_results; - var terms = (options.exact_match) ? $.trim(elm.val()) : elm.val().split(/\s/); + var terms = (options.exactMatch) ? $.trim(elm.val()) : elm.val().split(/\s/); if (typeof(options.url) === "string" && options.url !== "") { - //TODO support fetching results from server-side + self.query_for_data(elm, options); } else { - var results = self.filter_data(terms, options.data, options); - }; - self.current_results = results; - if (results.length > 0) { - self.render(results, options); - self.show(); - } else { - self.hide(); + self.current_results = self.filter_data(terms, options.data, options); + self.prerender(self.current_results, options); }; }; $.fn.suggest_results.clear = function(elm, options){ var self = $.fn.suggest_results; elm.val(""); - self.hide(); + self.hide(0); + self.selected_result = null; + }; + + $.fn.suggest_results.no_results = function(options){ + var self = $.fn.suggest_results; + if (options.empty) { + //TODO display "No Results" label. + } else { + self.hide(0); + }; + }; + + $.fn.suggest_results.prerender = function(results, options){ + var self = $.fn.suggest_results; + if (results.length > 0) { + self.render(results, options); + self.show(); + } else { + self.no_results(options); + }; }; $.fn.suggest_results.render = function(results, options){ @@ -77,14 +100,16 @@ var results_length = results.length; var html = ""; for (var i=0; i < results_length; i++) { - var meta = {id: "suggested_result_" + i, "class": ""}; + 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.template.result, $.extend({}, meta, results[i])); + 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.box.html(""); - self.box.append(html); - $(".result", self.box).click(function(){ + self.list.html(""); + self.list.append(html); + $(".result", self.list).click(function(){ self.redirect_to($("a", $(this)).attr("href")); }); }; @@ -93,6 +118,7 @@ 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 @@ -112,7 +138,6 @@ width -= parseInt(self.box.css("border-left-width"), 10) + parseInt(self.box.css("border-right-width"), 10); self.box.css("width", width + "px"); }; - self.attached_to = elm_uid; }; }; @@ -121,12 +146,14 @@ $.fn.suggest_results.box.show(); }; - $.fn.suggest_results.hide = function(){ + $.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(); - }, 500); + }, delay); }; $.fn.suggest_results.select_next = function(elm, options){ @@ -140,6 +167,10 @@ $(".selected", self.box).removeClass("selected"); self.selected_result++; $("#suggested_result_" + self.selected_result, self.box).addClass("selected"); + } else { + $(".selected", self.box).removeClass("selected"); + self.selected_result = null; + elm.putCursorAtEnd(); }; }; return false; @@ -199,12 +230,44 @@ 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(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(self.current_results, options); + } + }); + }; + } else { + self.no_results(options); + }; + return []; + }; + $.fn.suggest_results.elm_uid = function(elm){ - var uid = ""; - if ( elm.attr("id") !== "" ) { uid += "#" + elm.attr("id"); }; - if ( elm.attr("class") !== "" ) { uid += "." + elm.attr("class"); }; - if ( elm.attr("name") !== "" ) { uid += "[" + elm.attr("name") + "]"; }; - return uid; + 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){ @@ -263,16 +326,34 @@ }; $.fn.suggest_results.defaults = { - delay: 150, + url: null, + url_query_var: "search", + url_method: "get", + empty: false, + empty_label: "No Results", + name: "", + delay: 100, limit: 6, data: null, - exact_match: true, - template: { - container_id: "suggest_results", - container: '
    ', - result: '
  1. {{title}}
  2. ', - category: '{{category}}' //TODO add support for categories - } + exactMatch: true, + tpl_container_id: "suggest_results", + tpl_container: '
      ', + tpl_result_begin: '
    1. ', + tpl_result_body: '{{title}}', + tpl_result_end: '
    2. ', + tpl_label: '
    3. ' //TODO add support for labels/categories }; -})(jQuery); \ No newline at end of file +})(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]); + }; +} \ No newline at end of file