--- /dev/null
+/*\r
+Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
+For licensing, see LICENSE.html or http://ckeditor.com/license\r
+*/\r
+\r
+/**\r
+ * @fileOverview Spell Check As You Type (SCAYT).\r
+ * Button name : Scayt.\r
+ */\r
+\r
+(function()\r
+{\r
+ var commandName = 'scaytcheck',\r
+ openPage = '';\r
+\r
+ // Checks if a value exists in an array\r
+ function in_array( needle, haystack )\r
+ {\r
+ var found = 0,\r
+ key;\r
+ for ( key in haystack )\r
+ {\r
+ if ( haystack[ key ] == needle )\r
+ {\r
+ found = 1;\r
+ break;\r
+ }\r
+ }\r
+ return found;\r
+ }\r
+\r
+ var onEngineLoad = function()\r
+ {\r
+ var editor = this;\r
+\r
+ var createInstance = function() // Create new instance every time Document is created.\r
+ {\r
+ var config = editor.config;\r
+ // Initialise Scayt instance.\r
+ var oParams = {};\r
+ // Get the iframe.\r
+ oParams.srcNodeRef = editor.document.getWindow().$.frameElement;\r
+ // syntax : AppName.AppVersion@AppRevision\r
+ oParams.assocApp = 'CKEDITOR.' + CKEDITOR.version + '@' + CKEDITOR.revision;\r
+ oParams.customerid = config.scayt_customerid || '1:WvF0D4-UtPqN1-43nkD4-NKvUm2-daQqk3-LmNiI-z7Ysb4-mwry24-T8YrS3-Q2tpq2';\r
+ oParams.customDictionaryIds = config.scayt_customDictionaryIds || '';\r
+ oParams.userDictionaryName = config.scayt_userDictionaryName || '';\r
+ oParams.sLang = config.scayt_sLang || 'en_US';\r
+\r
+ // Introduce SCAYT onLoad callback. (#5632)\r
+ oParams.onLoad = function()\r
+ {\r
+ // Draw down word marker to avoid being covered by background-color style.(#5466)\r
+ if ( !( CKEDITOR.env.ie && CKEDITOR.env.version < 8 ) )\r
+ this.addStyle( this.selectorCss(), 'padding-bottom: 2px !important;' );\r
+\r
+ // Call scayt_control.focus when SCAYT loaded\r
+ // and only if editor has focus and scayt control creates at first time (#5720)\r
+ if ( editor.focusManager.hasFocus && !plugin.isControlRestored( editor ) )\r
+ this.focus();\r
+\r
+ };\r
+\r
+ oParams.onBeforeChange = function()\r
+ {\r
+ if ( plugin.getScayt( editor ) && !editor.checkDirty() )\r
+ setTimeout( function(){ editor.resetDirty(); }, 0 );\r
+ };\r
+\r
+ var scayt_custom_params = window.scayt_custom_params;\r
+ if ( typeof scayt_custom_params == 'object' )\r
+ {\r
+ for ( var k in scayt_custom_params )\r
+ oParams[ k ] = scayt_custom_params[ k ];\r
+ }\r
+ // needs for restoring a specific scayt control settings\r
+ if ( plugin.getControlId( editor ) )\r
+ oParams.id = plugin.getControlId( editor );\r
+\r
+ var scayt_control = new window.scayt( oParams );\r
+\r
+ scayt_control.afterMarkupRemove.push( function( node )\r
+ {\r
+ ( new CKEDITOR.dom.element( node, scayt_control.document ) ).mergeSiblings();\r
+ } );\r
+\r
+ // Copy config.\r
+ var lastInstance = plugin.instances[ editor.name ];\r
+ if ( lastInstance )\r
+ {\r
+ scayt_control.sLang = lastInstance.sLang;\r
+ scayt_control.option( lastInstance.option() );\r
+ scayt_control.paused = lastInstance.paused;\r
+ }\r
+\r
+ plugin.instances[ editor.name ] = scayt_control;\r
+\r
+ try {\r
+ scayt_control.setDisabled( plugin.isPaused( editor ) === false );\r
+ } catch (e) {}\r
+\r
+ editor.fire( 'showScaytState' );\r
+ };\r
+\r
+ editor.on( 'contentDom', createInstance );\r
+ editor.on( 'contentDomUnload', function()\r
+ {\r
+ // Remove scripts.\r
+ var scripts = CKEDITOR.document.getElementsByTag( 'script' ),\r
+ scaytIdRegex = /^dojoIoScript(\d+)$/i,\r
+ scaytSrcRegex = /^https?:\/\/svc\.spellchecker\.net\/spellcheck\/script\/ssrv\.cgi/i;\r
+\r
+ for ( var i=0; i < scripts.count(); i++ )\r
+ {\r
+ var script = scripts.getItem( i ),\r
+ id = script.getId(),\r
+ src = script.getAttribute( 'src' );\r
+\r
+ if ( id && src && id.match( scaytIdRegex ) && src.match( scaytSrcRegex ))\r
+ script.remove();\r
+ }\r
+ });\r
+\r
+ editor.on( 'beforeCommandExec', function( ev ) // Disable SCAYT before Source command execution.\r
+ {\r
+ if ( ( ev.data.name == 'source' || ev.data.name == 'newpage' ) && editor.mode == 'wysiwyg' )\r
+ {\r
+ var scayt_instance = plugin.getScayt( editor );\r
+ if ( scayt_instance )\r
+ {\r
+ plugin.setPaused( editor, !scayt_instance.disabled );\r
+ // store a control id for restore a specific scayt control settings\r
+ plugin.setControlId( editor, scayt_instance.id );\r
+ scayt_instance.destroy( true );\r
+ delete plugin.instances[ editor.name ];\r
+ }\r
+ }\r
+ // Catch on source mode switch off (#5720)\r
+ else if ( ev.data.name == 'source' && editor.mode == 'source' )\r
+ plugin.markControlRestore( editor );\r
+ });\r
+\r
+ editor.on( 'afterCommandExec', function( ev )\r
+ {\r
+ if ( !plugin.isScaytEnabled( editor ) )\r
+ return;\r
+\r
+ if ( editor.mode == 'wysiwyg' && ( ev.data.name == 'undo' || ev.data.name == 'redo' ) )\r
+ window.setTimeout( function() { plugin.getScayt( editor ).refresh(); }, 10 );\r
+ });\r
+\r
+ editor.on( 'destroy', function( ev )\r
+ {\r
+ var editor = ev.editor,\r
+ scayt_instance = plugin.getScayt( editor );\r
+\r
+ // SCAYT instance might already get destroyed by mode switch (#5744).\r
+ if ( !scayt_instance )\r
+ return;\r
+\r
+ delete plugin.instances[ editor.name ];\r
+ // store a control id for restore a specific scayt control settings\r
+ plugin.setControlId( editor, scayt_instance.id );\r
+ scayt_instance.destroy( true );\r
+ });\r
+\r
+ // Listen to data manipulation to reflect scayt markup.\r
+ editor.on( 'afterSetData', function()\r
+ {\r
+ if ( plugin.isScaytEnabled( editor ) ) {\r
+ window.setTimeout( function()\r
+ {\r
+ var instance = plugin.getScayt( editor );\r
+ instance && instance.refresh();\r
+ }, 10 );\r
+ }\r
+ });\r
+\r
+ // Reload spell-checking for current word after insertion completed.\r
+ editor.on( 'insertElement', function()\r
+ {\r
+ var scayt_instance = plugin.getScayt( editor );\r
+ if ( plugin.isScaytEnabled( editor ) )\r
+ {\r
+ // Unlock the selection before reload, SCAYT will take\r
+ // care selection update.\r
+ if ( CKEDITOR.env.ie )\r
+ editor.getSelection().unlock( true );\r
+\r
+ // Return focus to the editor and refresh SCAYT markup (#5573).\r
+ window.setTimeout( function()\r
+ {\r
+ scayt_instance.focus();\r
+ scayt_instance.refresh();\r
+ }, 10 );\r
+ }\r
+ }, this, null, 50 );\r
+\r
+ editor.on( 'insertHtml', function()\r
+ {\r
+ var scayt_instance = plugin.getScayt( editor );\r
+ if ( plugin.isScaytEnabled( editor ) )\r
+ {\r
+ // Unlock the selection before reload, SCAYT will take\r
+ // care selection update.\r
+ if ( CKEDITOR.env.ie )\r
+ editor.getSelection().unlock( true );\r
+\r
+ // Return focus to the editor (#5573)\r
+ // Refresh SCAYT markup\r
+ window.setTimeout( function()\r
+ {\r
+ scayt_instance.focus();\r
+ scayt_instance.refresh();\r
+ }, 10 );\r
+ }\r
+ }, this, null, 50 );\r
+\r
+ editor.on( 'scaytDialog', function( ev ) // Communication with dialog.\r
+ {\r
+ ev.data.djConfig = window.djConfig;\r
+ ev.data.scayt_control = plugin.getScayt( editor );\r
+ ev.data.tab = openPage;\r
+ ev.data.scayt = window.scayt;\r
+ });\r
+\r
+ var dataProcessor = editor.dataProcessor,\r
+ htmlFilter = dataProcessor && dataProcessor.htmlFilter;\r
+\r
+ if ( htmlFilter )\r
+ {\r
+ htmlFilter.addRules(\r
+ {\r
+ elements :\r
+ {\r
+ span : function( element )\r
+ {\r
+ if ( element.attributes[ 'data-scayt_word' ]\r
+ && element.attributes[ 'data-scaytid' ] )\r
+ {\r
+ delete element.name; // Write children, but don't write this node.\r
+ return element;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ );\r
+ }\r
+\r
+ // Override Image.equals method avoid CK snapshot module to add SCAYT markup to snapshots. (#5546)\r
+ var undoImagePrototype = CKEDITOR.plugins.undo.Image.prototype;\r
+ undoImagePrototype.equals = CKEDITOR.tools.override( undoImagePrototype.equals, function( org )\r
+ {\r
+ return function( otherImage )\r
+ {\r
+ var thisContents = this.contents,\r
+ otherContents = otherImage.contents;\r
+ var scayt_instance = plugin.getScayt( this.editor );\r
+ // Making the comparison based on content without SCAYT word markers.\r
+ if ( scayt_instance && plugin.isScaytReady( this.editor ) )\r
+ {\r
+ // scayt::reset might return value undefined. (#5742)\r
+ this.contents = scayt_instance.reset( thisContents ) || '';\r
+ otherImage.contents = scayt_instance.reset( otherContents ) || '';\r
+ }\r
+\r
+ var retval = org.apply( this, arguments );\r
+\r
+ this.contents = thisContents;\r
+ otherImage.contents = otherContents;\r
+ return retval;\r
+ };\r
+ });\r
+\r
+ if ( editor.document )\r
+ createInstance();\r
+ };\r
+\r
+CKEDITOR.plugins.scayt =\r
+ {\r
+ engineLoaded : false,\r
+ instances : {},\r
+ // Data storage for SCAYT control, based on editor instances\r
+ controlInfo : {},\r
+ setControlInfo : function( editor, o )\r
+ {\r
+ if ( editor && editor.name && typeof ( this.controlInfo[ editor.name ] ) != 'object' )\r
+ this.controlInfo[ editor.name ] = {};\r
+\r
+ for ( var infoOpt in o )\r
+ this.controlInfo[ editor.name ][ infoOpt ] = o[ infoOpt ];\r
+ },\r
+ isControlRestored : function( editor )\r
+ {\r
+ if ( editor &&\r
+ editor.name &&\r
+ this.controlInfo[ editor.name ] )\r
+ {\r
+ return this.controlInfo[ editor.name ].restored ;\r
+ }\r
+ return false;\r
+ },\r
+ markControlRestore : function( editor )\r
+ {\r
+ this.setControlInfo( editor, { restored:true } );\r
+ },\r
+ setControlId: function( editor, id )\r
+ {\r
+ this.setControlInfo( editor, { id:id } );\r
+ },\r
+ getControlId: function( editor )\r
+ {\r
+ if ( editor &&\r
+ editor.name &&\r
+ this.controlInfo[ editor.name ] &&\r
+ this.controlInfo[ editor.name ].id )\r
+ {\r
+ return this.controlInfo[ editor.name ].id;\r
+ }\r
+ return null;\r
+ },\r
+ setPaused: function( editor , bool )\r
+ {\r
+ this.setControlInfo( editor, { paused:bool } );\r
+ },\r
+ isPaused: function( editor )\r
+ {\r
+ if ( editor &&\r
+ editor.name &&\r
+ this.controlInfo[editor.name] )\r
+ {\r
+ return this.controlInfo[editor.name].paused;\r
+ }\r
+ return undefined;\r
+ },\r
+ getScayt : function( editor )\r
+ {\r
+ return this.instances[ editor.name ];\r
+ },\r
+ isScaytReady : function( editor )\r
+ {\r
+ return this.engineLoaded === true &&\r
+ 'undefined' !== typeof window.scayt && this.getScayt( editor );\r
+ },\r
+ isScaytEnabled : function( editor )\r
+ {\r
+ var scayt_instance = this.getScayt( editor );\r
+ return ( scayt_instance ) ? scayt_instance.disabled === false : false;\r
+ },\r
+ getUiTabs : function( editor )\r
+ {\r
+ var uiTabs = [];\r
+\r
+ // read UI tabs value from config\r
+ var configUiTabs = editor.config.scayt_uiTabs || "1,1,1";\r
+\r
+ // convert string to array\r
+ configUiTabs = configUiTabs.split( ',' );\r
+\r
+ // "About us" should be always shown for standard config\r
+ configUiTabs[3] = "1";\r
+\r
+ for ( var i = 0; i < 4; i++ ) {\r
+ uiTabs[i] = (typeof window.scayt != "undefined" && typeof window.scayt.uiTags != "undefined")\r
+ ? (parseInt(configUiTabs[i],10) && window.scayt.uiTags[i])\r
+ : parseInt(configUiTabs[i],10);\r
+ }\r
+ return uiTabs;\r
+ },\r
+ loadEngine : function( editor )\r
+ {\r
+ // SCAYT doesn't work with Firefox2, Opera and AIR.\r
+ if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 || CKEDITOR.env.opera || CKEDITOR.env.air )\r
+ return editor.fire( 'showScaytState' );\r
+\r
+ if ( this.engineLoaded === true )\r
+ return onEngineLoad.apply( editor ); // Add new instance.\r
+ else if ( this.engineLoaded == -1 ) // We are waiting.\r
+ return CKEDITOR.on( 'scaytReady', function(){ onEngineLoad.apply( editor ); } ); // Use function(){} to avoid rejection as duplicate.\r
+\r
+ CKEDITOR.on( 'scaytReady', onEngineLoad, editor );\r
+ CKEDITOR.on( 'scaytReady', function()\r
+ {\r
+ this.engineLoaded = true;\r
+ },\r
+ this,\r
+ null,\r
+ 0\r
+ ); // First to run.\r
+\r
+ this.engineLoaded = -1; // Loading in progress.\r
+\r
+ // compose scayt url\r
+ var protocol = document.location.protocol;\r
+ // Default to 'http' for unknown.\r
+ protocol = protocol.search( /https?:/) != -1? protocol : 'http:';\r
+ var baseUrl = 'svc.spellchecker.net/scayt26/loader__base.js';\r
+\r
+ var scaytUrl = editor.config.scayt_srcUrl || ( protocol + '//' + baseUrl );\r
+ var scaytConfigBaseUrl = plugin.parseUrl( scaytUrl ).path + '/';\r
+\r
+ if( window.scayt == undefined )\r
+ {\r
+ CKEDITOR._djScaytConfig =\r
+ {\r
+ baseUrl: scaytConfigBaseUrl,\r
+ addOnLoad:\r
+ [\r
+ function()\r
+ {\r
+ CKEDITOR.fireOnce( 'scaytReady' );\r
+ }\r
+ ],\r
+ isDebug: false\r
+ };\r
+ // Append javascript code.\r
+ CKEDITOR.document.getHead().append(\r
+ CKEDITOR.document.createElement( 'script',\r
+ {\r
+ attributes :\r
+ {\r
+ type : 'text/javascript',\r
+ async : 'true',\r
+ src : scaytUrl\r
+ }\r
+ })\r
+ );\r
+ }\r
+ else\r
+ CKEDITOR.fireOnce( 'scaytReady' );\r
+\r
+ return null;\r
+ },\r
+ parseUrl : function ( data )\r
+ {\r
+ var match;\r
+ if ( data.match && ( match = data.match(/(.*)[\/\\](.*?\.\w+)$/) ) )\r
+ return { path: match[1], file: match[2] };\r
+ else\r
+ return data;\r
+ }\r
+ };\r
+\r
+ var plugin = CKEDITOR.plugins.scayt;\r
+\r
+ // Context menu constructing.\r
+ var addButtonCommand = function( editor, buttonName, buttonLabel, commandName, command, menugroup, menuOrder )\r
+ {\r
+ editor.addCommand( commandName, command );\r
+\r
+ // If the "menu" plugin is loaded, register the menu item.\r
+ editor.addMenuItem( commandName,\r
+ {\r
+ label : buttonLabel,\r
+ command : commandName,\r
+ group : menugroup,\r
+ order : menuOrder\r
+ });\r
+ };\r
+\r
+ var commandDefinition =\r
+ {\r
+ preserveState : true,\r
+ editorFocus : false,\r
+ canUndo : false,\r
+\r
+ exec: function( editor )\r
+ {\r
+ if ( plugin.isScaytReady( editor ) )\r
+ {\r
+ var isEnabled = plugin.isScaytEnabled( editor );\r
+\r
+ this.setState( isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_ON );\r
+\r
+ var scayt_control = plugin.getScayt( editor );\r
+ // the place where the status of editor focus should be restored\r
+ // after there will be ability to store its state before SCAYT button click\r
+ // if (storedFocusState is focused )\r
+ // scayt_control.focus();\r
+ //\r
+ // now focus is set certainly\r
+ scayt_control.focus();\r
+ scayt_control.setDisabled( isEnabled );\r
+ }\r
+ else if ( !editor.config.scayt_autoStartup && plugin.engineLoaded >= 0 ) // Load first time\r
+ {\r
+ this.setState( CKEDITOR.TRISTATE_DISABLED );\r
+ plugin.loadEngine( editor );\r
+ }\r
+ }\r
+ };\r
+\r
+ // Add scayt plugin.\r
+ CKEDITOR.plugins.add( 'scayt',\r
+ {\r
+ requires : [ 'menubutton' ],\r
+\r
+ beforeInit : function( editor )\r
+ {\r
+ var items_order = editor.config.scayt_contextMenuItemsOrder\r
+ || 'suggest|moresuggest|control',\r
+ items_order_str = "";\r
+\r
+ items_order = items_order.split( '|' );\r
+\r
+ if ( items_order && items_order.length )\r
+ {\r
+ for ( var pos = 0 ; pos < items_order.length ; pos++ )\r
+ items_order_str += 'scayt_' + items_order[ pos ] + ( items_order.length != parseInt( pos, 10 ) + 1 ? ',' : '' );\r
+ }\r
+\r
+ // Put it on top of all context menu items (#5717)\r
+ editor.config.menu_groups = items_order_str + ',' + editor.config.menu_groups;\r
+ },\r
+\r
+ init : function( editor )\r
+ {\r
+ // Delete span[data-scaytid] when text pasting in editor (#6921)\r
+ var dataFilter = editor.dataProcessor && editor.dataProcessor.dataFilter;\r
+ var dataFilterRules =\r
+ {\r
+ elements :\r
+ {\r
+ span : function( element )\r
+ {\r
+ var attrs = element.attributes;\r
+ if ( attrs && attrs[ 'data-scaytid' ] )\r
+ delete element.name;\r
+ }\r
+ }\r
+ };\r
+ dataFilter && dataFilter.addRules( dataFilterRules );\r
+\r
+ var moreSuggestions = {},\r
+ mainSuggestions = {};\r
+\r
+ // Scayt command.\r
+ var command = editor.addCommand( commandName, commandDefinition );\r
+\r
+ // Add Options dialog.\r
+ CKEDITOR.dialog.add( commandName, CKEDITOR.getUrl( this.path + 'dialogs/options.js' ) );\r
+\r
+ var uiTabs = plugin.getUiTabs( editor );\r
+\r
+ var menuGroup = 'scaytButton';\r
+ editor.addMenuGroup( menuGroup );\r
+ // combine menu items to render\r
+ var uiMenuItems = {};\r
+\r
+ var lang = editor.lang.scayt;\r
+\r
+ // always added\r
+ uiMenuItems.scaytToggle =\r
+ {\r
+ label : lang.enable,\r
+ command : commandName,\r
+ group : menuGroup\r
+ };\r
+\r
+ if ( uiTabs[0] == 1 )\r
+ uiMenuItems.scaytOptions =\r
+ {\r
+ label : lang.options,\r
+ group : menuGroup,\r
+ onClick : function()\r
+ {\r
+ openPage = 'options';\r
+ editor.openDialog( commandName );\r
+ }\r
+ };\r
+\r
+ if ( uiTabs[1] == 1 )\r
+ uiMenuItems.scaytLangs =\r
+ {\r
+ label : lang.langs,\r
+ group : menuGroup,\r
+ onClick : function()\r
+ {\r
+ openPage = 'langs';\r
+ editor.openDialog( commandName );\r
+ }\r
+ };\r
+ if ( uiTabs[2] == 1 )\r
+ uiMenuItems.scaytDict =\r
+ {\r
+ label : lang.dictionariesTab,\r
+ group : menuGroup,\r
+ onClick : function()\r
+ {\r
+ openPage = 'dictionaries';\r
+ editor.openDialog( commandName );\r
+ }\r
+ };\r
+ // always added\r
+ uiMenuItems.scaytAbout =\r
+ {\r
+ label : editor.lang.scayt.about,\r
+ group : menuGroup,\r
+ onClick : function()\r
+ {\r
+ openPage = 'about';\r
+ editor.openDialog( commandName );\r
+ }\r
+ };\r
+\r
+ editor.addMenuItems( uiMenuItems );\r
+\r
+ editor.ui.add( 'Scayt', CKEDITOR.UI_MENUBUTTON,\r
+ {\r
+ label : lang.title,\r
+ title : CKEDITOR.env.opera ? lang.opera_title : lang.title,\r
+ className : 'cke_button_scayt',\r
+ modes : { wysiwyg : 1 },\r
+ onRender: function()\r
+ {\r
+ command.on( 'state', function()\r
+ {\r
+ this.setState( command.state );\r
+ },\r
+ this);\r
+ },\r
+ onMenu : function()\r
+ {\r
+ var isEnabled = plugin.isScaytEnabled( editor );\r
+\r
+ editor.getMenuItem( 'scaytToggle' ).label = lang[ isEnabled ? 'disable' : 'enable' ];\r
+\r
+ var uiTabs = plugin.getUiTabs( editor );\r
+\r
+ return {\r
+ scaytToggle : CKEDITOR.TRISTATE_OFF,\r
+ scaytOptions : isEnabled && uiTabs[0] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,\r
+ scaytLangs : isEnabled && uiTabs[1] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,\r
+ scaytDict : isEnabled && uiTabs[2] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,\r
+ scaytAbout : isEnabled && uiTabs[3] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED\r
+ };\r
+ }\r
+ });\r
+\r
+ // If the "contextmenu" plugin is loaded, register the listeners.\r
+ if ( editor.contextMenu && editor.addMenuItems )\r
+ {\r
+ editor.contextMenu.addListener( function( element, selection )\r
+ {\r
+ if ( !plugin.isScaytEnabled( editor )\r
+ || selection.getRanges()[ 0 ].checkReadOnly() )\r
+ return null;\r
+\r
+ var scayt_control = plugin.getScayt( editor ),\r
+ node = scayt_control.getScaytNode();\r
+\r
+ if ( !node )\r
+ return null;\r
+\r
+ var word = scayt_control.getWord( node );\r
+\r
+ if ( !word )\r
+ return null;\r
+\r
+ var sLang = scayt_control.getLang(),\r
+ _r = {},\r
+ items_suggestion = window.scayt.getSuggestion( word, sLang );\r
+ if ( !items_suggestion || !items_suggestion.length )\r
+ return null;\r
+ // Remove unused commands and menuitems\r
+ for ( i in moreSuggestions )\r
+ {\r
+ delete editor._.menuItems[ i ];\r
+ delete editor._.commands[ i ];\r
+ }\r
+ for ( i in mainSuggestions )\r
+ {\r
+ delete editor._.menuItems[ i ];\r
+ delete editor._.commands[ i ];\r
+ }\r
+ moreSuggestions = {}; // Reset items.\r
+ mainSuggestions = {};\r
+\r
+ var moreSuggestionsUnable = editor.config.scayt_moreSuggestions || 'on';\r
+ var moreSuggestionsUnableAdded = false;\r
+\r
+ var maxSuggestions = editor.config.scayt_maxSuggestions;\r
+ ( typeof maxSuggestions != 'number' ) && ( maxSuggestions = 5 );\r
+ !maxSuggestions && ( maxSuggestions = items_suggestion.length );\r
+\r
+ var contextCommands = editor.config.scayt_contextCommands || 'all';\r
+ contextCommands = contextCommands.split( '|' );\r
+\r
+ for ( var i = 0, l = items_suggestion.length; i < l; i += 1 )\r
+ {\r
+ var commandName = 'scayt_suggestion_' + items_suggestion[i].replace( ' ', '_' );\r
+ var exec = ( function( el, s )\r
+ {\r
+ return {\r
+ exec: function()\r
+ {\r
+ scayt_control.replace( el, s );\r
+ }\r
+ };\r
+ })( node, items_suggestion[i] );\r
+\r
+ if ( i < maxSuggestions )\r
+ {\r
+ addButtonCommand( editor, 'button_' + commandName, items_suggestion[i],\r
+ commandName, exec, 'scayt_suggest', i + 1 );\r
+ _r[ commandName ] = CKEDITOR.TRISTATE_OFF;\r
+ mainSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF;\r
+ }\r
+ else if ( moreSuggestionsUnable == 'on' )\r
+ {\r
+ addButtonCommand( editor, 'button_' + commandName, items_suggestion[i],\r
+ commandName, exec, 'scayt_moresuggest', i + 1 );\r
+ moreSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF;\r
+ moreSuggestionsUnableAdded = true;\r
+ }\r
+ }\r
+\r
+ if ( moreSuggestionsUnableAdded )\r
+ {\r
+ // Register the More suggestions group;\r
+ editor.addMenuItem( 'scayt_moresuggest',\r
+ {\r
+ label : lang.moreSuggestions,\r
+ group : 'scayt_moresuggest',\r
+ order : 10,\r
+ getItems : function()\r
+ {\r
+ return moreSuggestions;\r
+ }\r
+ });\r
+ mainSuggestions[ 'scayt_moresuggest' ] = CKEDITOR.TRISTATE_OFF;\r
+ }\r
+\r
+ if ( in_array( 'all', contextCommands ) || in_array( 'ignore', contextCommands) )\r
+ {\r
+ var ignore_command = {\r
+ exec: function(){\r
+ scayt_control.ignore( node );\r
+ }\r
+ };\r
+ addButtonCommand( editor, 'ignore', lang.ignore, 'scayt_ignore', ignore_command, 'scayt_control', 1 );\r
+ mainSuggestions[ 'scayt_ignore' ] = CKEDITOR.TRISTATE_OFF;\r
+ }\r
+\r
+ if ( in_array( 'all', contextCommands ) || in_array( 'ignoreall', contextCommands ) )\r
+ {\r
+ var ignore_all_command = {\r
+ exec: function(){\r
+ scayt_control.ignoreAll( node );\r
+ }\r
+ };\r
+ addButtonCommand(editor, 'ignore_all', lang.ignoreAll, 'scayt_ignore_all', ignore_all_command, 'scayt_control', 2);\r
+ mainSuggestions['scayt_ignore_all'] = CKEDITOR.TRISTATE_OFF;\r
+ }\r
+\r
+ if ( in_array( 'all', contextCommands ) || in_array( 'add', contextCommands ) )\r
+ {\r
+ var addword_command = {\r
+ exec: function(){\r
+ window.scayt.addWordToUserDictionary( node );\r
+ }\r
+ };\r
+ addButtonCommand(editor, 'add_word', lang.addWord, 'scayt_add_word', addword_command, 'scayt_control', 3);\r
+ mainSuggestions['scayt_add_word'] = CKEDITOR.TRISTATE_OFF;\r
+ }\r
+\r
+ if ( scayt_control.fireOnContextMenu )\r
+ scayt_control.fireOnContextMenu( editor );\r
+\r
+ return mainSuggestions;\r
+ });\r
+ }\r
+\r
+ var showInitialState = function()\r
+ {\r
+ editor.removeListener( 'showScaytState', showInitialState );\r
+\r
+ if ( !CKEDITOR.env.opera && !CKEDITOR.env.air )\r
+ command.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );\r
+ else\r
+ command.setState( CKEDITOR.TRISTATE_DISABLED );\r
+ };\r
+\r
+ editor.on( 'showScaytState', showInitialState );\r
+\r
+ if ( CKEDITOR.env.opera || CKEDITOR.env.air )\r
+ {\r
+ editor.on( 'instanceReady', function()\r
+ {\r
+ showInitialState();\r
+ });\r
+ }\r
+\r
+ // Start plugin\r
+ if ( editor.config.scayt_autoStartup )\r
+ {\r
+ editor.on( 'instanceReady', function()\r
+ {\r
+ plugin.loadEngine( editor );\r
+ });\r
+ }\r
+ },\r
+\r
+ afterInit : function( editor )\r
+ {\r
+ // Prevent word marker line from displaying in elements path and been removed when cleaning format. (#3570) (#4125)\r
+ var elementsPathFilters,\r
+ scaytFilter = function( element )\r
+ {\r
+ if ( element.hasAttribute( 'data-scaytid' ) )\r
+ return false;\r
+ };\r
+\r
+ if ( editor._.elementsPath && ( elementsPathFilters = editor._.elementsPath.filters ) )\r
+ elementsPathFilters.push( scaytFilter );\r
+\r
+ editor.addRemoveFormatFilter && editor.addRemoveFormatFilter( scaytFilter );\r
+\r
+ }\r
+ });\r
+})();\r
+\r
+/**\r
+ * If enabled (true), turns on SCAYT automatically after loading the editor.\r
+ * @name CKEDITOR.config.scayt_autoStartup\r
+ * @type Boolean\r
+ * @default false\r
+ * @example\r
+ * config.scayt_autoStartup = true;\r
+ */\r
+\r
+/**\r
+ * Defines the number of SCAYT suggestions to show in the main context menu.\r
+ * The possible values are:\r
+ * <ul>\r
+ * <li>0 (zero): All suggestions are displayed in the main context menu.</li>\r
+ * <li>Positive number: The maximum number of suggestions to shown in context\r
+ * menu. Other entries will be shown in "More Suggestions" sub-menu.</li>\r
+ * <li>Negative number: No suggestions are shown in the main context menu. All\r
+ * entries will be listed in the "Suggestions" sub-menu.</li>\r
+ * </ul>\r
+ * @name CKEDITOR.config.scayt_maxSuggestions\r
+ * @type Number\r
+ * @default 5\r
+ * @example\r
+ * // Display only three suggestions in the main context menu.\r
+ * config.scayt_maxSuggestions = 3;\r
+ * @example\r
+ * // Do not show the suggestions directly.\r
+ * config.scayt_maxSuggestions = -1;\r
+ */\r
+\r
+/**\r
+ * Sets the customer ID for SCAYT. Required for migration from free version\r
+ * with banner to paid version.\r
+ * @name CKEDITOR.config.scayt_customerid\r
+ * @type String\r
+ * @default ''\r
+ * @example\r
+ * // Load SCAYT using my customer ID.\r
+ * config.scayt_customerid = 'your-encrypted-customer-id';\r
+ */\r
+\r
+/**\r
+ * Enables/disables the "More Suggestions" sub-menu in the context menu.\r
+ * The possible values are "on" or "off".\r
+ * @name CKEDITOR.config.scayt_moreSuggestions\r
+ * @type String\r
+ * @default 'on'\r
+ * @example\r
+ * // Disables the "More Suggestions" sub-menu.\r
+ * config.scayt_moreSuggestions = 'off';\r
+ */\r
+\r
+/**\r
+ * Customizes the display of SCAYT context menu commands ("Add Word", "Ignore"\r
+ * and "Ignore All"). It must be a string with one or more of the following\r
+ * words separated by a pipe ("|"):\r
+ * <ul>\r
+ * <li>"off": disables all options.</li>\r
+ * <li>"all": enables all options.</li>\r
+ * <li>"ignore": enables the "Ignore" option.</li>\r
+ * <li>"ignoreall": enables the "Ignore All" option.</li>\r
+ * <li>"add": enables the "Add Word" option.</li>\r
+ * </ul>\r
+ * @name CKEDITOR.config.scayt_contextCommands\r
+ * @type String\r
+ * @default 'all'\r
+ * @example\r
+ * // Show only "Add Word" and "Ignore All" in the context menu.\r
+ * config.scayt_contextCommands = 'add|ignoreall';\r
+ */\r
+\r
+/**\r
+ * Sets the default spellchecking language for SCAYT.\r
+ * @name CKEDITOR.config.scayt_sLang\r
+ * @type String\r
+ * @default 'en_US'\r
+ * @example\r
+ * // Sets SCAYT to German.\r
+ * config.scayt_sLang = 'de_DE';\r
+ */\r
+\r
+/**\r
+ * Sets the visibility of the SCAYT tabs in the settings dialog and toolbar\r
+ * button. The value must contain a "1" (enabled) or "0" (disabled) number for\r
+ * each of the following entries, in this precise order, separated by a\r
+ * comma (","): "Options", "Languages" and "Dictionary".\r
+ * @name CKEDITOR.config.scayt_uiTabs\r
+ * @type String\r
+ * @default '1,1,1'\r
+ * @example\r
+ * // Hide the "Languages" tab.\r
+ * config.scayt_uiTabs = '1,0,1';\r
+ */\r
+\r
+\r
+/**\r
+ * Set the URL to SCAYT core. Required to switch to licensed version of SCAYT application.\r
+ * Further details at http://wiki.spellchecker.net/doku.php?id=3rd:wysiwyg:fckeditor:wscckf3l .\r
+ * @name CKEDITOR.config.scayt_srcUrl\r
+ * @type String\r
+ * @default ''\r
+ * @example\r
+ * config.scayt_srcUrl = "http://my-host/spellcheck/lf/scayt/scayt.js";\r
+ */\r
+\r
+/**\r
+ * Links SCAYT to custom dictionaries. It's a string containing dictionary ids\r
+ * separared by commas (","). Available only for licensed version.\r
+ * Further details at http://wiki.spellchecker.net/doku.php?id=custom_dictionary_support .\r
+ * @name CKEDITOR.config.scayt_customDictionaryIds\r
+ * @type String\r
+ * @default ''\r
+ * @example\r
+ * config.scayt_customDictionaryIds = '3021,3456,3478"';\r
+ */\r
+\r
+/**\r
+ * Makes it possible to activate a custom dictionary on SCAYT. The user\r
+ * dictionary name must be used. Available only for licensed version.\r
+ * @name CKEDITOR.config.scayt_userDictionaryName\r
+ * @type String\r
+ * @default ''\r
+ * @example\r
+ * config.scayt_userDictionaryName = 'MyDictionary';\r
+ */\r
+\r
+/**\r
+ * Define order of placing of SCAYT context menu items by groups.\r
+ * It must be a string with one or more of the following\r
+ * words separated by a pipe ("|"):\r
+ * <ul>\r
+ * <li>'suggest' - main suggestion word list,</li>\r
+ * <li>'moresuggest' - more suggestions word list,</li>\r
+ * <li>'control' - SCAYT commands, such as 'Ignore' and 'Add Word'</li>\r
+ * </ul>\r
+ *\r
+ * @name CKEDITOR.config.scayt_contextMenuItemsOrder\r
+ * @type String\r
+ * @default 'suggest|moresuggest|control'\r
+ * @example\r
+ * config.scayt_contextMenuItemsOrder = 'moresuggest|control|suggest';\r
+ */\r