Index: /FCKeditor/trunk/_test/automated/tests/fckw3crange.html
===================================================================
--- /FCKeditor/trunk/_test/automated/tests/fckw3crange.html	(revision 48)
+++ /FCKeditor/trunk/_test/automated/tests/fckw3crange.html	(revision 49)
@@ -174,6 +174,4 @@
 	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
 	assertFalse( 'range.collapsed', range.collapsed ) ;
-
-	ResetBody() ;
 }
 
@@ -193,6 +191,4 @@
 	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
 	assertFalse( 'range.collapsed', range.collapsed ) ;
-
-	ResetBody() ;
 }
 
@@ -213,6 +209,4 @@
 	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
 	assertFalse( 'range.collapsed', range.collapsed ) ;
-
-	ResetBody() ;
 }
 
@@ -236,6 +230,4 @@
 
 	assertEquals( 'Start must be on new node', range.startContainer.childNodes[range.startOffset], eNewNode ) ;
-
-	ResetBody() ;
 }
 
@@ -255,6 +247,4 @@
 	assertEquals( 'range.endOffset', 0, range.endOffset ) ;
 	assertFalse( 'range.collapsed', range.collapsed ) ;
-	
-	ResetBody() ;
 }
 
@@ -275,6 +265,4 @@
 	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
 	assertFalse( 'range.collapsed', range.collapsed ) ;
-	
-	ResetBody() ;
 }
 
@@ -295,16 +283,504 @@
 	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
 	assertFalse( 'range.collapsed', range.collapsed ) ;
