[ Index ]

WordPress Cross Reference

title

Body

[close]

/wp-includes/js/tinymce/plugins/spellchecker/ -> editor_plugin_src.js (source)

   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  })();


Generated: Tue Mar 25 01:41:18 2014 WordPress honlapkészítés: online1.hu