JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.2.2
[ckeditor.git] / _source / plugins / scayt / plugin.js
index f64d25e..2076207 100644 (file)
@@ -11,9 +11,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 (function()\r
 {\r
        var commandName         = 'scaytcheck',\r
-               openPage                = '',\r
-               scayt_paused    = null,\r
-               scayt_control_id = null;\r
+               openPage                = '';\r
 \r
        // Checks if a value exists in an array\r
        function in_array(needle, haystack)\r
@@ -47,9 +45,23 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        oParams.userDictionaryName = editor.config.scayt_userDictionaryName || '';\r
                        oParams.sLang = editor.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 ( !editor.checkDirty() )\r
+                               if ( plugin.getScayt( editor ) && !editor.checkDirty() )\r
                                        setTimeout( function(){ editor.resetDirty(); } );\r
                        };\r
 \r
@@ -62,11 +74,16 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                }\r
                        }\r
                        // needs for restoring a specific scayt control settings\r
-                       if ( scayt_control_id )\r
-                               oParams.id = scayt_control_id;\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
@@ -88,7 +105,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \r
                        plugin.uiTabs = fTabs;\r
                        try {\r
-                               scayt_control.setDisabled( scayt_paused === false );\r
+                               scayt_control.setDisabled( plugin.isPaused( editor ) === false );\r
                        } catch (e) {}\r
 \r
                        editor.fire( 'showScaytState' );\r
@@ -120,30 +137,51 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        var scayt_instance = plugin.getScayt( editor );\r
                                        if ( scayt_instance )\r
                                        {\r
-                                               scayt_paused = scayt_instance.paused = !scayt_instance.disabled;\r
+                                               plugin.setPaused( editor, !scayt_instance.disabled );\r
                                                // store a control id for restore a specific scayt control settings\r
-                                               scayt_control_id = scayt_instance.id;\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
-                               scayt_control_id = scayt_instance.id;\r
+                               plugin.setControlId( editor, scayt_instance.id );\r
                                scayt_instance.destroy( true );\r
-                               delete plugin.instances[ editor.name ];\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(){ plugin.getScayt( editor ).refresh(); }, 10 );\r
+                                       window.setTimeout( function()\r
+                                               {\r
+                                                       var instance = plugin.getScayt( editor );\r
+                                                       instance && instance.refresh();\r
+                                               }, 10 );\r
                                }\r
                        });\r
 \r
@@ -158,8 +196,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        if ( CKEDITOR.env.ie )\r
                                                editor.getSelection().unlock( true );\r
 \r
-                                       // Swallow any SCAYT engine errors.\r
-                                       window.setTimeout( function(){ scayt_instance.refresh(); }, 10 );\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
@@ -173,8 +215,13 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        if ( CKEDITOR.env.ie )\r
                                                editor.getSelection().unlock( true );\r
 \r
-                                       // Swallow any SCAYT engine errors.\r
-                                       window.setTimeout( function(){ scayt_instance.refresh(); },10 );\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
@@ -208,14 +255,92 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        );\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
+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
@@ -234,7 +359,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                {\r
                        // SCAYT doesn't work with Opera.\r
                        if ( CKEDITOR.env.opera )\r
-                               return null;\r
+                               return editor.fire( 'showScaytState' );\r
 \r
                        if ( this.engineLoaded === true )\r
                                return onEngineLoad.apply( editor );    // Add new instance.\r
@@ -257,34 +382,39 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        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/spellcheck31/lf/scayt/scayt22.js';\r
+                       var baseUrl  = 'svc.spellchecker.net/spellcheck31/lf/scayt24/loader__base.js';\r
 \r
                        var scaytUrl  =  editor.config.scayt_srcUrl || ( protocol + '//' + baseUrl );\r
                        var scaytConfigBaseUrl =  plugin.parseUrl( scaytUrl ).path +  '/';\r
 \r
-                       CKEDITOR._djScaytConfig =\r
+                       if( window.scayt == undefined )\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
-                                                               src : scaytUrl\r
-                                                       }\r
-                                       })\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
+                                                                       src : scaytUrl\r
+                                                               }\r
+                                               })\r
+                               );\r
+                       }\r
+                       else\r
+                               CKEDITOR.fireOnce( 'scaytReady' );\r
 \r
                        return null;\r
                },\r
@@ -322,6 +452,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \r
                exec: function( editor )\r
                {\r
+                       var autoStartup = editor.config.scayt_autoStartup;\r
+                       autoStartup = ( autoStartup == undefined ) || autoStartup;\r
+\r
                        if ( plugin.isScaytReady( editor ) )\r
                        {\r
                                var isEnabled = plugin.isScaytEnabled( editor );\r
@@ -329,19 +462,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                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
+                       else if ( !autoStartup && plugin.engineLoaded >= 0 )    // Load first time\r
                        {\r
                                this.setState( CKEDITOR.TRISTATE_DISABLED );\r
-\r
-                               editor.on( 'showScaytState', function()\r
-                                       {\r
-                                               this.removeListener();\r
-                                               this.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );\r
-                                       },\r
-                                       this);\r
-\r
                                plugin.loadEngine( editor );\r
                        }\r
                }\r
