/**
* Version 3.3 - 16.March.2009
* @copyright 2005 - 2009 Garrison Locke
* @author Garrison Locke (gplocke at gmail dot com) http://www.broken-notebook.com
*
*/
var sc_spellCheckers = null;
window.addEvent('domready', function() {
sc_spellCheckers = new SpellChecker(
'spell_check',
{
confirmAfterAllWordsChecked: false,
alertOnNoMisspellings: false
}
)
});
var SpellChecker = new Class({
options: {
useImages: true,
url: 'spell_checker.php',
confirmAfterAllWordsChecked: false,
alertOnNoMisspellings: false
},
textBoxes: null,
current: null,
suggestDiv: null,
currentSuggestionWord: null,
initialize: function(spellClass, options) {
document.addEvent('click', function(e) {
var event = new Event(e);
if (!$(event.target).hasClass('suggestion')) {
if (this.suggestDiv != null) {
this.suggestDiv.dispose();
this.suggestDiv = null;
if (!$(event.target).hasClass('spell_checker_cp_check')) {
this.checkUncheckedWords();
}
}
}
return true;
}.bind(this));
this.textBoxes = $$('.' + spellClass);
this.setOptions(options);
this.textBoxes.each(function (el) {
//generates the div to hold the spell checker controls
var cpDiv = new Element('div');
cpDiv.addClass('spell_checker_cp');
// add the link to check the spelling
if (this.options.useImages) {
var checkLink = new Element('a');
checkLink.set('html', ' ');
checkLink.addClass('spell_checker_cp_check');
checkLink.alt = 'Check Spelling';
} else {
var checkLink = new Element('a');
checkLink.set('html', 'Check Spelling');
}
checkLink.title = 'Check Spelling';
checkLink.addEvent('click', function (){
this.current = el;
this.spellCheck(el);
}.bind(this));
cpDiv.adopt(checkLink);
//add the link to resume editing
var resumeLink = new Element('a');
if (this.options.useImages) {
resumeLink.set('html', ' ');
resumeLink.addClass('spell_checker_cp_resume');
resumeLink.alt = 'Resume Editing';
} else {
resumeLink.set('html', 'Resume Editing');
}
resumeLink.title = 'Resume Editng';
resumeLink.addEvent('click', function (){
this.current = el;
this.resume(el);
}.bind(this));
resumeLink.setStyle('display', 'none');
cpDiv.adopt(resumeLink);
//the span that lets the user know of the status of the spell checker
var statusSpan = new Element('span');
statusSpan.addClass('spell_checker_cp_status');
statusSpan.set('html', ' ');
cpDiv.adopt(statusSpan);
var workingSpan = new Element('span');
workingSpan.set('html', ' ');
workingSpan.addClass('spell_checker_cp_working');
workingSpan.alt = 'Working...';
workingSpan.setStyle('display', 'none');
cpDiv.adopt(workingSpan);
cpDiv.injectBefore(el);
// add the div that will hold the spell check results
var resultDiv = new Element('div');
var elSize = el.getSize();
resultDiv.setStyle('width', elSize.x);
resultDiv.setStyle('height', elSize.y);
resultDiv.setStyle('display', 'none');
resultDiv.injectAfter(el);
}, this);
},
spellCheck: function(el) {
el.getPrevious().getLast().getPrevious().set('text', ''); // status span
el.getPrevious().getLast().set('styles', {'display': ''}); // progress indicator
var varStr = Hash.toQueryString({
spellText: el.value,
action: 'spellcheck'
});
var checkUrl = this.options.url;
var ajaxCall = new Request(
{
url: checkUrl,
method: 'post',
data: varStr,
onSuccess: this.spellCheck_cb.bind(this)
}
).send();
},
spellCheck_cb: function(txt, xml) {
if (txt == 0) {
if (this.options.alertOnNoMisspellings) {
alert('No misspellings found');
}
this.current.getPrevious().getLast().getPrevious().set('text', ''); // status span
} else {
var checkAction = this.current.getPrevious().getFirst();
checkAction.set('styles', {'display': 'none'});
var resumeAction = checkAction.getNext();
resumeAction.set('styles', {'display': ''});
var resultDiv = this.current.getNext();
this.current.set('styles', {'display': 'none'});
resultDiv.set('styles', {'display': ''});
resultDiv.addClass('spell_checker_cp_result');
resultDiv.innerHTML = txt;
resultDiv.getElements('span').each(function(el) {
// add this class to mark it as misspelled
el.addClass('sc_misspelled');
// add this class to show it's not been looked at yet
el.addClass('sc_unchecked');
el.addEvent('click', function(e) {
this.currentSuggestionWord = el;
this.current = resultDiv.getPrevious();
// we remove this class so we know it's been clicked on
el.removeClass('sc_unchecked');
var event = new Event(e);
event.stop();
var varStr = Hash.toQueryString({
suggestionText: el.get('text'),
action: 'suggest'
});
var checkUrl = this.options.url;
var ajaxCall = new Request(
{
url: checkUrl,
method: 'post',
data: varStr,
onSuccess: this.suggest_cb.bind(this)
}
).send();
}.bind(this));
}, this);
}
this.current.getPrevious().getLast().set('styles', {'display': 'none'}); //hide spinner
},
suggest_cb: function(txt, xml) {
if (this.suggestDiv != null) {
this.suggestDiv.dispose();
this.suggestDiv = null;
}
this.suggestDiv = new Element('div');
this.suggestDiv.set('styles', {'display': 'none'});
this.suggestDiv.addClass('suggestionBox');
this.suggestDiv.innerHTML = txt;
this.suggestDiv.injectAfter(this.currentSuggestionWord);
this.suggestDiv.getElements('div').each(function(el){
if (el.hasClass('suggestion')) {
el.addEvent('click', function(e) {
var event = new Event(e);
event.stop();
this.currentSuggestionWord.set('text', el.get('text'));
this.currentSuggestionWord.addClass('corrected');
this.suggestDiv.dispose();
this.suggestDiv = null;
this.checkUncheckedWords();
}.bind(this));
} else if (el.hasClass('addToDictionary')) {
el.addEvent('click', function(e) {
var event = new Event(e);
event.stop();
this.currentSuggestionWord.addClass('corrected');
var varStr = Hash.toQueryString({
wordToAdd: this.currentSuggestionWord.get('text'),
action: 'addToDictionary'
});
var checkUrl = this.options.url;
var ajaxCall = new Request(
{
url: checkUrl,
method: 'post',
data: varStr,
onSuccess: this.addToDictionary_cb.bind(this)
}
).send();
this.suggestDiv.dispose();
this.suggestDiv = null;
this.checkUncheckedWords();
}.bind(this));
}
}, this);
this.suggestDiv.setPosition({
relativeTo: this.currentSuggestionWord,
position: 'bottomLeft'
});
this.suggestDiv.set('styles', {'display': ''});
},
checkUncheckedWords: function() {
// check the result div to see if all the words have been touched
var done = true;
this.current.getNext().getElements('span').each(function(el) {
if (el.hasClass('sc_unchecked')) {
done = false;
}
}.bind(this));
if (done == true) {
if (this.options.confirmAfterAllWordsChecked) {
if (confirm("All the misspelled words have been looked at, would you like to return to edit mode?")) {
this.resume(this.current);
}
} else {
this.resume(this.current);
}
}
},
addToDictionary_cb: function(txt, xml) {
if (txt == 1) {
alert("Successfully added word to dictionary.");
} else {
alert("Failed adding word to dictionary.");
}
},
resume: function(el) {
if (this.suggestDiv != null) {
this.suggestDiv.dispose();
this.suggestDiv = null;
}
var resultDiv = el.getNext();
resultDiv.getElements('span').each(function(el) {
if (el.hasClass('sc_misspelled')) {
var tmp = document.newTextNode(el.get('text'));
el.parentNode.replaceChild(tmp, el);
}
}.bind(this));
el.value = resultDiv.get('html').replace(/
/gi, "\n");
resultDiv.set('styles', {'display': 'none'});
el.set('styles', {'display': ''});
var checkAction = el.getPrevious().getFirst();
checkAction.set('styles', {'display': ''});
var resumeAction = checkAction.getNext();
resumeAction.set('styles', {'display': 'none'});
},
resumeAll: function() {
this.textBoxes.each(function (el) {
if (el.getStyle('display') == 'none') {
this.resume(el);
}
}.bind(this));
}
});
SpellChecker.implement(new Options, new Events);
/*MooTools, My Object Oriented Javascript Tools. Copyright (c) 2006-2007 Valerio Proietti, , MIT Style License.||CNET Libraries Copyright (c) 2006-2008, http://clientside.cnet.com/wiki/cnet-libraries#license*/
Element.implement({
expose: function(){
if (this.getStyle('display') != 'none') return $empty;
var before = {};
['visibility', 'display', 'position'].each(function(style){
before[style] = this.style[style]||'';
}, this);
this.setStyles({
visibility: 'hidden',
display: 'block',
position:'absolute'
});
return (function(){
this.setStyles(before);
}).bind(this);
},
getDimensions: function(options) {
options = $merge({computeSize: false},options);
var dim = {};
function getSize(el, options){
if(options.computeSize) dim = el.getComputedSize(options);
else {
var sz = el.getSize();
dim.width = sz.x;
dim.height = sz.y;
}
return dim;
}
try {
dim = getSize(this, options);
}catch(e){}
if(this.getStyle('display') == 'none'){
var restore = this.expose();
dim = getSize(this, options);
restore();
}
return $merge(dim, {x: dim.width, y: dim.height});
},
getComputedSize: function(options){
options = $merge({
styles: ['padding','border'],
plains: {height: ['top','bottom'], width: ['left','right']},
mode: 'both'
}, options);
var size = {width: 0,height: 0};
switch (options.mode){
case 'vertical':
delete size.width;
delete options.plains.width;
break;
case 'horizontal':
delete size.height;
delete options.plains.height;
break;
}
var getStyles = [];
$each(options.plains, function(plain, key){
plain.each(function(edge){
options.styles.each(function(style){
getStyles.push((style=="border")?style+'-'+edge+'-'+'width':style+'-'+edge);
});
});
});
var styles = this.getStyles.apply(this, getStyles);
var subtracted = [];
$each(options.plains, function(plain, key){
size['total'+key.capitalize()] = 0;
size['computed'+key.capitalize()] = 0;
plain.each(function(edge){
size['computed'+edge.capitalize()] = 0;
getStyles.each(function(style,i){
if(style.test(edge)) {
styles[style] = styles[style].toInt();
if(isNaN(styles[style]))styles[style]=0;
size['total'+key.capitalize()] = size['total'+key.capitalize()]+styles[style];
size['computed'+edge.capitalize()] = size['computed'+edge.capitalize()]+styles[style];
}
if(style.test(edge) && key!=style &&
(style.test('border') || style.test('padding')) && !subtracted.contains(style)) {
subtracted.push(style);
size['computed'+key.capitalize()] = size['computed'+key.capitalize()]-styles[style];
}
});
});
});
if($chk(size.width)) {
size.width = size.width+this.offsetWidth+size.computedWidth;
size.totalWidth = size.width + size.totalWidth;
delete size.computedWidth;
}
if($chk(size.height)) {
size.height = size.height+this.offsetHeight+size.computedHeight;
size.totalHeight = size.height + size.totalHeight;
delete size.computedHeight;
}
return $merge(styles, size);
}
});
Element.implement({
setPosition: function(options){
options = $merge({
relativeTo: document.body,
position: {
x: 'center',
y: 'center'
},
edge: false,
offset: {x:0,y:0},
returnPos: false,
relFixedPosition: false,
ignoreMargins: false
}, options);
var parentOffset = {x: 0, y: 0};
var parentPositioned = false;
if(this.getParent() != document.body) {
var parent = this.getParent();
while(parent != document.body && parent.getStyle('position') == "static") {
parent = parent.getParent();
}
if(parent != document.body) {
parentOffset = parent.getPosition();
parentPositioned = true;
}
options.offset.x = options.offset.x - parentOffset.x;
options.offset.y = options.offset.y - parentOffset.y;
}
function fixValue(option) {
if($type(option) != "string") return option;
option = option.toLowerCase();
var val = {};
if(option.test('left')) val.x = 'left';
else if(option.test('right')) val.x = 'right';
else val.x = 'center';
if(option.test('upper')||option.test('top')) val.y = 'top';
else if (option.test('bottom')) val.y = 'bottom';
else val.y = 'center';
return val;
};
options.edge = fixValue(options.edge);
options.position = fixValue(options.position);
if(!options.edge) {
if(options.position.x == 'center' && options.position.y == 'center') options.edge = {x:'center',y:'center'};
else options.edge = {x:'left',y:'top'};
}
this.setStyle('position', 'absolute');
var rel = $(options.relativeTo) || document.body;
var top = (rel == document.body)?window.getScroll().y():rel.getTop();
var left = (rel == document.body)?window.getScroll().x():rel.getLeft();
if (top < 0) top = 0;
if (left < 0) left = 0;
var dim = this.getDimensions({computeSize: true, styles:['padding', 'border','margin']});
if (options.ignoreMargins) {
options.offset.x += ((options.edge && options.edge.x == "right")?dim['margin-right']:-dim['margin-left']);
options.offset.y += ((options.edge && options.edge.y == "bottom")?dim['margin-bottom']:-dim['margin-top']);
}
var pos = {};
var prefY = options.offset.y.toInt();
var prefX = options.offset.x.toInt();
switch(options.position.x) {
case 'left':
pos.x = left + prefX;
break;
case 'right':
pos.x = left + prefX + rel.offsetWidth;
break;
default:
pos.x = left + (((rel == document.body)?window.getSize().x:rel.offsetWidth)/2) + prefX;
break;
};
switch(options.position.y) {
case 'top':
pos.y = top + prefY;
break;
case 'bottom':
pos.y = top + prefY + rel.offsetHeight;
break;
default:
pos.y = top + (((rel == document.body)?window.getSize().y:rel.offsetHeight)/2) + prefY;
break;
};
if(options.edge){
var edgeOffset = {};
switch(options.edge.x) {
case 'left':
edgeOffset.x = 0;
break;
case 'right':
edgeOffset.x = -dim.x-dim.computedRight-dim.computedLeft;
break;
default:
edgeOffset.x = -(dim.x/2);
break;
};
switch(options.edge.y) {
case 'top':
edgeOffset.y = 0;
break;
case 'bottom':
edgeOffset.y = -dim.y-dim.computedTop-dim.computedBottom;
break;
default:
edgeOffset.y = -(dim.y/2);
break;
};
pos.x = pos.x+edgeOffset.x;
pos.y = pos.y+edgeOffset.y;
}
pos = {
left: ((pos.x >= 0 || parentPositioned)?pos.x:0).toInt(),
top: ((pos.y >= 0 || parentPositioned)?pos.y:0).toInt()
};
if(rel.getStyle('position') == "fixed"||options.relFixedPosition) {
pos.top = pos.top.toInt() + window.getScroll().y;
pos.left = pos.left.toInt() + window.getScroll().x;
}
if(options.returnPos) return pos;
else this.setStyles(pos);
return this;
}
});