-	
-	ResetBody() ;
-}
-
-// This function should be called by tests that change the DOM tree (after the test).
-function ResetBody()
-{
-	document.body.innerHTML = '<h1 id="_H1">FCKW3CRange Test</h1><p id="_P">This is <b id="_B">some</b> text.</p>' ;
-}
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 1
+function test_deleteContents_W3C_1()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_P' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_P' ), 2 ) ;
+	
+	range.deleteContents() ;
+	
+	assertEquals( 'HTML after deletion', 't text.', GetTestInnerHtml( document.getElementById( '_P' ) ) ) ;
+
+	assertEquals( 'range.startContainer', document.getElementById( '_P' ).firstChild, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_P' ).firstChild, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 2
+function test_deleteContents_W3C_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).nextSibling, 1 ) ;
+	
+	range.deleteContents() ;
+	
+	assertEquals( 'this is <b id=_b>s</b>text.', GetTestInnerHtml( document.getElementById( '_P' ) ) ) ;
+
+	assertEquals( 'range.startContainer', document.getElementById( '_P' ), range.startContainer ) ;
+	assertEquals( 'range.startOffset', 2, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_P' ), range.endContainer ) ;
+	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 3
+function test_deleteContents_W3C_3()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).previousSibling, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).firstChild, 1 ) ;
+	
+	range.deleteContents() ;
+	
+	assertEquals( 't<b id=_b>ome</b> text.', GetTestInnerHtml( document.getElementById( '_P' ) ) ) ;
+
+	assertEquals( 'range.startContainer', document.getElementById( '_P' ), range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_P' ), range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 4
+function test_deleteContents_W3C_4()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ).firstChild, 1 ) ;
+	range.setEnd( document.body.lastChild.firstChild, 1 ) ;
+
+	range.deleteContents() ;
+	
+	assertEquals( '<h1 id=_h1>f</h1><p>nother paragraph.</p>', GetTestInnerHtml( document.body ) ) ;
+
+	assertEquals( 'range.startContainer', document.body, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+function test_deleteContents_Other()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ), 0 ) ;
+	range.setEnd( document.body.lastChild, 1 ) ;
+	
+	range.deleteContents() ;
+
+	assertEquals( '<h1 id=_h1></h1><p></p>', GetTestInnerHtml( document.body ) ) ;
+
+	assertEquals( 'range.startContainer', document.body, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+function test_deleteContents_Other_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.body, 0 ) ;
+	range.setEnd( document.body, 2 ) ;
+	
+	range.deleteContents() ;
+
+	assertEquals( '<p>another paragraph.</p>', GetTestInnerHtml( document.body ) ) ;
+
+	assertEquals( 'range.startContainer', document.body, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 0, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 0, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.7 - Example 1
+function test_extractContents_W3C_1()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_P' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_P' ), 2 ) ;
+	
+	var docFrag = range.extractContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Extracted HTML', 'his is <b id=_b>some</b>', GetTestInnerHtml( tmpDiv ) ) ;
+	assertEquals( 'HTML after extraction', 't text.', GetTestInnerHtml( document.getElementById( '_P' ) ) ) ;
+
+	assertEquals( 'range.startContainer', document.getElementById( '_P' ).firstChild, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_P' ).firstChild, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.7 - Example 2
+function test_extractContents_W3C_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).nextSibling, 1 ) ;
+	
+	var docFrag = range.extractContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Extracted HTML', '<b id=_b>ome</b> ', GetTestInnerHtml( tmpDiv ) ) ;	
+	assertEquals( 'HTML after extraction', 'this is <b id=_b>s</b>text.', GetTestInnerHtml( document.getElementById( '_P' ) ) ) ;
+
+	assertEquals( 'range.startContainer', document.getElementById( '_P' ), range.startContainer ) ;
+	assertEquals( 'range.startOffset', 2, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_P' ), range.endContainer ) ;
+	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 3
+function test_extractContents_W3C_3()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).previousSibling, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).firstChild, 1 ) ;
+	
+	var docFrag = range.extractContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Extracted HTML', 'his is <b id=_b>s</b>', GetTestInnerHtml( tmpDiv ) ) ;	
+	assertEquals( 'HTML after extraction', 't<b id=_b>ome</b> text.', GetTestInnerHtml( document.getElementById( '_P' ) ) ) ;
+
+	assertEquals( 'range.startContainer', document.getElementById( '_P' ), range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_P' ), range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 4
+function test_extractContents_W3C_4()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ).firstChild, 1 ) ;
+	range.setEnd( document.body.lastChild.firstChild, 1 ) ;
+
+	var docFrag = range.extractContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Extracted HTML', '<h1 id=_h1>ckw3crange test</h1><p id=_p>this is <b id=_b>some</b> text.</p><p>a</p>', GetTestInnerHtml( tmpDiv ) ) ;	
+	assertEquals( '<h1 id=_h1>f</h1><p>nother paragraph.</p>', GetTestInnerHtml( document.body ) ) ;
+
+	assertEquals( 'range.startContainer', document.body, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+function test_extractContents_Other()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ), 0 ) ;
+	range.setEnd( document.body.lastChild, 1 ) ;
+	
+	var docFrag = range.extractContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Extracted HTML', '<h1 id=_h1>fckw3crange test</h1><p id=_p>this is <b id=_b>some</b> text.</p><p>another paragraph.</p>', GetTestInnerHtml( tmpDiv ) ) ;	
+	assertEquals( '<h1 id=_h1></h1><p></p>', GetTestInnerHtml( document.body ) ) ;
+
+	assertEquals( 'range.startContainer', document.body, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+function test_extractContents_Other_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.body, 0 ) ;
+	range.setEnd( document.body, 2 ) ;
+	
+	var docFrag = range.extractContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+	
+	assertEquals( 'Extracted HTML', '<h1 id=_h1>fckw3crange test</h1><p id=_p>this is <b id=_b>some</b> text.</p>', GetTestInnerHtml( tmpDiv ) ) ;	
+	assertEquals( '<p>another paragraph.</p>', document.body.innerHTML.replace( /id=_H1/, 'id="_H1"' ).toLowerCase().replace( /\n|\r/g, '' ) ) ;
+
+	assertEquals( 'range.startContainer', document.body, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 0, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 0, range.endOffset ) ;
+	assertTrue( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.7 - Example 1
+function test_cloneContents_W3C_1()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_P' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_P' ), 2 ) ;
+	
+	var bodyHtml = document.body.innerHTML ;
+	
+	var docFrag = range.cloneContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+	
+	assertEquals( 'Cloned HTML', 'his is <b id=_b>some</b>', GetTestInnerHtml( tmpDiv ) ) ;
+
+	// The body HTML must remain unchanged.
+	assertEquals( bodyHtml, document.body.innerHTML ) ;
+
+	// The range must also remain unchanged.
+	assertEquals( 'range.startContainer', document.getElementById( '_P' ).firstChild, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_P' ), range.endContainer ) ;
+	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
+	assertFalse( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.7 - Example 2
+function test_cloneContents_W3C_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).nextSibling, 1 ) ;
+	
+	var bodyHtml = document.body.innerHTML ;
+	
+	var docFrag = range.cloneContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Cloned HTML', '<b id=_b>ome</b> ', GetTestInnerHtml( tmpDiv ) ) ;	
+
+	// The body HTML must remain unchanged.
+	assertEquals( bodyHtml, document.body.innerHTML ) ;
+
+	// The range must also remain unchanged.
+	assertEquals( 'range.startContainer', document.getElementById( '_B' ).firstChild, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_B' ).nextSibling, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertFalse( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 3
+function test_cloneContents_W3C_3()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).previousSibling, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).firstChild, 1 ) ;
+	
+	var bodyHtml = document.body.innerHTML ;
+	
+	var docFrag = range.cloneContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Cloned HTML', 'his is <b id=_b>s</b>', GetTestInnerHtml( tmpDiv ) ) ;	
+
+	// The body HTML must remain unchanged.
+	assertEquals( bodyHtml, document.body.innerHTML ) ;
+
+	// The range must also remain unchanged.
+	assertEquals( 'range.startContainer', document.getElementById( '_B' ).previousSibling, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.getElementById( '_B' ).firstChild, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertFalse( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 4
+function test_cloneContents_W3C_4()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ).firstChild, 1 ) ;
+	range.setEnd( document.body.lastChild.firstChild, 1 ) ;
+
+	var bodyHtml = document.body.innerHTML ;
+	
+	var docFrag = range.cloneContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Cloned HTML', '<h1 id=_h1>ckw3crange test</h1><p id=_p>this is <b id=_b>some</b> text.</p><p>a</p>', GetTestInnerHtml( tmpDiv ) ) ;	
+
+	// The body HTML must remain unchanged.
+	assertEquals( bodyHtml, document.body.innerHTML ) ;
+
+	// The range must also remain unchanged.
+	assertEquals( 'range.startContainer', document.getElementById( '_H1' ).firstChild, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 1, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body.lastChild.firstChild, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertFalse( 'range.collapsed', range.collapsed ) ;
+}
+
+function test_cloneContents_Other()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ), 0 ) ;
+	range.setEnd( document.body.lastChild, 1 ) ;
+	
+	var bodyHtml = document.body.innerHTML ;
+	
+	var docFrag = range.cloneContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+
+	assertEquals( 'Cloned HTML', '<h1 id=_h1>fckw3crange test</h1><p id=_p>this is <b id=_b>some</b> text.</p><p>another paragraph.</p>', GetTestInnerHtml( tmpDiv ) ) ;	
+
+	// The body HTML must remain unchanged.
+	assertEquals( bodyHtml, document.body.innerHTML ) ;
+
+	// The range must also remain unchanged.
+	assertEquals( 'range.startContainer', document.getElementById( '_H1' ), range.startContainer ) ;
+	assertEquals( 'range.startOffset', 0, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body.lastChild, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 1, range.endOffset ) ;
+	assertFalse( 'range.collapsed', range.collapsed ) ;
+}
+
+function test_cloneContents_Other_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.body, 0 ) ;
+	range.setEnd( document.body, 2 ) ;
+	
+	var bodyHtml = document.body.innerHTML ;
+	
+	var docFrag = range.cloneContents() ;
+	
+	var tmpDiv = document.createElement( 'div' ) ;
+	if ( docFrag.AppendTo ) docFrag.AppendTo( tmpDiv ) ; else tmpDiv.appendChild( docFrag ) ;
+	
+	assertEquals( 'Cloned HTML', '<h1 id=_h1>fckw3crange test</h1><p id=_p>this is <b id=_b>some</b> text.</p>', GetTestInnerHtml( tmpDiv ) ) ;	
+
+	// The body HTML must remain unchanged.
+	assertEquals( bodyHtml, document.body.innerHTML ) ;
+
+	// The range must also remain unchanged.
+	assertEquals( 'range.startContainer', document.body, range.startContainer ) ;
+	assertEquals( 'range.startOffset', 0, range.startOffset ) ;
+	assertEquals( 'range.endContainer', document.body, range.endContainer ) ;
+	assertEquals( 'range.endOffset', 2, range.endOffset ) ;
+	assertFalse( 'range.collapsed', range.collapsed ) ;
+}
+
+// W3C DOM Range Specs - Section 2.7 - Example 1
+function test_toString_W3C_1()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_P' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_P' ), 2 ) ;
+	
+	assertEquals( 'his is some', range.toString() ) ;
+}
+
+
+// W3C DOM Range Specs - Section 2.7 - Example 2
+function test_toString_W3C_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).firstChild, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).nextSibling, 1 ) ;
+	
+	assertEquals( 'Cloned HTML', 'ome ', range.toString() ) ;	
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 3
+function test_toString_W3C_3()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_B' ).previousSibling, 1 ) ;
+	range.setEnd( document.getElementById( '_B' ).firstChild, 1 ) ;
+
+	assertEquals( 'Cloned HTML', 'his is s', range.toString() ) ;	
+}
+
+// W3C DOM Range Specs - Section 2.6 - Example 4
+function test_toString_W3C_4()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ).firstChild, 1 ) ;
+	range.setEnd( document.body.lastChild.firstChild, 1 ) ;
+
+	assertEquals( 'Cloned HTML', 'CKW3CRange TestThis is some text.A', range.toString() ) ;	
+}
+
+function test_toString_Other()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.getElementById( '_H1' ), 0 ) ;
+	range.setEnd( document.body.lastChild, 1 ) ;
+
+	assertEquals( 'Cloned HTML', 'FCKW3CRange TestThis is some text.Another paragraph.', range.toString() ) ;
+}
+
+function test_toString_Other_2()
+{
+	var range = FCKW3CRange.CreateRange( document ) ;
+
+	range.setStart( document.body, 0 ) ;
+	range.setEnd( document.body, 2 ) ;
+
+	assertEquals( 'Cloned HTML', 'FCKW3CRange TestThis is some text.', range.toString() ) ;	
+}
+
+	</script>
+<script type="text/javascript">
+
+// JsUnit special function called before every test start.
+function setUp()
+{
+	// Reset the body (because of changes by test functions).
+	document.body.innerHTML = '<h1 id="_H1">FCKW3CRange Test</h1><p id="_P">This is <b id="_B">some</b> text.</p><p>Another paragraph.</p>' ;	
+}
+
+// Use window.onload to call a test outside JsUnit (for debugging).
+// The "tests.js" script must be commented.
+//window.onload = function()
+//{
+//	test_cloneContents_W3C_1() ;
+//}
 
 	</script>
 </head>
