Index: _source/plugins/styles/plugin.js
===================================================================
--- _source/plugins/styles/plugin.js (revision 5347)
+++ _source/plugins/styles/plugin.js Thu Apr 22 14:16:05 CST 2010
@@ -550,7 +550,7 @@
styleRange.insertNode( styleNode );
// Let's merge our new style with its neighbors, if possible.
- mergeSiblings( styleNode );
+ styleNode.mergeSiblings();
// As the style system breaks text nodes constantly, let's normalize
// things for performance.
@@ -624,7 +624,7 @@
* no difference that they're separate entities in the DOM tree. So, merge
* them before removal.
*/
- mergeSiblings( element );
+ element.mergeSiblings();
removeFromElement( this, element );
}
@@ -1057,51 +1057,14 @@
if ( firstChild )
{
// Check the cached nodes for merging.
- mergeSiblings( firstChild );
+ firstChild.mergeSiblings();
if ( lastChild && !firstChild.equals( lastChild ) )
- mergeSiblings( lastChild );
+ lastChild.mergeSiblings();
}
}
}
- function mergeSiblings( element )
- {
- if ( !element || element.type != CKEDITOR.NODE_ELEMENT || !CKEDITOR.dtd.$removeEmpty[ element.getName() ] )
- return;
-
- mergeElements( element, element.getNext(), true );
- mergeElements( element, element.getPrevious() );
- }
-
- function mergeElements( element, sibling, isNext )
- {
- if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT )
- {
- var hasBookmark = sibling.getAttribute( '_fck_bookmark' );
-
- if ( hasBookmark )
- sibling = isNext ? sibling.getNext() : sibling.getPrevious();
-
- if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT && element.isIdentical( sibling ) )
- {
- // Save the last child to be checked too, to merge things like
- // =>
- var innerSibling = isNext ? element.getLast() : element.getFirst();
-
- if ( hasBookmark )
- ( isNext ? sibling.getPrevious() : sibling.getNext() ).move( element, !isNext );
-
- sibling.moveChildren( element, !isNext );
- sibling.remove();
-
- // Now check the last inner child (see two comments above).
- if ( innerSibling )
- mergeSiblings( innerSibling );
- }
- }
- }
-
function getElement( style, targetDocument )
{
var el;
Index: _source/core/dom/element.js
===================================================================
--- _source/core/dom/element.js (revision 5206)
+++ _source/core/dom/element.js Thu Apr 22 14:24:14 CST 2010
@@ -777,6 +777,31 @@
},
/**
+ * Whether it's an empty inline elements which has no visual impact when removed.
+ */
+ isEmptyInlineRemoveable : function()
+ {
+ if ( !CKEDITOR.dtd.$removeEmpty[ this.getName() ] )
+ return false;
+
+ var children = this.getChildren();
+ for ( var i = 0, count = children.count(); i < count; i++ )
+ {
+ var child = children.getItem( i );
+
+ if ( child.type == CKEDITOR.NODE_ELEMENT && child.getAttribute( '_fck_bookmark' ) )
+ continue;
+
+ if ( child.type == CKEDITOR.NODE_ELEMENT && !child.isEmptyInlineRemoveable()
+ || child.type == CKEDITOR.NODE_TEXT && CKEDITOR.tools.trim( child.getText() ) )
+ {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ /**
* Indicates that the element has defined attributes.
* @returns {Boolean} True if the element has attributes.
* @example
Index: _source/core/dom/node.js
===================================================================
--- _source/core/dom/node.js (revision 5189)
+++ _source/core/dom/node.js Thu Apr 22 14:24:49 CST 2010
@@ -550,6 +550,59 @@
target.append( this.remove(), toStart );
},
+ mergeSiblings : ( function()
+ {
+ function mergeElements( element, sibling, isNext )
+ {
+ if ( sibling && sibling.type == CKEDITOR.NODE_ELEMENT )
+ {
+ // Jumping over bookmark nodes and empty inline elements, e.g. ,
+ // queuing them to be moved later. (#5567)
+ var ignore,
+ pendingNodes = [];
+
+ while ( ignore = sibling.getAttribute( '_fck_bookmark' )
+ || sibling.isEmptyInlineRemoveable() )
+ {
+ pendingNodes.push( sibling );
+ sibling = isNext ? sibling.getNext() : sibling.getPrevious();
+ if ( !sibling || sibling.type != CKEDITOR.NODE_ELEMENT )
+ return;
+ }
+
+ if ( element.isIdentical( sibling ) )
+ {
+ // Save the last child to be checked too, to merge things like
+ // =>
+ var innerSibling = isNext ? element.getLast() : element.getFirst();
+
+ // Move pending nodes first into the target element.
+ while( pendingNodes.length )
+ pendingNodes.shift().move( element, !isNext );
+
+ sibling.moveChildren( element, !isNext );
+ sibling.remove();
+
+ // Now check the last inner child (see two comments above).
+ if ( innerSibling )
+ innerSibling.mergeSiblings();
+ }
+ }
+ }
+
+ return function()
+ {
+ if ( this.type != CKEDITOR.NODE_ELEMENT
+ || !CKEDITOR.dtd.$removeEmpty[ this.getName() ]
+ // Merge links but not anchors. (#5567)
+ && ( !this.is( 'a' ) || this.hasAttribute( 'name' ) ) )
+ return;
+
+ mergeElements( this, this.getNext(), true );
+ mergeElements( this, this.getPrevious() );
+ }
+ } )(),
+
/**
* Removes this node from the document DOM.
* @param {Boolean} [preserveChildren] Indicates that the children