annotate media/js/tiny_mce/plugins/spellchecker/editor_plugin_src.js @ 197:2baadae33f2e

Got autocomplete working for the member search. Updated django and ran into a bug where url tags with comma separated kwargs starting consuming tons of CPU throughput. The work-around is to cut over to using spaces between arguments. This is now allowed to be consistent with other tags. Did some query optimization for the news app.
author Brian Neal <bgneal@gmail.com>
date Sat, 10 Apr 2010 04:32:24 +0000
parents 149c3567fec1
children 237710206167
rev   line source
bgneal@45 1 /**
bgneal@183 2 * editor_plugin_src.js
bgneal@45 3 *
bgneal@183 4 * Copyright 2009, Moxiecode Systems AB
bgneal@183 5 * Released under LGPL License.
bgneal@183 6 *
bgneal@183 7 * License: http://tinymce.moxiecode.com/license
bgneal@183 8 * Contributing: http://tinymce.moxiecode.com/contributing
bgneal@45 9 */
bgneal@45 10
bgneal@45 11 (function() {
bgneal@45 12 var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM;
bgneal@45 13
bgneal@45 14 tinymce.create('tinymce.plugins.SpellcheckerPlugin', {
bgneal@45 15 getInfo : function() {
bgneal@45 16 return {
bgneal@45 17 longname : 'Spellchecker',
bgneal@45 18 author : 'Moxiecode Systems AB',
bgneal@45 19 authorurl : 'http://tinymce.moxiecode.com',
bgneal@45 20 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker',
bgneal@45 21 version : tinymce.majorVersion + "." + tinymce.minorVersion
bgneal@45 22 };
bgneal@45 23 },
bgneal@45 24
bgneal@45 25 init : function(ed, url) {
bgneal@45 26 var t = this, cm;
bgneal@45 27
bgneal@45 28 t.url = url;
bgneal@45 29 t.editor = ed;
bgneal@45 30
bgneal@45 31 // Register commands
bgneal@45 32 ed.addCommand('mceSpellCheck', function() {
bgneal@45 33 if (!t.active) {
bgneal@45 34 ed.setProgressState(1);
bgneal@45 35 t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) {
bgneal@45 36 if (r.length > 0) {
bgneal@45 37 t.active = 1;
bgneal@45 38 t._markWords(r);
bgneal@45 39 ed.setProgressState(0);
bgneal@45 40 ed.nodeChanged();
bgneal@45 41 } else {
bgneal@45 42 ed.setProgressState(0);
bgneal@45 43 ed.windowManager.alert('spellchecker.no_mpell');
bgneal@45 44 }
bgneal@45 45 });
bgneal@45 46 } else
bgneal@45 47 t._done();
bgneal@45 48 });
bgneal@45 49
bgneal@45 50 ed.onInit.add(function() {
bgneal@45 51 if (ed.settings.content_css !== false)
bgneal@45 52 ed.dom.loadCSS(url + '/css/content.css');
bgneal@45 53 });
bgneal@45 54
bgneal@45 55 ed.onClick.add(t._showMenu, t);
bgneal@45 56 ed.onContextMenu.add(t._showMenu, t);
bgneal@45 57 ed.onBeforeGetContent.add(function() {
bgneal@45 58 if (t.active)
bgneal@45 59 t._removeWords();
bgneal@45 60 });
bgneal@45 61
bgneal@45 62 ed.onNodeChange.add(function(ed, cm) {
bgneal@45 63 cm.setActive('spellchecker', t.active);
bgneal@45 64 });
bgneal@45 65
bgneal@45 66 ed.onSetContent.add(function() {
bgneal@45 67 t._done();
bgneal@45 68 });
bgneal@45 69
bgneal@45 70 ed.onBeforeGetContent.add(function() {
bgneal@45 71 t._done();
bgneal@45 72 });
bgneal@45 73
bgneal@45 74 ed.onBeforeExecCommand.add(function(ed, cmd) {
bgneal@45 75 if (cmd == 'mceFullScreen')
bgneal@45 76 t._done();
bgneal@45 77 });
bgneal@45 78
bgneal@45 79 // Find selected language
bgneal@45 80 t.languages = {};
bgneal@45 81 each(ed.getParam('spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv', 'hash'), function(v, k) {
bgneal@45 82 if (k.indexOf('+') === 0) {
bgneal@45 83 k = k.substring(1);
bgneal@45 84 t.selectedLang = v;
bgneal@45 85 }
bgneal@45 86
bgneal@45 87 t.languages[k] = v;
bgneal@45 88 });
bgneal@45 89 },
bgneal@45 90
bgneal@45 91 createControl : function(n, cm) {
bgneal@45 92 var t = this, c, ed = t.editor;
bgneal@45 93
bgneal@45 94 if (n == 'spellchecker') {
bgneal@45 95 c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t});
bgneal@45 96
bgneal@45 97 c.onRenderMenu.add(function(c, m) {
bgneal@45 98 m.add({title : 'spellchecker.langs', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
bgneal@45 99 each(t.languages, function(v, k) {
bgneal@45 100 var o = {icon : 1}, mi;
bgneal@45 101
bgneal@45 102 o.onclick = function() {
bgneal@45 103 mi.setSelected(1);
bgneal@45 104 t.selectedItem.setSelected(0);
bgneal@45 105 t.selectedItem = mi;
bgneal@45 106 t.selectedLang = v;
bgneal@45 107 };
bgneal@45 108
bgneal@45 109 o.title = k;
bgneal@45 110 mi = m.add(o);
bgneal@45 111 mi.setSelected(v == t.selectedLang);
bgneal@45 112
bgneal@45 113 if (v == t.selectedLang)
bgneal@45 114 t.selectedItem = mi;
bgneal@45 115 })
bgneal@45 116 });
bgneal@45 117
bgneal@45 118 return c;
bgneal@45 119 }
bgneal@45 120 },
bgneal@45 121
bgneal@45 122 // Internal functions
bgneal@45 123
bgneal@45 124 _walk : function(n, f) {
bgneal@45 125 var d = this.editor.getDoc(), w;
bgneal@45 126
bgneal@45 127 if (d.createTreeWalker) {
bgneal@45 128 w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
bgneal@45 129
bgneal@45 130 while ((n = w.nextNode()) != null)
bgneal@45 131 f.call(this, n);
bgneal@45 132 } else
bgneal@45 133 tinymce.walk(n, f, 'childNodes');
bgneal@45 134 },
bgneal@45 135
bgneal@45 136 _getSeparators : function() {
bgneal@45 137 var re = '', i, str = this.editor.getParam('spellchecker_word_separator_chars', '\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}§©«®±¶·¸»¼½¾¿×÷¤\u201d\u201c');
bgneal@45 138
bgneal@45 139 // Build word separator regexp
bgneal@45 140 for (i=0; i<str.length; i++)
bgneal@45 141 re += '\\' + str.charAt(i);
bgneal@45 142
bgneal@45 143 return re;
bgneal@45 144 },
bgneal@45 145
bgneal@45 146 _getWords : function() {
bgneal@45 147 var ed = this.editor, wl = [], tx = '', lo = {};
bgneal@45 148
bgneal@45 149 // Get area text
bgneal@45 150 this._walk(ed.getBody(), function(n) {
bgneal@45 151 if (n.nodeType == 3)
bgneal@45 152 tx += n.nodeValue + ' ';
bgneal@45 153 });
bgneal@45 154
bgneal@45 155 // Split words by separator
bgneal@45 156 tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' ');
bgneal@45 157 tx = tinymce.trim(tx.replace(/(\s+)/g, ' '));
bgneal@45 158
bgneal@45 159 // Build word array and remove duplicates
bgneal@45 160 each(tx.split(' '), function(v) {
bgneal@45 161 if (!lo[v]) {
bgneal@45 162 wl.push(v);
bgneal@45 163 lo[v] = 1;
bgneal@45 164 }
bgneal@45 165 });
bgneal@45 166
bgneal@45 167 return wl;
bgneal@45 168 },
bgneal@45 169
bgneal@45 170 _removeWords : function(w) {
bgneal@45 171 var ed = this.editor, dom = ed.dom, se = ed.selection, b = se.getBookmark();
bgneal@45 172
bgneal@45 173 each(dom.select('span').reverse(), function(n) {
bgneal@45 174 if (n && (dom.hasClass(n, 'mceItemHiddenSpellWord') || dom.hasClass(n, 'mceItemHidden'))) {
bgneal@45 175 if (!w || dom.decode(n.innerHTML) == w)
bgneal@45 176 dom.remove(n, 1);
bgneal@45 177 }
bgneal@45 178 });
bgneal@45 179
bgneal@45 180 se.moveToBookmark(b);
bgneal@45 181 },
bgneal@45 182
bgneal@45 183 _markWords : function(wl) {
bgneal@45 184 var r1, r2, r3, r4, r5, w = '', ed = this.editor, re = this._getSeparators(), dom = ed.dom, nl = [];
bgneal@45 185 var se = ed.selection, b = se.getBookmark();
bgneal@45 186
bgneal@45 187 each(wl, function(v) {
bgneal@45 188 w += (w ? '|' : '') + v;
bgneal@45 189 });
bgneal@45 190
bgneal@45 191 r1 = new RegExp('([' + re + '])(' + w + ')([' + re + '])', 'g');
bgneal@45 192 r2 = new RegExp('^(' + w + ')', 'g');
bgneal@45 193 r3 = new RegExp('(' + w + ')([' + re + ']?)$', 'g');
bgneal@45 194 r4 = new RegExp('^(' + w + ')([' + re + ']?)$', 'g');
bgneal@45 195 r5 = new RegExp('(' + w + ')([' + re + '])', 'g');
bgneal@45 196
bgneal@45 197 // Collect all text nodes
bgneal@45 198 this._walk(this.editor.getBody(), function(n) {
bgneal@45 199 if (n.nodeType == 3) {
bgneal@45 200 nl.push(n);
bgneal@45 201 }
bgneal@45 202 });
bgneal@45 203
bgneal@45 204 // Wrap incorrect words in spans
bgneal@45 205 each(nl, function(n) {
bgneal@45 206 var v;
bgneal@45 207
bgneal@45 208 if (n.nodeType == 3) {
bgneal@45 209 v = n.nodeValue;
bgneal@45 210
bgneal@45 211 if (r1.test(v) || r2.test(v) || r3.test(v) || r4.test(v)) {
bgneal@45 212 v = dom.encode(v);
bgneal@45 213 v = v.replace(r5, '<span class="mceItemHiddenSpellWord">$1</span>$2');
bgneal@45 214 v = v.replace(r3, '<span class="mceItemHiddenSpellWord">$1</span>$2');
bgneal@45 215
bgneal@45 216 dom.replace(dom.create('span', {'class' : 'mceItemHidden'}, v), n);
bgneal@45 217 }
bgneal@45 218 }
bgneal@45 219 });
bgneal@45 220
bgneal@45 221 se.moveToBookmark(b);
bgneal@45 222 },
bgneal@45 223
bgneal@45 224 _showMenu : function(ed, e) {
bgneal@45 225 var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin());
bgneal@45 226
bgneal@45 227 if (!m) {
bgneal@45 228 p1 = DOM.getPos(ed.getContentAreaContainer());
bgneal@45 229 //p2 = DOM.getPos(ed.getContainer());
bgneal@45 230
bgneal@45 231 m = ed.controlManager.createDropMenu('spellcheckermenu', {
bgneal@45 232 offset_x : p1.x,
bgneal@45 233 offset_y : p1.y,
bgneal@45 234 'class' : 'mceNoIcons'
bgneal@45 235 });
bgneal@45 236
bgneal@45 237 t._menu = m;
bgneal@45 238 }
bgneal@45 239
bgneal@45 240 if (dom.hasClass(e.target, 'mceItemHiddenSpellWord')) {
bgneal@45 241 m.removeAll();
bgneal@45 242 m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
bgneal@45 243
bgneal@45 244 t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(e.target.innerHTML)], function(r) {
bgneal@45 245 m.removeAll();
bgneal@45 246
bgneal@45 247 if (r.length > 0) {
bgneal@45 248 m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
bgneal@45 249 each(r, function(v) {
bgneal@45 250 m.add({title : v, onclick : function() {
bgneal@45 251 dom.replace(ed.getDoc().createTextNode(v), e.target);
bgneal@45 252 t._checkDone();
bgneal@45 253 }});
bgneal@45 254 });
bgneal@45 255
bgneal@45 256 m.addSeparator();
bgneal@45 257 } else
bgneal@45 258 m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
bgneal@45 259
bgneal@45 260 m.add({
bgneal@45 261 title : 'spellchecker.ignore_word',
bgneal@45 262 onclick : function() {
bgneal@45 263 dom.remove(e.target, 1);
bgneal@45 264 t._checkDone();
bgneal@45 265 }
bgneal@45 266 });
bgneal@45 267
bgneal@45 268 m.add({
bgneal@45 269 title : 'spellchecker.ignore_words',
bgneal@45 270 onclick : function() {
bgneal@45 271 t._removeWords(dom.decode(e.target.innerHTML));
bgneal@45 272 t._checkDone();
bgneal@45 273 }
bgneal@45 274 });
bgneal@45 275
bgneal@45 276 m.update();
bgneal@45 277 });
bgneal@45 278
bgneal@45 279 ed.selection.select(e.target);
bgneal@45 280 p1 = dom.getPos(e.target);
bgneal@45 281 m.showMenu(p1.x, p1.y + e.target.offsetHeight - vp.y);
bgneal@45 282
bgneal@45 283 return tinymce.dom.Event.cancel(e);
bgneal@45 284 } else
bgneal@45 285 m.hideMenu();
bgneal@45 286 },
bgneal@45 287
bgneal@45 288 _checkDone : function() {
bgneal@45 289 var t = this, ed = t.editor, dom = ed.dom, o;
bgneal@45 290
bgneal@45 291 each(dom.select('span'), function(n) {
bgneal@45 292 if (n && dom.hasClass(n, 'mceItemHiddenSpellWord')) {
bgneal@45 293 o = true;
bgneal@45 294 return false;
bgneal@45 295 }
bgneal@45 296 });
bgneal@45 297
bgneal@45 298 if (!o)
bgneal@45 299 t._done();
bgneal@45 300 },
bgneal@45 301
bgneal@45 302 _done : function() {
bgneal@45 303 var t = this, la = t.active;
bgneal@45 304
bgneal@45 305 if (t.active) {
bgneal@45 306 t.active = 0;
bgneal@45 307 t._removeWords();
bgneal@45 308
bgneal@45 309 if (t._menu)
bgneal@45 310 t._menu.hideMenu();
bgneal@45 311
bgneal@45 312 if (la)
bgneal@45 313 t.editor.nodeChanged();
bgneal@45 314 }
bgneal@45 315 },
bgneal@45 316
bgneal@45 317 _sendRPC : function(m, p, cb) {
bgneal@45 318 var t = this, url = t.editor.getParam("spellchecker_rpc_url", "{backend}");
bgneal@45 319
bgneal@45 320 if (url == '{backend}') {
bgneal@45 321 t.editor.setProgressState(0);
bgneal@45 322 alert('Please specify: spellchecker_rpc_url');
bgneal@45 323 return;
bgneal@45 324 }
bgneal@45 325
bgneal@45 326 JSONRequest.sendRPC({
bgneal@45 327 url : url,
bgneal@45 328 method : m,
bgneal@45 329 params : p,
bgneal@45 330 success : cb,
bgneal@45 331 error : function(e, x) {
bgneal@45 332 t.editor.setProgressState(0);
bgneal@45 333 t.editor.windowManager.alert(e.errstr || ('Error response: ' + x.responseText));
bgneal@45 334 }
bgneal@45 335 });
bgneal@45 336 }
bgneal@45 337 });
bgneal@45 338
bgneal@45 339 // Register plugin
bgneal@45 340 tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin);
bgneal@45 341 })();