{"id":2860,"date":"2013-03-07T20:43:44","date_gmt":"2013-03-08T02:43:44","guid":{"rendered":"http:\/\/bililite.com\/blog\/?p=2860"},"modified":"2013-12-11T17:47:24","modified_gmt":"2013-12-11T23:47:24","slug":"new-jquery-plugin-livesearch","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2013\/03\/07\/new-jquery-plugin-livesearch\/","title":{"rendered":"New jQuery plugin, <code>livesearch<\/code>"},"content":{"rendered":"<p><strong>Edited 2013-12-11 to use focusout rather than blur event<\/strong><\/p>\r\n<p>Continuing <a href=\"\/blog\/2013\/02\/22\/parsing-keydown-events\/\">my adventures<\/a> in developing an online editor, I wanted to be able to do \"live\" searching: having the text scroll to the sought string as it is being typed. I can use <a href=\"http:\/\/bililite.com\/blog\/2013\/02\/08\/bililiterange-plugins\/\" title=\"bililiteRange Plugins\">my <code>bililiteRange<\/code> utilities<\/a> to find an arbitrary regular expression, but after much hair-pulling, realized that <a href=\"http:\/\/bililite.com\/blog\/2013\/03\/01\/highlighting-textareas\/\" title=\"Highlighting textareas\">my <code>texthighlight<\/code> plugin<\/a> is just too flaky and hack-dependent to be used reliably. So I went a different route: instead of trying to highlight strings in a <code class=\"language-html\" >&lt;textarea&gt;<\/code>, I overlay a <code class=\"language-html\" >&lt;pre&gt;<\/code> element desinged to look similar enough to the <code class=\"language-html\" >&lt;textarea&gt;<\/code> and highlight the string in <em>that<\/em> with normal HTML. When the user is done typing his search string (signaled by a <code class=\"language-javascript\" >blur<\/code> event on the <code class=\"language-html\" >&lt;input&gt;<\/code> element being typed in), remove the  <code class=\"language-html\" >&lt;pre&gt;<\/code> and select the desired string in the original <code class=\"language-html\" >&lt;textarea&gt;<\/code>. There's a jump but not as bad as with <code>texthighlight<\/code>.<\/p>\r\n<p><a href=\/inc\/jquery.livesearch.js >Download the code<\/a>.<\/p>\r\n<p>See <a href=\"\/blog\/blogfiles\/vi\/livesearch.html\">a simple demo<\/a>, <a href=\"\/blog\/blogfiles\/vi\/livesearch2.html\">a demo that uses the parameters<\/a>, and <a href=\"\/blog\/blogfiles\/vi\/livesearch3.html\">a demo that searches three elements at once<\/a>.<\/p>\r\n<!--more-->\r\n<h4>Usage<\/h4>\r\n<p><code class=\"language-javascript\" >$('textarea').livesearch()<\/code> returns a function (<em>not<\/em> a jQuery object!) that is intended to be an event handler for the <code class=\"language-javascript\" >input<\/code>, <code class=\"language-javascript\" >focus<\/code> and <code class=\"language-javascript\" >focusout<\/code> events (use <code class=\"language-javascript\" >focusout<\/code> rather than <code class=\"language-javascript\" >blur<\/code> since <code class=\"language-javascript\" >focusout<\/code> allows for bubbling and jQuery delegation). Since Internet Explorer &lt; 9 does not trigger <code class=\"language-javascript\" >input<\/code>, it can be used with <code class=\"language-javascript\" >keyup<\/code> events as well. Thus:<\/p>\r\n<pre><code class=\"language-html\" >&lt;textarea&gt;\r\n&lt;input&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript\" >$('input').on('input focus focusout', $('textarea').livesearch(back, filter))<\/code><\/pre>\r\n<p>As you type in the <code class=\"language-html\" >&lt;input&gt;<\/code> element, its value is passed to <code class=\"language-javascript\" >new RegExp(input.value)<\/code> and that is sought in the <code class=\"language-html\" >&lt;textarea&gt;<\/code>'s text, starting from the current selection. The search display is scrolled to keep the found string in view. If nothing is found or the regular expression is invalid, the original selection is highlighted.<\/p>\r\n<h4>Parameters<\/h4>\r\n<dl>\r\n<dt><code>back {Boolean}<\/code><\/dt><dd>Set to <code class=\"language-javascript\" >true<\/code> to search backwards.<\/dd>\r\n<dt><code>filter {Function}<\/code><\/dt><dd>Function to return the regular expression used for the search. For instance, to search only for whole words, use <code class=\"language-javascript\" >filter = function(string){ return new RegExp ('\\\\b'+string.replace(\/\\w\/g, '')+'\\\\b') }<\/code>. Default: <code class=\"language-javascript\" >function(string) { try { return new RegExp(string); }catch(e){ return \/(?:)\/ } }<\/code>. The <code>try\/catch<\/code> is important since the input string may not represent a valid regular expression.<\/dd>\r\n<\/dl>\r\n<h4>Styling<\/h4>\r\n<p>The display of the search process has the following structure:<\/p>\r\n<pre><code class=\"language-html\" >&lt;pre class=livesearch&gt;\r\nSome text\r\n&lt;span&gt;Search term&lt;\/span&gt;\r\nSome more text\r\n&lt;\/pre&gt;<\/code><\/pre>\r\n<p>At the least, the <code class=\"language-html\" >&lt;pre&gt;<\/code> element needs an opaque background (otherwise the underlying element will show through) and the <code class=\"language-html\" >&lt;span&gt;<\/code> needs some kind of highlighting so it is distinct from the surrounding text, taking into account the fact that the found string may have zero length (i.e. do something more than <code class=\"language-css\" >text-decoration:underline<\/code>). In the demo I used:<\/p>\r\n<pre><code class=\"language-css\" >pre.livesearch{\r\n  background: white;\r\n  border: 1px solid black;\r\n}\r\npre.livesearch span {\r\n  border: 1px solid #f0f; \/* will show up even if the string is zero length *\/\r\n  background: #f0f; \/* in demo number 3 *\/\r\n}<\/code><\/pre>\r\n<h4>Events<\/h4>\r\n<p>Triggers a \"<code>livesearch<\/code>\" event with each input on the <em><code class=\"language-html\" >&lt;textarea&gt;<\/code><\/em> element, with two parameters: the string used to create the regular expression and the result of the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/JavaScript\/Reference\/Global_Objects\/RegExp\/exec\"><code>exec<\/code><\/a> call. Thus<\/p>\r\n<pre><code class=\"language-javascript\" >$('input').on('input focus blur', $('textarea').livesearch());\r\n$('textarea').on('livesearch', function (event, searchstring, result){\r\n  if (result){\r\n    alert(result[0]+' found at position '+result.index);\r\n  }else{\r\n    alert(searchstring+' not Found!');\r\n  }\r\n});<\/code><\/pre>\r\n<p>Would be a highly annoying way to provide feedback with each keystroke.<\/p>\r\n<p>When the searching is done (the <code class=\"language-html\" >&lt;input&gt;<\/code> element loses focus), triggers a \"<code>livesearchdone<\/code>\" event with the same parameter.<\/p>","protected":false},"excerpt":{"rendered":"Edited 2013-12-11 to use focusout rather than blur event Continuing my adventures in developing an online editor, I wanted to be able to do \"live\" searching: having the text scroll to the sought string as it is being typed. I can use my bililiteRange utilities to find an arbitrary regular expression, but after much hair-pulling, [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2860"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=2860"}],"version-history":[{"count":15,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2860\/revisions"}],"predecessor-version":[{"id":3036,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2860\/revisions\/3036"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=2860"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=2860"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=2860"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}