-<body><h1 id="_H1">FCKW3CRange Test</h1><p id="_P">This is <b id="_B">some</b> text.</p></body>
+<body><h1 id="_H1">FCKW3CRange Test</h1><p id="_P">This is <b id="_B">some</b> text.</p><p>Another paragraph.</p></body>
 </html>
Index: /FCKeditor/trunk/_test/automated/tests/tests.js
===================================================================
--- /FCKeditor/trunk/_test/automated/tests/tests.js	(revision 48)
+++ /FCKeditor/trunk/_test/automated/tests/tests.js	(revision 49)
@@ -1,2 +1,10 @@
 ﻿if ( window == window.top )
 	window.location = '../_jsunit/testRunner.html?testpage=' + document.location.pathname ;
+
+function GetTestInnerHtml( element )
+{
+	// IE and others change the innerHTML to an internal format (without
+	// quotes, uppercased and linebreaks). Transform it in something usable for
+	// the tests assertions.
+	return element.innerHTML.replace( /"/g, '' ).toLowerCase().replace( /\n|\r/g, '' )
+}
Index: /FCKeditor/trunk/_test/manual/fckenterkey/test1.html
===================================================================
--- /FCKeditor/trunk/_test/manual/fckenterkey/test1.html	(revision 48)
+++ /FCKeditor/trunk/_test/manual/fckenterkey/test1.html	(revision 49)
@@ -7,8 +7,12 @@
 var FCK = {} ;
 
+FCKScriptLoader.Load( 'FCKDebug' ) ;
 FCKScriptLoader.Load( 'FCKEnterKey' ) ;
 
 	</script>
 	<script type="text/javascript">
+
+FCKConfig.Debug = true ;
+FCKConfig.BasePath = '../../../editor/' ;
 
 var oInnerWindow ;
Index: /FCKeditor/trunk/editor/_source/classes/fckw3crange.js
===================================================================
--- /FCKeditor/trunk/editor/_source/classes/fckw3crange.js	(revision 48)
+++ /FCKeditor/trunk/editor/_source/classes/fckw3crange.js	(revision 49)
@@ -150,8 +150,4 @@
 	},
 
