Tuesday, 10 February 2009

Creating a Spell as you type jQuery plugin - Part 2

In my previous post, I outlined solutions to the technical challenges I faced trying to implement a complete client side browser based spell checking solution.
With the technical challenges sorted, I looked into writing a JQuery plug-in. The tutorials on the JQuery website are a good place to start. I also found the plugin development pattern from Mike Alsup extremely useful. It helps you set up a closure to keep your methods and variables private as well as setting up defaults and options (passed in as a JSON). I won’t go into these details here as they are covered so well in the articles I’ve referenced here.
Detecting non-IE browsers in your plug-in. The first task once the structure of the plug-in was in place and the options set up was to block non IE clients from using the plug-in, or more simply to exit the main function without executing any additional code. This was made very simple by using the following built-in JQuery code
//This plugin is only for IE 6.0 + users
if (!.browser.msie) return;
if (.browser.version <> 6) return;
Loading the dictionary using JQuery AJAX
The next item of code I wanted to tackle was getting the text-based dictionary into a structure the plug-in could understand and use. The $.ajax function provided an asynchronous way of retrieving data from the server. This is useful, because you don’t want the interface to be blocked whilst you potentially download a large file.
The success function passes the data to the loadDictionary function. When successful, the .fn.spellayt.loaded() function is called if it has been set on the plug-in. This is similar the event model used in c# programming. Note that this is how function pointers are exposed outside of the plug-in.
The loadDictionary function loads the words in the dictionary into a three dimensional array, consisting of an array for the first letter of the word, the length and the matching words. In this way, the words starting with the same letter and of the same length can be checked very quickly, as they will most likely have the closest Levenshtein distance.
//Load the dictionary from a url
$.ajax({
  type: "GET",
  url: $.fn.spellayt.global.options.url,
  dataType: "text",
  success: function(data) {

    //Load the dictionary into the dictionaryArray.
    loadDictionary(data);
    if ($.fn.spellayt.loaded != null) $.fn.spellayt.loaded();

  },

  error: function(XMLHttpRequest, textStatus, errorThrown) {
    if ($.fn.spellayt.loadError != null) fn.spellayt.loadError(textStatus);
  }
Highlighting words that have been misspellt
When the input gains focus, a few things need to happen on a regular basis as the user types
  • find new words to check
  • check if a word exists in the dictionary
  • Highlight misspellt words

This is done by using the setTimer and setInterval functions – the difference between them is minimal - the one fires a function every x milliseconds, the other calls a function once after the next x seconds.

$(this).focus(function(event) {

var g = $.fn.spellayt.global;
if (g.ready) {
 g.current = this;

 //Set a timer to break words every 1 second
 g.breakTimer = setInterval(function() {
   if (g.wordQueue.length == 0) breakText(g.current); }, 1000);

 //Set a timer to highlight words every 1/2 second
 g.highlight = setInterval(function() {
   $.fn.spellayt.highlight(g.current); }, 500);

 //Start the the word breaking queue
 doWordBreak()
}
});
The sentence and word breaking is done by the use of regular expression parameters – this is incredibly useful – a word breaking regex can be set as a parameter for e.g. a different language.

In the next part of this series, Ill look into the problems I faced when the processor intensive code for word breaking and checking blocked the UI and how to emulate a multi-threaded environment in the current version of javascript.

No comments: