Tuesday 3 March 2009

Creating a Spell as you type jQuery plug-in - Part 3

In my previous posts, I described how to create a jQuery plug-in called spellayt (Spell as you Type) that provided spelling correction to Internet Explorer users.

The timed work queue pattern

The performance of initial implementations of the spellayt were disappointing, you would often wait a few seconds whilst the latest words typed in were checked and highlighted. Even worse, you could get the dreaded "A script on this page is causing Internet Explorer to run slowly." message. I soon found I needed a solution usng a multi-threaded approach so that the spell checking could happen in the background to the user typing. A quick check confirmed that JavaScript does not support more than one thread although the search did reveal some interesting options.

Because the word breaking and dictionary checks could potentially take a few seconds each, I decided that only one word could be checked against the dictionary at a time. The trick is to use lots of short functions at regular intervals, so that the UI can continue to process events from the user.

This gave me the idea for implementing the following pattern which I call the Timed Work Queue pattern. In the plug-in, a call to doWordBreak() starts the ball rolling when the input receives focus:

//Global values
$.fn.spellayt.global = {
  options: null,         //plug-in options
  wordQueue: new Array() //word breaking queue
};

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

  //Start the the word breaking queue
  doWordBreak();
});

The doWordBreak() function is actually really straight forward. It shifts the oldest work item off the queue and executes that item. The function then calls itself again in a predetermined time (50 ms seems to be a good figure)

//Pops the next word off the word breaking queue
function doWordBreak() {
  var g = $.fn.spellayt.global;

  //Get an item off the queue
  if (g.wordQueue.length > 0) {
     var work = g.wordQueue.shift();
     work.call(work.data);
  }

  //Process the next item
  g.wordTimer = setTimeout(function() { doWordBreak(); }, g.options.milliseconds);
}

So what does the object look like that we are pushing onto the work queue ? The breaktext function breaks text into sentences and words, and loads words onto the queue one at a time

//Check the spelling for all words in the input provided
function breakText(input) {
  if (input == null) return;

  //Split text into a 2d array of sentences and words
  var sentences = splitWords(input.value);

  if (sentences == null) return;

  //Add the call to checkWord() to the work queue for each word in each sentence
  for (var i = 0; i < sentences.length; i++) {

    $.fn.spellayt.global.wordQueue.push({ call: function(parm) { checkSentence(parm); }, data: sentences[i] });

  }
};

The object consists of a function pointer call and data to be passed to the function data. As long as your function has a single parameter (e.g. a JSON object), you could queue up any combination of functions to execute.

This is really handy as you can push completely different function pointers onto the queue, as well as putting some items ahead of others with a higher priority.

8 comments:

BarrettJ said...

Is there any place where we can download your jquery check spelling as you type plugin? I see instructions for how to make it, but I can't seem to find the download. Thanks!

James Westgate said...

You can try https://plugins.jquery.com/project/spellayt

Anonymous said...

Can additional dictionary be opened at the same time with the main dictionary?

James Westgate said...

No. It should be pretty easy to modify to allow a second dictionary. Some work could be done to include ignore list, user specific dictionaries etc.

Or you could add your list to the main dictionary - as long as you reorder the words so that they are in alphanumeric sequence.

Anonymous said...

Can you point or show some example on how to add a second dictionary. Can the spell check using both dictionaries at the same time?
(No from previously you have to check using single dictionary at a time?)
Adding to the list will make the dictionary file bigger, ie slower speed to check?
Thank you

James Westgate said...

The latest version of Open Spell at Codeplex provides an .exe which you can use to combine dictionary files and output them in the correct format.

Anonymous said...

Hi James ,

Whenever i am trying to run the example2.htm from our server, all the words gets highlighted, wherein this works fine on local. Can you please suggest! Thanks!

Anonymous said...

Hello

The spellayt plugin does not give suggestions for the last word, though it highlights it. If the last word is followed by any character the suggestion does come.'

Please help on how can we get suggestion for the last word also.

-Thanks