Ticket #5773: 5773.patch
File 5773.patch, 38.7 KB (added by , 13 years ago) |
---|
-
_source/plugins/scayt/plugin.js
28 28 } 29 29 return found; 30 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 31 279 32 CKEDITOR.plugins.scayt = 280 33 { 281 34 engineLoaded : false, 35 editor: '', 282 36 instances : {}, 283 37 // Data storage for SCAYT control, based on editor instances 284 38 controlInfo : {}, … … 345 99 isScaytEnabled : function( editor ) 346 100 { 347 101 var scayt_instance = this.getScayt( editor ); 348 return ( scayt_instance ) ? scayt_instance.disabled === false : false; 102 return ( scayt_instance ) ? scayt_instance.disabled === false : false; 349 103 }, 350 104 getUiTabs : function( editor ) 351 105 { … … 360 114 // "About us" should be always shown for standard config 361 115 configUiTabs[3] = "1"; 362 116 363 for ( var i = 0; i < 4; i++ ) { 117 for ( var i = 0; i < 4; i++ ) 118 { 364 119 uiTabs[i] = (typeof window.scayt != "undefined" && typeof window.scayt.uiTags != "undefined") 365 120 ? (parseInt(configUiTabs[i],10) && window.scayt.uiTags[i]) 366 121 : parseInt(configUiTabs[i],10); 367 122 } 368 123 return uiTabs; 369 124 }, 125 126 createInstance: function() 127 { 128 var editor = this; 129 var config = editor.config; 130 131 // Initialise Scayt instance. 132 var oParams = {}; 133 134 // Get the iframe. 135 oParams.srcNodeRef = editor.document.getWindow().$.frameElement; 136 137 // syntax : AppName.AppVersion@AppRevision 138 oParams.assocApp = 'CKEDITOR.' + CKEDITOR.version + '@' + CKEDITOR.revision; 139 oParams.customerid = config.scayt_customerid || '1:WvF0D4-UtPqN1-43nkD4-NKvUm2-daQqk3-LmNiI-z7Ysb4-mwry24-T8YrS3-Q2tpq2'; 140 oParams.customDictionaryIds = config.scayt_customDictionaryIds || ''; 141 oParams.userDictionaryName = config.scayt_userDictionaryName || ''; 142 oParams.sLang = config.scayt_sLang || 'en_US'; 143 144 // Introduce SCAYT onLoad callback. (#5632) 145 oParams.onLoad = function() 146 { 147 // Draw down word marker to avoid being covered by background-color style.(#5466) 148 if ( !( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) ) 149 this.addStyle( this.selectorCss(), 'padding-bottom: 2px !important;' ); 150 151 // Call scayt_control.focus when SCAYT loaded 152 // and only if editor has focus and scayt control creates at first time (#5720) 153 if ( editor.focusManager.hasFocus && !plugin.isControlRestored( editor ) ) 154 this.focus(); 155 }; 156 157 oParams.onBeforeChange = function() 158 { 159 if ( plugin.getScayt( editor ) && !editor.checkDirty() ) 160 setTimeout( function(){ editor.resetDirty(); }, 0 ); 161 }; 162 163 var scayt_custom_params = window.scayt_custom_params; 164 if ( typeof scayt_custom_params == 'object' ) 165 { 166 for ( var k in scayt_custom_params ) 167 oParams[ k ] = scayt_custom_params[ k ]; 168 } 169 170 // needs for restoring a specific scayt control settings 171 if ( plugin.getControlId( editor ) ) 172 oParams.id = plugin.getControlId( editor ); 173 174 setTimeout(function() 175 { 176 if(typeof window.scayt == "function") 177 { 178 var scayt_control = new window.scayt(oParams); 179 scayt_control.afterMarkupRemove.push( function( node ) 180 { 181 ( new CKEDITOR.dom.element( node, scayt_control.document ) ).mergeSiblings(); 182 } ); 183 // Copy config. 184 var lastInstance = plugin.instances[ editor.name ]; 185 if ( lastInstance ) 186 { 187 scayt_control.sLang = lastInstance.sLang; 188 scayt_control.option( lastInstance.option() ); 189 scayt_control.paused = lastInstance.paused; 190 } 191 plugin.instances[ editor.name ] = scayt_control; 192 scayt_control.setDisabled( plugin.isPaused( editor ) === false ); 193 editor.fire( 'showScaytState' ); 194 } 195 196 }, 100); 197 }, 198 199 onEngineLoad : function() 200 { 201 var editor = this; 202 editor.on( 'contentDom', plugin.createInstance ); 203 editor.on( 'contentDomUnload', function() 204 { 205 // Remove scripts. 206 var scripts = CKEDITOR.document.getElementsByTag( 'script' ), 207 scaytIdRegex = /^dojoIoScript(\d+)$/i, 208 scaytSrcRegex = /^https?:\/\/svc\.webspellchecker\.net\/spellcheck\/script\/ssrv\.cgi/i; 209 210 for ( var i=0; i < scripts.count(); i++ ) 211 { 212 var script = scripts.getItem( i ), 213 id = script.getId(), 214 src = script.getAttribute( 'src' ); 215 216 if ( id && src && id.match( scaytIdRegex ) && src.match( scaytSrcRegex )) 217 script.remove(); 218 } 219 }); 220 221 editor.on( 'destroy', function( ev ) 222 { 223 var editor = ev.editor, 224 scayt_instance = plugin.getScayt( editor ); 225 // SCAYT instance might already get destroyed by mode switch (#5744). 226 227 if ( !scayt_instance ) 228 return; 229 230 delete plugin.instances[ editor.name ]; 231 // store a control id for restore a specific scayt control settings 232 plugin.setControlId( editor, scayt_instance.id ); 233 scayt_instance.destroy( true ); 234 }); 235 236 // Listen to data manipulation to reflect scayt markup. 237 editor.on( 'dialogShow', function( ev ) 238 { 239 var editor = ev.editor; 240 if ( plugin.isScaytEnabled( editor ) ) 241 { 242 var instance = plugin.getScayt( editor ); 243 instance.setPaused(true); 244 } 245 }); 246 247 editor.on( 'dialogHide', function( ev ) 248 { 249 var editor = ev.editor; 250 if ( plugin.isScaytEnabled( editor ) ) 251 { 252 window.setTimeout( function() 253 { 254 var instance = plugin.getScayt( editor ); 255 256 instance.setPaused(false); 257 instance && instance.refresh(); 258 }, 1 ); 259 } 260 }); 261 262 var dataProcessor = editor.dataProcessor, 263 htmlFilter = dataProcessor && dataProcessor.htmlFilter; 264 265 if ( htmlFilter ) 266 { 267 htmlFilter.addRules( 268 { 269 elements : 270 { 271 span : function( element ) 272 { 273 if ( element.attributes[ 'data-scayt_word' ] 274 && element.attributes[ 'data-scaytid' ] ) 275 { 276 delete element.name; // Write children, but don't write this node. 277 return element; 278 } 279 } 280 }, 281 attributes : 282 { 283 'class' : function( value, element ) 284 { 285 return value.replace( /(scayt-enabled)|(scayt-disabled)/, '' ) || false; 286 } 287 } 288 } ); 289 } 290 291 // Override Image.equals method avoid CK snapshot module to add SCAYT markup to snapshots. (#5546) 292 var undoImagePrototype = CKEDITOR.plugins.undo.Image.prototype; 293 undoImagePrototype.equals = CKEDITOR.tools.override( undoImagePrototype.equals, function( org ) 294 { 295 return function( otherImage ) 296 { 297 var thisContents = this.contents, 298 otherContents = otherImage.contents; 299 var scayt_instance = plugin.getScayt( this.editor ); 300 // Making the comparison based on content without SCAYT word markers. 301 if ( scayt_instance && plugin.isScaytReady( this.editor ) ) 302 { 303 // scayt::reset might return value undefined. (#5742) 304 this.contents = scayt_instance.reset( thisContents ) || ''; 305 otherImage.contents = scayt_instance.reset( otherContents ) || ''; 306 } 307 308 var retval = org.apply( this, arguments ); 309 310 this.contents = thisContents; 311 otherImage.contents = otherContents; 312 return retval; 313 }; 314 }); 315 316 if ( editor.document ) 317 { 318 plugin.createInstance.apply(editor); 319 } 320 321 return true; 322 }, 323 370 324 loadEngine : function( editor ) 371 325 { 372 326 // SCAYT doesn't work with Firefox2, Opera and AIR. 373 327 if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 || CKEDITOR.env.opera || CKEDITOR.env.air ) 374 328 return editor.fire( 'showScaytState' ); 375 329 376 330 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.331 { 332 return this.onEngineLoad.apply(editor); 333 } 380 334 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 335 // Loading in progress. 393 336 // compose scayt url 394 337 var protocol = document.location.protocol; 395 338 // Default to 'http' for unknown. … … 399 342 var scaytUrl = editor.config.scayt_srcUrl || ( protocol + '//' + baseUrl ); 400 343 var scaytConfigBaseUrl = plugin.parseUrl( scaytUrl ).path + '/'; 401 344 402 if( window.scayt == undefined )345 if( window.scayt == undefined && this.engineLoaded != -1) 403 346 { 347 this.engineLoaded = -1; 404 348 CKEDITOR._djScaytConfig = 405 349 { 406 350 baseUrl: scaytConfigBaseUrl, … … 414 358 isDebug: false 415 359 }; 416 360 // Append javascript code. 361 417 362 CKEDITOR.document.getHead().append( 418 363 CKEDITOR.document.createElement( 'script', 419 364 { … … 429 374 else 430 375 CKEDITOR.fireOnce( 'scaytReady' ); 431 376 377 CKEDITOR.on( 'scaytReady', function() 378 { 379 this.engineLoaded = true; 380 for(var oi in CKEDITOR.instances) 381 { 382 if(CKEDITOR.instances[oi].config.scayt_autoStartup && !CKEDITOR.plugins.scayt.instances[oi]) 383 this.onEngineLoad.apply(CKEDITOR.instances[oi]); 384 } 385 }, 386 this, 387 null, 388 0 389 ); // First to run. */ 432 390 return null; 433 391 }, 392 434 393 parseUrl : function ( data ) 435 394 { 436 395 var match; … … 485 444 else if ( !editor.config.scayt_autoStartup && plugin.engineLoaded >= 0 ) // Load first time 486 445 { 487 446 this.setState( CKEDITOR.TRISTATE_DISABLED ); 447 448 editor.config.scayt_autoStartup = true; 488 449 plugin.loadEngine( editor ); 489 450 } 490 451 } … … 515 476 516 477 init : function( editor ) 517 478 { 518 // Delete span[data-scaytid] when text pasting in editor (#6921)519 479 var dataFilter = editor.dataProcessor && editor.dataProcessor.dataFilter; 520 480 var dataFilterRules = 521 481 { 522 elements : 482 elements : 483 { 484 span : function( element ) 523 485 { 524 span : function( element ) 525 { 526 var attrs = element.attributes; 527 if ( attrs && attrs[ 'data-scaytid' ] ) 528 delete element.name; 529 } 486 var attrs = element.attributes; 487 if ( attrs && attrs[ 'data-scaytid' ] ) 488 delete element.name; 530 489 } 490 } 531 491 }; 532 492 dataFilter && dataFilter.addRules( dataFilterRules ); 533 493 … … 551 511 552 512 // always added 553 513 uiMenuItems.scaytToggle = 554 555 556 557 558 514 { 515 label : lang.enable, 516 command : commandName, 517 group : menuGroup 518 }; 559 519 560 520 if ( uiTabs[0] == 1 ) 561 521 uiMenuItems.scaytOptions = … … 580 540 editor.openDialog( commandName ); 581 541 } 582 542 }; 543 583 544 if ( uiTabs[2] == 1 ) 584 545 uiMenuItems.scaytDict = 585 546 { … … 591 552 editor.openDialog( commandName ); 592 553 } 593 554 }; 594 // always added 555 556 // always added 595 557 uiMenuItems.scaytAbout = 596 558 { 597 559 label : editor.lang.scayt.about, … … 605 567 606 568 editor.addMenuItems( uiMenuItems ); 607 569 608 editor.ui.add( 'Scayt', CKEDITOR.UI_MENUBUTTON, 570 editor.ui.add( 'Scayt', CKEDITOR.UI_MENUBUTTON, 571 { 572 label : lang.title, 573 title : "Spell Check As You Type", 574 className : 'cke_button_scayt', 575 modes : { wysiwyg : 1 }, 576 onRender: function() 609 577 { 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() 578 command.on( 'state', function() 615 579 { 616 command.on( 'state', function() 617 { 618 this.setState( command.state ); 619 }, 620 this); 580 this.setState( command.state ); 621 581 }, 622 onMenu : function() 623 { 624 var isEnabled = plugin.isScaytEnabled( editor ); 582 this); 583 }, 584 onMenu : function() 585 { 586 var isEnabled = plugin.isScaytEnabled( editor ); 625 587 626 588 editor.getMenuItem( 'scaytToggle' ).label = lang[ isEnabled ? 'disable' : 'enable' ]; 627 589 628 590 var uiTabs = plugin.getUiTabs( editor ); 629 591 630 631 632 633 634 635 636 637 638 592 return { 593 scaytToggle : CKEDITOR.TRISTATE_OFF, 594 scaytOptions : isEnabled && uiTabs[0] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 595 scaytLangs : isEnabled && uiTabs[1] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 596 scaytDict : isEnabled && uiTabs[2] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 597 scaytAbout : isEnabled && uiTabs[3] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED 598 }; 599 } 600 }); 639 601 640 602 // If the "contextmenu" plugin is loaded, register the listeners. 641 603 if ( editor.contextMenu && editor.addMenuItems ) … … 643 605 editor.contextMenu.addListener( function( element, selection ) 644 606 { 645 607 if ( !plugin.isScaytEnabled( editor ) 646 || selection.getRanges()[ 0 ].checkReadOnly() )608 || ( selection.getRanges().length && selection.getCommonAncestor().isReadOnly() ) ) 647 609 return null; 648 610 649 611 var scayt_control = plugin.getScayt( editor ), 650 node = scayt_control.getScaytNode();612 node = CKEDITOR.env.mac || CKEDITOR.env.opera ? scayt_control.getScaytNode(editor.contextMenu._.target.$) : scayt_control.getScaytNode(); 651 613 652 614 if ( !node ) 653 615 return null; 654 616 655 617 var word = scayt_control.getWord( node ); 656 618 657 619 if ( !word ) 658 620 return null; 659 621 660 622 var sLang = scayt_control.getLang(), 661 _r = {},662 623 items_suggestion = window.scayt.getSuggestion( word, sLang ); 663 if ( !items_suggestion || !items_suggestion.length )664 return null;665 624 // Remove unused commands and menuitems 666 for ( var min moreSuggestions )625 for ( var i in moreSuggestions ) 667 626 { 668 delete editor._.menuItems[ m];669 delete editor._.commands[ m];627 delete editor._.menuItems[ i ]; 628 delete editor._.commands[ i ]; 670 629 } 671 for ( min mainSuggestions )630 for ( i in mainSuggestions ) 672 631 { 673 delete editor._.menuItems[ m];674 delete editor._.commands[ m];632 delete editor._.menuItems[ i ]; 633 delete editor._.commands[ i ]; 675 634 } 676 635 moreSuggestions = {}; // Reset items. 677 636 mainSuggestions = {}; … … 686 645 var contextCommands = editor.config.scayt_contextCommands || 'all'; 687 646 contextCommands = contextCommands.split( '|' ); 688 647 689 for ( var i = 0, l = items_suggestion.length; i < l; i += 1 )648 if ( items_suggestion && items_suggestion.length ) 690 649 { 691 var commandName = 'scayt_suggestion_' + items_suggestion[i].replace( ' ', '_' ); 692 var exec = ( function( el, s ) 650 for ( i = 0, l = items_suggestion.length; i < l; i += 1 ) 651 { 652 var commandName = 'scayt_suggestion_' + items_suggestion[i].replace( ' ', '_' ); 653 var exec = ( function( el, s ) 654 { 655 return { 656 exec: function() 657 { 658 scayt_control.replace(el, s); 659 } 660 }; 661 })( node, items_suggestion[i] ); 662 663 if ( i < maxSuggestions ) 693 664 { 694 return { 695 exec: function() 696 { 697 scayt_control.replace( el, s ); 698 } 699 }; 700 })( node, items_suggestion[i] ); 665 addButtonCommand( editor, 'button_' + commandName, items_suggestion[i], 666 commandName, exec, 'scayt_suggest', i + 1 ); 667 mainSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF; 668 } 669 else if ( moreSuggestionsUnable == 'on' ) 670 { 671 addButtonCommand( editor, 'button_' + commandName, items_suggestion[i], 672 commandName, exec, 'scayt_moresuggest', i + 1 ); 673 moreSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF; 674 moreSuggestionsUnableAdded = true; 675 } 676 } 701 677 702 if ( i < maxSuggestions)678 if ( moreSuggestionsUnableAdded ) 703 679 { 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; 680 // Register the More suggestions group; 681 editor.addMenuItem( 'scayt_moresuggest', 682 { 683 label : editor.lang.scayt.moreSuggestions, 684 group : 'scayt_moresuggest', 685 order : 10, 686 getItems : function() 687 { 688 return moreSuggestions; 689 } 690 }); 691 mainSuggestions[ 'scayt_moresuggest' ] = CKEDITOR.TRISTATE_OFF; 708 692 } 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 693 } 717 718 if ( moreSuggestionsUnableAdded ) 694 else 719 695 { 720 // Register the More suggestions group;721 editor.addMenuItem( 'scayt_ moresuggest',696 // "No suggestions" feature 697 editor.addMenuItem( 'scayt_nosuggest', 722 698 { 723 label : lang.moreSuggestions, 724 group : 'scayt_moresuggest', 725 order : 10, 726 getItems : function() 727 { 728 return moreSuggestions; 729 } 699 label : editor.lang.scayt.noSuggestions ? editor.lang.scayt.noSuggestions : (editor.lang.spellCheck.noSuggestions ? editor.lang.spellCheck.noSuggestions : 'No suggestions'), 700 group : 'scayt_suggest', 701 order : 1 730 702 }); 731 mainSuggestions[ 'scayt_ moresuggest' ] = CKEDITOR.TRISTATE_OFF;703 mainSuggestions[ 'scayt_nosuggest' ] = CKEDITOR.TRISTATE_OFF; 732 704 } 733 705 734 706 if ( in_array( 'all', contextCommands ) || in_array( 'ignore', contextCommands) ) 735 707 { 736 708 var ignore_command = { … … 765 737 } 766 738 767 739 if ( scayt_control.fireOnContextMenu ) 740 { 768 741 scayt_control.fireOnContextMenu( editor ); 769 742 } 743 770 744 return mainSuggestions; 771 745 }); 772 746 } 773 747 774 748 var showInitialState = function() 775 776 749 { 750 editor.removeListener( 'showScaytState', showInitialState ); 777 751 778 779 780 781 782 752 if ( !CKEDITOR.env.opera && !CKEDITOR.env.air ) 753 command.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF ); 754 else 755 command.setState( CKEDITOR.TRISTATE_DISABLED ); 756 }; 783 757 784 758 editor.on( 'showScaytState', showInitialState ); 785 759 … … 799 773 plugin.loadEngine( editor ); 800 774 }); 801 775 } 802 },803 776 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 ) 777 // Delete span[data-scaytid] when text pasting in editor (#6921) 778 editor.on( 'afterSetData', function() 779 { 780 if ( plugin.isScaytEnabled( editor ) ) 781 { 782 window.setTimeout( function() 783 { 784 var instance = plugin.getScayt( editor ); 785 786 instance && instance.refresh(); 787 }, 10 ); 788 } 789 }); 790 791 editor.on( 'beforeCommandExec', function( ev ) // Disable SCAYT before Source command execution. 792 { 793 if ( ( ev.data.name == 'source' || ev.data.name == 'newpage' || ev.data.name == 'checkspell' || ev.data.name =='templates' ) && editor.mode == 'wysiwyg' ) 809 794 { 810 if ( element.hasAttribute( 'data-scaytid' ) ) 811 return false; 812 }; 795 var scayt_instance = plugin.getScayt( editor ); 796 if ( scayt_instance ) 797 { 798 plugin.setPaused( editor, !scayt_instance.disabled ); 799 // store a control id for restore a specific scayt control settings 800 plugin.setControlId( editor, scayt_instance.id ); 801 scayt_instance.destroy( true ); 802 delete plugin.instances[ editor.name ]; 803 804 } 805 } 806 // Catch on source mode switch off (#5720) 807 else if ( ev.data.name == 'source' && editor.mode == 'source' ) 808 { 809 plugin.markControlRestore( editor ); 810 } 811 }); 812 editor.on( 'afterCommandExec', function( ev ) 813 { 814 if ( !plugin.isScaytEnabled( editor ) ) 815 return; 813 816 814 if ( editor._.elementsPath && ( elementsPathFilters = editor._.elementsPath.filters ) ) 815 elementsPathFilters.push( scaytFilter ); 817 if ( editor.mode == 'wysiwyg' && ( ev.data.name == 'undo' || ev.data.name == 'redo' ) ) 818 { 819 window.setTimeout( function() { plugin.getScayt( editor ).refresh(); }, 10 ); 820 } 821 }); 816 822 817 editor.addRemoveFormatFilter && editor.addRemoveFormatFilter( scaytFilter ); 823 editor.on( 'destroy', function( ev ) 824 { 825 var editor = ev.editor, 826 scayt_instance = plugin.getScayt( editor ); 818 827 819 }820 });821 })();828 // SCAYT instance might already get destroyed by mode switch (#5744). 829 if ( !scayt_instance ) 830 return; 822 831 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 delete plugin.instances[ editor.name ]; 833 // store a control id for restore a specific scayt control settings 834 plugin.setControlId( editor, scayt_instance.id ); 835 scayt_instance.destroy( true ); 836 }); 832 837 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 */ 838 // Listen to data manipulation to reflect scayt markup. 839 editor.on( 'afterSetData', function() 840 { 841 if ( plugin.isScaytEnabled( editor ) ) { 842 window.setTimeout( function() 843 { 844 var instance = plugin.getScayt( editor ); 845 instance && instance.refresh(); 846 }, 10 ); 847 } 848 }); 853 849 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 * @example861 * // Load SCAYT using my customer ID.862 * config.scayt_customerid = 'your-encrypted-customer-id'; 863 */ 850 // Reload spell-checking for current word after insertion completed. 851 editor.on( 'insertElement', function() 852 { 853 var scayt_instance = plugin.getScayt( editor ); 854 if ( plugin.isScaytEnabled( editor ) ) 855 { 856 // Unlock the selection before reload, SCAYT will take 857 // care selection update. 858 if ( CKEDITOR.env.ie ) 859 editor.getSelection().unlock( true ); 864 860 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 */ 861 // Return focus to the editor and refresh SCAYT markup (#5573). 862 window.setTimeout( function() 863 { 864 scayt_instance.focus(); 865 scayt_instance.refresh(); 866 }, 10 ); 867 } 868 }, this, null, 50 ); 875 869 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 */ 870 editor.on( 'insertHtml', function() 871 { 872 var scayt_instance = plugin.getScayt( editor ); 873 if ( plugin.isScaytEnabled( editor ) ) 874 { 875 // Unlock the selection before reload, SCAYT will take 876 // care selection update. 877 if ( CKEDITOR.env.ie ) 878 editor.getSelection().unlock( true ); 894 879 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 */ 880 // Return focus to the editor (#5573) 881 // Refresh SCAYT markup 882 window.setTimeout( function() 883 { 884 scayt_instance.focus(); 885 scayt_instance.refresh(); 886 }, 10 ); 887 } 888 }, this, null, 50 ); 908 889 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 */ 890 editor.on( 'scaytDialog', function( ev ) // Communication with dialog. 891 { 892 ev.data.djConfig = window.djConfig; 893 ev.data.scayt_control = plugin.getScayt( editor ); 894 ev.data.tab = openPage; 895 ev.data.scayt = window.scayt; 896 }); 897 }, 921 898 899 afterInit : function( editor ) 900 { 901 // Prevent word marker line from displaying in elements path and been removed when cleaning format. (#3570) (#4125) 902 var elementsPathFilters, 903 scaytFilter = function( element ) 904 { 905 if ( element.hasAttribute( 'data-scaytid' ) ) 906 return false; 907 }; 922 908 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 */ 909 if ( editor._.elementsPath && ( elementsPathFilters = editor._.elementsPath.filters ) ) 910 elementsPathFilters.push( scaytFilter ); 934 911 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 */ 912 editor.addRemoveFormatFilter && editor.addRemoveFormatFilter( scaytFilter ); 913 } 914 }); 915 })();