\r
t.url = url;\r
t.editor = ed;\r
+ t.rpcUrl = ed.getParam("spellchecker_rpc_url", "{backend}");\r
+\r
+ if (t.rpcUrl == '{backend}') {\r
+ // Sniff if the browser supports native spellchecking (Don't know of a better way)\r
+ if (tinymce.isIE)\r
+ return;\r
+\r
+ t.hasSupport = true;\r
+\r
+ // Disable the context menu when spellchecking is active\r
+ ed.onContextMenu.addToTop(function(ed, e) {\r
+ if (t.active)\r
+ return false;\r
+ });\r
+ }\r
\r
// Register commands\r
ed.addCommand('mceSpellCheck', function() {\r
+ if (t.rpcUrl == '{backend}') {\r
+ // Enable/disable native spellchecker\r
+ t.editor.getBody().spellcheck = t.active = !t.active;\r
+ return;\r
+ }\r
+\r
if (!t.active) {\r
ed.setProgressState(1);\r
t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) {\r
ed.nodeChanged();\r
} else {\r
ed.setProgressState(0);\r
- ed.windowManager.alert('spellchecker.no_mpell');\r
+\r
+ if (ed.getParam('spellchecker_report_no_misspellings', true))\r
+ ed.windowManager.alert('spellchecker.no_mpell');\r
}\r
});\r
} else\r
var t = this, c, ed = t.editor;\r
\r
if (n == 'spellchecker') {\r
+ // Use basic button if we use the native spellchecker\r
+ if (t.rpcUrl == '{backend}') {\r
+ // Create simple toggle button if we have native support\r
+ if (t.hasSupport)\r
+ c = cm.createButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t});\r
+\r
+ return c;\r
+ }\r
+\r
c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t});\r
\r
c.onRenderMenu.add(function(c, m) {\r
},\r
\r
_getWords : function() {\r
- var ed = this.editor, wl = [], tx = '', lo = {};\r
+ var ed = this.editor, wl = [], tx = '', lo = {}, rawWords = [];\r
\r
// Get area text\r
this._walk(ed.getBody(), function(n) {\r
tx += n.nodeValue + ' ';\r
});\r
\r
- // Split words by separator\r
- tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' ');\r
- tx = tinymce.trim(tx.replace(/(\s+)/g, ' '));\r
+ // split the text up into individual words\r
+ if (ed.getParam('spellchecker_word_pattern')) {\r
+ // look for words that match the pattern\r
+ rawWords = tx.match('(' + ed.getParam('spellchecker_word_pattern') + ')', 'gi');\r
+ } else {\r
+ // Split words by separator\r
+ tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' ');\r
+ tx = tinymce.trim(tx.replace(/(\s+)/g, ' '));\r
+ rawWords = tx.split(' ');\r
+ }\r
\r
// Build word array and remove duplicates\r
- each(tx.split(' '), function(v) {\r
+ each(rawWords, function(v) {\r
if (!lo[v]) {\r
wl.push(v);\r
lo[v] = 1;\r
},\r
\r
_showMenu : function(ed, e) {\r
- var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin());\r
+ var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin()), wordSpan = e.target;\r
+\r
+ e = 0; // Fixes IE memory leak\r
\r
if (!m) {\r
p1 = DOM.getPos(ed.getContentAreaContainer());\r
t._menu = m;\r
}\r
\r
- if (dom.hasClass(e.target, 'mceItemHiddenSpellWord')) {\r
+ if (dom.hasClass(wordSpan, 'mceItemHiddenSpellWord')) {\r
m.removeAll();\r
m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1);\r
\r
- t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(e.target.innerHTML)], function(r) {\r
+ t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(wordSpan.innerHTML)], function(r) {\r
+ var ignoreRpc;\r
+\r
m.removeAll();\r
\r
if (r.length > 0) {\r
m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);\r
each(r, function(v) {\r
m.add({title : v, onclick : function() {\r
- dom.replace(ed.getDoc().createTextNode(v), e.target);\r
+ dom.replace(ed.getDoc().createTextNode(v), wordSpan);\r
t._checkDone();\r
}});\r
});\r
} else\r
m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);\r
\r
+ ignoreRpc = t.editor.getParam("spellchecker_enable_ignore_rpc", '');\r
m.add({\r
title : 'spellchecker.ignore_word',\r
onclick : function() {\r
- dom.remove(e.target, 1);\r
+ var word = wordSpan.innerHTML;\r
+\r
+ dom.remove(wordSpan, 1);\r
t._checkDone();\r
+\r
+ // tell the server if we need to\r
+ if (ignoreRpc) {\r
+ ed.setProgressState(1);\r
+ t._sendRPC('ignoreWord', [t.selectedLang, word], function(r) {\r
+ ed.setProgressState(0);\r
+ });\r
+ }\r
}\r
});\r
\r
m.add({\r
title : 'spellchecker.ignore_words',\r
onclick : function() {\r
- t._removeWords(dom.decode(e.target.innerHTML));\r
+ var word = wordSpan.innerHTML;\r
+\r
+ t._removeWords(dom.decode(word));\r
t._checkDone();\r
+\r
+ // tell the server if we need to\r
+ if (ignoreRpc) {\r
+ ed.setProgressState(1);\r
+ t._sendRPC('ignoreWords', [t.selectedLang, word], function(r) {\r
+ ed.setProgressState(0);\r
+ });\r
+ }\r
}\r
});\r
\r
+\r
+ if (t.editor.getParam("spellchecker_enable_learn_rpc")) {\r
+ m.add({\r
+ title : 'spellchecker.learn_word',\r
+ onclick : function() {\r
+ var word = wordSpan.innerHTML;\r
+\r
+ dom.remove(wordSpan, 1);\r
+ t._checkDone();\r
+\r
+ ed.setProgressState(1);\r
+ t._sendRPC('learnWord', [t.selectedLang, word], function(r) {\r
+ ed.setProgressState(0);\r
+ });\r
+ }\r
+ });\r
+ }\r
+\r
m.update();\r
});\r
\r
- ed.selection.select(e.target);\r
- p1 = dom.getPos(e.target);\r
- m.showMenu(p1.x, p1.y + e.target.offsetHeight - vp.y);\r
+ ed.selection.select(wordSpan);\r
+ p1 = dom.getPos(wordSpan);\r
+ m.showMenu(p1.x, p1.y + wordSpan.offsetHeight - vp.y);\r
\r
return tinymce.dom.Event.cancel(e);\r
} else\r
},\r
\r
_sendRPC : function(m, p, cb) {\r
- var t = this, url = t.editor.getParam("spellchecker_rpc_url", "{backend}");\r
-\r
- if (url == '{backend}') {\r
- t.editor.setProgressState(0);\r
- alert('Please specify: spellchecker_rpc_url');\r
- return;\r
- }\r
+ var t = this;\r
\r
JSONRequest.sendRPC({\r
- url : url,\r
+ url : t.rpcUrl,\r
method : m,\r
params : p,\r
success : cb,\r
\r
// Register plugin\r
tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin);\r
-})();
\ No newline at end of file
+})();\r