-	cloneContents : function()
-	{
-	},
-
 	deleteContents : function()
 	{
@@ -159,10 +155,240 @@
 			return ;
 		
-		var startParents	= FCKDomTools.GetParents( this.startBoundary ) ;
-		var endParents		= FCKDomTools.GetParents( this.endBoundary ) ;
+		this._ExecContentsAction( 0 ) ;
 	},
 
 	extractContents : function()
 	{
+		var docFrag = new FCKDocumentFragment( this._Document ) ;
+
+		if ( !this.collapsed )
+			this._ExecContentsAction( 1, docFrag ) ;
+
+		return docFrag ;
+	},
+
+	cloneContents : function()
+	{
+		var docFrag = new FCKDocumentFragment( this._Document ) ;
+
+		if ( !this.collapsed )
+			this._ExecContentsAction( 2, docFrag ) ;
+
+		return docFrag ;
+	},
+
+	_ExecContentsAction : function( action, docFrag )
+	{	
+		var startNode	= this.startContainer ;
+		var endNode		= this.endContainer ;
+		
+		var startOffset	= this.startOffset ;
+		var endOffset	= this.endOffset ;
+		
+		var removeStartNode	= false ;
+		var removeEndNode	= false ;
+		
+		// Check the start and end nodes and make the necessary removals or changes.
+		
+		// Start from the end, otherwise DOM mutations (splitText) made in the
+		// start boundary may interfere on the results here.
+
+		// For text containers, we must simply split the node and point to the
+		// second part. The removal will be handled by the rest of the code .
+		if ( endNode.nodeType == 3 )
+			endNode = endNode.splitText( endOffset ) ;
+		else
+		{
+			// If the end container has children and the offset is pointing
+			// to a child, then we should start from it.
+			if ( endNode.childNodes.length > 0 )
+			{
+				// If the offset points after the last node, we let's use
+				// the last one, but mark it for removal.
+				if ( endOffset > endNode.childNodes.length - 1 )
+				{
+					endNode = endNode.lastChild ;
+					removeEndNode = true ;
+				}
+				else
+					endNode = endNode.childNodes[ endOffset ] ;
+			}
+		}
+
+		// For text containers, we must simply split the node. The removal will
+		// be handled by the rest of the code .
+		if ( startNode.nodeType == 3 )
+			startNode.splitText( startOffset ) ;
+		else
+		{
+			// If the start container has children and the offset is pointing
+			// to a child, then we should start from its previous sibling.
+			if ( startNode.childNodes.length > 0 &&  startOffset <= startNode.childNodes.length - 1 )
+			{
+				// If the offset points to the first node, we don't have a
+				// sibling, so let's use the first one, but mark it for removal.
+				if ( startOffset == 0 )
+				{
+					startNode = startNode.firstChild ;
+					removeStartNode = true ;
+				}
+				else
+					startNode = startNode.childNodes[ startOffset ].previousSibling ;
+			}
+		}
+		
+		// Get the parent nodes tree for the start and end boundaries.
+		var startParents	= FCKDomTools.GetParents( startNode ) ;
+		var endParents		= FCKDomTools.GetParents( endNode ) ;
+		
+		// Compare them, to find the top most siblings.
+		var i, topStart, topEnd ;
+		
+		for ( i = 0 ; i < startParents.length ; i++ )
+		{
+			topStart	= startParents[i] ;
+			topEnd		= endParents[i] ;
+			
+			// The compared nodes will match until we find the top most
+			// siblings (different nodes that have the same parent).
+			// "i" will hold the index in the parants array for the top 
+			// most element.
+			if ( topStart != topEnd )
+				break ;
+		}
+
+		var clone ;
+		
+		if ( docFrag )
+			clone = docFrag.RootNode ;
+
+		// Remove all successive sibling nodes for every node in the
+		// startParents tree.
+		for ( var j = i ; j < startParents.length ; j++ )
+		{
+			var levelStartNode = startParents[j] ;
+			
+			// For Extract and Clone, we must clone this level.
+			if ( clone && ( removeStartNode || levelStartNode != startNode ) )		// action = 0 = Delete
+				var levelClone = clone.appendChild( levelStartNode.cloneNode( removeStartNode && levelStartNode == startNode ) ) ;
+			
+			var currentNode = levelStartNode.nextSibling ;
+			
+			while( currentNode )
+			{
+				// Stop processing when the current node matches a node in the
+				// endParents tree or if it is the endNode.
+				if ( currentNode == endParents[j] || currentNode == endNode )
+					break ;
+				
+				// Cache the next sibling.
+				var currentSibling = currentNode.nextSibling ;
+
+				// If clonning, just clone it.
+				if ( action == 2 )	// 2 = Clone
+					clone.appendChild( currentNode.cloneNode( true ) ) ;
+				else
+				{
+					// Both Delete and Extract will remove the node.
+					currentNode.parentNode.removeChild( currentNode ) ;
+					
+					// When Extracting, move the removed node to the docFrag.
+					if ( action == 1 )	// 1 = Extract
+						clone.appendChild( currentNode ) ;
+				}
+				
+				currentNode = currentSibling ;
+			}
+			
+			if ( clone )
+				clone = levelClone ;
+		}
+		
+		if ( docFrag )
+			clone = docFrag.RootNode ;
+
+		// Remove all previous sibling nodes for every node in the
+		// endParents tree.
+		for ( var j = i ; j < endParents.length ; j++ )
+		{
+			var levelStartNode = endParents[j] ;
+			
+			// For Extract and Clone, we must clone this level.
+			if ( action > 0 && ( removeEndNode || levelStartNode != endNode ) )		// action = 0 = Delete
+				var levelClone = clone.appendChild( levelStartNode.cloneNode( removeEndNode && levelStartNode == endNode ) ) ;
+
+			// The processing of siblings may have already been done by the parent.
+			if ( !startParents[j] || levelStartNode.parentNode != startParents[j].parentNode )
+			{
+				var currentNode = levelStartNode.previousSibling ;
+
+				while( currentNode )
+				{
+					// Stop processing when the current node matches a node in the
+					// startParents tree or if it is the startNode.
+					if ( currentNode == startParents[j] || currentNode == startNode )
+						break ;
+
+					// Cache the next sibling.
+					var currentSibling = currentNode.previousSibling ;
+
+					// If clonning, just clone it.
+					if ( action == 2 )	// 2 = Clone
+						clone.insertBefore( currentNode.cloneNode( true ), clone.firstChild ) ;
+					else
+					{
+						// Both Delete and Extract will remove the node.
+						currentNode.parentNode.removeChild( currentNode ) ;
+						
+						// When Extracting, mode the removed node to the docFrag.
+						if ( action == 1 )	// 1 = Extract
+							clone.insertBefore( currentNode, clone.firstChild ) ;
+					}
+
+					currentNode = currentSibling ;
+				}
+			}
+			
+			if ( clone )
+				clone = levelClone ;
+		}
+		
+		if ( action == 2 )		// 2 = Clone.
+		{
+			// No changes in the DOM should be done, so fix the split text (if any).
+
+			startNode = this.startContainer ;
+			if ( startNode.nodeType == 3 )
+			{
+				startNode.data += startNode.nextSibling.data ;
+				startNode.parentNode.removeChild( startNode.nextSibling ) ;
+			}
+
+			endNode = this.endContainer ;
+			if ( endNode.nodeType == 3 )
+			{
+				endNode.data += endNode.nextSibling.data ;
+				endNode.parentNode.removeChild( endNode.nextSibling ) ;
+			}
+		}
+		else
+		{
+			// Collapse the range.
+	
+			// If a node has been partially selected, collapse the range between
+			// topStart and topEnd. Otherwise, simply collapse it to the start. (W3C specs).
+			if ( topStart && topEnd && ( startNode.parentNode != topStart.parentNode || endNode.parentNode != topEnd.parentNode ) )
+				this.setStart( topEnd.parentNode, FCKDomTools.GetIndexOf( topEnd ) ) ;
+			
+			// Collapse it to the start.
+			this.collapse( true ) ;
+
+			// Cleanup any marked node.
+			if( removeStartNode )
+				startNode.parentNode.removeChild( startNode ) ;
+
+			if( removeEndNode )
+				endNode.parentNode.removeChild( endNode ) ;
+		}
 	},
 
