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