Index: /CKEditor/trunk/_samples/enterkey.html
===================================================================
--- /CKEditor/trunk/_samples/enterkey.html	(revision 3194)
+++ /CKEditor/trunk/_samples/enterkey.html	(revision 3194)
@@ -0,0 +1,74 @@
+<!--
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+-->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>ENTER Key Configuration - CKEditor Sample</title>
+	<script type="text/javascript" src="sample.js"></script>
+	<script id="headscript" type="text/javascript">
+	//<![CDATA[
+
+var editor;
+
+function changeEnter()
+{
+	// If we already have an editor, let's destroy it first.
+	if ( editor )
+		editor.destroy();
+
+	// Create the editor again, with the appropriate settings.
+	editor = CKEDITOR.replace( 'editor1',
+		{
+			enterMode		: Number( document.getElementById( 'xEnter' ).value ),
+			shiftEnterMode	: Number( document.getElementById( 'xShiftEnter' ).value )
+		});
+}
+
+window.onload = changeEnter;
+
+	//]]>
+	</script>
+</head>
+<body>
+	<!--
+		The values in the select boxes represent the contants taht can be used
+		to configure the enter key. You can use the constants directly instead
+		of their numeric values:
+			- CKEDITOR.ENTER_P		= 1;
+			- CKEDITOR.ENTER_BR		= 2;
+			- CKEDITOR.ENTER_DIV	= 3;
+	-->
+	<div id="html">
+		<div style="float: left; margin-right: 20px">
+			When ENTER is pressed:<br />
+			<select id="xEnter" onchange="changeEnter();">
+				<option value="1" selected="selected">Create new &lt;P&gt; (recommended)</option>
+				<option value="3">Create new &lt;DIV&gt;</option>
+				<option value="2">Break the line with a &lt;BR&gt;</option>
+			</select>
+		</div>
+		<div style="float: left">
+			When SHIFT + ENTER is pressed:<br />
+			<select id="xShiftEnter" onchange="changeEnter();">
+				<option value="1">Create new &lt;P&gt;</option>
+				<option value="3">Create new &lt;DIV&gt;</option>
+				<option value="2" selected="selected">Break the line with a &lt;BR&gt; (recommended)</option>
+			</select>
+		</div>
+		<br style="clear: both" />
+		<form action="sample_posteddata.php" method="post">
+			<p>
+				<br />
+				<textarea id="editor1" name="editor1" rows="10" cols="80">&lt;p&gt;This is some &lt;strong&gt;sample text&lt;/strong&gt;. You are using &lt;a href="http://www.fckeditor.net/"&gt;FCKeditor&lt;/a&gt;.&lt;/p&gt;</textarea>
+			</p>
+			<p>
+				<input type="submit" value="Submit" />
+			</p>
+		</form>
+	</div>
+	<div id="code">
+		<pre></pre>
+	</div>
+</body>
+</html>
Index: /CKEditor/trunk/_source/core/config.js
===================================================================
--- /CKEditor/trunk/_source/core/config.js	(revision 3193)
+++ /CKEditor/trunk/_source/core/config.js	(revision 3194)
@@ -8,4 +8,8 @@
  * default configuration settings.
  */
+
+CKEDITOR.ENTER_P	= 1;
+CKEDITOR.ENTER_BR	= 2;
+CKEDITOR.ENTER_DIV	= 3;
 
 /**
@@ -96,6 +100,6 @@
 	defaultLanguage : 'en',
 
-	enterMode : 'p',
-	shiftEnterMode : 'br',
+	enterMode : CKEDITOR.ENTER_P,
+	shiftEnterMode : CKEDITOR.ENTER_BR,
 
 	/**
@@ -148,5 +152,5 @@
 	 */
 
