[ Index ] |
WordPress Cross Reference |
[Summary view] [Print] [Text view]
1 /** 2 * editor_plugin_src.js 3 * 4 * Copyright 2009, Moxiecode Systems AB 5 * Released under LGPL License. 6 * 7 * License: http://tinymce.moxiecode.com/license 8 * Contributing: http://tinymce.moxiecode.com/contributing 9 */ 10 11 (function() { 12 var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM; 13 14 tinymce.create('tinymce.plugins.SpellcheckerPlugin', { 15 getInfo : function() { 16 return { 17 longname : 'Spellchecker', 18 author : 'Moxiecode Systems AB', 19 authorurl : 'http://tinymce.moxiecode.com', 20 infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker', 21 version : tinymce.majorVersion + "." + tinymce.minorVersion 22 }; 23 }, 24 25 init : function(ed, url) { 26 var t = this, cm; 27 28 t.url = url; 29 t.editor = ed; 30 t.rpcUrl = ed.getParam("spellchecker_rpc_url", "{backend}"); 31 32 if (t.rpcUrl == '{backend}') { 33 // Sniff if the browser supports native spellchecking (Don't know of a better way) 34 if (tinymce.isIE) 35 return; 36 37 t.hasSupport = true; 38 39 // Disable the context menu when spellchecking is active 40 ed.onContextMenu.addToTop(function(ed, e) { 41 if (t.active) 42 return false; 43 }); 44 } 45 46 // Register commands 47 ed.addCommand('mceSpellCheck', function() { 48 if (t.rpcUrl == '{backend}') { 49 // Enable/disable native spellchecker 50 t.editor.getBody().spellcheck = t.active = !t.active; 51 return; 52 } 53 54 if (!t.active) { 55 ed.setProgressState(1); 56 t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) { 57 if (r.length > 0) { 58 t.active = 1; 59 t._markWords(r); 60 ed.setProgressState(0); 61 ed.nodeChanged(); 62 } else { 63 ed.setProgressState(0); 64 65 if (ed.getParam('spellchecker_report_no_misspellings', true)) 66 ed.windowManager.alert('spellchecker.no_mpell'); 67 } 68 }); 69 } else 70 t._done(); 71 }); 72 73 if (ed.settings.content_css !== false) 74 ed.contentCSS.push(url + '/css/content.css'); 75 76 ed.onClick.add(t._showMenu, t); 77 ed.onContextMenu.add(t._showMenu, t); 78 ed.onBeforeGetContent.add(function() { 79 if (t.active) 80 t._removeWords(); 81 }); 82 83 ed.onNodeChange.add(function(ed, cm) { 84 cm.setActive('spellchecker', t.active); 85 }); 86 87 ed.onSetContent.add(function() { 88 t._done(); 89 }); 90 91 ed.onBeforeGetContent.add(function() { 92 t._done(); 93 }); 94 95 ed.onBeforeExecCommand.add(function(ed, cmd) { 96 if (cmd == 'mceFullScreen') 97 t._done(); 98 }); 99 100 // Find selected language 101 t.languages = {}; 102 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) { 103 if (k.indexOf('+') === 0) { 104 k = k.substring(1); 105 t.selectedLang = v; 106 } 107 108 t.languages[k] = v; 109 }); 110 }, 111 112 createControl : function(n, cm) { 113 var t = this, c, ed = t.editor; 114 115 if (n == 'spellchecker') { 116 // Use basic button if we use the native spellchecker 117 if (t.rpcUrl == '{backend}') { 118 // Create simple toggle button if we have native support 119 if (t.hasSupport) 120 c = cm.createButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t}); 121 122 return c; 123 } 124 125 c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t}); 126 127 c.onRenderMenu.add(function(c, m) { 128 m.add({title : 'spellchecker.langs', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 129 t.menuItems = {}; 130 each(t.languages, function(v, k) { 131 var o = {icon : 1}, mi; 132 133 o.onclick = function() { 134 if (v == t.selectedLang) { 135 return; 136 } 137 t._updateMenu(mi); 138 t.selectedLang = v; 139 }; 140 141 o.title = k; 142 mi = m.add(o); 143 mi.setSelected(v == t.selectedLang); 144 t.menuItems[v] = mi; 145 if (v == t.selectedLang) 146 t.selectedItem = mi; 147 }); 148 }); 149 150 151 152 return c; 153 } 154 }, 155 156 setLanguage: function(lang) { 157 var t = this; 158 159 if (lang == t.selectedLang) { 160 // allowed 161 return; 162 } 163 164 if (tinymce.grep(t.languages, function(v) { return v === lang; }).length === 0) { 165 throw "Unknown language: " + lang; 166 } 167 168 t.selectedLang = lang; 169 170 // if the menu has been shown, update it as well 171 if (t.menuItems) { 172 t._updateMenu(t.menuItems[lang]); 173 } 174 175 if (t.active) { 176 // clear error in the old language. 177 t._done(); 178 179 // Don't immediately block the UI to check spelling in the new language, this is an API not a user action. 180 } 181 }, 182 183 // Internal functions 184 185 _updateMenu: function(mi) { 186 mi.setSelected(1); 187 this.selectedItem.setSelected(0); 188 this.selectedItem = mi; 189 }, 190 191 _walk : function(n, f) { 192 var d = this.editor.getDoc(), w; 193 194 if (d.createTreeWalker) { 195 w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false); 196 197 while ((n = w.nextNode()) != null) 198 f.call(this, n); 199 } else 200 tinymce.walk(n, f, 'childNodes'); 201 }, 202 203 _getSeparators : function() { 204 var re = '', i, str = this.editor.getParam('spellchecker_word_separator_chars', '\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}§©«®±¶·¸»¼½¾¿×÷¤\u201d\u201c'); 205 206 // Build word separator regexp 207 for (i=0; i<str.length; i++) 208 re += '\\' + str.charAt(i); 209 210 return re; 211 }, 212 213 _getWords : function() { 214 var ed = this.editor, wl = [], tx = '', lo = {}, rawWords = []; 215 216 // Get area text 217 this._walk(ed.getBody(), function(n) { 218 if (n.nodeType == 3) 219 tx += n.nodeValue + ' '; 220 }); 221 222 // split the text up into individual words 223 if (ed.getParam('spellchecker_word_pattern')) { 224 // look for words that match the pattern 225 rawWords = tx.match('(' + ed.getParam('spellchecker_word_pattern') + ')', 'gi'); 226 } else { 227 // Split words by separator 228 tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' '); 229 tx = tinymce.trim(tx.replace(/(\s+)/g, ' ')); 230 rawWords = tx.split(' '); 231 } 232 233 // Build word array and remove duplicates 234 each(rawWords, function(v) { 235 if (!lo[v]) { 236 wl.push(v); 237 lo[v] = 1; 238 } 239 }); 240 241 return wl; 242 }, 243 244 _removeWords : function(w) { 245 var ed = this.editor, dom = ed.dom, se = ed.selection, r = se.getRng(true); 246 247 each(dom.select('span').reverse(), function(n) { 248 if (n && (dom.hasClass(n, 'mceItemHiddenSpellWord') || dom.hasClass(n, 'mceItemHidden'))) { 249 if (!w || dom.decode(n.innerHTML) == w) 250 dom.remove(n, 1); 251 } 252 }); 253 254 se.setRng(r); 255 }, 256 257 _markWords : function(wl) { 258 var ed = this.editor, dom = ed.dom, doc = ed.getDoc(), se = ed.selection, r = se.getRng(true), nl = [], 259 w = wl.join('|'), re = this._getSeparators(), rx = new RegExp('(^|[' + re + '])(' + w + ')(?=[' + re + ']|$)', 'g'); 260 261 // Collect all text nodes 262 this._walk(ed.getBody(), function(n) { 263 if (n.nodeType == 3) { 264 nl.push(n); 265 } 266 }); 267 268 // Wrap incorrect words in spans 269 each(nl, function(n) { 270 var node, elem, txt, pos, v = n.nodeValue; 271 272 rx.lastIndex = 0; 273 if (rx.test(v)) { 274 // Encode the content 275 v = dom.encode(v); 276 // Create container element 277 elem = dom.create('span', {'class' : 'mceItemHidden'}); 278 279 // Following code fixes IE issues by creating text nodes 280 // using DOM methods instead of innerHTML. 281 // Bug #3124: <PRE> elements content is broken after spellchecking. 282 // Bug #1408: Preceding whitespace characters are removed 283 // @TODO: I'm not sure that both are still issues on IE9. 284 if (tinymce.isIE) { 285 // Enclose mispelled words with temporal tag 286 v = v.replace(rx, '$1<mcespell>$2</mcespell>'); 287 // Loop over the content finding mispelled words 288 while ((pos = v.indexOf('<mcespell>')) != -1) { 289 // Add text node for the content before the word 290 txt = v.substring(0, pos); 291 if (txt.length) { 292 node = doc.createTextNode(dom.decode(txt)); 293 elem.appendChild(node); 294 } 295 v = v.substring(pos+10); 296 pos = v.indexOf('</mcespell>'); 297 txt = v.substring(0, pos); 298 v = v.substring(pos+11); 299 // Add span element for the word 300 elem.appendChild(dom.create('span', {'class' : 'mceItemHiddenSpellWord'}, txt)); 301 } 302 // Add text node for the rest of the content 303 if (v.length) { 304 node = doc.createTextNode(dom.decode(v)); 305 elem.appendChild(node); 306 } 307 } else { 308 // Other browsers preserve whitespace characters on innerHTML usage 309 elem.innerHTML = v.replace(rx, '$1<span class="mceItemHiddenSpellWord">$2</span>'); 310 } 311 312 // Finally, replace the node with the container 313 dom.replace(elem, n); 314 } 315 }); 316 317 se.setRng(r); 318 }, 319 320 _showMenu : function(ed, e) { 321 var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin()), wordSpan = e.target; 322 323 e = 0; // Fixes IE memory leak 324 325 if (!m) { 326 m = ed.controlManager.createDropMenu('spellcheckermenu', {'class' : 'mceNoIcons'}); 327 t._menu = m; 328 } 329 330 if (dom.hasClass(wordSpan, 'mceItemHiddenSpellWord')) { 331 m.removeAll(); 332 m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 333 334 t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(wordSpan.innerHTML)], function(r) { 335 var ignoreRpc; 336 337 m.removeAll(); 338 339 if (r.length > 0) { 340 m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 341 each(r, function(v) { 342 m.add({title : v, onclick : function() { 343 dom.replace(ed.getDoc().createTextNode(v), wordSpan); 344 t._checkDone(); 345 }}); 346 }); 347 348 m.addSeparator(); 349 } else 350 m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1); 351 352 if (ed.getParam('show_ignore_words', true)) { 353 ignoreRpc = t.editor.getParam("spellchecker_enable_ignore_rpc", ''); 354 m.add({ 355 title : 'spellchecker.ignore_word', 356 onclick : function() { 357 var word = wordSpan.innerHTML; 358 359 dom.remove(wordSpan, 1); 360 t._checkDone(); 361 362 // tell the server if we need to 363 if (ignoreRpc) { 364 ed.setProgressState(1); 365 t._sendRPC('ignoreWord', [t.selectedLang, word], function(r) { 366 ed.setProgressState(0); 367 }); 368 } 369 } 370 }); 371 372 m.add({ 373 title : 'spellchecker.ignore_words', 374 onclick : function() { 375 var word = wordSpan.innerHTML; 376 377 t._removeWords(dom.decode(word)); 378 t._checkDone(); 379 380 // tell the server if we need to 381 if (ignoreRpc) { 382 ed.setProgressState(1); 383 t._sendRPC('ignoreWords', [t.selectedLang, word], function(r) { 384 ed.setProgressState(0); 385 }); 386 } 387 } 388 }); 389 } 390 391 if (t.editor.getParam("spellchecker_enable_learn_rpc")) { 392 m.add({ 393 title : 'spellchecker.learn_word', 394 onclick : function() { 395 var word = wordSpan.innerHTML; 396 397 dom.remove(wordSpan, 1); 398 t._checkDone(); 399 400 ed.setProgressState(1); 401 t._sendRPC('learnWord', [t.selectedLang, word], function(r) { 402 ed.setProgressState(0); 403 }); 404 } 405 }); 406 } 407 408 m.update(); 409 }); 410 411 p1 = DOM.getPos(ed.getContentAreaContainer()); 412 m.settings.offset_x = p1.x; 413 m.settings.offset_y = p1.y; 414 415 ed.selection.select(wordSpan); 416 p1 = dom.getPos(wordSpan); 417 m.showMenu(p1.x, p1.y + wordSpan.offsetHeight - vp.y); 418 419 return tinymce.dom.Event.cancel(e); 420 } else 421 m.hideMenu(); 422 }, 423 424 _checkDone : function() { 425 var t = this, ed = t.editor, dom = ed.dom, o; 426 427 each(dom.select('span'), function(n) { 428 if (n && dom.hasClass(n, 'mceItemHiddenSpellWord')) { 429 o = true; 430 return false; 431 } 432 }); 433 434 if (!o) 435 t._done(); 436 }, 437 438 _done : function() { 439 var t = this, la = t.active; 440 441 if (t.active) { 442 t.active = 0; 443 t._removeWords(); 444 445 if (t._menu) 446 t._menu.hideMenu(); 447 448 if (la) 449 t.editor.nodeChanged(); 450 } 451 }, 452 453 _sendRPC : function(m, p, cb) { 454 var t = this; 455 456 JSONRequest.sendRPC({ 457 url : t.rpcUrl, 458 method : m, 459 params : p, 460 success : cb, 461 error : function(e, x) { 462 t.editor.setProgressState(0); 463 t.editor.windowManager.alert(e.errstr || ('Error response: ' + x.responseText)); 464 } 465 }); 466 } 467 }); 468 469 // Register plugin 470 tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin); 471 })();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 25 01:41:18 2014 | WordPress honlapkészÃtés: online1.hu |