1 /* 2 Copyright (c) 2003-2009, 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 sc_on_cssclass = 'scayt_enabled', 15 sc_off_cssclass = 'scayt_disabled', 16 openPage = ''; 17 18 var onEngineLoad = function() 19 { 20 var editor = this; 21 dojo.requireLocalization( 'scayt', 'caption', '', 'ROOT' ); 22 23 var createInstance = function() // Create new instance every time Document is created. 24 { 25 // Initialise Scayt instance. 26 var oParams = CKEDITOR.config.scaytParams || {}; 27 oParams.srcNodeRef = editor.document.getWindow().$.frameElement; // Get the iframe. 28 // syntax : AppName.AppVersion@AppRevision 29 oParams.assocApp = "CKEDITOR." + CKEDITOR.version + "@" + CKEDITOR.revision; 30 var scayt_control = new scayt( oParams ); 31 32 // Copy config. 33 var lastInstance = plugin.instances[ editor.name ]; 34 if ( lastInstance ) 35 { 36 scayt_control.sLang = lastInstance.sLang; 37 scayt_control.option( lastInstance.option() ); 38 scayt_control.paused = lastInstance.paused; 39 } 40 41 plugin.instances[ editor.name ] = scayt_control; 42 43 try { 44 scayt_control.setDisabled( scayt_control.paused === false ); // I really don't know why it causes JS error in IE 45 } catch (e) {} 46 editor.fire( 'showScaytState' ); 47 }; 48 49 editor.on( 'contentDom', createInstance ); 50 editor.on( 'contentDomUnload', function() 51 { 52 // Remove scripts. 53 var scripts = CKEDITOR.document.getElementsByTag( 'script' ), 54 scaytIdRegex = /^dojoIoScript(\d+)$/i, 55 scaytSrcRegex = /^https?:\/\/svc\.spellchecker\.net\/spellcheck\/script\/ssrv\.cgi/i; 56 57 for ( var i=0; i < scripts.count(); i++ ) 58 { 59 var script = scripts.getItem( i ), 60 id = script.getId(), 61 src = script.getAttribute( 'src' ); 62 63 if ( id && src && id.match( scaytIdRegex ) && src.match( scaytSrcRegex )) 64 script.remove(); 65 } 66 }); 67 68 editor.on( 'beforeCommandExec', function( ev ) // Disable SCAYT before Source command execution. 69 { 70 if ( ev.data.name == 'source' && editor.mode == 'wysiwyg' ) 71 { 72 var scayt = plugin.getScayt( editor ); 73 if ( scayt ) 74 { 75 scayt.paused = !scayt.disabled; 76 scayt.setDisabled( true ); 77 } 78 } 79 }); 80 81 // Listen to data manipulation to reflect scayt markup. 82 editor.on( 'afterSetData', function() 83 { 84 if ( plugin.isScaytEnabled( editor ) ) 85 plugin.getScayt( editor ).refresh(); 86 }); 87 88 editor.on( 'scaytDialog', function( ev ) // Communication with dialog. 89 { 90 ev.data.djConfig = djConfig; 91 ev.data.scayt_control = plugin.getScayt( editor ); 92 ev.data.tab = openPage; 93 ev.data.scayt = scayt; 94 }); 95 96 var dataProcessor = editor.dataProcessor, 97 htmlFilter = dataProcessor && dataProcessor.htmlFilter; 98 if ( htmlFilter ) 99 { 100 htmlFilter.addRules( 101 { 102 elements : 103 { 104 span : function( element ) 105 { 106 if ( element.attributes.scayt_word && element.attributes.scaytid ) 107 { 108 delete element.name; // Write children, but don't write this node. 109 return element; 110 } 111 } 112 } 113 } 114 ); 115 } 116 117 if ( editor.document ) 118 createInstance(); 119 }; 120 121 CKEDITOR.plugins.scayt = 122 { 123 engineLoaded : false, 124 instances : {}, 125 getScayt : function( editor ) 126 { 127 var instance = this.instances[ editor.name ]; 128 return instance; 129 }, 130 isScaytReady : function( editor ) 131 { 132 return this.engineLoaded === true && 133 'undefined' !== typeof scayt && this.getScayt( editor ); 134 }, 135 isScaytEnabled : function( editor ) 136 { 137 var scayt = this.getScayt( editor ); 138 return ( scayt ) ? scayt.disabled === false : false; 139 }, 140 loadEngine : function( editor ) 141 { 142 if ( this.engineLoaded === true ) 143 return onEngineLoad.apply( editor ); // Add new instance. 144 else if ( this.engineLoaded == -1 ) // We are waiting. 145 return CKEDITOR.on( 'scaytReady', function(){ onEngineLoad.apply( editor );} ); // Use function(){} to avoid rejection as duplicate. 146 147 CKEDITOR.on( 'scaytReady', onEngineLoad, editor ); 148 CKEDITOR.on( 'scaytReady', function() 149 { 150 this.engineLoaded = true; 151 }, 152 this, 153 null, 154 0 ); // First to run. 155 156 this.engineLoaded = -1; // Loading in progress. 157 // assign diojo configurable vars 158 var parseUrl = function(data) 159 { 160 var m = data.match(/(.*)[\/\\]([^\/\\]+\.\w+)$/); 161 return { path: m[1], file: m[2] }; 162 }; 163 164 // compose scayt url 165 var protocol = document.location.protocol; 166 var baseUrl = "svc.spellchecker.net/spellcheck/lf/scayt/scayt.js"; 167 var scaytUrl = editor.config.scaytParams.srcScayt || 168 (protocol + "//" + baseUrl); 169 var scaytConfigBaseUrl = parseUrl(scaytUrl).path + "/"; 170 171 djScaytConfig = 172 { 173 baseUrl: scaytConfigBaseUrl, 174 addOnLoad: 175 [ 176 function() 177 { 178 CKEDITOR.fireOnce( "scaytReady" ); 179 } 180 ], 181 isDebug: false 182 }; 183 // Append javascript code. 184 CKEDITOR.document.getHead().append( 185 CKEDITOR.document.createElement( 'script', 186 { 187 attributes : 188 { 189 type : 'text/javascript', 190 src : scaytUrl 191 } 192 }) 193 ); 194 195 return null; 196 } 197 }; 198 199 var plugin = CKEDITOR.plugins.scayt; 200 201 // Context menu constructing. 202 var addButtonCommand = function( editor, buttonName, buttonLabel, commandName, command, menugroup, menuOrder ) 203 { 204 editor.addCommand( commandName, command ); 205 206 // If the "menu" plugin is loaded, register the menu item. 207 editor.addMenuItem( commandName, 208 { 209 label : buttonLabel, 210 command : commandName, 211 group : menugroup, 212 order : menuOrder 213 }); 214 }; 215 216 var commandDefinition = 217 { 218 preserveState : true, 219 220 exec: function( editor ) 221 { 222 if ( plugin.isScaytReady( editor ) ) 223 { 224 var isEnabled = plugin.isScaytEnabled( editor ); 225 226 this.setState( isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_ON ); 227 228 var scayt_control = plugin.getScayt( editor ); 229 scayt_control.setDisabled( isEnabled ); 230 } 231 else if ( !editor.config.scayt_autoStartup && plugin.engineLoaded >= 0 ) // Load first time 232 { 233 this.setState( CKEDITOR.TRISTATE_DISABLED ); 234 235 editor.on( 'showScaytState', function() 236 { 237 this.removeListener(); 238 this.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF ); 239 }, 240 this); 241 242 plugin.loadEngine( editor ); 243 } 244 } 245 }; 246 247 // Add scayt plugin. 248 CKEDITOR.plugins.add( 'scayt', 249 { 250 requires : [ 'menubutton' ], 251 252 beforeInit : function( editor ) 253 { 254 // Register own rbc menu group. 255 editor.config.menu_groups = 'scayt_suggest,scayt_moresuggest,scayt_control,' + editor.config.menu_groups; 256 }, 257 258 init : function( editor ) 259 { 260 var moreSuggestions = {}; 261 var mainSuggestions = {}; 262 263 // Scayt command. 264 var command = editor.addCommand( commandName, commandDefinition ); 265 266 // Add Options dialog. 267 CKEDITOR.dialog.add( commandName, CKEDITOR.getUrl( this.path + 'dialogs/options.js' ) ); 268 269 var menuGroup = 'scaytButton'; 270 editor.addMenuGroup( menuGroup ); 271 editor.addMenuItems( 272 { 273 scaytToggle : 274 { 275 label : editor.lang.scayt.enable, 276 command : commandName, 277 group : menuGroup 278 }, 279 280 scaytOptions : 281 { 282 label : editor.lang.scayt.options, 283 group : menuGroup, 284 onClick : function() 285 { 286 openPage = 'options'; 287 editor.openDialog( commandName ); 288 } 289 }, 290 291 scaytLangs : 292 { 293 label : editor.lang.scayt.langs, 294 group : menuGroup, 295 onClick : function() 296 { 297 openPage = 'langs'; 298 editor.openDialog( commandName ); 299 } 300 }, 301 302 scaytAbout : 303 { 304 label : editor.lang.scayt.about, 305 group : menuGroup, 306 onClick : function() 307 { 308 openPage = 'about'; 309 editor.openDialog( commandName ); 310 } 311 } 312 }); 313 314 // Disabling it on IE for now, as it's blocking the browser (#3802). 315 if ( !CKEDITOR.env.ie ) 316 { 317 editor.ui.add( 'Scayt', CKEDITOR.UI_MENUBUTTON, 318 { 319 label : editor.lang.scayt.title, 320 title : editor.lang.scayt.title, 321 className : 'cke_button_scayt', 322 onRender: function() 323 { 324 command.on( 'state', function() 325 { 326 this.setState( command.state ); 327 }, 328 this); 329 }, 330 onMenu : function() 331 { 332 var isEnabled = plugin.isScaytEnabled( editor ); 333 334 editor.getMenuItem( 'scaytToggle' ).label = editor.lang.scayt[ isEnabled ? 'disable' : 'enable' ]; 335 336 return { 337 scaytToggle : CKEDITOR.TRISTATE_OFF, 338 scaytOptions : isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 339 scaytLangs : isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED, 340 scaytAbout : isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED 341 }; 342 } 343 }); 344 } 345 346 // If the "contextmenu" plugin is loaded, register the listeners. 347 if ( editor.contextMenu && editor.addMenuItems ) 348 { 349 editor.contextMenu.addListener( function( element, selection ) 350 { 351 var scayt_control = plugin.getScayt( editor ); 352 if ( !plugin.isScaytEnabled( editor ) || !element || !element.$ ) 353 return null; 354 355 var word = scayt_control.getWord( element.$ ); 356 357 if ( !word ) 358 return null; 359 360 var sLang = scayt_control.getLang(), 361 _r = {}, 362 items_suggestion = scayt.getSuggestion( word, sLang ); 363 if (!items_suggestion || !items_suggestion.length ) 364 return null; 365 // Remove unused commands and menuitems 366 for ( i in moreSuggestions ) 367 { 368 delete editor._.menuItems[ i ]; 369 delete editor._.commands[ i ]; 370 } 371 for ( i in mainSuggestions ) 372 { 373 delete editor._.menuItems[ i ]; 374 delete editor._.commands[ i ]; 375 } 376 moreSuggestions = {}; // Reset items. 377 mainSuggestions = {}; 378 379 var moreSuggestionsUnable = false; 380 381 for ( var i = 0, l = items_suggestion.length; i < l; i += 1 ) 382 { 383 var commandName = 'scayt_suggestion_' + items_suggestion[i].replace( ' ', '_' ); 384 var exec = ( function( el, s ) 385 { 386 return { 387 exec: function( editor ) 388 { 389 scayt_control.replace(el, s); 390 } 391 }; 392 })( element.$, items_suggestion[i] ); 393 394 if ( i < editor.config.scayt_maxSuggestions ) 395 { 396 addButtonCommand( editor, 'button_' + commandName, items_suggestion[i], 397 commandName, exec, 'scayt_suggest', i + 1 ); 398 _r[ commandName ] = CKEDITOR.TRISTATE_OFF; 399 mainSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF; 400 } 401 else 402 { 403 addButtonCommand( editor, 'button_' + commandName, items_suggestion[i], 404 commandName, exec, 'scayt_moresuggest', i + 1 ); 405 moreSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF; 406 moreSuggestionsUnable = true; 407 } 408 } 409 if ( moreSuggestionsUnable ) 410 // Rgister the More suggestions group; 411 editor.addMenuItem( 'scayt_moresuggest', 412 { 413 label : editor.lang.scayt.moreSuggestions, 414 group : 'scayt_moresuggest', 415 order : 10, 416 getItems : function() 417 { 418 return moreSuggestions; 419 } 420 }); 421 422 423 var ignore_command = 424 { 425 exec: function() 426 { 427 scayt_control.ignore( element.$ ); 428 } 429 }; 430 var ignore_all_command = 431 { 432 exec: function() 433 { 434 scayt_control.ignoreAll( element.$ ); 435 } 436 }; 437 var addword_command = 438 { 439 exec: function() 440 { 441 scayt.addWordToUserDictionary( element.$ ); 442 } 443 }; 444 445 addButtonCommand( editor, 'ignore', editor.lang.scayt.ignore, 446 'scayt_ignore', ignore_command, 'scayt_control', 1); 447 addButtonCommand( editor, 'ignore_all', editor.lang.scayt.ignoreAll, 448 'scayt_ignore_all', ignore_all_command, 'scayt_control', 2); 449 addButtonCommand( editor, 'add_word', editor.lang.scayt.addWord, 450 'scayt_add_word', addword_command, 'scayt_control', 3); 451 452 mainSuggestions[ 'scayt_moresuggest' ] = CKEDITOR.TRISTATE_OFF; 453 mainSuggestions[ 'scayt_ignore' ] = CKEDITOR.TRISTATE_OFF; 454 mainSuggestions[ 'scayt_ignore_all' ] = CKEDITOR.TRISTATE_OFF; 455 mainSuggestions[ 'scayt_add_word' ] = CKEDITOR.TRISTATE_OFF; 456 457 // ** ahow ads entry point 458 // ** hide ads listener register 459 // try{ 460 //scayt_control.showBanner( editor ) 461 // }catch(err){} 462 463 return mainSuggestions; 464 }); 465 } 466 467 // Start plugin 468 if ( editor.config.scayt_autoStartup ) 469 { 470 var showInitialState = function() 471 { 472 editor.removeListener( 'showScaytState', showInitialState ); 473 command.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF ); 474 }; 475 editor.on( 'showScaytState', showInitialState ); 476 477 plugin.loadEngine( editor ); 478 } 479 } 480 }); 481 })(); 482 483 CKEDITOR.config.scaytParams = CKEDITOR.config.scaytParams || {}; 484 CKEDITOR.config.scayt_maxSuggestions = 5; 485 CKEDITOR.config.scayt_autoStartup = false; 486