-	plugins : 'basicstyles,blockquote,button,clipboard,colorbutton,contextmenu,elementspath,entities,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,stylescombo,table,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc',
+	plugins : 'basicstyles,blockquote,button,clipboard,colorbutton,contextmenu,elementspath,enterkey,entities,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,stylescombo,table,specialchar,tab,templates,toolbar,undo,wysiwygarea,wsc',
 
 	/**
Index: /CKEditor/trunk/_source/core/dom/element.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/element.js	(revision 3193)
+++ /CKEditor/trunk/_source/core/dom/element.js	(revision 3194)
@@ -194,5 +194,5 @@
 		{
 			if ( typeof node == 'string' )
-				node = new CKEDITOR.dom.element( node );
+				node = this.getDocument().createElement( node );
 
 			if ( toStart )
@@ -206,7 +206,12 @@
 		appendHtml : function( html )
 		{
-			var temp = new CKEDITOR.dom.element( 'div', this.getDocument() );
-			temp.setHtml( html );
-			temp.moveChildren( this );
+			if ( !this.$.childNodes.length )
+				this.setHtml( html );
+			else
+			{
+				var temp = new CKEDITOR.dom.element( 'div', this.getDocument() );
+				temp.setHtml( html );
+				temp.moveChildren( this );
+			}
 		},
 
@@ -228,4 +233,21 @@
 			else
 				this.append( new CKEDITOR.dom.text( text ) );
+		},
+
+		appendBogus : function()
+		{
+			var lastChild = this.getLast() ;
+
+			// Ignore empty/spaces text.
+			while ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT && CKEDITOR.tools.rtrim( lastChild.getText() ).length == 0 )
+				lastChild = lastChild.getPrevious();
+
+			if ( !lastChild || ( lastChild.is && ( !lastChild.is( 'br' ) || !lastChild.getAttribute( '_cke_bogus' ) ) ) )
+			{
+				this.append(
+					CKEDITOR.env.opera ?
+						this.getDocument().createText('') :
+						this.getDocument().createElement( 'br', { attributes : { _cke_bogus : 1 } } ) );
+			}
 		},
 
@@ -657,4 +679,17 @@
 			}
 			return false;
+		},
+
+		isEditable : function()
+		{
+			// Get the element name.
+			var name = this.getName();
+
+			// Get the element DTD (defaults to span for unknown elements).
+			var dtd = !CKEDITOR.dtd.$nonEditable[ name ]
+						&& ( CKEDITOR.dtd[ name ] || CKEDITOR.dtd.span );
+
+			// In the DTD # == text node.
+			return ( dtd && dtd['#'] );
 		},
 
Index: /CKEditor/trunk/_source/core/dom/node.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/node.js	(revision 3193)
+++ /CKEditor/trunk/_source/core/dom/node.js	(revision 3194)
@@ -95,5 +95,14 @@
 		clone : function( includeChildren )
 		{
-			return new CKEDITOR.dom.node( this.$.cloneNode( includeChildren ) );
+			var $clone = this.$.cloneNode( includeChildren );
+			
+			if ( this.type == CKEDITOR.NODE_ELEMENT )
+			{
+				// The "id" attribute should never be cloned to avoid duplication.
+				$clone.removeAttribute( 'id', false ) ;
+				$clone.removeAttribute( '_cke_expando', false ) ;
+			}
+			
+			return new CKEDITOR.dom.node( $clone );
 		},
 
Index: /CKEditor/trunk/_source/core/dom/range.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/range.js	(revision 3193)
+++ /CKEditor/trunk/_source/core/dom/range.js	(revision 3194)
@@ -1096,25 +1096,50 @@
 				case CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS:
 					// DFS backward to get the block/list item boundary at or before the start.
-					var boundaryNodes = this.getBoundaryNodes(),
-						startNode = boundaryNodes.startNode,
-						endNode = boundaryNodes.endNode,
-						guardFunction = ( unit == CKEDITOR.ENLARGE_BLOCK_CONTENTS ?
-							CKEDITOR.dom.domWalker.blockBoundary() :
-							CKEDITOR.dom.domWalker.listItemBoundary() ),
-						walker = new CKEDITOR.dom.domWalker( startNode ),
-						data = walker.reverse( guardFunction ),
+					
+					// Get the boundaries nodes.
+					var startNode = this.getTouchedStartNode(),
+						endNode = this.getTouchedEndNode();
+
+					if ( startNode.isBlockBoundary() )
+					{
+						this.setStartAt( startNode, 
+							CKEDITOR.dtd.$empty[ startNode.getName() ] ?
+								CKEDITOR.POSITION_AFTER_END :
+								CKEDITOR.POSITION_AFTER_START );
+					}
+					else
+					{					
+						// Get the function used to check the enlaarging limits.
+						var guardFunction = ( unit == CKEDITOR.ENLARGE_BLOCK_CONTENTS ?
+								CKEDITOR.dom.domWalker.blockBoundary() :
+								CKEDITOR.dom.domWalker.listItemBoundary() );
+
+						// Create the DOM walker, which will traverse the DOM.
+						var walker = new CKEDITOR.dom.domWalker( startNode );
+						
+						// Go walk in reverse sense.
+						var data = walker.reverse( guardFunction );
+					
+						var boundaryEvent = data.events.shift();
+
+						this.setStartBefore( boundaryEvent.from );
+					}
+
+					if ( endNode.isBlockBoundary() )
+					{
+						this.setEndAt( endNode, 
+							CKEDITOR.dtd.$empty[ startNode.getName() ] ?
+								CKEDITOR.POSITION_BEFORE_START :
+								CKEDITOR.POSITION_BEFORE_END );
+					}
+					else
+					{					
+						// DFS forward to get the block/list item boundary at or before the end.
+						walker.setNode( endNode );
+						data = walker.forward( guardFunction );
 						boundaryEvent = data.events.shift();
 
-					this.setStartBefore( boundaryEvent.from );
-
-					// DFS forward to get the block/list item boundary at or before the end.
-					walker.setNode( endNode );
-					data = walker.forward( guardFunction );
-					boundaryEvent = data.events.shift();
-
-					this.setEndAfter( boundaryEvent.from );
-					break;
-
-				default:
+						this.setEndAfter( boundaryEvent.from );
+					}
 			}
 		},
@@ -1282,15 +1307,23 @@
 		},
 
-		// TODO: Does not add bogus <br> to empty fixed blocks.
 		fixBlock : function( isStart, blockTag )
 		{
 			var bookmark = this.createBookmark(),
-				fixedBlock = new CKEDITOR.dom.element( blockTag, this.document );
+				fixedBlock = this.document.createElement( blockTag );
+
 			this.collapse( isStart );
+
 			this.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
+
 			this.extractContents().appendTo( fixedBlock );
 			fixedBlock.trim();
+
+			if ( !CKEDITOR.env.ie )
+				fixedBlock.appendBogus();
+
 			this.insertNode( fixedBlock );
+
 			this.moveToBookmark( bookmark );
+
 			return fixedBlock;
 		},
@@ -1298,12 +1331,16 @@
 		splitBlock : function( blockTag )
 		{
-			var startPath = new CKEDITOR.dom.elementPath( this.startContainer ),
-				endPath = new CKEDITOR.dom.elementPath( this.endContainer ),
-				startBlockLimit = startPath.blockLimit,
-				endBlockLimit = endPath.blockLimit,
-				startBlock = startPath.block,
-				endBlock = endPath.block,
-				elementPath = null;
-
+			var startPath	= new CKEDITOR.dom.elementPath( this.startContainer ),
+				endPath		= new CKEDITOR.dom.elementPath( this.endContainer );
+
+			var startBlockLimit	= startPath.blockLimit,
+				endBlockLimit	= endPath.blockLimit;
+
+			var startBlock	= startPath.block,
+				endBlock	= endPath.block;
+
+			var elementPath = null;
+
+			// Do nothing if the boundaries are in different block limits.
 			if ( !startBlockLimit.equals( endBlockLimit ) )
 				return null;
@@ -1315,5 +1352,5 @@
 				{
 					startBlock = this.fixBlock( true, blockTag );
-					endBlock = new CKEDITOR.dom.elementPath( this.endContainer );
+					endBlock = new CKEDITOR.dom.elementPath( this.endContainer ).block;
 				}
 
@@ -1353,5 +1390,4 @@
 					// Duplicate the block element after it.
 					endBlock = startBlock.clone( false );
-					endBlock.removeAttribute( 'id' );
 
 					// Place the extracted contents into the duplicated block.
@@ -1360,5 +1396,9 @@
 					this.moveToPosition( startBlock, CKEDITOR.POSITION_AFTER_END );
 
-					// TODO: Append bogus br to startBlock for Gecko
+					// In Gecko, the last child node must be a bogus <br>.
+					// Note: bogus <br> added under <ul> or <ol> would cause
+					// lists to be incorrectly rendered.
+					if ( !CKEDITOR.env.ie && !startBlock.is( 'ul', 'ol') )
+						startBlock.appendBogus() ;
 				}
 			}
@@ -1419,4 +1459,50 @@
 
 			return !walker.checkFailed;
+		},
+
+		/**
+		 * Moves the range boundaries to the first editing point inside an
+		 * element. For example, in an element tree like
+		 * "&lt;p&gt;&lt;b&gt;&lt;i&gt;&lt;/i&gt;&lt;/b&gt; Text&lt;/p&gt;", the start editing point is
+		 * "&lt;p&gt;&lt;b&gt;&lt;i&gt;^&lt;/i&gt;&lt;/b&gt; Text&lt;/p&gt;" (inside &lt;i&gt;).
+		 * @param {CKEDITOR.dom.element} targetElement The element into which
+		 *		look for the editing spot.
+		 */
+		moveToElementEditStart : function( targetElement )
+		{
+			var editableElement;
+
+			while ( targetElement && targetElement.type == CKEDITOR.NODE_ELEMENT )
+			{
+				if ( targetElement.isEditable() )
+					editableElement = targetElement;
+				else if ( editableElement )
+					break ;		// If we already found an editable element, stop the loop.
+
+				targetElement = targetElement.getFirst();
+			}
+
+			if ( editableElement )
+				this.moveToPosition( editableElement, CKEDITOR.POSITION_AFTER_START );
+		},
+
+		getTouchedStartNode : function()
+		{
+			var container = this.startContainer ;
+
+			if ( this.collapsed || container.type != CKEDITOR.NODE_ELEMENT )
+				return container ;
+
+			return container.getChild( this.startOffset ) || container ;
+		},
+
+		getTouchedEndNode : function()
+		{
+			var container = this.endContainer ;
+
+			if ( this.collapsed || container.type != CKEDITOR.NODE_ELEMENT )
+				return container ;
+
+			return container.getChild[ this.endOffset - 1 ] || container ;
 		}
 	};
