Index: /CKEditor/trunk/_source/core/dom/documentFragment.js
===================================================================
--- /CKEditor/trunk/_source/core/dom/documentFragment.js	(revision 3212)
+++ /CKEditor/trunk/_source/core/dom/documentFragment.js	(revision 3213)
@@ -3,64 +3,44 @@
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */
-
+/**
+ * DocumentFragment is a "lightweight" or "minimal" Document object. It is
+ * commonly used to extract a portion of a document's tree or to create a new
+ * fragment of a document. Various operations may take DocumentFragment objects
+ * as arguments and results in all the child nodes of the DocumentFragment being
+ * moved to the child list of this node.
+ * 
+ * @param {Object} ownerDocument
+ */
 CKEDITOR.dom.documentFragment = function( ownerDocument )
 {
-	this.$ = CKEDITOR.env.ie ? ownerDocument.$.createElement( 'div' ) : ownerDocument.$.createDocumentFragment();
+	ownerDocument = ownerDocument || CKEDITOR.document;
+	this.$ = ownerDocument.$.createDocumentFragment();
 };
 
-(function()
-{
-	var elementPrototype = CKEDITOR.dom.element.prototype;
-
-	CKEDITOR.dom.documentFragment.prototype =
+CKEDITOR.tools.extend( CKEDITOR.dom.documentFragment.prototype, 
+	CKEDITOR.dom.element.prototype, 
 	{
 		type : CKEDITOR.NODE_DOCUMENT_FRAGMENT,
-
-		append : elementPrototype.append,
-
-		getFirst : elementPrototype.getFirst,
-
-		getLast : elementPrototype.getLast,
-
-		appendTo : function( targetElement )
-		{
-			if ( CKEDITOR.env.ie )
-				elementPrototype.moveChildren.call( this, targetElement );
-			else
-				targetElement.$.appendChild( this.$ );
-		},
-
-		moveChildren : elementPrototype.moveChildren,
-
 		insertAfterNode : function( node )
 		{
-			var $ = this.$;
-			var $node = node.$;
-			var $parent = $node.parentNode;
-
-			if ( CKEDITOR.env.ie )
-			{
-				for ( var child ; child = $.lastChild ; )
-					$parent.insertBefore( $.removeChild( child ), $node.nextSibling );
-			}
-			else
-				$parent.insertBefore( $, $node.nextSibling );
-		},
-
-		replace : function( nodeToReplace )
-		{
-			this.insertAfterNode( nodeToReplace );
-			nodeToReplace.remove();
-		},
-
-		trim : elementPrototype.trim,
-		ltrim : elementPrototype.ltrim,
-		rtrim : elementPrototype.rtrim,
-		getFirst : elementPrototype.getFirst,
-		getLast : elementPrototype.getLast,
-		getDocument : elementPrototype.getDocument,
-		getChildCount : elementPrototype.getChildCount,
-		getChild : elementPrototype.getChild,
-		contains : elementPrototype.contains
-	};
-})();
+			node = node.$;
+			node.parentNode.insertBefore( this.$, node.nextSibling );
+		}
+	},
+	true,
+	{ 
+		'append' : 1,
+		'getFirst' : 1,
+		'getLast' : 1,
+		'appendTo' : 1,
+		'moveChildren' : 1,
+		'insertAfterNode' : 1,
+		'replace' : 1,
+		'trim' : 1,
+		'ltrim' : 1,
+		'rtrim' : 1,
+		'getDocument' : 1,
+		'getChildCount' : 1,
+		'getChild' : 1,
+		'getChildren' : 1 
+	} );
Index: /CKEditor/trunk/_source/core/tools.js
===================================================================
--- /CKEditor/trunk/_source/core/tools.js	(revision 3212)
+++ /CKEditor/trunk/_source/core/tools.js	(revision 3213)
@@ -84,7 +84,9 @@
 		 * @param {Object} source[,souce(n)] The objects from which copy
 		 *		properties. Any number of objects can be passed to this function.
-		 * @param {Boolean} [overwrite] Indicates that properties already present
-		 *		in the target object must be overwritten. This must be the last
-		 *		parameter in the function call.
+		 * @param {Boolean} [overwrite] If 'true' is specified it indicates that
+		 *            properties already present in the target object could be
+		 *            overwritten by subsequent objects.
+		 * @param {Object} [properties] Only properties within the specified names
+		 *            list will be received from the source object.
 		 * @returns {Object} the extended object (target).
 		 * @example
