JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
ba42fa9159c754f04c09e5afd678fdbba5939c9e
[ckeditor.git] / _source / plugins / scayt / plugin.js
1 /*\r
2 Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
3 For licensing, see LICENSE.html or http://ckeditor.com/license\r
4 */\r
5 \r
6 /**\r
7  * @fileOverview Spell Check As You Type (SCAYT).\r
8  * Button name : Scayt.\r
9  */\r
10 \r
11 (function()\r
12 {\r
13         var commandName         = 'scaytcheck',\r
14                 openPage                = '';\r
15 \r
16         // Checks if a value exists in an array\r
17         function in_array(needle, haystack)\r
18         {\r
19                 var found = false, key;\r
20                 for (key in haystack)\r
21                 {\r
22                         if ((haystack[key] === needle) || ( haystack[key] == needle))\r
23                         {\r
24                                 found = true;\r
25                                 break;\r
26                         }\r
27                 }\r
28                 return found;\r
29         }\r
30 \r
31         var onEngineLoad = function()\r
32         {\r
33                 var editor = this;\r
34 \r
35                 var createInstance = function() // Create new instance every time Document is created.\r
36                 {\r
37                         // Initialise Scayt instance.\r
38                         var oParams = {};\r
39                         // Get the iframe.\r
40                         oParams.srcNodeRef = editor.document.getWindow().$.frameElement;\r
41                         // syntax : AppName.AppVersion@AppRevision\r
42                         oParams.assocApp  = 'CKEDITOR.' + CKEDITOR.version + '@' + CKEDITOR.revision;\r
43                         oParams.customerid = editor.config.scayt_customerid  || '1:WvF0D4-UtPqN1-43nkD4-NKvUm2-daQqk3-LmNiI-z7Ysb4-mwry24-T8YrS3-Q2tpq2';\r
44                         oParams.customDictionaryIds = editor.config.scayt_customDictionaryIds || '';\r
45                         oParams.userDictionaryName = editor.config.scayt_userDictionaryName || '';\r
46                         oParams.sLang = editor.config.scayt_sLang || 'en_US';\r
47 \r
48                         // Introduce SCAYT onLoad callback. (#5632)\r
49                         oParams.onLoad = function()\r
50                                 {\r
51                                         // Draw down word marker to avoid being covered by background-color style.(#5466)\r
52                                         if ( !( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) )\r
53                                                 this.addStyle( this.selectorCss(), 'padding-bottom: 2px !important;' );\r
54 \r
55                                         // Call scayt_control.focus when SCAYT loaded\r
56                                         // and only if editor has focus and scayt control creates at first time (#5720)\r
57                                         if ( editor.focusManager.hasFocus && !plugin.isControlRestored( editor ) )\r
58                                                 this.focus();\r
59 \r
60                                 };\r
61 \r
62                         oParams.onBeforeChange = function()\r
63                         {\r
64                                 if ( plugin.getScayt( editor ) && !editor.checkDirty() )\r
65                                         setTimeout( function(){ editor.resetDirty(); } );\r
66                         };\r
67 \r
68                         var scayt_custom_params = window.scayt_custom_params;\r
69                         if ( typeof scayt_custom_params == 'object')\r
70                         {\r
71                                 for ( var k in scayt_custom_params )\r
72                                 {\r
73                                         oParams[ k ] = scayt_custom_params[ k ];\r
74                                 }\r
75                         }\r
76                         // needs for restoring a specific scayt control settings\r
77                         if ( plugin.getControlId(editor) )\r
78                                 oParams.id = plugin.getControlId(editor);\r
79 \r
80                         var scayt_control = new window.scayt( oParams );\r
81 \r
82                         scayt_control.afterMarkupRemove.push( function( node )\r
83                         {\r
84                                 ( new CKEDITOR.dom.element( node, scayt_control.document ) ).mergeSiblings();\r
85                         } );\r
86 \r
87                         // Copy config.\r
88                         var     lastInstance = plugin.instances[ editor.name ];\r
89                         if ( lastInstance )\r
90                         {\r
91                                 scayt_control.sLang = lastInstance.sLang;\r
92                                 scayt_control.option( lastInstance.option() );\r
93                                 scayt_control.paused = lastInstance.paused;\r
94                         }\r
95 \r
96                         plugin.instances[ editor.name ] = scayt_control;\r
97 \r
98                         //window.scayt.uiTags\r
99                         var menuGroup = 'scaytButton';\r
100                         var uiTabs = window.scayt.uiTags;\r
101                         var fTabs  = [];\r
102 \r
103                         for (var i = 0,l=4; i<l; i++)\r
104                             fTabs.push( uiTabs[i] && plugin.uiTabs[i] );\r
105 \r
106                         plugin.uiTabs = fTabs;\r
107                         try {\r
108                                 scayt_control.setDisabled( plugin.isPaused( editor ) === false );\r
109                         } catch (e) {}\r
110 \r
111                         editor.fire( 'showScaytState' );\r
112                 };\r
113 \r
114                 editor.on( 'contentDom', createInstance );\r
115                 editor.on( 'contentDomUnload', function()\r
116                         {\r
117                                 // Remove scripts.\r
118                                 var scripts = CKEDITOR.document.getElementsByTag( 'script' ),\r
119                                         scaytIdRegex =  /^dojoIoScript(\d+)$/i,\r
120                                         scaytSrcRegex =  /^https?:\/\/svc\.spellchecker\.net\/spellcheck\/script\/ssrv\.cgi/i;\r
121 \r
122                                 for ( var i=0; i < scripts.count(); i++ )\r
123                                 {\r
124                                         var script = scripts.getItem( i ),\r
125                                                 id = script.getId(),\r
126                                                 src = script.getAttribute( 'src' );\r
127 \r
128                                         if ( id && src && id.match( scaytIdRegex ) && src.match( scaytSrcRegex ))\r
129                                                 script.remove();\r
130                                 }\r
131                         });\r
132 \r
133                 editor.on( 'beforeCommandExec', function( ev )          // Disable SCAYT before Source command execution.\r
134                         {\r
135                                 if ( (ev.data.name == 'source' ||  ev.data.name == 'newpage') && editor.mode == 'wysiwyg' )\r
136                                 {\r
137                                         var scayt_instance = plugin.getScayt( editor );\r
138                                         if ( scayt_instance )\r
139                                         {\r
140                                                 plugin.setPaused( editor, !scayt_instance.disabled );\r
141                                                 // store a control id for restore a specific scayt control settings\r
142                                                 plugin.setControlId( editor, scayt_instance.id );\r
143                                                 scayt_instance.destroy( true );\r
144                                                 delete plugin.instances[ editor.name ];\r
145                                         }\r
146                                 }\r
147                                 // Catch on source mode switch off (#5720)\r
148                                 else if ( ev.data.name == 'source'  && editor.mode == 'source' )\r
149                                         plugin.markControlRestore( editor );\r
150                         });\r
151 \r
152                 editor.on( 'afterCommandExec', function( ev )\r
153                         {\r
154                                 if ( !plugin.isScaytEnabled( editor ) )\r
155                                         return;\r
156 \r
157                                 if ( editor.mode == 'wysiwyg' && ( ev.data.name == 'undo' || ev.data.name == 'redo' ) )\r
158                                         window.setTimeout( function() { plugin.getScayt( editor ).refresh(); }, 10 );\r
159                         });\r
160 \r
161                 editor.on( 'destroy', function( ev )\r
162                         {\r
163                                 var editor = ev.editor,\r
164                                         scayt_instance = plugin.getScayt( editor );\r
165 \r
166                                 // SCAYT instance might already get destroyed by mode switch (#5744).\r
167                                 if ( !scayt_instance )\r
168                                         return;\r
169 \r
170                                 delete plugin.instances[ editor.name ];\r
171                                 // store a control id for restore a specific scayt control settings\r
172                                 plugin.setControlId( editor, scayt_instance.id );\r
173                                 scayt_instance.destroy( true );\r
174                         });\r
175 \r
176                 // Listen to data manipulation to reflect scayt markup.\r
177                 editor.on( 'afterSetData', function()\r
178                         {\r
179                                 if ( plugin.isScaytEnabled( editor ) ) {\r
180                                         window.setTimeout( function()\r
181                                                 {\r
182                                                         var instance = plugin.getScayt( editor );\r
183                                                         instance && instance.refresh();\r
184                                                 }, 10 );\r
185                                 }\r
186                         });\r
187 \r
188                 // Reload spell-checking for current word after insertion completed.\r
189                 editor.on( 'insertElement', function()\r
190                         {\r
191                                 var scayt_instance = plugin.getScayt( editor );\r
192                                 if ( plugin.isScaytEnabled( editor ) )\r
193                                 {\r
194                                         // Unlock the selection before reload, SCAYT will take\r
195                                         // care selection update.\r
196                                         if ( CKEDITOR.env.ie )\r
197                                                 editor.getSelection().unlock( true );\r
198 \r
199                                         // Return focus to the editor and refresh SCAYT markup (#5573).\r
200                                         window.setTimeout( function()\r
201                                         {\r
202                                                 scayt_instance.focus();\r
203                                                 scayt_instance.refresh();\r
204                                         }, 10 );\r
205                                 }\r
206                         }, this, null, 50 );\r
207 \r
208                 editor.on( 'insertHtml', function()\r
209                         {\r
210                                 var scayt_instance = plugin.getScayt( editor );\r
211                                 if ( plugin.isScaytEnabled( editor ) )\r
212                                 {\r
213                                         // Unlock the selection before reload, SCAYT will take\r
214                                         // care selection update.\r
215                                         if ( CKEDITOR.env.ie )\r
216                                                 editor.getSelection().unlock( true );\r
217 \r
218                                         // Return focus to the editor (#5573)\r
219                                         // Refresh SCAYT markup\r
220                                         window.setTimeout( function()\r
221                                         {\r
222                                                 scayt_instance.focus();\r
223                                                 scayt_instance.refresh();\r
224                                         }, 10 );\r
225                                 }\r
226                         }, this, null, 50 );\r
227 \r
228                 editor.on( 'scaytDialog', function( ev )        // Communication with dialog.\r
229                         {\r
230                                 ev.data.djConfig = window.djConfig;\r
231                                 ev.data.scayt_control = plugin.getScayt( editor );\r
232                                 ev.data.tab = openPage;\r
233                                 ev.data.scayt = window.scayt;\r
234                         });\r
235 \r
236                 var dataProcessor = editor.dataProcessor,\r
237                         htmlFilter = dataProcessor && dataProcessor.htmlFilter;\r
238 \r
239                 if ( htmlFilter )\r
240                 {\r
241                         htmlFilter.addRules(\r
242                                 {\r
243                                         elements :\r
244                                         {\r
245                                                 span : function( element )\r
246                                                 {\r
247                                                         if ( element.attributes.scayt_word && element.attributes.scaytid )\r
248                                                         {\r
249                                                                 delete element.name;    // Write children, but don't write this node.\r
250                                                                 return element;\r
251                                                         }\r
252                                                 }\r
253                                         }\r
254                                 }\r
255                         );\r
256                 }\r
257 \r
258                 // Override Image.equals method avoid CK snapshot module to add SCAYT markup to snapshots. (#5546)\r
259                 var undoImagePrototype = CKEDITOR.plugins.undo.Image.prototype;\r
260                 undoImagePrototype.equals =      CKEDITOR.tools.override( undoImagePrototype.equals, function( org )\r
261                 {\r
262                         return function( otherImage )\r
263                         {\r
264                                 var thisContents = this.contents,\r
265                                         otherContents = otherImage.contents;\r
266                                 var scayt_instance = plugin.getScayt( this.editor );\r
267                                 // Making the comparison based on content without SCAYT word markers.\r
268                                 if ( scayt_instance && plugin.isScaytReady( this.editor ) )\r
269                                 {\r
270                                         // scayt::reset might return value undefined. (#5742)\r
271                                         this.contents = scayt_instance.reset( thisContents ) || '';\r
272                                         otherImage.contents = scayt_instance.reset( otherContents ) || '';\r
273                                 }\r
274 \r
275                                 var retval = org.apply( this, arguments );\r
276 \r
277                                 this.contents = thisContents;\r
278                                 otherImage.contents = otherContents;\r
279                                 return retval;\r
280                         };\r
281                 });\r
282 \r
283                 if ( editor.document )\r
284                         createInstance();\r
285         };\r
286 \r
287 CKEDITOR.plugins.scayt =\r
288         {\r
289                 engineLoaded : false,\r
290                 instances : {},\r
291                 // Data storage for SCAYT control, based on editor instances\r
292                 controlInfo : {},\r
293                 setControlInfo : function( editor, o )\r
294                 {\r
295                         if ( editor && editor.name && typeof ( this.controlInfo[ editor.name ] ) != 'object' )\r
296                                 this.controlInfo[ editor.name ] = {};\r
297 \r
298                         for ( var infoOpt in o )\r
299                                 this.controlInfo[ editor.name ][ infoOpt ] = o[ infoOpt ];\r
300                 },\r
301                 isControlRestored : function ( editor )\r
302                 {\r
303                         if ( editor &&\r
304                                         editor.name &&\r
305                                         this.controlInfo[ editor.name ] )\r
306                         {\r
307                                 return this.controlInfo[ editor.name ].restored ;\r
308                         }\r
309                         return false;\r
310                 },\r
311                 markControlRestore : function ( editor )\r
312                 {\r
313                         this.setControlInfo( editor,{ restored:true } );\r
314                 },\r
315                 setControlId: function (editor, id)\r
316                 {\r
317                         this.setControlInfo( editor,{ id:id } );\r
318                 },\r
319                 getControlId: function (editor)\r
320                 {\r
321                         if ( editor &&\r
322                                         editor.name &&\r
323                                         this.controlInfo[ editor.name ] &&\r
324                                         this.controlInfo[ editor.name ].id )\r
325                         {\r
326                                 return this.controlInfo[ editor.name ].id;\r
327                         }\r
328                         return null;\r
329                 },\r
330                 setPaused: function ( editor , bool )\r
331                 {\r
332                         this.setControlInfo( editor,{ paused:bool } );\r
333                 },\r
334                 isPaused: function (editor)\r
335                 {\r
336                         if ( editor &&\r
337                                         editor.name &&\r
338                                         this.controlInfo[editor.name] )\r
339                         {\r
340                                 return this.controlInfo[editor.name].paused ;\r
341                         }\r
342                         return undefined;\r
343                 },\r
344                 getScayt : function( editor )\r
345                 {\r
346                         return this.instances[ editor.name ];\r
347                 },\r
348                 isScaytReady : function( editor )\r
349                 {\r
350                         return this.engineLoaded === true &&\r
351                                 'undefined' !== typeof window.scayt && this.getScayt( editor );\r
352                 },\r
353                 isScaytEnabled : function( editor )\r
354                 {\r
355                         var scayt_instance = this.getScayt( editor );\r
356                         return ( scayt_instance ) ? scayt_instance.disabled === false : false;\r
357                 },\r
358                 loadEngine : function( editor )\r
359                 {\r
360                         // SCAYT doesn't work with Firefox2, Opera.\r
361                         if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 || CKEDITOR.env.opera )\r
362                                 return editor.fire( 'showScaytState' );\r
363 \r
364                         if ( this.engineLoaded === true )\r
365                                 return onEngineLoad.apply( editor );    // Add new instance.\r
366                         else if ( this.engineLoaded == -1 )                     // We are waiting.\r
367                                 return CKEDITOR.on( 'scaytReady', function(){ onEngineLoad.apply( editor ); } );        // Use function(){} to avoid rejection as duplicate.\r
368 \r
369                         CKEDITOR.on( 'scaytReady', onEngineLoad, editor );\r
370                         CKEDITOR.on( 'scaytReady', function()\r
371                                 {\r
372                                         this.engineLoaded = true;\r
373                                 },\r
374                                 this,\r
375                                 null,\r
376                                 0\r
377                         );      // First to run.\r
378 \r
379                         this.engineLoaded = -1; // Loading in progress.\r
380 \r
381                         // compose scayt url\r
382                         var protocol = document.location.protocol;\r
383                         // Default to 'http' for unknown.\r
384                         protocol = protocol.search( /https?:/) != -1? protocol : 'http:';\r
385                         var baseUrl  = 'svc.spellchecker.net/spellcheck31/lf/scayt24/loader__base.js';\r
386 \r
387                         var scaytUrl  =  editor.config.scayt_srcUrl || ( protocol + '//' + baseUrl );\r
388                         var scaytConfigBaseUrl =  plugin.parseUrl( scaytUrl ).path +  '/';\r
389 \r
390                         if( window.scayt == undefined )\r
391                         {\r
392                                 CKEDITOR._djScaytConfig =\r
393                                 {\r
394                                         baseUrl: scaytConfigBaseUrl,\r
395                                         addOnLoad:\r
396                                         [\r
397                                                 function()\r
398                                                 {\r
399                                                         CKEDITOR.fireOnce( 'scaytReady' );\r
400                                                 }\r
401                                         ],\r
402                                         isDebug: false\r
403                                 };\r
404                                 // Append javascript code.\r
405                                 CKEDITOR.document.getHead().append(\r
406                                         CKEDITOR.document.createElement( 'script',\r
407                                                 {\r
408                                                         attributes :\r
409                                                                 {\r
410                                                                         type : 'text/javascript',\r
411                                                                         async : 'true',\r
412                                                                         src : scaytUrl\r
413                                                                 }\r
414                                                 })\r
415                                 );\r
416                         }\r
417                         else\r
418                                 CKEDITOR.fireOnce( 'scaytReady' );\r
419 \r
420                         return null;\r
421                 },\r
422                 parseUrl : function ( data )\r
423                 {\r
424                         var match;\r
425                         if ( data.match && ( match = data.match(/(.*)[\/\\](.*?\.\w+)$/) ) )\r
426                                 return { path: match[1], file: match[2] };\r
427                         else\r
428                                 return data;\r
429                 }\r
430         };\r
431 \r
432         var plugin = CKEDITOR.plugins.scayt;\r
433 \r
434         // Context menu constructing.\r
435         var addButtonCommand = function( editor, buttonName, buttonLabel, commandName, command, menugroup, menuOrder )\r
436         {\r
437                 editor.addCommand( commandName, command );\r
438 \r
439                 // If the "menu" plugin is loaded, register the menu item.\r
440                 editor.addMenuItem( commandName,\r
441                         {\r
442                                 label : buttonLabel,\r
443                                 command : commandName,\r
444                                 group : menugroup,\r
445                                 order : menuOrder\r
446                         });\r
447         };\r
448 \r
449         var commandDefinition =\r
450         {\r
451                 preserveState : true,\r
452                 editorFocus : false,\r
453 \r
454                 exec: function( editor )\r
455                 {\r
456                         var autoStartup = editor.config.scayt_autoStartup;\r
457                         autoStartup = ( autoStartup == undefined ) || autoStartup;\r
458 \r
459                         if ( plugin.isScaytReady( editor ) )\r
460                         {\r
461                                 var isEnabled = plugin.isScaytEnabled( editor );\r
462 \r
463                                 this.setState( isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_ON );\r
464 \r
465                                 var scayt_control = plugin.getScayt( editor );\r
466                                 // the place where the status of editor focus should be restored\r
467                                 // after there will be ability to store its state before SCAYT button click\r
468                                 // if (storedFocusState is focused )\r
469                                 //   scayt_control.focus();\r
470                                 //\r
471                                 // now focus is set certainly\r
472                                 scayt_control.focus( );\r
473                                 scayt_control.setDisabled( isEnabled );\r
474                         }\r
475                         else if ( !autoStartup && plugin.engineLoaded >= 0 )    // Load first time\r
476                         {\r
477                                 this.setState( CKEDITOR.TRISTATE_DISABLED );\r
478                                 plugin.loadEngine( editor );\r
479                         }\r
480                 }\r
481         };\r
482 \r
483         // Add scayt plugin.\r
484         CKEDITOR.plugins.add( 'scayt',\r
485         {\r
486                 requires : [ 'menubutton' ],\r
487 \r
488                 beforeInit : function( editor )\r
489                 {\r
490                         var items_order = editor.config.scayt_contextMenuItemsOrder\r
491                                         || 'suggest|moresuggest|control',\r
492                                 items_order_str = "";\r
493 \r
494                         items_order = items_order.split( '|' );\r
495 \r
496                         if ( items_order && items_order.length )\r
497                         {\r
498                                 for ( var pos in items_order )\r
499                                         items_order_str += 'scayt_' + items_order[ pos ] + ( items_order.length != parseInt( pos, 10 ) + 1 ? ',' : '' );\r
500                         }\r
501 \r
502                         // Register scayt rbc menu group.\r
503                         if ( editor.config.scayt_contextMenuOntop )\r
504                                 // Put it on top of all context menu items\r
505                                 editor.config.menu_groups =  items_order_str + ',' + editor.config.menu_groups;\r
506                         else\r
507                                 // Put it down\r
508                                 editor.config.menu_groups = editor.config.menu_groups + ',' +items_order_str;\r
509                 },\r
510 \r
511                 init : function( editor )\r
512                 {\r
513                         var moreSuggestions = {};\r
514                         var mainSuggestions = {};\r
515 \r
516                         // Scayt command.\r
517                         var command = editor.addCommand( commandName, commandDefinition );\r
518 \r
519                         // Add Options dialog.\r
520                         CKEDITOR.dialog.add( commandName, CKEDITOR.getUrl( this.path + 'dialogs/options.js' ) );\r
521                         // read ui tags\r
522                         var confuiTabs = editor.config.scayt_uiTabs || '1,1,1';\r
523                         var uiTabs =[];\r
524                         // string to array convert\r
525                         confuiTabs = confuiTabs.split( ',' );\r
526                         // check array length ! always must be 3 filled with 1 or 0\r
527                         for (var i=0,l=3; i<l; i++)\r
528                         {\r
529                                 var flag = parseInt(confuiTabs[i] || '1' ,10);\r
530                                 uiTabs.push( flag );\r
531                         }\r
532 \r
533                         var menuGroup = 'scaytButton';\r
534                         editor.addMenuGroup( menuGroup );\r
535                         // combine menu items to render\r
536                         var uiMuneItems = {};\r
537 \r
538                         // always added\r
539                         uiMuneItems.scaytToggle =\r
540                                 {\r
541                                         label : editor.lang.scayt.enable,\r
542                                         command : commandName,\r
543                                         group : menuGroup\r
544                                 };\r
545 \r
546                         if (uiTabs[0] == 1)\r
547                                 uiMuneItems.scaytOptions =\r
548                                 {\r
549                                         label : editor.lang.scayt.options,\r
550                                         group : menuGroup,\r
551                                         onClick : function()\r
552                                         {\r
553                                                 openPage = 'options';\r
554                                                 editor.openDialog( commandName );\r
555                                         }\r
556                                 };\r
557 \r
558                         if (uiTabs[1] == 1)\r
559                                 uiMuneItems.scaytLangs =\r
560                                 {\r
561                                         label : editor.lang.scayt.langs,\r
562                                         group : menuGroup,\r
563                                         onClick : function()\r
564                                         {\r
565                                                 openPage = 'langs';\r
566                                                 editor.openDialog( commandName );\r
567                                         }\r
568                                 };\r
569                         if (uiTabs[2] == 1)\r
570                                 uiMuneItems.scaytDict =\r
571                                 {\r
572                                         label : editor.lang.scayt.dictionariesTab,\r
573                                         group : menuGroup,\r
574                                         onClick : function()\r
575                                         {\r
576                                                 openPage = 'dictionaries';\r
577                                                 editor.openDialog( commandName );\r
578                                         }\r
579                                 };\r
580                         // always added\r
581                         uiMuneItems.scaytAbout =\r
582                                 {\r
583                                         label : editor.lang.scayt.about,\r
584                                         group : menuGroup,\r
585                                         onClick : function()\r
586                                         {\r
587                                                 openPage = 'about';\r
588                                                 editor.openDialog( commandName );\r
589                                         }\r
590                                 }\r
591                         ;\r
592 \r
593                         uiTabs[3] = 1; // about us tab is always on\r
594                         plugin.uiTabs = uiTabs;\r
595 \r
596                         editor.addMenuItems( uiMuneItems );\r
597 \r
598                                 editor.ui.add( 'Scayt', CKEDITOR.UI_MENUBUTTON,\r
599                                         {\r
600                                                 label : editor.lang.scayt.title,\r
601                                                 title : CKEDITOR.env.opera ? editor.lang.scayt.opera_title : editor.lang.scayt.title,\r
602                                                 className : 'cke_button_scayt',\r
603                                                 onRender: function()\r
604                                                 {\r
605                                                         command.on( 'state', function()\r
606                                                         {\r
607                                                                 this.setState( command.state );\r
608                                                         },\r
609                                                         this);\r
610                                                 },\r
611                                                 onMenu : function()\r
612                                                 {\r
613                                                         var isEnabled = plugin.isScaytEnabled( editor );\r
614 \r
615                                                         editor.getMenuItem( 'scaytToggle' ).label = editor.lang.scayt[ isEnabled ? 'disable' : 'enable' ];\r
616 \r
617                                                         return {\r
618                                                                 scaytToggle  : CKEDITOR.TRISTATE_OFF,\r
619                                                                 scaytOptions : isEnabled && plugin.uiTabs[0] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,\r
620                                                                 scaytLangs   : isEnabled && plugin.uiTabs[1] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,\r
621                                                                 scaytDict    : isEnabled && plugin.uiTabs[2] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,\r
622                                                                 scaytAbout   : isEnabled && plugin.uiTabs[3] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED\r
623                                                         };\r
624                                                 }\r
625                                         });\r
626 \r
627                         // If the "contextmenu" plugin is loaded, register the listeners.\r
628                         if ( editor.contextMenu && editor.addMenuItems )\r
629                         {\r
630                                 editor.contextMenu.addListener( function(  )\r
631                                         {\r
632                                                 if ( !plugin.isScaytEnabled( editor ) )\r
633                                                         return null;\r
634 \r
635                                                 var scayt_control = plugin.getScayt( editor ),\r
636                                                         node = scayt_control.getScaytNode();\r
637 \r
638                                                 if ( !node )\r
639                                                         return null;\r
640 \r
641                                                         var word = scayt_control.getWord( node );\r
642 \r
643                                                 if ( !word )\r
644                                                         return null;\r
645 \r
646                                                 var sLang = scayt_control.getLang(),\r
647                                                         _r = {},\r
648                                                         items_suggestion = window.scayt.getSuggestion( word, sLang );\r
649                                                 if ( !items_suggestion || !items_suggestion.length )\r
650                                                         return null;\r
651                                                 // Remove unused commands and menuitems\r
652                                                 for ( i in moreSuggestions )\r
653                                                 {\r
654                                                         delete editor._.menuItems[ i ];\r
655                                                         delete editor._.commands[ i ];\r
656                                                 }\r
657                                                 for ( i in mainSuggestions )\r
658                                                 {\r
659                                                         delete editor._.menuItems[ i ];\r
660                                                         delete editor._.commands[ i ];\r
661                                                 }\r
662                                                 moreSuggestions = {};           // Reset items.\r
663                                                 mainSuggestions = {};\r
664 \r
665                                                 var moreSuggestionsUnable = editor.config.scayt_moreSuggestions || 'on';\r
666                                                 var moreSuggestionsUnableAdded = false;\r
667 \r
668                                                 var maxSuggestions = editor.config.scayt_maxSuggestions;\r
669                                                 ( typeof maxSuggestions != 'number' ) && ( maxSuggestions = 5 );\r
670                                                 !maxSuggestions && ( maxSuggestions = items_suggestion.length );\r
671 \r
672                                                 var contextCommands = editor.config.scayt_contextCommands || 'all';\r
673                                                 contextCommands = contextCommands.split( '|' );\r
674 \r
675                                                 for ( var i = 0, l = items_suggestion.length; i < l; i += 1 )\r
676                                                 {\r
677                                                         var commandName = 'scayt_suggestion_' + items_suggestion[i].replace( ' ', '_' );\r
678                                                         var exec = ( function( el, s )\r
679                                                                 {\r
680                                                                         return {\r
681                                                                                 exec: function()\r
682                                                                                 {\r
683                                                                                         scayt_control.replace(el, s);\r
684                                                                                 }\r
685                                                                         };\r
686                                                                 })( node, items_suggestion[i] );\r
687 \r
688                                                         if ( i < maxSuggestions )\r
689                                                         {\r
690                                                                 addButtonCommand( editor, 'button_' + commandName, items_suggestion[i],\r
691                                                                         commandName, exec, 'scayt_suggest', i + 1 );\r
692                                                                 _r[ commandName ] = CKEDITOR.TRISTATE_OFF;\r
693                                                                 mainSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF;\r
694                                                         }\r
695                                                         else if ( moreSuggestionsUnable == 'on' )\r
696                                                         {\r
697                                                                 addButtonCommand( editor, 'button_' + commandName, items_suggestion[i],\r
698                                                                         commandName, exec, 'scayt_moresuggest', i + 1 );\r
699                                                                 moreSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF;\r
700                                                                 moreSuggestionsUnableAdded = true;\r
701                                                         }\r
702                                                 }\r
703 \r
704                                                 if ( moreSuggestionsUnableAdded )\r
705                                                 {\r
706                                                         // Register the More suggestions group;\r
707                                                         editor.addMenuItem( 'scayt_moresuggest',\r
708                                                         {\r
709                                                                 label : editor.lang.scayt.moreSuggestions,\r
710                                                                 group : 'scayt_moresuggest',\r
711                                                                 order : 10,\r
712                                                                 getItems : function()\r
713                                                                 {\r
714                                                                         return moreSuggestions;\r
715                                                                 }\r
716                                                         });\r
717                                                         mainSuggestions[ 'scayt_moresuggest' ] = CKEDITOR.TRISTATE_OFF;\r
718                                                 }\r
719 \r
720                                                 if ( in_array( 'all', contextCommands )  || in_array( 'ignore', contextCommands)  )\r
721                                                 {\r
722                                                         var ignore_command = {\r
723                                                                 exec: function(){\r
724                                                                         scayt_control.ignore( node );\r
725                                                                 }\r
726                                                         };\r
727                                                         addButtonCommand( editor, 'ignore', editor.lang.scayt.ignore, 'scayt_ignore', ignore_command, 'scayt_control', 1 );\r
728                                                         mainSuggestions[ 'scayt_ignore' ] = CKEDITOR.TRISTATE_OFF;\r
729                                                 }\r
730 \r
731                                                 if ( in_array( 'all', contextCommands )  || in_array( 'ignoreall', contextCommands ) )\r
732                                                 {\r
733                                                         var ignore_all_command = {\r
734                                                                 exec: function(){\r
735                                                                         scayt_control.ignoreAll( node );\r
736                                                                 }\r
737                                                         };\r
738                                                         addButtonCommand(editor, 'ignore_all', editor.lang.scayt.ignoreAll, 'scayt_ignore_all', ignore_all_command, 'scayt_control', 2);\r
739                                                         mainSuggestions['scayt_ignore_all'] = CKEDITOR.TRISTATE_OFF;\r
740                                                 }\r
741 \r
742                                                 if ( in_array( 'all', contextCommands )  || in_array( 'add', contextCommands ) )\r
743                                                 {\r
744                                                         var addword_command = {\r
745                                                                 exec: function(){\r
746                                                                         window.scayt.addWordToUserDictionary( node );\r
747                                                                 }\r
748                                                         };\r
749                                                         addButtonCommand(editor, 'add_word', editor.lang.scayt.addWord, 'scayt_add_word', addword_command, 'scayt_control', 3);\r
750                                                         mainSuggestions['scayt_add_word'] = CKEDITOR.TRISTATE_OFF;\r
751                                                 }\r
752 \r
753                                                 if ( scayt_control.fireOnContextMenu )\r
754                                                         scayt_control.fireOnContextMenu( editor );\r
755 \r
756                                                 return mainSuggestions;\r
757                                         });\r
758                         }\r
759 \r
760                         var showInitialState = function()\r
761                                 {\r
762                                         editor.removeListener( 'showScaytState', showInitialState );\r
763 \r
764                                         if ( !CKEDITOR.env.opera )\r
765                                                 command.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );\r
766                                         else\r
767                                                 command.setState( CKEDITOR.TRISTATE_DISABLED );\r
768                                 };\r
769 \r
770                         editor.on( 'showScaytState', showInitialState );\r
771 \r
772                         if ( CKEDITOR.env.opera )\r
773                         {\r
774                                 editor.on( 'instanceReady', function()\r
775                                 {\r
776                                         showInitialState();\r
777                                 });\r
778                         }\r
779 \r
780                         // Start plugin\r
781                         var autoStartup = editor.config.scayt_autoStartup;\r
782                         if ( ( autoStartup == undefined ) || autoStartup )\r
783                         {\r
784                                 editor.on( 'instanceReady', function()\r
785                                 {\r
786                                         plugin.loadEngine( editor );\r
787                                 });\r
788                         }\r
789                 },\r
790 \r
791                 afterInit : function( editor )\r
792                 {\r
793                         // Prevent word marker line from displaying in elements path and been removed when cleaning format. (#3570) (#4125)\r
794                         var elementsPathFilters,\r
795                                         scaytFilter = function( element )\r
796                                         {\r
797                                                 if ( element.hasAttribute( 'scaytid' ) )\r
798                                                         return false;\r
799                                         };\r
800 \r
801                         if ( editor._.elementsPath && ( elementsPathFilters = editor._.elementsPath.filters ) )\r
802                                 elementsPathFilters.push( scaytFilter );\r
803 \r
804                         editor.addRemoveFormatFilter && editor.addRemoveFormatFilter( scaytFilter );\r
805 \r
806                 }\r
807         });\r
808 })();\r
809 \r
810 /**\r
811  * If enabled (true), turns on SCAYT automatically after loading the editor.\r
812  * @name CKEDITOR.config.scayt_autoStartup\r
813  * @type Boolean\r
814  * @default true\r
815  * @example\r
816  * config.scayt_autoStartup = false;\r
817  */\r
818 \r
819 /**\r
820  * Defines the number of SCAYT suggestions to show in the main context menu.\r
821  * The possible values are:\r
822  * <ul>\r
823  *      <li>0 (zero): All suggestions are displayed in the main context menu.</li>\r
824  *      <li>Positive number: The maximum number of suggestions to shown in context\r
825  *              menu. Other entries will be shown in "More Suggestions" sub-menu.</li>\r
826  *      <li>Negative number: No suggestions are shown in the main context menu. All\r
827  *              entries will be listed in the "Suggestions" sub-menu.</li>\r
828  * </ul>\r
829  * @name CKEDITOR.config.scayt_maxSuggestions\r
830  * @type Number\r
831  * @default 5\r
832  * @example\r
833  * // Display only three suggestions in the main context menu.\r
834  * config.scayt_maxSuggestions = 3;\r
835  * @example\r
836  * // Do not show the suggestions directly.\r
837  * config.scayt_maxSuggestions = -1;\r
838  */\r
839 \r
840 /**\r
841  * Sets the customer ID for SCAYT. Required for migration from free version\r
842  * with banner to paid version.\r
843  * @name CKEDITOR.config.scayt_customerid\r
844  * @type String\r
845  * @default ''\r
846  * @example\r
847  * // Load SCAYT using my customer ID.\r
848  * config.scayt_customerid  = 'your-encrypted-customer-id';\r
849  */\r
850 \r
851 /**\r
852  * Enables/disables the "More Suggestions" sub-menu in the context menu.\r
853  * The possible values are "on" or "off".\r
854  * @name CKEDITOR.config.scayt_moreSuggestions\r
855  * @type String\r
856  * @default 'on'\r
857  * @example\r
858  * // Disables the "More Suggestions" sub-menu.\r
859  * config.scayt_moreSuggestions = 'off';\r
860  */\r
861 \r
862 /**\r
863  * Customizes the display of SCAYT context menu commands ("Add Word", "Ignore"\r
864  * and "Ignore All"). It must be a string with one or more of the following\r
865  * words separated by a pipe ("|"):\r
866  * <ul>\r
867  *      <li>"off": disables all options.</li>\r
868  *      <li>"all": enables all options.</li>\r
869  *      <li>"ignore": enables the "Ignore" option.</li>\r
870  *      <li>"ignoreall": enables the "Ignore All" option.</li>\r
871  *      <li>"add": enables the "Add Word" option.</li>\r
872  * </ul>\r
873  * @name CKEDITOR.config.scayt_contextCommands\r
874  * @type String\r
875  * @default 'all'\r
876  * @example\r
877  * // Show only "Add Word" and "Ignore All" in the context menu.\r
878  * config.scayt_contextCommands = 'add|ignoreall';\r
879  */\r
880 \r
881 /**\r
882  * Sets the default spellchecking language for SCAYT.\r
883  * @name CKEDITOR.config.scayt_sLang\r
884  * @type String\r
885  * @default 'en_US'\r
886  * @example\r
887  * // Sets SCAYT to German.\r
888  * config.scayt_sLang = 'de_DE';\r
889  */\r
890 \r
891 /**\r
892  * Sets the visibility of the SCAYT tabs in the settings dialog and toolbar\r
893  * button. The value must contain a "1" (enabled) or "0" (disabled) number for\r
894  * each of the following entries, in this precise order, separated by a\r
895  * comma (","): "Options", "Languages" and "Dictionary".\r
896  * @name CKEDITOR.config.scayt_uiTabs\r
897  * @type String\r
898  * @default '1,1,1'\r
899  * @example\r
900  * // Hide the "Languages" tab.\r
901  * config.scayt_uiTabs = '1,0,1';\r
902  */\r
903 \r
904 \r
905 /**\r
906  * Set the URL to SCAYT core. Required to switch to licensed version of SCAYT application.\r
907  * Further details at http://wiki.spellchecker.net/doku.php?id=3rd:wysiwyg:fckeditor:wscckf3l .\r
908  * @name CKEDITOR.config.scayt_srcUrl\r
909  * @type String\r
910  * @default ''\r
911  * @example\r
912  * config.scayt_srcUrl = "http://my-host/spellcheck/lf/scayt/scayt.js";\r
913  */\r
914 \r
915 /**\r
916  * Links SCAYT to custom dictionaries. It's a string containing dictionary ids\r
917  * separared by commas (","). Available only for licensed version.\r
918  * Further details at http://wiki.spellchecker.net/doku.php?id=custom_dictionary_support .\r
919  * @name CKEDITOR.config.scayt_customDictionaryIds\r
920  * @type String\r
921  * @default ''\r
922  * @example\r
923  * config.scayt_customDictionaryIds = '3021,3456,3478"';\r
924  */\r
925 \r
926 /**\r
927  * Makes it possible to activate a custom dictionary on SCAYT. The user\r
928  * dictionary name must be used. Available only for licensed version.\r
929  * @name CKEDITOR.config.scayt_userDictionaryName\r
930  * @type String\r
931  * @default ''\r
932  * @example\r
933  * config.scayt_userDictionaryName = 'MyDictionary';\r
934  */\r
935 \r
936 /**\r
937  * Makes it possible to place the SCAYT context menu items above others.\r
938  * @name CKEDITOR.config.scayt_contextMenuOntop\r
939  * @type Boolean\r
940  * @default false\r
941  * @example\r
942  * config.scayt_contextMenuOntop = true;\r
943  */\r
944 \r
945 /**\r
946  * Define order of placing of SCAYT context menu items by groups.\r
947  * It must be a string with one or more of the following\r
948  * words separated by a pipe ("|"):\r
949  * <ul>\r
950  *     <li>'suggest'     - main suggestion word list,</li>\r
951  *     <li>'moresuggest' - more suggestions word list,</li>\r
952  *     <li>'control'     - SCAYT commands, such as 'Ignore' and 'Add Word'</li>\r
953  * </ul>\r
954  *\r
955  * @name CKEDITOR.config.scayt_contextMenuItemsOrder\r
956  * @type String\r
957  * @default 'suggest|moresuggest|control'\r
958  * @example\r
959  * config.scayt_contextMenuItemsOrder = 'moresuggest|control|suggest';\r
960  */\r