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