@@ -174,4 +400,10 @@
 	toString : function()
 	{
+		var docFrag = this.cloneContents() ;
+		
+		var tmpDiv = this._Document.createElement( 'div' ) ;
+		docFrag.AppendTo( tmpDiv ) ;
+		
+		return tmpDiv.textContent || tmpDiv.innerText ;
 	}
 } ;
Index: /FCKeditor/trunk/editor/_source/fckscriptloader.js
===================================================================
--- /FCKeditor/trunk/editor/_source/fckscriptloader.js	(revision 48)
+++ /FCKeditor/trunk/editor/_source/fckscriptloader.js	(revision 49)
@@ -88,5 +88,5 @@
 FCKScriptLoader.AddScript( 'FCKKeystrokeHandler', 'classes/'	, ['FCKConstants','FCKBrowserInfo','FCKTools'], FCK_GENERIC ) ;
 FCKScriptLoader.AddScript( 'FCKListHandler'		, 'internals/'	, ['FCKJSCoreExtensions','FCKDomTools','FCKTools'], FCK_GENERIC ) ;
-FCKScriptLoader.AddScript( 'FCKW3CRange'		, 'classes/'	, ['FCKDomTools','FCKTools'], FCK_GENERIC ) ;
+FCKScriptLoader.AddScript( 'FCKW3CRange'		, 'classes/'	, ['FCKDomTools','FCKTools','FCKDocumentFragment'], FCK_GENERIC ) ;
 
 // ####################################
