Index: _source/plugins/wysiwygarea/plugin.js
===================================================================
--- _source/plugins/wysiwygarea/plugin.js (revision 3489)
+++ _source/plugins/wysiwygarea/plugin.js Tue May 26 19:03:58 CST 2009
@@ -114,7 +114,58 @@
this.getSelection().lock();
}
}
-
+
+ /**
+ * Auto-fixing block-less content by wrapping paragraph, prevent
+ * non-exitable-block by padding extra br.
+ */
+ function onSelectionChangeFixBody( evt )
+ {
+ var editor = evt.editor,
+ path = evt.data.path,
+ blockLimit = path.blockLimit,
+ body = editor.document.getBody(),
+ enterMode = editor.config.enterMode;
+
+ // When enterMode set to block, we'll establing new paragraph if the
+ // current range is block-less within body.
+ if ( enterMode != CKEDITOR.ENTER_BR
+ && blockLimit.getName() == 'body'
+ && !path.block )
+ {
+ var range = evt.data.selection.getRanges()[0],
+ fixedBlock = range.fixBlock( true,
+ editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
+
+ // For IE, we'll be removing any bogus br ( introduce by fixing body )
+ // right now to prevent it introducing visual line break.
+ if ( CKEDITOR.env.ie )
+ {
+ var children = fixedBlock.getChildren(), child;
+ for ( var i = 0 ; i < children.count() ; i++ ) {
+ if ( ( child = children.getItem( i ) ) && child.is
+ && child.is( 'br' ) && child.hasAttribute( '_cke_bogus' ) )
+ child.remove();
+ }
+ }
+
+ // It's been guaranteed we're always at the beginning of text in this case.
+ range.moveToElementEditStart( fixedBlock );
+ range.select();
+ }
+
+ // Inserting the padding-br before body if it's preceded by an
+ // unexitable block.
+ var lastNode = body.getLast( true );
+ if ( lastNode.getName && ( lastNode.getName() in CKEDITOR.dtd.$nonExitable ) )
+ {
+ var paddingBlock = editor.document.createElement(
+ ( CKEDITOR.env.ie && enterMode != CKEDITOR.ENTER_BR ) ?
+ '
' : 'br' );
+ body.append( paddingBlock );
+ }
+ }
+
CKEDITOR.plugins.add( 'wysiwygarea',
{
requires : [ 'editingblock' ],
@@ -449,6 +500,8 @@
editor.on( 'insertHtml', onInsertHtml, null, null, 20 );
editor.on( 'insertElement', onInsertElement, null, null, 20 );
+ // Auto fixing on some document structure weakness to enhance usabilities. (#3190 and #3189)
+ editor.on( 'selectionChange', onSelectionChangeFixBody, null, null, 1 );
});
}
});
Index: _source/core/dom/element.js
===================================================================
--- _source/core/dom/element.js (revision 3517)
+++ _source/core/dom/element.js Tue May 26 18:20:06 CST 2009
@@ -643,10 +643,17 @@
return $ ? new CKEDITOR.dom.node( $ ) : null;
},
- getLast : function()
+ /**
+ * @param ignoreEmpty Skip empty text nodes.
+ */
+ getLast : function( ignoreEmpty )
{
var $ = this.$.lastChild;
+ if ( ignoreEmpty && $ && ( $.nodeType == CKEDITOR.NODE_TEXT )
+ && !CKEDITOR.tools.trim( $.nodeValue ) )
+ return new CKEDITOR.dom.node( $ ).getPrevious( true );
+ else
- return $ ? new CKEDITOR.dom.node( $ ) : null;
+ return $ ? new CKEDITOR.dom.node( $ ) : null;
},
getStyle : function( name )
Index: _source/core/dom/node.js
===================================================================
--- _source/core/dom/node.js (revision 3536)
+++ _source/core/dom/node.js Tue May 26 18:22:36 CST 2009
@@ -259,16 +259,6 @@
return -1;
},
- /**
- * Gets the node following this node (next sibling).
- * @returns {CKEDITOR.dom.node} The next node.
- */
- getNext : function()
- {
- var next = this.$.nextSibling;
- return next ? new CKEDITOR.dom.node( next ) : null;
- },
-
getNextSourceNode : function( startFromSibling, nodeType, guard )
{
// If "guard" is a node, transform it in a function.
@@ -360,14 +350,19 @@
return node;
},
- getPrevious : function()
+ getPrevious : function( ignoreEmpty )
{
var previous = this.$.previousSibling;
+ if ( ignoreEmpty && previous && ( previous.nodeType == CKEDITOR.NODE_TEXT )
+ && !CKEDITOR.tools.trim( previous.nodeValue ) )
+ return new CKEDITOR.dom.node( previous ).getPrevious();
+ else
- return previous ? new CKEDITOR.dom.node( previous ) : null;
+ return previous ? new CKEDITOR.dom.node( previous ) : null;
},
/**
* Gets the node that follows this element in its parent's child list.
+ * @param {Boolean} ignoreEmpty Whether should ignore empty text nodes.
* @returns {CKEDITOR.dom.node} The next node or null if not
* available.
* @example
@@ -375,10 +370,14 @@
* var first = element.getFirst().getNext();
* alert( first.getName() ); // "i"
*/
- getNext : function()
+ getNext : function( ignoreEmpty )
{
- var $ = this.$.nextSibling;
- return $ ? new CKEDITOR.dom.node( $ ) : null;
+ var next = this.$.nextSibling;
+ if ( ignoreEmpty && next && ( next.nodeType == CKEDITOR.NODE_TEXT )
+ && !CKEDITOR.tools.trim( next.nodeValue ) )
+ return new CKEDITOR.dom.node( next ).getNext();
+ else
+ return next ? new CKEDITOR.dom.node( next ) : null;
},
/**
Index: _source/core/dtd.js
===================================================================
--- _source/core/dtd.js (revision 3496)
+++ _source/core/dtd.js Tue May 26 18:33:54 CST 2009
@@ -113,6 +113,11 @@
*/
$tableContent : {caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1},
+ /**
+ * List of elements in which has no way to move editing focus outside.
+ */
+ $nonExitable :{table:1,pre:1},
+
col : {},
tr : {td:1,th:1},
img : {},
Index: _source/core/dom/range.js
===================================================================
--- _source/core/dom/range.js (revision 3477)
+++ _source/core/dom/range.js Tue May 26 18:51:34 CST 2009
@@ -31,6 +31,8 @@
// V2
var execContentsAction = function( range, action, docFrag )
{
+ range.optimizeBookmark();
+
var startNode = range.startContainer;
var endNode = range.endContainer;
@@ -653,6 +655,22 @@
}
},
+ /**
+ * Move the range out of bookmark nodes if they're been the container.
+ */
+ optimizeBookmark: function()
+ {
+ var startNode = this.startContainer,
+ endNode = this.endContainer;
+
+ if ( startNode.is && startNode.is( 'span' )
+ && startNode.hasAttribute( '_fck_bookmark' ) )
+ this.setStartAt( startNode, CKEDITOR.POSITION_BEFORE_START );
+ if ( endNode && endNode.is && endNode.is( 'span' )
+ && endNode.hasAttribute( '_fck_bookmark' ) )
+ this.setEndAt( endNode, CKEDITOR.POSITION_AFTER_END );
+ },
+
trim : function( ignoreStart, ignoreEnd )
{
var startContainer = this.startContainer;
@@ -1136,6 +1154,7 @@
*/
insertNode : function( node )
{
+ this.optimizeBookmark();
this.trim( false, true );
var startContainer = this.startContainer;