@@ -109,19 +111,26 @@
 		{
 			var argsLength = arguments.length,
-				overwrite = arguments[ argsLength - 1 ];
-
-			if ( typeof overwrite == 'boolean' )
+				overwrite, propertiesList;
+
+			if ( typeof ( overwrite = arguments[ argsLength - 1 ] ) == 'boolean')
 				argsLength--;
-			else
-				overwrite = false;
-
+			else if ( typeof ( overwrite = arguments[ argsLength - 2 ] ) == 'boolean' )
+			{
+				propertiesList = arguments [ argsLength -1 ];
+				argsLength-=2;
+			}
 			for ( var i = 1 ; i < argsLength ; i++ )
 			{
 				var source = arguments[ i ];
-
 				for ( var propertyName in source )
 				{
-					if ( overwrite || target[ propertyName ] == undefined )
-						target[ propertyName ] = source[ propertyName ];
+					// Only copy existed fields if in overwrite mode. 
+					if ( overwrite === true || target[ propertyName ] == undefined ) 
+					{
+						// Only copy  specified fields if list is provided.
+						if ( !propertiesList || ( propertyName in propertiesList ) )
+							target[ propertyName ] = source[ propertyName ];
+							
+					} 
 				}
 			}
Index: /CKEditor/trunk/_source/tests/core/dom/documentFragment.html
===================================================================
--- /CKEditor/trunk/_source/tests/core/dom/documentFragment.html	(revision 3213)
+++ /CKEditor/trunk/_source/tests/core/dom/documentFragment.html	(revision 3213)
@@ -0,0 +1,223 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<title>CKEDITOR.dom.documentFragment</title>
+	<link rel="stylesheet" type="text/css" href="../../test.css" />
+	<script type="text/javascript" src="../../../../ckeditor_source.js"></script> <!-- %REMOVE_LINE%
+	<script type="text/javascript" src="../../../ckeditor.js"></script>
+	%REMOVE_LINE% -->
+	<script type="text/javascript" src="../../test.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+CKEDITOR.test.addTestCase( ( function()
+{
+	// Local reference to the "assert" object.
+	var assert = YAHOO.util.Assert;
+
+	return {
+		
+		test_appendTo : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner = 
+					new CKEDITOR.dom.element( 'b' );
+			frag.append( inner );
+			var container = CKEDITOR.document.getById( 'fragmentContainer1' );
+			frag.appendTo( container );
+			assert.isTrue( container.getLast().equals( inner ) );
+		},
+
+		test_append : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner = 
+					new CKEDITOR.dom.element( 'b' );
+			frag.append( inner );
+			var container = CKEDITOR.document.getById( 'fragmentContainer3' );
+			container.append( frag );
+			assert.isTrue( container.getLast().equals( inner ) );
+		},
+
+		test_getFirst : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner = 
+					new CKEDITOR.dom.element( 'b' );
+			frag.append( inner );
+			var first = frag.getFirst();
+			assert.isTrue( first.equals( inner ) );
+		},
+
+		test_getLast : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner = 
+					new CKEDITOR.dom.element( 'b' ), lastInner = inner.clone();
+			frag.append( inner );
+			frag.append( lastInner );
+			var last = frag.getLast();
+			assert.isTrue( last.equals( lastInner ) );
+		},
+
+		test_moveChildren : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner1 = new CKEDITOR.dom.element( 'b' ), 
+			inner2 = new CKEDITOR.dom.element( 'i' );
+			frag.append( inner1 );
+			frag.append( inner2 );
+
+			// Move to element
+			var element = new CKEDITOR.dom.element( 'span' );
+			frag.moveChildren( element, true );
+			assert.isTrue( element.getFirst().equals( inner1 ) );
+			assert.isTrue( element.getLast().equals( inner2 ) );
+		},
+
+		test_moveChildren2 : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner1 = new CKEDITOR.dom.element( 'b' ), 
+				inner2 = new CKEDITOR.dom.element( 'i' );
+			frag.append( inner1 );
+			frag.append( inner2 );
+
+			// Move to fragment
+			var anotherFrag = new CKEDITOR.dom.documentFragment(
+				CKEDITOR.document );
+			frag.moveChildren( anotherFrag, true );
+			assert.isTrue( anotherFrag.getFirst().equals( inner1 ) );
+			assert.isTrue( anotherFrag.getLast().equals( inner2 ) );
+		},
+
+		test_appendText : function()
+		{
+			var element = new CKEDITOR.dom.element( 'script' );
+			element.appendText( 'Test appendText' );
+			assert.areEqual( 'Test appendText', element.$.text );
+		},
+
+		test_ltrim : function()
+		{
+			var element = CKEDITOR.document.getById( 'trimTarget' )
+				.clone( true );
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			element.moveChildren( frag );
+			frag.ltrim();
+			var ct = new CKEDITOR.dom.element( 'div' );
+			ct.append( frag );
+			assert.areSame( 'text \t\n', ct.getText() );
+		},
+
+		test_rtrim : function()
+		{
+			var element = CKEDITOR.document.getById( 'trimTarget' )
+				.clone( true );
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			element.moveChildren( frag );
+			frag.rtrim();
+			var ct = new CKEDITOR.dom.element( 'div' );
+			ct.append( frag );
+			assert.areSame( ' \t\ntext', ct.getText() );
+		},
+
+		test_trim : function()
+		{
+			var element = 
+					CKEDITOR.document.getById( 'trimTarget' ).clone( true );
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			element.moveChildren( frag );
+			frag.trim();
+			var ct = new CKEDITOR.dom.element( 'div' );
+			ct.append( frag );
+			assert.areSame( 'text', ct.getText() );
+		},
+
+		test_insertAfter : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner = new CKEDITOR.dom.element( 'b' );
+			frag.append( inner );
+			var container = CKEDITOR.document.getById( 'fragmentContainer2' );
+			var sibling = CKEDITOR.document.getById( 'fragmentSibling1' );
+			frag.insertAfterNode( sibling );
+			assert.isTrue( container.getLast().equals( inner ) );
+		},
+
+		test_getChildCount : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner1 = new CKEDITOR.dom.element( 'b' ), 
+				inner2 = new CKEDITOR.dom.element( 'i' );
+			frag.append( inner1 );
+			frag.append( inner2 );
+
+			assert.areEqual( 2, frag.getChildCount() );
+		},
+
+		test_getChild : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner1 = new CKEDITOR.dom.element( 'b' ), 
+				inner2 = new CKEDITOR.dom.element( 'i' );
+			frag.append( inner1 );
+			frag.append( inner2 );
+
+			assert.isTrue( inner2.equals( frag.getChild( 1 ) ) );
+		},
+
+		test_getChildren : function()
+		{
+			var frag = 
+					new CKEDITOR.dom.documentFragment( CKEDITOR.document );
+			var inner1 = new CKEDITOR.dom.element( 'b' ), 
+				inner2 = new CKEDITOR.dom.element( 'i' );
+			frag.append( inner1 );
+			frag.append( inner2 );
+
+			var childNodesList = frag.getChildren();
+			assert.areEqual( 2, childNodesList.count() );
+			assert.isTrue( inner2.equals( childNodesList.getItem( 1 ) ) );
+		},
+
+		test_getDocument : function()
+		{
+			var doc = CKEDITOR.document, 
+				innerDoc = new CKEDITOR.dom.document( 
+					doc.getById( 'innerFrame' ).$.contentWindow.document );
+			var frag1 = new CKEDITOR.dom.documentFragment( doc ), 
+				frag2 = new CKEDITOR.dom.documentFragment( innerDoc );
+
+			assert.isTrue( doc.equals( frag1.getDocument() ) );
+			assert.isTrue( innerDoc.equals( frag2.getDocument() ) );
+		},
+
+		name :document.title
+	};
+} )() );
+
+	//]]>
+	</script>
+</head>
+<body>
+	<div id="fragmentContainer1"></div>
+	<div id="fragmentContainer2"><div id="fragmentSibling1"></div></div>
+	<div id="fragmentContainer3"></div>
+	<div id="trimTarget"> 	
+text 	
+</div>
+	<iframe id="innerFrame" name="innerFrame" src="about:blank"></iframe>
+</body>
+</html>