@@ -354,8 +486,25 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \r
                beforeInit : function( editor )\r
                {\r
-                       // Register own rbc menu group.\r
-                       editor.config.menu_groups = 'scayt_suggest,scayt_moresuggest,scayt_control,' + editor.config.menu_groups;\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 in items_order )\r
+                                       items_order_str += 'scayt_' + items_order[ pos ] + ( items_order.length != parseInt( pos, 10 ) + 1 ? ',' : '' );\r
+                       }\r
+\r
+                       // Register scayt rbc menu group.\r
+                       if ( editor.config.scayt_contextMenuOntop )\r
+                               // Put it on top of all context menu items\r
+                               editor.config.menu_groups =  items_order_str + ',' + editor.config.menu_groups;\r
+                       else\r
+                               // Put it down\r
+                               editor.config.menu_groups = editor.config.menu_groups + ',' +items_order_str;\r
                },\r
 \r
                init : function( editor )\r
@@ -448,7 +597,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                editor.ui.add( 'Scayt', CKEDITOR.UI_MENUBUTTON,\r
                                        {\r
                                                label : editor.lang.scayt.title,\r
-                                               title : editor.lang.scayt.title,\r
+                                               title : CKEDITOR.env.opera ? editor.lang.scayt.opera_title : editor.lang.scayt.title,\r
                                                className : 'cke_button_scayt',\r
                                                onRender: function()\r
                                                {\r
@@ -607,15 +756,30 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        });\r
                        }\r
 \r
-                       // Start plugin\r
-                       if ( editor.config.scayt_autoStartup )\r
-                       {\r
-                               var showInitialState = function()\r
+                       var showInitialState = function()\r
                                {\r
                                        editor.removeListener( 'showScaytState', showInitialState );\r
-                                       command.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );\r
+\r
+                                       if ( !CKEDITOR.env.opera )\r
+                                               command.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );\r
+                                       else\r
+                                               command.setState( CKEDITOR.TRISTATE_DISABLED );\r
                                };\r
-                               editor.on( 'showScaytState', showInitialState );\r
+\r
+                       editor.on( 'showScaytState', showInitialState );\r
+\r
+                       if ( CKEDITOR.env.opera )\r
+                       {\r
+                               editor.on( 'instanceReady', function()\r
+                               {\r
+                                       showInitialState();\r
+                               });\r
+                       }\r
+\r
+                       // Start plugin\r
+                       var autoStartup = editor.config.scayt_autoStartup;\r
+                       if ( ( autoStartup == undefined ) || autoStartup )\r
+                       {\r
                                editor.on( 'instanceReady', function()\r
                                {\r
                                        plugin.loadEngine( editor );\r
@@ -625,16 +789,18 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
 \r
                afterInit : function( editor )\r
                {\r
-                       // Prevent word marker line from displaying in elements path. (#3570)\r
-                       var elementsPathFilters;\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( 'scaytid' ) )\r
+                                                       return false;\r
+                                       };\r
+\r
                        if ( editor._.elementsPath && ( elementsPathFilters = editor._.elementsPath.filters ) )\r
-                       {\r
-                               elementsPathFilters.push( function( element )\r
-                               {\r
-                                       if ( element.hasAttribute( 'scaytid' ) )\r
-                                               return false;\r
-                               } );\r
-                       }\r
+                               elementsPathFilters.push( scaytFilter );\r
+\r
+                       editor.addRemoveFormatFilter && editor.addRemoveFormatFilter( scaytFilter );\r
 \r
                }\r
        });\r
@@ -644,9 +810,9 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
  * If enabled (true), turns on SCAYT automatically after loading the editor.\r
  * @name CKEDITOR.config.scayt_autoStartup\r
  * @type Boolean\r
- * @default false\r
+ * @default true\r
  * @example\r
- * config.scayt_autoStartup = true;\r
+ * config.scayt_autoStartup = false;\r
  */\r
 \r
 /**\r
@@ -765,3 +931,29 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
  * @example\r
  * config.scayt_userDictionaryName = 'MyDictionary';\r
  */\r
+\r
+/**\r
+ * Makes it possible to place the SCAYT context menu items above others.\r
+ * @name CKEDITOR.config.scayt_contextMenuOntop\r
+ * @type Boolean\r
+ * @default false\r
+ * @example\r
+ * config.scayt_contextMenuOntop = true;\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