Index: /CKEditor/trunk/_source/core/dtd.js
===================================================================
--- /CKEditor/trunk/_source/core/dtd.js	(revision 3193)
+++ /CKEditor/trunk/_source/core/dtd.js	(revision 3194)
@@ -80,9 +80,17 @@
 
 		/**
+		 * Elements that accept text nodes, but are not possible to edit into
+		 * the browser.
+		 * @type Object
+		 * @example
+		 */
+		$nonEditable : {applet:1,button:1,embed:1,iframe:1,map:1,object:1,option:1,script:1,textarea:1},
+
+		/**
 		 * List of elements that can be ignored if empty, like "b" or "span".
 		 * @type Object
 		 * @example
 		 */
-		$removeEmpty : {abbr:1,acronym:1,address:1,b:1,bdo:1,big:1,cite:1,code:1,dfn:1,em:1,font:1,i:1,kbd:1,q:1,s:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1},
+		$removeEmpty : {abbr:1,acronym:1,address:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,s:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1},
 
 		/**
Index: /CKEditor/trunk/_source/core/plugins.js
===================================================================
--- /CKEditor/trunk/_source/core/plugins.js	(revision 3193)
+++ /CKEditor/trunk/_source/core/plugins.js	(revision 3194)
@@ -18,4 +18,6 @@
 	'_source/' +	// %REMOVE_LINE%
 	'plugins/', 'plugin' );
+
+// PACKAGER_RENAME( CKEDITOR.plugins )
 
 CKEDITOR.plugins.load = CKEDITOR.tools.override( CKEDITOR.plugins.load, function( originalLoad )
Index: /CKEditor/trunk/_source/plugins/enterkey/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/enterkey/plugin.js	(revision 3194)
+++ /CKEditor/trunk/_source/plugins/enterkey/plugin.js	(revision 3194)
@@ -0,0 +1,296 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	CKEDITOR.plugins.add( 'enterkey',
+	{
+		requires : [ 'keystrokes' ],
+
+		init : function( editor )
+		{
+			var specialKeys = editor.specialKeys;
+			specialKeys[ 13 ] = enter;
+			specialKeys[ CKEDITOR.SHIFT + 13 ] = shiftEnter;
+		}
+	});
+
+	var forceMode,
+		headerTagRegex = /^h[1-6]$/;
+
+	function shiftEnter( editor )
+	{
+		// On SHIFT+ENTER we want to enforce the mode to be respected, instead
+		// of cloning the current block. (#77)
+		forceMode = 1;
+
+		return enter( editor, editor.config.shiftEnterMode );
+	}
+
+	function enter( editor, mode )
+	{
+		if ( !mode )
+			mode = editor.config.enterMode;
+
+		// Use setTimout so the keys get cancelled immediatelly.
+		setTimeout( function()
+			{
+				if ( mode == CKEDITOR.ENTER_BR || editor.getSelection().getStartElement().hasAscendant( 'pre', true ) )
+					enterBr( editor, mode );
+				else
+					enterBlock( editor, mode );
+
+				forceMode = 0;
+			}, 0 );
+
+		return true;
+	}
+
+	function enterBlock( editor, mode, range )
+	{
+		// Get the range for the current selection.
+		range = range || getRange( editor );
+
+		var doc = range.document;
+
+		// Determine the block element to be used.
+		var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
+
+		// Split the range.
+		var splitInfo = range.splitBlock( blockTag );
+
+		if ( !splitInfo )
+			return;
+
+		// Get the current blocks.
+		var previousBlock	= splitInfo.previousBlock,
+			nextBlock		= splitInfo.nextBlock;
+
+		var isStartOfBlock	= splitInfo.wasStartOfBlock,
+			isEndOfBlock	= splitInfo.wasEndOfBlock;
+
+		var node;
+
+		// If this is a block under a list item, split it as well. (#1647)
+		if ( nextBlock )
+		{
+			node = nextBlock.getParent();
+			if ( node.is( 'li' ) )
+			{
+				nextBlock.breakParent( node );
+				nextBlock.move( nextBlock.getNext(), true );
+			}
+		}
+		else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) )
+		{
+			previousBlock.breakParent( node );
+			range.moveToElementEditStart( previousBlock.getNext() );
+			previousBlock.move( previousBlock.getPrevious() );
+		}
+
+		// If we have both the previous and next blocks, it means that the
+		// boundaries were on separated blocks, or none of them where on the
+		// block limits (start/end).
+		if ( !isStartOfBlock && !isEndOfBlock )
+		{
+			// If the next block is an <li> with another list tree as the first
+			// child, we'll need to append a placeholder or the list item
+			// wouldn't be editable. (#1420)
+			if ( nextBlock.is( 'li' ) && ( node = nextBlock.getFirst() )
+					&& node.is && node.is( 'ul', 'ol') )
+				nextBlock.insertBefore( doc.createText( '\xa0' ), node );
+
+			// Move the selection to the end block.
+			if ( nextBlock )
+				range.moveToElementEditStart( nextBlock );
+		}
+		else
+		{
+			var newBlock;
+
+			if ( previousBlock )
+			{
+				// Do not enter this block if it's a header tag, or we are in
+				// a Shift+Enter (#77). Create a new block element instead
+				// (later in the code).
+				if ( !forceMode && !headerTagRegex.test( previousBlock.getName() ) )
+				{
+					// Otherwise, duplicate the previous block.
+					newBlock = previousBlock.clone();
+				}
+			}
+			else if ( nextBlock )
+				newBlock = nextBlock.clone();
+
+			if ( !newBlock )
+				newBlock = doc.createElement( blockTag );
+
+			// Recreate the inline elements tree, which was available
+			// before hitting enter, so the same styles will be available in
+			// the new block.
+			var elementPath = splitInfo.elementPath;
+			if ( elementPath )
+			{
+				for ( var i = 0, len = elementPath.elements.length ; i < len ; i++ )
+				{
+					var element = elementPath.elements[ i ];
+
+					if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) )
+						break;
+
+					if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] )
+					{
+						element = element.clone();
+						newBlock.moveChildren( element );
+						newBlock.append( element );
+					}
+				}
+			}
+
+			if ( !CKEDITOR.env.ie )
+				newBlock.appendBogus();
+
+			range.insertNode( newBlock );
+
+			// This is tricky, but to make the new block visible correctly
+			// we must select it.
+			// The previousBlock check has been included because it may be
+			// empty if we have fixed a block-less space (like ENTER into an
+			// empty table cell).
+			if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) )
+			{
+				// Move the selection to the new block.
+				range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock );
+				range.select();
+			}
+
+			// Move the selection to the new block.
+			range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock );
+		}
+
+		if ( !CKEDITOR.env.ie )
+		{
+			if ( nextBlock )
+			{
+				// If we have split the block, adds a temporary span at the
+				// range position and scroll relatively to it.
+				var tmpNode = doc.createElement( 'span' );
+
+				// We need some content for Safari.
+				tmpNode.setHtml( '&nbsp;' );
+
+				range.insertNode( tmpNode );
+				tmpNode.scrollIntoView();
+				range.deleteContents();
+			}
+			else
+			{
+				// We may use the above scroll logic for the new block case
+				// too, but it gives some weird result with Opera.
+				newBlock.scrollIntoView();
+			}
+		}
+
+		range.select();
+	}
+
+	function enterBr( editor, mode )
+	{
+		// Get the range for the current selection.
+		var range = getRange( editor ),
+			doc = range.document;
+
+		// Determine the block element to be used.
+		var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
+
+		var isEndOfBlock = range.checkEndOfBlock();
+
+		var elementPath = new CKEDITOR.dom.elementPath( range.getBoundaryNodes().startNode );
+
+		var startBlock = elementPath.block,
+			startBlockTag = startBlock && elementPath.block.getName();
+
+		var isPre = false;
+
+		if ( !forceMode && startBlockTag == 'li' )
+			return enterBlock( editor, mode, range );
+
+		// If we are at the end of a header block.
+		if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) )
+		{
+			// Insert a <br> after the current paragraph.
+			doc.createElement( 'br' ).insertAfter( startBlock );
+
+			// A text node is required by Gecko only to make the cursor blink.
+			if ( CKEDITOR.env.gecko )
+				doc.createText( '' ).insertAfter( startBlock );
+
+			// IE has different behaviors regarding position.
+			range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START );
+		}
+		else
+		{
+			var lineBreak;
+
+			isPre = ( startBlockTag == 'pre' );
+
+			if ( isPre )
+				lineBreak = doc.createText( CKEDITOR.env.ie ? '\r' : '\n' );
+			else
+				lineBreak = doc.createElement( 'br' );
+
+			range.insertNode( lineBreak );
+
+			// A text node is required by Gecko only to make the cursor blink.
+			if ( CKEDITOR.env.gecko )
+				doc.createText( '' ).insertAfter( lineBreak );
+
+			// If we are at the end of a block, we must be sure the bogus node is available in that block.
+			if ( isEndOfBlock && !CKEDITOR.env.ie )
+				lineBreak.getParent().appendBogus();
+
+			// IE has different behavior regarding position.
+			if ( CKEDITOR.env.ie )
+				range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END );
+			else
+				range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START );
+
+			// Scroll into view, for non IE.
+			if ( !CKEDITOR.env.ie )
+			{
+				var dummy = null;
+
+				if ( CKEDITOR.env.opera )
+					dummy = doc.createElement( 'span' );
+				else
+					dummy = doc.createElement( 'br' );
+
+				dummy.insertBefore( lineBreak.getNext() );
+				dummy.scrollIntoView();
+				dummy.remove();
+			}
+		}
+
+		// This collapse guarantees the cursor will be blinking.
+		range.collapse( true );
+
+		range.select( isPre );
+	}
+
+	function getRange( editor )
+	{
+		// Get the selection ranges.
+		var ranges = editor.getSelection().getRanges();
+
+		// Delete the contents of all ranges except the first one.
+		for ( var i = ranges.length - 1 ; i > 0 ; i-- )
+		{
+			ranges[ i ].deleteContents();
+		}
+
+		// Return the first range.
+		return ranges[ 0 ];
+	}
+})();
Index: /CKEditor/trunk/_source/plugins/keystrokes/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/keystrokes/plugin.js	(revision 3193)
+++ /CKEditor/trunk/_source/plugins/keystrokes/plugin.js	(revision 3194)
@@ -16,4 +16,6 @@
 		 */
 		editor.keystrokeHandler = new CKEDITOR.keystrokeHandler( editor );
