Annotation of kupuMPIWG/common/kupuspellchecker.js, revision 1.1.1.1
1.1 dwinter 1: function KupuSpellChecker(buttonid, scripturl, spanstyle,
2: winwidth, winheight, skip_tags) {
3: this.button = document.getElementById(buttonid);
4: this.scripturl = scripturl;
5: this.spanstyle = spanstyle || 'color: red; ' +
6: 'text-decoration: underline;';
7: this.winwidth = winwidth || '600';
8: this.winheight = winheight || '400';
9: this.skip_tags = skip_tags || ['head', 'script'];
10: };
11:
12: KupuSpellChecker.prototype = new KupuTool;
13:
14: KupuSpellChecker.prototype.initialize = function(editor) {
15: this.editor = editor;
16: addEventHandler(this.button, 'click', this.check, this);
17: };
18:
19: KupuSpellChecker.prototype.check = function() {
20: var request = new XMLHttpRequest();
21: request.open('POST', this.scripturl, true);
22: request.setRequestHeader('Content-Type',
23: 'application/x-www-form-urlencoded');
24: request.onreadystatechange = new ContextFixer(
25: this.stateChangeHandler,
26: this,
27: request).execute;
28: var result = this.getCurrentContents();
29: result = escape(result.strip().replace('\n', ' ').reduceWhitespace());
30: request.send('text=' + result);
31: };
32:
33: KupuSpellChecker.prototype.stateChangeHandler = function(request) {
34: if (request.readyState == 4) {
35: if (request.status == '200') {
36: var result = request.responseXML;
37: result = this.xmlToMapping(result);
38: if (!result) {
39: alert(_('There were no errors.'));
40: } else {
41: this.displayUnrecognized(result);
42: };
43: } else {
44: alert(_('Error loading data, status ${status}',
45: {'status': request.status}));
46: };
47: };
48: };
49:
50: KupuSpellChecker.prototype.getCurrentContents = function() {
51: var doc = this.editor.getInnerDocument().documentElement;
52: var iterator = new NodeIterator(doc);
53: var bits = [];
54: while (true) {
55: var node = iterator.next();
56: if (!node) {
57: break;
58: };
59: while (this.skip_tags.contains(node.nodeName.toLowerCase())) {
60: node = node.nextSibling;
61: iterator.setCurrent(node);
62: };
63: if (node.nodeType == 3) {
64: bits.push(node.nodeValue);
65: };
66: };
67: return bits.join(' ');
68: };
69:
70: KupuSpellChecker.prototype.displayUnrecognized = function(mapping) {
71: // copy the current editable document into a new window
72: var doc = this.editor.getInnerDocument();
73: var docel = doc.documentElement;
74: var win = window.open('kupublank.html', 'spellchecker',
75: 'width=' + this.winwidth + ',' +
76: 'height=' + this.winheight + ',toolbar=no,' +
77: 'menubar=no,scrollbars=yes,status=yes');
78: if (!win) {
79: alert(
80: _('This feature requires pop-ups to be enabled on your browser!'));
81: return;
82: };
83: var html = docel.innerHTML;
84: // when Moz tries to set the content-type, for some reason leaving this
85: // in breaks the feature(?!?)
86: html = html.replace(/<meta[^>]*http-equiv="[Cc]ontent-[Tt]ype"[^>]*>/gm,
87: '');
88: win.document.write('<html>' + html + '</html>');
89: win.deentitize = function(str) {return str.deentitize()};
90: win.document.close();
91: if (!win.document.getElementsByTagName('body').length) {
92: addEventHandler(win, 'load', this.continueDisplay, this, win, mapping);
93: } else {
94: this.continueDisplay(win, mapping);
95: };
96: };
97:
98: KupuSpellChecker.prototype.continueDisplay = function(win, mapping) {
99: /* walk through all elements of the body, colouring the text nodes */
100: // start it all with a timeout to make Mozilla render the content first
101: timer_instance.registerFunction(this, this.continueDisplayHelper,
102: 1000, win, mapping);
103: };
104:
105: KupuSpellChecker.prototype.continueDisplayHelper = function(win, mapping) {
106: var body = win.document.getElementsByTagName('body')[0];
107: body.setAttribute('contentEditable', 'false');
108: var iterator = new NodeIterator(body);
109: var node = iterator.next();
110: timer_instance.registerFunction(this, this.displayHelperNodeLoop,
111: 10, iterator, node, win, mapping);
112: };
113:
114: KupuSpellChecker.prototype.displayHelperNodeLoop = function(iterator, node,
115: win, mapping) {
116: if (!node) {
117: return;
118: };
119: var next = iterator.next();
120: if (node.nodeType == 3) {
121: if (win.closed) {
122: return;
123: };
124: var span = win.document.createElement('span');
125: var before = node.nodeValue;
126: var after = this.colourText(before, mapping);
127: if (before != after) {
128: span.innerHTML = after;
129: var last = span.lastChild;
130: var parent = node.parentNode;
131: parent.replaceChild(last, node);
132: while (span.hasChildNodes()) {
133: parent.insertBefore(span.firstChild, last);
134: };
135: };
136: } else if (node.nodeType == 1 && node.nodeName.toLowerCase() == 'a') {
137: var cancelEvent = function(e) {
138: if (e.preventDefault) {
139: e.preventDefault();
140: } else {
141: e.returnValue = false;
142: };
143: return false;
144: };
145: addEventHandler(node, 'click', cancelEvent);
146: addEventHandler(node, 'mousedown', cancelEvent);
147: addEventHandler(node, 'mouseup', cancelEvent);
148: };
149: // using a timeout here makes Moz render the coloring while it's busy, and
150: // will make it stop popping up 'do you want to continue' prompts...
151: timer_instance.registerFunction(this, this.displayHelperNodeLoop,
152: 10, iterator, next, win, mapping);
153: };
154:
155: KupuSpellChecker.prototype.colourText = function(text, mapping) {
156: var currtext = text;
157: var newtext = '';
158: for (var word in mapping) {
159: var replacements = mapping[word];
160: replacements = replacements.entitize();
161: replacements = replacements.replace(/\'/g, "'");
162: var reg = new RegExp('^(.*\\\W)?(' + word + ')(\\\W.*)?$', 'mg');
163: while (true) {
164: var match = reg.exec(currtext);
165: if (!match) {
166: newtext += currtext;
167: currtext = newtext;
168: newtext = '';
169: break;
170: };
171: var m = (match[1] || '') + match[2];
172: newtext += currtext.substr(0, currtext.indexOf(m));
173: newtext += (match[1] || '') +
174: '<span style="' + this.spanstyle + '" ' +
175: 'onclick="alert(deentitize(\'' +
176: replacements + '\'));" ' +
177: 'title="' + replacements + '">' +
178: match[2] +
179: '</span>';
180: currtext = currtext.substr(currtext.indexOf(m) + m.length);
181: };
182: };
183: return currtext;
184: };
185:
186: KupuSpellChecker.prototype.xmlToMapping = function(docnode) {
187: var docel = docnode.documentElement;
188: var result = {};
189: var incorrect = docel.getElementsByTagName('incorrect');
190: for (var i=0; i < incorrect.length; i++) {
191: var word = incorrect[i].firstChild.firstChild.nodeValue;
192: var replacements = '';
193: if (incorrect[i].lastChild.hasChildNodes()) {
194: replacements = incorrect[i].lastChild.firstChild.nodeValue;
195: };
196: result[word] = replacements;
197: };
198: var attrs = [];
199: return result;
200: };
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>