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, realized that my texthighlight plugin 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 <textarea>, I overlay a <pre> element desinged to look similar enough to the <textarea> and highlight the string in that with normal HTML. When the user is done typing his search string (signaled by a blur event on the <input> element being typed in), remove the <pre> and select the desired string in the original <textarea>. There's a jump but not as bad as with texthighlight.

Download the code.

See a simple demo, a demo that uses the parameters, and a demo that searches three elements at once.

Usage

$('textarea').livesearch() returns a function (not a jQuery object!) that is intended to be an event handler for the input, focus and focusout events (use focusout rather than blur since focusout allows for bubbling and jQuery delegation). Since Internet Explorer < 9 does not trigger input, it can be used with keyup events as well. Thus:

<textarea>
<input>
$('input').on('input focus focusout', $('textarea').livesearch(back, filter))

As you type in the <input> element, its value is passed to new RegExp(input.value) and that is sought in the <textarea>'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.

Parameters

back {Boolean}
Set to true to search backwards.
filter {Function}
Function to return the regular expression used for the search. For instance, to search only for whole words, use filter = function(string){ return new RegExp ('\\b'+string.replace(/\w/g, '')+'\\b') }. Default: function(string) { try { return new RegExp(string); }catch(e){ return /(?:)/ } }. The try/catch is important since the input string may not represent a valid regular expression.

Styling

The display of the search process has the following structure:

<pre class=livesearch>
Some text
<span>Search term</span>
Some more text
</pre>

At the least, the <pre> element needs an opaque background (otherwise the underlying element will show through) and the <span> 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 text-decoration:underline). In the demo I used:

pre.livesearch{
  background: white;
  border: 1px solid black;
}
pre.livesearch span {
  border: 1px solid #f0f; /* will show up even if the string is zero length */
  background: #f0f; /* in demo number 3 */
}

Events

Triggers a "livesearch" event with each input on the <textarea> element, with two parameters: the string used to create the regular expression and the result of the exec call. Thus

$('input').on('input focus blur', $('textarea').livesearch());
$('textarea').on('livesearch', function (event, searchstring, result){
  if (result){
    alert(result[0]+' found at position '+result.index);
  }else{
    alert(searchstring+' not Found!');
  }
});

Would be a highly annoying way to provide feedback with each keystroke.

When the searching is done (the <input> element loses focus), triggers a "livesearchdone" event with the same parameter.

Leave a Reply


Warning: Undefined variable $user_ID in /home/public/blog/wp-content/themes/evanescence/comments.php on line 75