+
+		editor.specialKeys = {};
 	},
 
@@ -85,6 +87,7 @@
 		var keyCombination = event.getKeystroke();
 		var command = this.keystrokes[ keyCombination ];
+		var editor = this._.editor;
 
-		cancel = ( this._.editor.fire( 'key', { keyCode : keyCombination } ) === true );
+		cancel = ( editor.fire( 'key', { keyCode : keyCombination } ) === true );
 
 		if ( !cancel )
@@ -93,9 +96,15 @@
 			{
 				var data = { from : 'keystrokeHandler' };
-				cancel = ( this._.editor.execCommand( command, data ) !== false );
+				cancel = ( editor.execCommand( command, data ) !== false );
 			}
 
-			if ( !cancel )
-				cancel = !!this.blockedKeystrokes[ keyCombination ];
+			if  ( !cancel )
+			{
+				var handler = editor.specialKeys[ keyCombination ],
+					cancel = ( handler && handler( editor ) === true );
+
+				if ( !cancel )
+					cancel = !!this.blockedKeystrokes[ keyCombination ];
+			}
 		}
 
@@ -167,9 +176,9 @@
 	[ CKEDITOR.CTRL + 89 /*Y*/, 'redo' ],
 	[ CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/, 'redo' ],
+
 	[ CKEDITOR.CTRL + 76 /*L*/, 'link' ],
+
 	[ CKEDITOR.CTRL + 66 /*B*/, 'bold' ],
 	[ CKEDITOR.CTRL + 73 /*I*/, 'italic' ],
-	[ CKEDITOR.CTRL + 85 /*U*/, 'underline' ],
-	[ CKEDITOR.CTRL + CKEDITOR.ALT + 13 /*ENTER*/, 'fitWindow' ],
-	[ CKEDITOR.SHIFT + 32 /*SPACE*/, 'nbsp' ]
+	[ CKEDITOR.CTRL + 85 /*U*/, 'underline' ]
 ];
Index: /CKEditor/trunk/_source/plugins/selection/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 3193)
+++ /CKEditor/trunk/_source/plugins/selection/plugin.js	(revision 3194)
@@ -699,6 +699,17 @@
 			else
 			{
-				isStartMakerAlone = ( !startNode.hasPrevious() || ( startNode.getPrevious().is && startNode.getPrevious().is( 'br' ) ) )
-					&& !startNode.hasNext();
+// The isStartMakerAlone logic comes from V2. It guarantees that the lines
+// will expand and that the cursor will be blinking on the right place.
+// Actually, we are using this flag just to avoid using this hack in all
+// situations, but just on those needed.
+
+// But, in V3, somehow it is not interested on working whe hitting SHIFT+ENTER
+// inside text. So, let's jsut leave the hack happen always.
+
+// I'm still leaving the code here just in case. We may find some other IE
+// weirdness and uncommenting this stuff may be useful.
+
+//				isStartMakerAlone = ( !startNode.hasPrevious() || ( startNode.getPrevious().is && startNode.getPrevious().is( 'br' ) ) )
+//					&& !startNode.hasNext();
 
 				// Append a temporary <span>&#65279;</span> before the selection.
@@ -711,12 +722,12 @@
 				dummySpan.insertBefore( startNode );
 
-				if ( isStartMakerAlone )
-				{
+//				if ( isStartMakerAlone )
+//				{
 					// To expand empty blocks or line spaces after <br>, we need
 					// instead to have any char, which will be later deleted using the
 					// selection.
-					// \ufeff = Zero Width No-Break Space (U+FEFF). See #1359.
+					// \ufeff = Zero Width No-Break Space (U+FEFF). (#1359)
 					this.document.createText( '\ufeff' ).insertBefore( startNode );
-				}
+//				}
 			}
 
@@ -727,16 +738,16 @@
 			if ( collapsed )
 			{
-				if ( isStartMakerAlone )
-				{
-					// Move the selection start to include the temporary &#65279;.
-					//ieRange.moveStart( 'character', -1 );
+//				if ( isStartMakerAlone )
+//				{
+					// Move the selection start to include the temporary \ufeff.
+					ieRange.moveStart( 'character', -1 );
 
 					ieRange.select();
 
 					// Remove our temporary stuff.
-//					this.document.$.selection.clear();
-				}
-				else
-					ieRange.select();
+					this.document.$.selection.clear();
+//				}
+//				else
+//					ieRange.select();
 
 				dummySpan.remove();
Index: /CKEditor/trunk/ckeditor.pack
===================================================================
--- /CKEditor/trunk/ckeditor.pack	(revision 3193)
+++ /CKEditor/trunk/ckeditor.pack	(revision 3194)
@@ -30,4 +30,7 @@
 		'CKEDITOR.POSITION_IS_CONTAINED' : 8,
 		'CKEDITOR.POSITION_CONTAINS' : 16,
+		'CKEDITOR.ENTER_P' : 1,
+		'CKEDITOR.ENTER_BR' : 2,
+		'CKEDITOR.ENTER_DIV' : 3,
 		'CKEDITOR.TRISTATE_ON' : 1,
 		'CKEDITOR.TRISTATE_OFF' : 2,
@@ -127,4 +130,6 @@
 					'_source/plugins/contextmenu/plugin.js',
 					'_source/plugins/elementspath/plugin.js',
+					'_source/plugins/enterkey/plugin.js',
+					'_source/plugins/entities/plugin.js',
 					'_source/plugins/find/plugin.js',
 					'_source/plugins/flash/plugin.js',
