(function($){$.fn.extend({spellchecker:function(options,callback){return this.each(function(){var obj=$(this).data('spellchecker');if(obj&&String===options.constructor&&obj[options]){obj[options](callback);}else if(obj){obj.init();}else{$(this).data('spellchecker',new SpellChecker(this,(Object===options.constructor?options:null)));(String===options.constructor)&&$(this).data('spellchecker')[options](callback);}});}});var SpellChecker=function(domObj,options){this.options=$.extend({url:'checkspelling.php',lang:'en',engine:'pspell',addToDictionary:false,wordlist:{action:'after',element:domObj},suggestBoxPosition:'below',innerDocument:false},options||{});this.$domObj=$(domObj);this.elements={};this.init();};SpellChecker.prototype={init:function(){var self=this;this.createElements();this.$domObj.addClass('spellcheck-container');$(document).bind('click',function(e){(!$(e.target).hasClass('spellcheck-word-highlight')&&!$(e.target).parents().filter('.spellcheck-suggestbox').length)&&self.hideBox();});},option:function(newopts){for(optname in newopts){this.options[optname]=newopts[optname];} return this;},check:function(callback){var self=this,node=this.$domObj.get(0).nodeName,tagExp='<[^>]+>',puncExp='^[^a-zA-Z\\u00A1-\\uFFFF]|[^a-zA-Z\\u00A1-\\uFFFF]+[^a-zA-Z\\u00A1-\\uFFFF]|[^a-zA-Z\\u00A1-\\uFFFF]$|\\n|\\t|\\s{2,}';if(node=='TEXTAREA'||node=='INPUT'){this.type='textarea';var text=$.trim(this.$domObj.val().replace(new RegExp(tagExp,'g'),'').replace(new RegExp(puncExp,'g'),' '));}else{this.type='html';var text=$.trim(this.$domObj.text().replace(new RegExp(puncExp,'g')," "));} this.postJson(this.options.url,{text:encodeURIComponent(text).replace(/%20/g,'+')},function(json){self.type=='html'&&self.options.innerDocument?self.highlightWords(json,callback):self.buildBadwordsBox(json,callback);});},highlightWords:function(json,callback){if(!json.length){callback.call(this.$domObj,true);return;} var self=this,html=this.$domObj.html();$.each(json,function(key,replaceWord){html=html.replace(new RegExp('([^a-zA-Z\\u00A1-\\uFFFF])('+replaceWord+')([^a-zA-Z\\u00A1-\\uFFFF])','g'),'$1$2$3');});this.$domObj.html(html).find('.spellcheck-word-highlight').each(function(){self.elements.highlightWords.push($(this).click(function(){self.suggest(this);}));});(callback)&&callback();},buildBadwordsBox:function(json,callback){if(!json.length){callback.call(this.$domObj,true);return;} var self=this,words=[];$(this.options.wordlist.element)[this.options.wordlist.action](this.elements.$badwords);this.elements.$badwords.empty() $.each(json,function(key,badword){if($.inArray(badword,words)===-1){self.elements.highlightWords.push($(''+badword+'').click(function(){self.suggest(this);}).appendTo(self.elements.$badwords).after(', '));words.push(badword);}});$('.spellcheck-sep:last',self.elements.$badwords).addClass('spellcheck-sep-last');(callback)&&callback();},suggest:function(word){var self=this,$word=$(word),offset=$word.offset();this.$curWord=$word;if(this.options.innerDocument){this.elements.$suggestBox=this.elements.$body.find('.spellcheck-suggestbox');this.elements.$suggestWords=this.elements.$body.find('.spellcheck-suggestbox-words');this.elements.$suggestFoot=this.elements.$body.find('.spellcheck-suggestbox-foot');} this.elements.$suggestFoot.hide();this.elements.$suggestBox.stop().hide().css({opacity:1,width:"auto",left:offset.left+"px",top:(this.options.suggestBoxPosition=="above"?(offset.top-($word.outerHeight()+10))+"px":(offset.top+$word.outerHeight())+"px")}).fadeIn(200);this.elements.$suggestWords.html('Loading..');this.postJson(this.options.url,{suggest:encodeURIComponent($.trim($word.text()))},function(json){self.buildSuggestBox(json,offset);});},buildSuggestBox:function(json,offset){var self=this,$word=this.$curWord;this.elements.$suggestWords.empty();for(var i=0;i<(json.length<5?json.length:5);i++){this.elements.$suggestWords.append($(''+json[i]+'').addClass((!i?'first':'')).click(function(){return false;}).mousedown(function(e){e.preventDefault();self.replace(this.innerHTML);self.hideBox();}));} (!i)&&this.elements.$suggestWords.append('(no suggestions)');var viewportHeight=window.innerHeight?window.innerHeight:$(window).height();this.elements.$suggestFoot.show();self.elements.$suggestBox.css({top:(this.options.suggestBoxPosition=='above')||(offset.top+$word.outerHeight()+this.elements.$suggestBox.outerHeight()>viewportHeight+10)?(offset.top-(this.elements.$suggestBox.height()+5))+"px":(offset.top+$word.outerHeight()+"px"),width:'auto',left:(this.elements.$suggestBox.outerWidth()+offset.left>$('body').width()?(offset.left-this.elements.$suggestBox.width())+$word.outerWidth()+'px':offset.left+'px')});},hideBox:function(callback){this.elements.$suggestBox.fadeOut(250,function(){(callback)&&callback();});},replace:function(replace){switch(this.type){case'textarea':this.replaceTextbox(replace);break;case'html':this.replaceHtml(replace);break;}},replaceWord:function(text,replace){return text.replace(new RegExp("([^a-zA-Z\\u00A1-\\uFFFF]?)("+this.$curWord.text()+")([^a-zA-Z\\u00A1-\\uFFFF]?)","g"),'$1'+replace+'$3').replace(new RegExp("^("+this.$curWord.text()+")([^a-zA-Z\\u00A1-\\uFFFF])","g"),replace+'$2').replace(new RegExp("([^a-zA-Z\\u00A1-\\uFFFF])("+this.$curWord.text()+")$","g"),'$1'+replace);},replaceTextbox:function(replace){this.removeBadword(this.$curWord);this.$domObj.val(this.replaceWord(this.$domObj.val(),replace));},replaceHtml:function(replace){var words=this.$domObj.find('.spellcheck-word-highlight:contains('+this.$curWord.text()+')') if(words.length){words.after(replace).remove();}else{$(this.$domObj).html(this.replaceWord($(this.$domObj).html(),replace));this.removeBadword(this.$curWord);}},ignore:function(){if(this.type=='textarea'){this.removeBadword(this.$curWord);}else{this.$curWord.after(this.$curWord.html()).remove();}},ignoreAll:function(){var self=this;if(this.type=='textarea'){this.removeBadword(this.$curWord);}else{$('.spellcheck-word-highlight',this.$domObj).each(function(){(new RegExp(self.$curWord.text(),'i').test(this.innerHTML))&&$(this).after(this.innerHTML).remove();});}},removeBadword:function($domObj){($domObj.next().hasClass('spellcheck-sep'))&&$domObj.next().remove();$domObj.remove();if(!$('.spellcheck-sep',this.elements.$badwords).length){this.elements.$badwords.remove();}else{$('.spellcheck-sep:last',this.elements.$badwords).addClass('spellcheck-sep-last');}},addToDictionary:function(){var self=this;this.hideBox(function(){confirm('Are you sure you want to add the word "'+self.$curWord.text()+'" to the dictionary?')&&self.postJson(self.options.url,{addtodictionary:self.$curWord.text()},function(){self.ignoreAll();self.check();});});},remove:function(destroy){destroy=destroy||true;$.each(this.elements.highlightWords,function(val){this.after(this.innerHTML).remove()});this.elements.$badwords.remove();this.elements.$suggestBox.remove();$(this.domObj).removeClass('spellcheck-container');(destroy)&&$(this.domObj).data('spellchecker',null);},postJson:function(url,data,callback){var xhr=$.ajax({type:'POST',url:url,data:$.extend(data,{engine:this.options.engine,lang:this.options.lang}),dataType:'json',cache:false,error:function(XHR,status,error){alert('Sorry, there was an error processing the request.');},success:function(json){(callback)&&callback(json);}});return xhr;},createElements:function(){var self=this;this.elements.$body=this.options.innerDocument?this.$domObj.parents().filter('html:first').find("body"):$('body');this.elements.highlightWords=[];this.elements.$suggestWords=this.elements.$suggestWords||$('
').addClass('spellcheck-suggestbox-words');this.elements.$ignoreWord=this.elements.$ignoreWord||$('Ignore Word').click(function(e){e.preventDefault();self.ignore();self.hideBox();});this.elements.$ignoreAllWords=this.elements.$ignoreAllWords||$('Ignore all').click(function(e){e.preventDefault();self.ignoreAll();self.hideBox();});this.elements.$ignoreWordsForever=this.elements.$ignoreWordsForever||$('Ignore forever').click(function(e){e.preventDefault();self.addToDictionary();self.hideBox();});this.elements.$suggestFoot=this.elements.$suggestFoot||$('
').addClass('spellcheck-suggestbox-foot').append(this.elements.$ignoreWord).append(this.elements.$ignoreAllWords).append(this.options.engine=="pspell"&&self.options.addToDictionary?this.elements.$ignoreWordsForever:false);this.elements.$badwords=this.elements.$badwords||$('
').addClass('spellcheck-badwords');this.elements.$suggestBox=this.elements.$suggestBox||$('
').addClass('spellcheck-suggestbox').append(this.elements.$suggestWords).append(this.elements.$suggestFoot).prependTo(this.elements.$body);}};})(jQuery);