Index: core/tools.js
===================================================================
--- core/tools.js (revision 3504)
+++ core/tools.js (working copy)
@@ -169,6 +169,18 @@
},
/**
+ * Determine whether an given object has no own property.
+ * @param {Object|null|undefined} object
+ */
+ isEmpty : function( object )
+ {
+ for ( var property in object )
+ if ( object.hasOwnProperty( property ) )
+ return false;
+ return true;
+ },
+
+ /**
* Transforms a CSS property name to its relative DOM style name.
* @param {String} cssName The CSS property name.
* @returns {String} The transformed name.
Index: plugins/styles/plugin.js
===================================================================
--- plugins/styles/plugin.js (revision 3524)
+++ plugins/styles/plugin.js (working copy)
@@ -81,7 +81,19 @@
var objectElements = { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,ul:1 };
var semicolonFixRegex = /\s*(?:;\s*|$)/;
-
+ // Customizing CKEDITOR.dom.node::getNext for ignoring bookmark nodes.
+ function getNextSibling( currentNode )
+ {
+ var next = currentNode;
+ do
+ {
+ next = next.getNext();
+ }
+ while( next && next.getName
+ && next.getName() == 'span'
+ && next.getAttribute( '_fck_bookmark' ) );
+ return next;
+ }
CKEDITOR.style = function( styleDefinition, variablesValues )
{
if ( variablesValues )
@@ -363,7 +375,9 @@
var nodeType = currentNode.type;
var nodeName = nodeType == CKEDITOR.NODE_ELEMENT ? currentNode.getName() : null;
- if ( nodeName && currentNode.getAttribute( '_fck_bookmark' ) )
+ // Ignore bookmark nodes.
+ if ( nodeName && currentNode.hasAttribute( '_fck_bookmark' )
+ || !nodeName && currentNode.getParent().hasAttribute( '_fck_bookmark' ) )
{
currentNode = currentNode.getNextSourceNode( true );
continue;
@@ -399,19 +413,17 @@
// if this is the last node in its parent, we must also
// check if the parent itself can be added completelly
// to the range.
- while ( !includedNode.$.nextSibling
+ while ( !getNextSibling( includedNode )
&& ( parentNode = includedNode.getParent(), dtd[ parentNode.getName() ] )
&& ( parentNode.getPosition( firstNode ) | CKEDITOR.POSITION_FOLLOWING | CKEDITOR.POSITION_IDENTICAL | CKEDITOR.POSITION_IS_CONTAINED ) == ( CKEDITOR.POSITION_FOLLOWING + CKEDITOR.POSITION_IDENTICAL + CKEDITOR.POSITION_IS_CONTAINED ) )
- {
includedNode = parentNode;
- }
styleRange.setEndAfter( includedNode );
// If the included node still is the last node in its
// parent, it means that the parent can't be included
// in this style DTD, so apply the style immediately.
- if ( !includedNode.$.nextSibling )
+ if ( !getNextSibling( includedNode ) )
applyStyle = true;
if ( !hasContents )
@@ -675,31 +687,32 @@
function removeFromElement( style, element )
{
var def = style._.definition,
- attributes = def.attributes,
+ attributes = CKEDITOR.tools.extend( {},
+ def.attributes,
+ // Override styles on the element.
+ getOverrides( style )[ element.getName() ] ),
styles = def.styles,
- overrides = getOverrides( style );
+ // If the style is only about the element itself, we have to remove the element.
+ removeEmpty = CKEDITOR.tools.isEmpty( attributes ) && CKEDITOR.tools.isEmpty( styles );
- function removeAttrs()
+ // If there's any to-be-removed style/attribute, remove them from the element,
+ // then only remove the element if it's empty.
+ for ( var attName in attributes )
{
- for ( var attName in attributes )
- {
- // The 'class' element value must match (#1318).
- if ( attName == 'class' && element.getAttribute( attName ) != attributes[ attName ] )
- continue;
- element.removeAttribute( attName );
- }
+ // The 'class' element value must match (#1318).
+ if ( attName == 'class' && element.getAttribute( attName ) != attributes[ attName ] )
+ continue;
+ element.removeAttribute( attName );
+ removeEmpty = true;
}
- // Remove definition attributes/style from the elemnt.
- removeAttrs();
for ( var styleName in styles )
+ {
element.removeStyle( styleName );
-
- // Now remove override styles on the element.
- attributes = overrides[ element.getName() ];
- if( attributes )
- removeAttrs();
- removeNoAttribsElement( element );
+ removeEmpty = true;
+ }
+ if ( removeEmpty )
+ removeNoAttribsElement( element );
}
// Removes a style from inside an element.
Index: tests/plugins/styles/styles.html
===================================================================
--- tests/plugins/styles/styles.html (revision 3515)
+++ tests/plugins/styles/styles.html (working copy)
@@ -206,10 +206,10 @@
} );
style.applyToRange( range );
- assert.areSame( 'this is some sample text', getInnerHtml( '_P1' ) );
+ assert.areSame( 'this is some sample text', getInnerHtml( '_P1' ) );
},
- test_inline11 : function()
+ test_inline12 : function()
{
doc.getById( '_P1' ).setHtml( 'this is some sample text' );
@@ -223,9 +223,9 @@
assert.areSame( 'this is some sample text', getInnerHtml( '_P1' ) );
},
- test_inline12 : function()
+ test_inline13 : function()
{
- doc.getById( '_P1' ).setHtml( 'this is some sample text' );
+ doc.getById( '_P1' ).setHtml( 'this is some sample text' );
var range = new CKEDITOR.dom.range( doc );
range.setStart( doc.getById( '_P1' ), 0 );
@@ -237,7 +237,7 @@
assert.areSame( 'this is some sample text', getInnerHtml( '_P1' ) );
},
- test_inline13 : function()
+ test_inline14 : function()
{
doc.getById( '_P1' ).setHtml( 'this is some sample text' );
@@ -251,7 +251,7 @@
assert.areSame( 'this is some sample text', getInnerHtml( '_P1' ) );
},
- test_inline14 : function()
+ test_inline15 : function()
{
var para = doc.getById( '_P1' );
@@ -277,7 +277,7 @@
assert.areSame( 'this is some sample text', getInnerHtml( '_P1' ), 'Second range' );
},
- test_inline15 : function()
+ test_inline16 : function()
{
var para = doc.getById( '_P1' );
@@ -304,7 +304,7 @@
assert.areSame( 'this is some sample text', getInnerHtml( '_P1' ), 'Second range' );
},
- test_inline16 : function()
+ test_inline17 : function()
{
var para = doc.getById( '_P1' );
@@ -336,7 +336,7 @@
test_ticket_2040 : function()
{
- doc.getById( '_P1' ).setHtml( 'This is some sample text<\/strong>. You are using CKEditor<\/a>.' );
+ doc.getById( '_P1' ).setHtml( 'This is some sample text<\/strong>. You are using ckeditor<\/a>.' );
var range = new CKEDITOR.dom.range( doc );
range.setStart( doc.getById( '_P1' ), 1 );
@@ -345,7 +345,7 @@
var style = new CKEDITOR.style( { element : 'i' } );
style.applyToRange( range );
- assert.areSame( 'this is some sample text<\/strong>. you are using CKEditor<\/a>.', getInnerHtml( '_P1' ) );
+ assert.areSame( 'this is some sample text<\/strong>. you are using ckeditor<\/a>.', getInnerHtml( '_P1' ) );
},
test_checkElementRemovable1 : function()
@@ -486,10 +486,24 @@
assert.areSame( 'text
outter', getInnerHtml( element ) );
},
+ test_ticket_3576 : function()
+ {
+ var element = doc.getById( '_P1' );
+ element.setHtml( 'inline' );
+
+ var range = new CKEDITOR.dom.range( doc );
+ range.selectNodeContents( element.getFirst().getFirst() );
+
+ var style = new CKEDITOR.style( { element : 'span', attributes : { class : 'style' } } );
+ style.applyToRange( range );
+
+ assert.areSame( 'inline', getInnerHtml( element ) );
+ },
+
name : document.title
};
})() );
-
+//window.onload = testCase.test_inline11;
//]]>