JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
vanilla ckeditor-3.0.2
[ckeditor.git] / _source / plugins / wysiwygarea / plugin.js
index ab06245..d3b9e62 100644 (file)
@@ -15,7 +15,7 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
         */\r
        var nonExitableElementNames = { table:1,pre:1 };\r
        // Matching an empty paragraph at the end of document.\r
-       var emptyParagraphRegexp = /\s*<(p|div|address|h\d|center)[^>]*>\s*(?:<br[^>]*>|&nbsp;|&#160;)\s*(:?<\/\1>)?\s*$/gi;\r
+       var emptyParagraphRegexp = /\s*<(p|div|address|h\d|center)[^>]*>\s*(?:<br[^>]*>|&nbsp;|\u00A0|&#160;)?\s*(:?<\/\1>)?\s*$/gi;\r
 \r
        function onInsertHtml( evt )\r
        {\r
@@ -88,9 +88,12 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        && ( dtd = CKEDITOR.dtd[ current.getName() ] )\r
                                                        && !( dtd && dtd [ elementName ] ) )\r
                                        {\r
+                                               // Split up inline elements.\r
+                                               if ( current.getName() in CKEDITOR.dtd.span )\r
+                                                       range.splitElement( current );\r
                                                // If we're in an empty block which indicate a new paragraph,\r
                                                // simply replace it with the inserting block.(#3664)\r
-                                               if ( range.checkStartOfBlock()\r
+                                               else if ( range.checkStartOfBlock()\r
                                                         && range.checkEndOfBlock() )\r
                                                {\r
                                                        range.setStartBefore( current );\r
@@ -139,6 +142,20 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                        setTimeout( function(){ editor.resetDirty(); } );\r
        }\r
 \r
+       var isNotWhitespace = CKEDITOR.dom.walker.whitespaces( true ),\r
+               isNotBookmark = CKEDITOR.dom.walker.bookmark( false, true );\r
+\r
+       function isNotEmpty( node )\r
+       {\r
+               return isNotWhitespace( node ) && isNotBookmark( node );\r
+       }\r
+\r
+       function isNbsp( node )\r
+       {\r
+               return node.type == CKEDITOR.NODE_TEXT\r
+                          && CKEDITOR.tools.trim( node.getText() ).match( /^(?:&nbsp;|\xa0)$/ );\r
+       }\r
+\r
        /**\r
         *  Auto-fixing block-less content by wrapping paragraph (#3190), prevent\r
         *  non-exitable-block by padding extra br.(#3189)\r
@@ -161,61 +178,52 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                         && !path.block )\r
                {\r
                        restoreDirty( editor );\r
-                       var bms = selection.createBookmarks(),\r
-                               fixedBlock = range.fixBlock( true,\r
+                       var fixedBlock = range.fixBlock( true,\r
                                        editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p'  );\r
 \r
-                       // For IE, we'll be removing any bogus br ( introduce by fixing body )\r
-                       // right now to prevent it introducing visual line break.\r
+                       // For IE, we should remove any filler node which was introduced before.\r
                        if ( CKEDITOR.env.ie )\r
                        {\r
-                               var brNodeList = fixedBlock.getElementsByTag( 'br' ), brNode;\r
-                               for ( var i = 0 ; i < brNodeList.count() ; i++ )\r
-                               {\r
-                                       if( ( brNode = brNodeList.getItem( i ) ) && brNode.hasAttribute( '_cke_bogus' ) )\r
-                                               brNode.remove();\r
-                               }\r
+                               var first = fixedBlock.getFirst( isNotEmpty );\r
+                               first && isNbsp( first ) && first.remove();\r
                        }\r
 \r
-                       selection.selectBookmarks( bms );\r
-\r
-                       // If the fixed block is blank and is already followed by a exitable\r
-                       // block, we should drop it and move to the exist block(#3684).\r
-                       var children = fixedBlock.getChildren(),\r
-                               count = children.count(),\r
-                               firstChild,\r
-                               whitespaceGuard = CKEDITOR.dom.walker.whitespaces( true ),\r
-                               previousElement = fixedBlock.getPrevious( whitespaceGuard ),\r
-                               nextElement = fixedBlock.getNext( whitespaceGuard ),\r
-                               enterBlock;\r
-                       if ( previousElement && previousElement.getName\r
-                                && !( previousElement.getName() in nonExitableElementNames ) )\r
-                               enterBlock = previousElement;\r
-                       else if ( nextElement && nextElement.getName\r
-                                         && !( nextElement.getName() in nonExitableElementNames ) )\r
-                               enterBlock = nextElement;\r
-\r
-                       // Not all blocks are editable, e.g. <hr />, further checking it.(#3994)\r
-                       if( ( !count\r
-                                 || ( firstChild = children.getItem( 0 ) ) && firstChild.is && firstChild.is( 'br' ) )\r
-                               && enterBlock\r
-                               && range.moveToElementEditStart( enterBlock ) )\r
+                       // If the fixed block is blank and already followed by a exitable\r
+                       // block, we should revert the fix. (#3684)\r
+                       if( fixedBlock.getOuterHtml().match( emptyParagraphRegexp ) )\r
                        {\r
-                               fixedBlock.remove();\r
-                               range.select();\r
+                               var previousElement = fixedBlock.getPrevious( isNotWhitespace ),\r
+                                       nextElement = fixedBlock.getNext( isNotWhitespace );\r
+\r
+\r
+                               if ( previousElement && previousElement.getName\r
+                                        && !( previousElement.getName() in nonExitableElementNames )\r
+                                        && range.moveToElementEditStart( previousElement )\r
+                                        || nextElement && nextElement.getName\r
+                                          && !( nextElement.getName() in nonExitableElementNames )\r
+                                          && range.moveToElementEditStart( nextElement ) )\r
+                               {\r
+                                       fixedBlock.remove();\r
+                               }\r
                        }\r
+\r
+                       range.select();\r
+                       // Notify non-IE that selection has changed.\r
+                       if( !CKEDITOR.env.ie )\r
+                               editor.selectionChange();\r
                }\r
 \r
-               // Inserting the padding-br before body if it's preceded by an\r
-               // unexitable block.\r
+               // All browsers are incapable to moving cursor out of certain non-exitable\r
+               // blocks (e.g. table, list, pre) at the end of document, make this happen by\r
+               // place a bogus node there, which would be later removed by dataprocessor.\r
                var lastNode = body.getLast( CKEDITOR.dom.walker.whitespaces( true ) );\r
                if ( lastNode && lastNode.getName && ( lastNode.getName() in nonExitableElementNames ) )\r
                {\r
                        restoreDirty( editor );\r
-                       var paddingBlock = editor.document.createElement(\r
-                                       ( CKEDITOR.env.ie && enterMode != CKEDITOR.ENTER_BR ) ?\r
-                                               '<br _cke_bogus="true" />' : 'br' );\r
-                       body.append( paddingBlock );\r
+                       if( !CKEDITOR.env.ie )\r
+                               body.appendBogus();\r
+                       else\r
+                               body.append( editor.document.createText( '\xa0' ) );\r
                }\r
        }\r
 \r
@@ -329,16 +337,11 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        mainElement.append( iframe );\r
                                        };\r
 \r
-                                       // The script that is appended to the data being loaded. It\r
-                                       // enables editing, and makes some\r
+                                       // The script that launches the bootstrap logic on 'domReady', so the document\r
+                                       // is fully editable even before the editing iframe is fully loaded (#4455).\r
                                        var activationScript =\r
                                                '<script id="cke_actscrpt" type="text/javascript">' +\r
-                                                       'window.onload = function()' +\r
-                                                       '{' +\r
-                                                               // Call the temporary function for the editing\r
-                                                               // boostrap.\r
-                                                               'window.parent.CKEDITOR._["contentDomReady' + editor.name + '"]( window );' +\r
-                                                       '}' +\r
+                                                       'window.parent.CKEDITOR._["contentDomReady' + editor.name + '"]( window );' +\r
                                                '</script>';\r
 \r
                                        // Editing area bootstrap code.\r
@@ -411,6 +414,22 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                        } );\r
                                                }\r
 \r
+                                               // IE standard compliant in editing frame doesn't focus the editor when\r
+                                               // clicking outside actual content, manually apply the focus. (#1659)\r
+                                               if( CKEDITOR.env.ie\r
+                                                       && domDocument.$.compatMode == 'CSS1Compat' )\r
+                                               {\r
+                                                       var htmlElement = domDocument.getDocumentElement();\r
+                                                       htmlElement.on( 'mousedown', function( evt )\r
+                                                       {\r
+                                                               // Setting focus directly on editor doesn't work, we\r
+                                                               // have to use here a temporary element to 'redirect'\r
+                                                               // the focus.\r
+                                                               if ( evt.data.getTarget().equals( htmlElement ) )\r
+                                                                       ieFocusGrabber.focus();\r
+                                                       } );\r
+                                               }\r
+\r
                                                var focusTarget = ( CKEDITOR.env.ie || CKEDITOR.env.webkit ) ?\r
                                                                domWindow : domDocument;\r
 \r
@@ -454,13 +473,13 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                if ( keystrokeHandler )\r
                                                        keystrokeHandler.attach( domDocument );\r
 \r
-                                               // Cancel default action for backspace in IE on control types. (#4047)\r
                                                if ( CKEDITOR.env.ie )\r
                                                {\r
-                                                       editor.on( 'key', function( event )\r
+                                                       // Cancel default action for backspace in IE on control types. (#4047)\r
+                                                       domDocument.on( 'keydown', function( evt )\r
                                                        {\r
                                                                // Backspace.\r
-                                                               var control = event.data.keyCode == 8\r
+                                                               var control = evt.data.getKeystroke() == 8\r
                                                                                          && editor.getSelection().getSelectedElement();\r
                                                                if ( control )\r
                                                                {\r
@@ -469,14 +488,31 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                                        // Remove manually.\r
                                                                        control.remove();\r
                                                                        editor.fire( 'saveSnapshot' );\r
-                                                                       event.cancel();\r
+                                                                       evt.cancel();\r
                                                                }\r
                                                        } );\r
+\r
+                                                       // PageUp/PageDown scrolling is broken in document\r
+                                                       // with standard doctype, manually fix it. (#4736)\r
+                                                       if( domDocument.$.compatMode == 'CSS1Compat' )\r
+                                                       {\r
+                                                               var pageUpDownKeys = { 33 : 1, 34 : 1 };\r
+                                                               domDocument.on( 'keydown', function( evt )\r
+                                                               {\r
+                                                                       if( evt.data.getKeystroke() in pageUpDownKeys )\r
+                                                                       {\r
+                                                                               setTimeout( function ()\r
+                                                                               {\r
+                                                                                       editor.getSelection().scrollIntoView();\r
+                                                                               }, 0 );\r
+                                                                       }\r
+                                                               } );\r
+                                                       }\r
                                                }\r
 \r
                                                // Adds the document body as a context menu target.\r
                                                if ( editor.contextMenu )\r
-                                                       editor.contextMenu.addTarget( domDocument );\r
+                                                       editor.contextMenu.addTarget( domDocument, editor.config.browserContextMenuOnCtrl !== false );\r
 \r
                                                setTimeout( function()\r
                                                        {\r
@@ -625,6 +661,25 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                                                else if ( editor.window )\r
                                                                {\r
                                                                        editor.window.focus();\r
+\r
+                                                                       // Force the selection to happen, in this way\r
+                                                                       // we guarantee the focus will be there. (#4848)\r
+                                                                       if ( CKEDITOR.env.ie )\r
+                                                                       {\r
+                                                                               try\r
+                                                                               {\r
+                                                                                       var sel = editor.getSelection();\r
+                                                                                       sel = sel && sel.getNative();\r
+                                                                                       var range = sel && sel.type && sel.createRange();\r
+                                                                                       if ( range )\r
+                                                                                       {\r
+                                                                                                       sel.empty();\r
+                                                                                                       range.select();\r
+                                                                                       }\r
+                                                                               }\r
+                                                                               catch (e) {}\r
+                                                                       }\r
+\r
                                                                        editor.selectionChange();\r
                                                                }\r
                                                        }\r
@@ -635,8 +690,60 @@ For licensing, see LICENSE.html or http://ckeditor.com/license
                                        // Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189)\r
                                        editor.on( 'selectionChange', onSelectionChangeFixBody, null, null, 1 );\r
                                });\r
+\r
+                       // Create an invisible element to grab focus.\r
+                       if( CKEDITOR.env.ie )\r
+                       {\r
+                               var ieFocusGrabber;\r
+                               editor.on( 'uiReady', function()\r
+                               {\r
+                                       ieFocusGrabber = editor.container.append( CKEDITOR.dom.element.createFromHtml(\r
+                                       '<input tabindex="-1" style="position:absolute; left:-10000">' ) );\r
+\r
+                                       ieFocusGrabber.on( 'focus', function()\r
+                                               {\r
+                                                       editor.focus();\r
+                                               } );\r
+                               } );\r
+                       }\r
                }\r
        });\r
+\r
+       // Fixing Firefox 'Back-Forward Cache' break design mode. (#4514)\r
+       if( CKEDITOR.env.gecko )\r
+       {\r
+               var topWin = window.top;\r
+\r
+               ( function ()\r
+               {\r
+                       var topBody = topWin.document.body;\r
+\r
+                       if( !topBody )\r
+                               topWin.addEventListener( 'load', arguments.callee, false );\r
+                       else\r
+                       {\r
+                               topBody.setAttribute( 'onpageshow', topBody.getAttribute( 'onpageshow' )\r
+                                               + ';event.persisted && CKEDITOR.tools.callFunction(' +\r
+                                               CKEDITOR.tools.addFunction( function()\r
+                                               {\r
+                                                       var allInstances = CKEDITOR.instances,\r
+                                                               editor,\r
+                                                               doc;\r
+                                                       for( var i in allInstances )\r
+                                                       {\r
+                                                               editor = allInstances[ i ];\r
+                                                               doc = editor.document;\r
+                                                               if( doc )\r
+                                                               {\r
+                                                                       doc.$.designMode = 'off';\r
+                                                                       doc.$.designMode = 'on';\r
+                                                               }\r
+                                                       }\r
+                                               } ) + ')' );\r
+                       }\r
+               } )();\r
+\r
+       }\r
 })();\r
 \r
 /**\r