Index: /CKEditor/branches/tests/editor/core/_editor/custom_config_1.js
===================================================================
--- /CKEditor/branches/tests/editor/core/_editor/custom_config_1.js	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/_editor/custom_config_1.js	(revision 4087)
@@ -0,0 +1,10 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.editorConfig = function( config )
+{
+	config.customConfig = '_editor/custom_config_2.js';
+	config.test_custom1 = 'Ok';
+};
Index: /CKEditor/branches/tests/editor/core/_editor/custom_config_2.js
===================================================================
--- /CKEditor/branches/tests/editor/core/_editor/custom_config_2.js	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/_editor/custom_config_2.js	(revision 4087)
@@ -0,0 +1,9 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.editorConfig = function( config )
+{
+	config.test_custom2 = 'Ok';
+};
Index: /CKEditor/branches/tests/editor/core/ajax.html
===================================================================
--- /CKEditor/branches/tests/editor/core/ajax.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/ajax.html	(revision 4087)
@@ -0,0 +1,160 @@
+<!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.ajax</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.loader.load( 'core/ajax' );
+
+	//]]>
+	</script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_load_sync : function()
+		{
+			var data = CKEDITOR.ajax.load( '../_assets/sample.txt' );
+			assert.areSame( 'Sample Text\r\n', data, 'The loaded data doesn\'t match' );
+		},
+
+		test_load_sync_404 : function()
+		{
+			var data = CKEDITOR.ajax.load( '../_assets/404.txt' );
+			assert.isNull( data );
+		},
+
+		test_load_async : function()
+		{
+			var testCase = this;
+			var callback = function( data )
+			{
+				testCase.resume( function()
+					{
+						assert.areSame( 'Sample Text\r\n', data, 'The loaded data doesn\'t match' );
+					} );
+			};
+
+			CKEDITOR.ajax.load( '../_assets/sample.txt', callback );
+			this.wait();
+		},
+
+		test_load_async_404 : function()
+		{
+			var testCase = this;
+			var callback = function( data )
+			{
+				testCase.resume( function()
+					{
+						assert.isNull( data );
+					} );
+			};
+
+			CKEDITOR.ajax.load( '../_assets/404.txt', callback );
+			this.wait();
+		},
+
+		test_loadXml_sync : function()
+		{
+			var data = CKEDITOR.ajax.loadXml( '../_assets/sample.xml' );
+			assert.isInstanceOf( CKEDITOR.xml, data );
+			assert.isNotNull( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (null)' );
+			assert.isNotUndefined( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (undefined)' );
+		},
+
+		test_loadXml_sync_404 : function()
+		{
+			var data = CKEDITOR.ajax.loadXml( '../_assets/404.xml' );
+			assert.isNull( data );
+		},
+
+		test_loadXml_async : function()
+		{
+			var testCase = this;
+			var callback = function( data )
+			{
+				testCase.resume( function()
+					{
+						assert.isInstanceOf( CKEDITOR.xml, data );
+						assert.isNotNull( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (null)' );
+						assert.isNotUndefined( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (undefined)' );
+					} );
+			};
+
+			CKEDITOR.ajax.loadXml( '../_assets/sample.xml', callback );
+			this.wait();
+		},
+
+		test_loadXml_async_404 : function()
+		{
+			var testCase = this;
+			var callback = function( data )
+			{
+				testCase.resume( function()
+					{
+						assert.isNull( data );
+					} );
+			};
+
+			CKEDITOR.ajax.loadXml( '../_assets/404.xml', callback );
+			this.wait();
+		},
+
+		test_loadXml_sync_txt : function()
+		{
+			var data = CKEDITOR.ajax.loadXml( '../_assets/sample_xml.txt' );
+			assert.isInstanceOf( CKEDITOR.xml, data );
+			assert.isNotNull( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (null)' );
+			assert.isNotUndefined( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (undefined)' );
+		},
+
+		test_loadXml_async_txt : function()
+		{
+			var testCase = this;
+			var callback = function( data )
+			{
+				testCase.resume( function()
+					{
+						assert.isInstanceOf( CKEDITOR.xml, data );
+						assert.isNotNull( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (null)' );
+						assert.isNotUndefined( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (undefined)' );
+					} );
+			};
+
+			CKEDITOR.ajax.loadXml( '../_assets/sample_xml.txt', callback );
+			this.wait();
+		},
+
+		test_parseXml : function()
+		{
+			var data = new CKEDITOR.xml( '<?xml version="1.0" encoding="utf-8" ?><list><item id="test1" /><item id="test2" /></list>' );
+			assert.isInstanceOf( CKEDITOR.xml, data );
+			assert.isNotNull( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (null)' );
+			assert.isNotUndefined( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (undefined)' );
+		},
+
+		test_parseXml_nbsp : function()
+		{
+			var data = new CKEDITOR.xml( '<?xml version="1.0" encoding="utf-8" ?><list><item id="test1">&nbsp;</item><item id="test2" /></list>' );
+			assert.isInstanceOf( CKEDITOR.xml, data );
+			assert.isNotNull( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (null)' );
+			assert.isNotUndefined( data.selectSingleNode( '//list/item' ), 'The loaded data doesn\'t match (undefined)' );
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/bootstrap.html
===================================================================
--- /CKEditor/branches/tests/editor/core/bootstrap.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/bootstrap.html	(revision 4087)
@@ -0,0 +1,64 @@
+﻿<!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.bootstrap</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+var before_loadFullCore = CKEDITOR.status;
+
+var isLoaded;
+
+CKEDITOR.on( 'loaded', function()
+	{
+		isLoaded = true;
+	});
+
+
+CKEDITOR.loadFullCore();
+
+	//]]>
+	</script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_status1 : function()
+		{
+			assert.areSame( 'basic_loaded', before_loadFullCore );
+		},
+
+		test_status2 : function()
+		{
+			// In IE, CKEDITOR.on( 'loaded' ) will be called immediately if the scripts are cached.
+			if ( isLoaded )
+				return;
+
+			var testCase = this;
+			CKEDITOR.on( 'loaded', function()
+				{
+					testCase.resume( function()
+						{
+							assert.areSame( 'loaded', CKEDITOR.status );
+						});
+				});
+
+			this.wait();
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/ckeditor.html
===================================================================
--- /CKEditor/branches/tests/editor/core/ckeditor.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/ckeditor.html	(revision 4087)
@@ -0,0 +1,158 @@
+﻿<!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</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+	// Clean up all instances been created on the page.
+	function removeAllInstances()
+	{
+		var allInstances = CKEDITOR.instances;
+		for( var i in allInstances )
+		{
+			CKEDITOR.remove(  allInstances[ i ] );
+		}
+	}
+
+	CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_replaceClass : function()
+		{
+			// Asserts the default value.
+			assert.areSame( 'ckeditor', CKEDITOR.replaceClass );
+		},
+
+		test_replaceByClassEnabled : function()
+		{
+			// Asserts the default value.
+			assert.isTrue( CKEDITOR.replaceByClassEnabled );
+		},
+
+		test_replaceId : function()
+		{
+			CKEDITOR.replace( 'editor1' );
+			assert.isObject( CKEDITOR.instances.editor1, 'editor instance not found' );
+			assert.areSame( 'editor1', CKEDITOR.instances.editor1.name, 'instance name doesn\'t match' );
+			assert.areSame( document.getElementById( 'editor1' ), CKEDITOR.instances.editor1.element.$, 'instance element doesn\'t match' );
+		},
+
+		test_replaceName : function()
+		{
+			CKEDITOR.replace( 'editor2' );
+			assert.isObject( CKEDITOR.instances.editor2, 'editor instance not found' );
+			assert.areSame( 'editor2', CKEDITOR.instances.editor2.name, 'instance name doesn\'t match' );
+			assert.areSame( document.getElementsByName( 'editor2' )[0], CKEDITOR.instances.editor2.element.$, 'instance element doesn\'t match' );
+		},
+
+		test_replaceElement : function()
+		{
+			CKEDITOR.replace( document.getElementById( 'editor5' ) );
+			assert.isObject( CKEDITOR.instances.editor5, 'editor instance not found' );
+			assert.areSame( 'editor5', CKEDITOR.instances.editor5.name, 'instance name doesn\'t match' );
+			assert.areSame( document.getElementById( 'editor5' ), CKEDITOR.instances.editor5.element.$, 'instance element doesn\'t match' );
+		},
+
+
+		test_replaceError : function()
+		{
+			try
+			{
+				CKEDITOR.replace( 'error' );
+			}
+			catch ( e )
+			{
+				assert.areSame( '[CKEDITOR.editor.replace] The element with id or name "error" was not found.', e );
+			}
+		},
+
+		test_replaceAll_Class : function()
+		{
+			CKEDITOR.replaceAll( 'myclass' );
+
+			assert.isObject( CKEDITOR.instances.editor3, 'editor3 instance not found' );
+			assert.areSame( 'editor3', CKEDITOR.instances.editor3.name, 'editor3 instance name doesn\'t match' );
+			assert.areSame( document.getElementById( 'editor3' ), CKEDITOR.instances.editor3.element.$, 'editor3 instance element doesn\'t match' );
+
+			assert.isObject( CKEDITOR.instances.editor4, 'editor4 instance not found' );
+			assert.areSame( 'editor4', CKEDITOR.instances.editor4.name, 'editor4 instance name doesn\'t match' );
+			assert.areSame( document.getElementsByName( 'editor4' )[0], CKEDITOR.instances.editor4.element.$, 'editor4 instance element doesn\'t match' );
+
+			assert.isUndefined( CKEDITOR.instances.editor6, 'editor6 should be undefined' );
+			assert.isUndefined( CKEDITOR.instances.editor7, 'editor7 should be undefined' );
+			assert.isUndefined( CKEDITOR.instances.editor8, 'editor8 should be undefined' );
+			assert.isUndefined( CKEDITOR.instances.editor8, 'editor9 should be undefined' );
+		},
+
+		test_replaceAll_Function : function()
+		{
+			CKEDITOR.replaceAll( function( textarea )
+				{
+					return ( textarea.id != 'editor6' && textarea.id != 'editor8' );
+				} );
+
+			assert.isObject( CKEDITOR.instances.editor7, 'editor7 instance not found' );
+			assert.areSame( 'editor7', CKEDITOR.instances.editor7.name, 'editor7 instance name doesn\'t match' );
+			assert.areSame( document.getElementById( 'editor7' ), CKEDITOR.instances.editor7.element.$, 'editor7 instance element doesn\'t match' );
+
+			assert.isObject( CKEDITOR.instances.editor9, 'editor9 instance not found' );
+			assert.areSame( 'editor9', CKEDITOR.instances.editor9.name, 'editor9 instance name doesn\'t match' );
+			assert.areSame( document.getElementById( 'editor9' ), CKEDITOR.instances.editor9.element.$, 'editor9 instance element doesn\'t match' );
+
+			assert.isUndefined( CKEDITOR.instances.editor6, 'editor6 should be undefined' );
+			assert.isUndefined( CKEDITOR.instances.editor8, 'editor8 should be undefined' );
+		},
+
+		test_replaceAll : function()
+		{
+			CKEDITOR.replaceAll();
+
+			assert.isObject( CKEDITOR.instances.editor6, 'editor6 instance not found' );
+			assert.areSame( 'editor6', CKEDITOR.instances.editor6.name, 'editor6 instance name doesn\'t match' );
+			assert.areSame( document.getElementById( 'editor6' ), CKEDITOR.instances.editor6.element.$, 'editor6 instance element doesn\'t match' );
+
+			assert.isObject( CKEDITOR.instances.editor8, 'editor8 editor instance not found' );
+			assert.areSame( 'editor8', CKEDITOR.instances.editor8.name, 'editor8 instance name doesn\'t match' );
+			assert.areSame( document.getElementById( 'editor8' ), CKEDITOR.instances.editor8.element.$, 'editor8 instance element doesn\'t match' );
+		},
+
+		test_add : function()
+		{
+			var textarea = CKEDITOR.dom.element.createFromHtml( '<textarea id="test_add">&lt;p&gt;test_add&lt;/p&gt;<\/textarea>' );
+			textarea.appendTo( new CKEDITOR.dom.element( document.body ) );
+
+			var editor = new CKEDITOR.editor( {}, textarea, CKEDITOR.ELEMENT_MODE_REPLACE );
+
+			CKEDITOR.add( editor );
+
+			assert.areSame( editor, CKEDITOR.instances.test_add );
+		},
+
+		setUp : function()
+		{
+			removeAllInstances();
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+	<textarea id="editor1" cols="80" rows="10"></textarea>
+	<textarea name="editor2" cols="80" rows="10"></textarea>
+	<textarea id="editor3" name="editor3" class="myclass" cols="80" rows="10"></textarea>
+	<textarea name="editor4" class="myclass" cols="80" rows="10"></textarea>
+	<textarea id="editor5" cols="80" rows="10"></textarea>
+	<textarea id="editor6" cols="80" rows="10"></textarea>
+	<textarea id="editor7" cols="80" rows="10"></textarea>
+	<textarea id="editor8" cols="80" rows="10"></textarea>
+	<textarea id="editor9" cols="80" rows="10"></textarea>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/document.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/document.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/document.html	(revision 4087)
@@ -0,0 +1,125 @@
+﻿<!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.document</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert,
+		arrayAssert = YAHOO.util.ArrayAssert;
+
+	return {
+		test_$ : function()
+		{
+			var doc = new CKEDITOR.dom.document( document );
+			assert.areSame( document, doc.$ );
+		},
+
+		test_appendStyleSheet : function()
+		{
+			var cssUrl = CKEDITOR.basePath + '_tests/';
+			cssUrl = CKEDITOR.basePath + '_source/tests/';	// %REMOVE_LINE%
+			cssUrl += '_assets/sample.css';
+
+			var doc = new CKEDITOR.dom.document( document );
+			doc.appendStyleSheet( cssUrl );
+
+			var links = document.getElementsByTagName( 'link' );
+
+			for ( var i = 0 ; i < links.length ; i++ )
+			{
+				if ( links[i].href == cssUrl )
+					return ;
+			}
+
+			assert.fail( 'The link element was not found' );
+		},
+
+		test_equals1 : function()
+		{
+			// Actually checks the real need for equals().
+			var doc1 = new CKEDITOR.dom.document( document );
+			assert.isFalse( doc1 == document );
+		},
+
+		test_equals2 : function()
+		{
+			// Actually checks the real need for equals().
+			var doc1 = new CKEDITOR.dom.document( document );
+			var doc2 = new CKEDITOR.dom.document( document );
+			assert.isFalse( doc1 == doc2, 'doc1 == doc2' );
+		},
+
+		test_equals3 : function()
+		{
+			var doc1 = new CKEDITOR.dom.document( document );
+			var doc2 = new CKEDITOR.dom.document( document );
+			assert.isTrue( doc1.equals( doc2 ), 'doc1.equals( doc2 )' );
+			assert.isTrue( doc2.equals( doc1 ), 'doc2.equals( doc1 )' );
+		},
+
+		test_getById1 : function()
+		{
+			var doc = new CKEDITOR.dom.document( document );
+			var element = doc.getById( 'test1' );
+			assert.areSame( document.getElementById( 'test1' ), element.$ );
+		},
+
+		test_getById2 : function()
+		{
+			var doc = new CKEDITOR.dom.document( document );
+			var element = doc.getById( 'test_invalid' );
+			assert.isNull( element );
+		},
+
+		test_getHead : function()
+		{
+			var doc = new CKEDITOR.dom.document( document );
+			assert.areSame( document.getElementsByTagName( 'head' )[0], doc.getHead().$ );
+		},
+
+		test_getBody : function()
+		{
+			var doc = new CKEDITOR.dom.document( document );
+			assert.areSame( document.body, doc.getBody().$, '1st call failed' );
+			assert.areSame( document.body, doc.getBody().$, '2nd call failed' );
+		},
+		test_createText : function()
+		{
+			var doc = new CKEDITOR.dom.document( document ), contentText = 'text content';
+			var textNode = doc.createText( contentText );
+			assert.areSame( contentText, textNode.getText(),
+				'Create text node content doesn\'t match.' );
+		},
+
+		test_getByAddress1 : function()
+		{
+			var doc = new CKEDITOR.dom.document( document );
+			var node = doc.getByAddress( [ 1, 1, 0, 1, 0, 0 ] );
+			assert.areSame( 'target', node.getText(),
+				'Addressing target doesn\'t match.' );
+		},
+
+		test_getElementsByTag : function()
+		{
+			var nodeList = new CKEDITOR.dom.document( document ).getElementsByTag( 'span' ),
+				results = [];
+			for( var i = 0; i < nodeList.count(); i++ ){
+				results.push( nodeList.getItem( i ).$ );
+			}
+			arrayAssert.itemsAreEqual( results, document.getElementsByTagName( 'span' ) );
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body><div id="test1"></div><div><p>text<span><b id="addressTarget1">target</b>text</span>text</p></div><span ><b id="addressTarget2">target</b></span></body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/documentfragment.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/documentfragment.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/documentfragment.html	(revision 4087)
@@ -0,0 +1,290 @@
+<!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>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+var tc;
+CKEDITOR.test.addTestCase( tc = ( function()
+{
+	// Local reference to the "assert" object.
+	var assert = YAHOO.util.Assert,
+		doc = CKEDITOR.document;
+
+	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()
+		{
+			// IE need special treatement to setup this tc, see
+			// next tc for this.
+			if ( CKEDITOR.env.ie )
+				return;
+			var element = CKEDITOR.dom.element.createFromHtml(
+				'<div id="trimTarget">\t\ntext\t\n</div>'
+			);
+			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_ltrim_ie : function()
+		{
+			if ( !CKEDITOR.env.ie )
+				return;
+			// IE dom operation will trim preceding empty text,
+			// here we use 'splitText' way to create leading spaces
+			// instead for testing.
+			var emptyTextNode = doc.createText( '@ \ttext\t ');
+			var frag =
+					new CKEDITOR.dom.documentFragment( doc );
+			frag.append( emptyTextNode );
+			frag.getFirst().$.splitText( 1 );
+			frag.getFirst().remove();
+			frag.ltrim();
+			var ct = new CKEDITOR.dom.element( 'div' );
+			ct.append( frag );
+			assert.areSame( 'text\t ', ct.getText() );
+		},
+
+		test_rtrim : function()
+		{
+			if ( CKEDITOR.env.ie )
+				return;
+			var element = CKEDITOR.dom.element.createFromHtml(
+				'<div id="trimTarget">\t\ntext\t\n</div>'
+			);
+			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() );
+		},
+
+		/**
+		 *@see test_ltrim_ie
+		 */
+		test_rtrim_ie : function()
+		{
+			if ( !CKEDITOR.env.ie )
+				return;
+			var emptyTextNode = doc.createText( '@ \ttext\t ');
+			var frag =
+					new CKEDITOR.dom.documentFragment( doc );
+			frag.append( emptyTextNode );
+			frag.getFirst().$.splitText( 1 );
+			frag.getFirst().remove();
+			frag.rtrim();
+			var ct = new CKEDITOR.dom.element( 'div' );
+			ct.append( frag );
+			assert.areSame( ' \ttext', ct.getText() );
+		},
+
+
+		test_trim : function()
+		{
+			if ( !CKEDITOR.env.ie )
+				return;
+			var element = CKEDITOR.dom.element.createFromHtml(
+				'<div id="trimTarget">\t\ntext\t\n</div>'
+			);
+			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() );
+		},
+
+
+		/**
+		 *@see test_ltrim_ie
+		 */
+		test_trim_ie : function()
+		{
+			if ( !CKEDITOR.env.ie )
+				return;
+			var emptyTextNode = doc.createText( '@ \t\ntext\t\n ');
+			var frag =
+					new CKEDITOR.dom.documentFragment( doc );
+			frag.append( emptyTextNode );
+			frag.getFirst().$.splitText( 1 );
+			frag.getFirst().remove();
+			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
+	};
+} )() );
+
+//window.onload = tc.test_rtrim_ie;
+	//]]>
+	</script>
+</head>
+<body>
+	<div id="fragmentContainer1"></div>
+	<div id="fragmentContainer2"><div id="fragmentSibling1"></div></div>
+	<div id="fragmentContainer3"></div>
+	<iframe id="innerFrame" name="innerFrame" src="about:blank"></iframe>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/element.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/element.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/element.html	(revision 4087)
@@ -0,0 +1,635 @@
+﻿<!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.element</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+	var getInnerHtml = CKEDITOR.test.getInnerHtml;
+
+	return {
+		test_$ : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			assert.areSame( document.getElementById( 'test1' ), element.$ );
+		},
+
+		test_getId1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			assert.areEqual( 'test1', element.getId() );
+		},
+
+		test_getId2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementsByTagName( 'div' )[0] );
+			assert.isNull( element.getId() );
+		},
+
+		test_getNameAtt1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementsByName( 'named1' )[0] );
+			assert.areEqual( 'named1', element.getNameAtt() );
+		},
+
+		test_getNameAtt2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			assert.isNull( element.getNameAtt() );
+		},
+
+		test_getName : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			assert.areEqual( 'textarea', element.getName(), 'First call' );
+			assert.areEqual( 'textarea', element.getName(), 'Second call' );
+		},
+
+		test_hide : function()
+		{
+			var nativeElement = document.getElementById( 'test1' );
+			nativeElement.style.display = '';
+
+			var element = new CKEDITOR.dom.element( nativeElement );
+			element.hide();
+
+			assert.areEqual( 'none', nativeElement.style.display );
+		},
+
+		test_show : function()
+		{
+			var nativeElement = document.getElementById( 'test1' );
+			nativeElement.style.display = '';
+
+			var element = new CKEDITOR.dom.element( nativeElement );
+			element.show();
+
+			assert.areEqual( '', nativeElement.style.display );
+		},
+
+		test_createFromHtml : function()
+		{
+			var element = CKEDITOR.dom.element.createFromHtml( '<p>My test</p>' );
+			assert.areEqual( 'p', element.getName(), 'element name doesn\'t match' );
+			assert.areEqual( 'My test', element.$.innerHTML, 'the innerHTML doesn\'t match' );
+		},
+
+		test_createFromHtml2 : function()
+		{
+			var element = new CKEDITOR.dom.element.createFromHtml( '<div><x:x><p>Test</p></div>' );
+			assert.areNotEqual( 'Test', element.getChild( 0, 0 ).innerHTML );
+		},
+
+		test_append1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			element.append( new CKEDITOR.dom.element( 'b' ) );
+			assert.areEqual( 'b', document.getElementById( 'append' ).firstChild.nodeName.toLowerCase() );
+		},
+
+		test_append2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			element.append( 'i' );
+			assert.areEqual( 'i', document.getElementById( 'append' ).lastChild.nodeName.toLowerCase() );
+		},
+
+		test_appendText1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			element.setHtml( '' );
+			element.appendText( 'Test appendText' );
+			assert.areEqual( 'Test appendText', document.getElementById( 'append' ).innerHTML );
+		},
+
+		test_appendText2 : function()
+		{
+			var element = new CKEDITOR.dom.element( 'script' );
+			element.appendText( 'Test appendText' );
+			assert.areEqual( 'Test appendText', element.$.text );
+		},
+
+		test_setHtml : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			element.setHtml( '<b>Test</b>' );
+			assert.areEqual( '<b>test</b>', document.getElementById( 'append' ).innerHTML.toLowerCase(), 'First call doesn\'t match' );
+			element.setHtml( 'Another test' );
+			assert.areEqual( 'Another test', document.getElementById( 'append' ).innerHTML, 'Second call doesn\'t match' );
+		},
+
+		test_getDocument1 : function()
+		{
+			var element = new CKEDITOR.dom.element( 'div' );
+			assert.areSame( document, element.getDocument().$, 'First call' );
+			assert.areSame( document, element.getDocument().$, 'Second call' );
+		},
+
+		test_getDocument2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.body );
+			assert.areSame( document, element.getDocument().$, 'First call' );
+			assert.areSame( document, element.getDocument().$, 'Second call' );
+		},
+
+		test_getFirst1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			element.setHtml( '<b>Test</b>' );
+			var first = element.getFirst();
+			assert.areSame( 'b', first.getName() );
+		},
+
+		test_getFirst2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			element.setHtml( 'Test' );
+			var first = element.getFirst();
+			assert.areSame( 'Test', first.$.nodeValue );
+		},
+
+		test_getFirst3 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			element.setHtml( '' );
+			var first = element.getFirst();
+			assert.isNull( first );
+		},
+
+		test_setAttribute1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			element.setAttribute( 'class', 'Test' );
+
+			assert.areSame( 'Test', document.getElementById( 'test1' ).className );
+		},
+
+		test_setAttribute2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			element.setAttribute( 'style', 'position: absolute;' );
+
+			assert.areEqual( 'position: absolute;', CKEDITOR.test.getAttribute( element, 'style' ) );
+		},
+
+		test_setAttribute3 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			element.setAttribute( 'name', 'TestName' );
+
+			assert.areEqual( 'TestName', document.getElementById( 'test1' ).name );
+		},
+
+		test_setAttribute4 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			element.setAttribute( 'rows', 5 );
+
+			assert.areEqual( 5, document.getElementById( 'test1' ).rows );
+		},
+
+		test_setAttributes : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'test2' ) );
+			element.setAttributes({
+				'class'	: 'Test',
+				'style'	: 'position: absolute;',
+				'name'	: 'TestName',
+				'rows'	: 5 });
+
+			assert.areSame( 'Test', document.getElementById( 'test1' ).className, 'class is wrong' );
+			assert.areEqual( 'position: absolute;', CKEDITOR.test.getAttribute( element, 'style'), 'style is wrong' );
+			assert.areEqual( 'TestName', document.getElementById( 'test1' ).name, 'name is wrong' );
+			assert.areEqual( 5, document.getElementById( 'test1' ).rows, 'rows is wrong' );
+		},
+
+		test_setStyle1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'setStyle' ) );
+			element.setStyle( 'position', 'absolute' );
+
+			assert.areEqual( 'absolute', document.getElementById( 'setStyle' ).style.position );
+		},
+
+		test_setStyle2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'setStyle' ) );
+			element.setStyle( 'float', 'right' );
+
+			assert.areEqual( 'right', document.getElementById( 'setStyle' ).style.cssFloat );
+		},
+
+		test_setStyles : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'setStyle' ) );
+			element.setStyles({
+					'position' : 'absolute',
+					'float' : 'right'
+				});
+
+			assert.areEqual( 'absolute', document.getElementById( 'setStyle' ).style.position );
+			assert.areEqual( 'right', document.getElementById( 'setStyle' ).style.cssFloat );
+		},
+
+		test_setText1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'setText' ) );
+			element.setText( 'A & B' );
+			assert.areSame( 'A &amp; B', document.getElementById( 'setText' ).innerHTML );
+		},
+
+		test_setText2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'setText' ) );
+			element.setText( 'C & D' );
+			assert.areSame( 'C &amp; D', document.getElementById( 'setText' ).innerHTML );
+		},
+
+		test_addClass1 : function()
+		{
+			var element = new CKEDITOR.dom.element( 'div' );
+			element.addClass( 'classA' );
+			assert.areSame( 'classA', element.$.className );
+		},
+
+		test_addClass2 : function()
+		{
+			var element = new CKEDITOR.dom.element( 'div' );
+			element.addClass( 'classA' );
+			element.addClass( 'classA' );
+			assert.areSame( 'classA', element.$.className );
+		},
+
+		test_addClass3 : function()
+		{
+			var element = new CKEDITOR.dom.element( 'div' );
+			element.addClass( 'classA' );
+			element.addClass( 'classB' );
+			element.addClass( 'classC' );
+			assert.areSame( 'classA classB classC', element.$.className );
+		},
+
+		test_addClass4 : function()
+		{
+			var element = new CKEDITOR.dom.element( 'div' );
+			element.addClass( 'classA' );
+			element.addClass( 'classB' );
+			element.addClass( 'classC' );
+			element.addClass( 'classA' );
+			element.addClass( 'classB' );
+			element.addClass( 'classC' );
+			assert.areSame( 'classA classB classC', element.$.className );
+		},
+
+		test_removeClass1 : function()
+		{
+			document.getElementById( 'removeClass' ).innerHTML = '';
+
+			var element = CKEDITOR.dom.element.createFromHtml( '<div class="classA"></div>' );
+			element.appendTo( new CKEDITOR.dom.element( document.getElementById( 'removeClass' ) ) );
+
+			assert.areSame( '<div class="classa"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classA' );
+			assert.areSame( '<div></div>', getInnerHtml( 'removeClass' ) );
+		},
+
+		test_removeClass2 : function()
+		{
+			document.getElementById( 'removeClass' ).innerHTML = '';
+
+			var element = CKEDITOR.dom.element.createFromHtml( '<div class="classA classB classC classD"></div>' );
+			element.appendTo( new CKEDITOR.dom.element( document.getElementById( 'removeClass' ) ) );
+
+			assert.areSame( '<div class="classa classb classc classd"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classA' );
+			assert.areSame( '<div class="classb classc classd"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classC' );
+			assert.areSame( '<div class="classb classd"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classD' );
+			assert.areSame( '<div class="classb"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classB' );
+			assert.areSame( '<div></div>', getInnerHtml( 'removeClass' ) );
+		},
+
+		test_removeClass3 : function()
+		{
+			document.getElementById( 'removeClass' ).innerHTML = '';
+
+			var element = CKEDITOR.dom.element.createFromHtml( '<div class="classA classB"></div>' );
+			element.appendTo( new CKEDITOR.dom.element( document.getElementById( 'removeClass' ) ) );
+
+			assert.areSame( '<div class="classa classb"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classXXX' );
+			assert.areSame( '<div class="classa classb"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classB' );
+			assert.areSame( '<div class="classa"></div>', getInnerHtml( 'removeClass' ) );
+			element.removeClass( 'classYYY' );
+			assert.areSame( '<div class="classa"></div>', getInnerHtml( 'removeClass' ) );
+		},
+
+		test_removeAttribute1 : function()
+		{
+			document.getElementById( 'removeClass' ).innerHTML = '';
+
+			var element = CKEDITOR.dom.element.createFromHtml( '<div class="classA"></div>' );
+			element.appendTo( new CKEDITOR.dom.element( document.getElementById( 'removeClass' ) ) );
+
+			element.removeAttribute( 'class' );
+			assert.areSame( '<div></div>', getInnerHtml( 'removeClass' ) );
+		},
+
+		test_removeAttribute2 : function()
+		{
+			document.getElementById( 'removeClass' ).innerHTML = '';
+
+			var element = CKEDITOR.dom.element.createFromHtml( '<div style="position:absolute"></div>' );
+			element.appendTo( new CKEDITOR.dom.element( document.getElementById( 'removeClass' ) ) );
+
+			element.removeAttribute( 'style' );
+			assert.areSame( '<div></div>', getInnerHtml( 'removeClass' ) );
+		},
+
+		test_removeAttribute3 : function()
+		{
+			document.getElementById( 'removeClass' ).innerHTML = '';
+
+			var element = CKEDITOR.dom.element.createFromHtml( '<div title="Test"></div>' );
+			element.appendTo( new CKEDITOR.dom.element( document.getElementById( 'removeClass' ) ) );
+
+			element.removeAttribute( 'title' );
+			assert.areSame( '<div></div>', getInnerHtml( 'removeClass' ) );
+		},
+
+		test_remove : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'removeInner' ) );
+			element.remove();
+
+			assert.areSame( '', getInnerHtml( 'removeOuter' ) );
+		},
+
+		test_getAttribute_tabindex1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndex10' ) );
+			assert.areEqual( 10, CKEDITOR.test.getAttribute( element, 'tabindex' ) );
+		},
+
+		test_getAttribute_tabindex2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexDef' ) );
+			assert.isNull( CKEDITOR.test.getAttribute( element, 'tabindex' ) );
+		},
+
+		test_getAttribute_tabindex3 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexInputDef' ) );
+			assert.isNull( CKEDITOR.test.getAttribute( element, 'tabindex' ) );
+		},
+
+		test_getAttribute_tabindex4 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexInput20' ) );
+			assert.areEqual( 20, CKEDITOR.test.getAttribute( element, 'tabindex' ) );
+		},
+
+		test_getAttribute_tabindex5 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexScriptDef' ) );
+			assert.areEqual( null, CKEDITOR.test.getAttribute( element, 'tabindex' ) );
+		},
+
+		/**
+		 *  Test getAttribute and getAttribute will ingore  '_cke_expando' attribute.
+		 */
+		test_getAttribute_ignoreExpandoAttributes : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'testExpandoAttributes' ) );
+
+			assert.areEqual( 1, CKEDITOR.test.getAttribute( element, 'tabindex' ), 'tabindex is wrong' );
+			element.removeAttribute( 'tabindex' );
+
+			assert.areEqual( 'hasExpando', CKEDITOR.test.getAttribute( element, 'class' ), 'class is wrong' );
+			element.removeAttribute( 'class' );
+
+			assert.areEqual( 'float: right;', CKEDITOR.test.getAttribute( element, 'style' ) );
+
+			element.removeAttribute( 'style' );
+			element.removeAttribute( 'id' );
+			assert.isFalse( element.hasAttributes(), 'hasAttributes should be false' );
+		},
+
+		test_getTabIndex1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndex10' ) );
+			assert.areSame( 10, element.getTabIndex() );
+		},
+
+		test_getTabIndex2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexDef' ) );
+			assert.areSame( -1, element.getTabIndex() );
+		},
+
+		test_getTabIndex3 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexInputDef' ) );
+			assert.areSame( 0, element.getTabIndex() );
+		},
+
+		test_getTabIndex4 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexInput20' ) );
+			assert.areSame( 20, element.getTabIndex() );
+		},
+
+		test_getTabIndex5 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'tabIndexScriptDef' ) );
+			assert.areSame( -1, element.getTabIndex() );
+		},
+
+		test_private1 : function()
+		{
+			var a = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			var b = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+
+			assert.areSame( a.getPrivate(), b.getPrivate() );
+		},
+
+		test_private2 : function()
+		{
+			var a = new CKEDITOR.dom.element( document.getElementById( 'test1' ) );
+			var b = new CKEDITOR.dom.element( document.getElementById( 'test2' ) );
+
+			assert.areNotSame( a.getPrivate(), b.getPrivate() );
+		},
+
+		test_getText1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'getText' ) );
+
+			// IE gives us a different result, which is ok for us (see code comments).
+			if ( CKEDITOR.env.ie )
+				assert.areSame( 'Some \nsample text for testing', element.getText().replace( /\r\n|\r/g, '\n' ) );
+			else
+				assert.areSame( 'Some  sample text    for    testing', element.getText() );
+		},
+
+		test_getText2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'getText2' ).getElementsByTagName( 'b' )[0] );
+			assert.areSame( ' ', element.getText() );
+		},
+
+		test_getText3 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'getText3' ) );
+
+			// IE gives us a different result, which is ok for us (see code comments).
+			if ( CKEDITOR.env.ie )
+				assert.areSame( 'A B', element.getText() );
+			else
+				assert.areSame( 'A\nB', element.getText().replace( /\r\n|\r/g, '\n' ) );
+		},
+
+		test_hasAttributes1 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementsByTagName( 'big' )[0] );
+			assert.isFalse( element.hasAttributes() );
+		},
+
+		test_hasAttributes2 : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementsByTagName( 'small' )[0] );
+			assert.isTrue( element.hasAttributes() );
+		},
+
+		/**
+		 * Test detecting of 'class' attribute in IE6/7.
+		 */
+		test_hasAttributes_4075 : function()
+		{
+			if ( !CKEDITOR.env.ie && ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) )
+				return;
+			var element = new CKEDITOR.dom.element( 'span' );
+			element.setAttribute( 'class', 'value' );
+			assert.isTrue( element.hasAttributes(), 'Failed to detect "class" attribute existence.' );
+		},
+
+		test_getDocumentPosition : function()
+		{
+			// Assign the page location of the element.
+			YAHOO.util.Dom.setXY('DocPositionTarget', [ 350, 450 ] );
+			var pos = CKEDITOR.document.getById( 'DocPositionTarget' ).getDocumentPosition();
+			if ( !CKEDITOR.env.ie || CKEDITOR.env.ie8 )
+			{
+				assert.areEqual( 350, pos.x, 'Position coordinates:x relative to document doesn\'t match.' );
+				assert.areEqual( 450, pos.y, 'Position coordinates:y relative to document doesn\'t match.' );
+			}
+			else
+			{
+				assert.isTrue( pos.x == 348 || pos.x == 349, 'Position coordinates:x relative to document doesn\'t match.' );
+				assert.areEqual( 448, pos.y, 'Position coordinates:y relative to document doesn\'t match.' );
+			}
+		},
+
+		// Test get last non-spaces child node.
+		test_getLast : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			var span1 = new CKEDITOR.dom.element( 'span' );
+			element.append( span1 );
+			element.append( new CKEDITOR.dom.text( ' ' ) );
+			element.append( new CKEDITOR.dom.text( ' ' ) );
+			var last = element.getLast( CKEDITOR.dom.walker.whitespaces( true ) );
+			assert.areSame( span1.$, last.$ );
+		},
+
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+	<style type="text/css" media="screen">
+		#test-computed {
+		    width:50%;
+		    margin:auto;
+		    padding:10px;
+		    z-index: 2;
+		}
+		.scroll
+		{
+			overflow: visible;
+		}
+		.block1
+		{
+			width: 100%;
+			height: 100px;
+			background-color: blue;
+			text-align: center;
+		}
+		.block2
+		{
+			margin: auto;
+			width: 200px;
+			height: 200px;
+			background-color: green;
+			position : relative;
+		}
+		.block3
+		{
+			position: absolute;
+			float:right;
+			width: 300px;
+			height: 300px;
+			background-color: black;
+		}
+		.block4
+		{
+			position: absolute;
+			left: 50px;
+			right: 50px;
+			width: 400px;
+			height: 400px;
+			background-color: pink;
+		}
+		#DocPositionTarget
+		{
+			background-color: red;
+		}
+	</style>
+</head>
+<body>
+	<textarea id="test1" rows="10" cols="80"></textarea>
+	<textarea id="test2" rows="10" cols="80"></textarea>
+	<textarea name="named1" rows="10" cols="80"></textarea>
+	<div>Test</div>
+	<div id="append"></div>
+	<div id="setStyle"></div>
+	<div id="setText"></div>
+	<div id="removeClass"></div>
+	<div id="removeOuter"><b id="removeInner"></b></div>
+	<div id="tabIndex10" tabindex="10"></div>
+	<div id="testExpandoAttributes" _cke_expando ="1" class="hasExpando" tabindex="1" style="float:right"></div>
+	<div id="tabIndexDef"></div>
+	<input id="tabIndexInputDef" />
+	<input id="tabIndexInput20" tabindex="20" />
+	<script id="tabIndexScriptDef" type="text/javascript"></script>
+	<div id="getText">Some <br /><b> sample text</b>    for <i>   testing</i></div>
+	<div id="getText2">A<b> </b>B</div>
+	<div id="getText3">A
+B</div>
+	<big>Test</big>
+	<small title="Testing">Test</small>
+
+	<div class="block1 scroll" id="block1"><div class="block2 scroll" id="block2"><div class="block3 scroll" id="block3"><div class="block4 scroll" id="block4"><div id="DocPositionTarget">target</div></div></div></div></div>
+
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/node.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/node.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/node.html	(revision 4087)
@@ -0,0 +1,162 @@
+<!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.node</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+var tc;
+CKEDITOR.test.addTestCase( tc = (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_getPosition1 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'p' )[0] );
+
+			assert.areSame( CKEDITOR.POSITION_PRECEDING, node1.getPosition( node2 ) );
+		},
+
+		test_getPosition2 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'p' )[0] );
+
+			assert.areSame( CKEDITOR.POSITION_FOLLOWING, node2.getPosition( node1 ) );
+		},
+
+		test_getPosition3 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'p' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'b' )[0] );
+
+			assert.areSame( CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING, node1.getPosition( node2 ) );
+		},
+
+		test_getPosition4 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'p' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'b' )[0] );
+
+			assert.areSame( CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING, node2.getPosition( node1 ) );
+		},
+
+		test_getPosition5 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'div' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'div' )[0] );
+
+			assert.areSame( CKEDITOR.POSITION_IDENTICAL, node1.getPosition( node2 ) );
+		},
+
+		test_getPosition6 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0].firstChild );
+
+			assert.areSame( CKEDITOR.POSITION_CONTAINS + CKEDITOR.POSITION_PRECEDING, node1.getPosition( node2 ) );
+		},
+
+		test_getPosition7 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0].firstChild );
+			assert.areSame( CKEDITOR.POSITION_IS_CONTAINED + CKEDITOR.POSITION_FOLLOWING, node2.getPosition( node1 ) );
+		},
+
+		test_getPosition8 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0].firstChild );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'b' )[0].firstChild );
+
+			assert.areSame( CKEDITOR.POSITION_PRECEDING, node1.getPosition( node2 ) );
+		},
+
+		test_getPosition9 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0].firstChild );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'b' )[0].firstChild );
+
+			assert.areSame( CKEDITOR.POSITION_FOLLOWING, node2.getPosition( node1 ) );
+		},
+
+		test_getPosition10 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'b' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'i' )[0] );
+
+			assert.areSame( CKEDITOR.POSITION_PRECEDING, node1.getPosition( node2 ) );
+		},
+
+		test_getPosition11 : function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'b' )[0] );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'i' )[0] );
+
+			assert.areSame( CKEDITOR.POSITION_FOLLOWING, node2.getPosition( node1 ) );
+		},
+
+		/**
+		 *  Test 'preceding' position.
+		 */
+		test_getPosition_3240: function()
+		{
+			var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'b' )[0].firstChild );
+			var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'span' )[0].firstChild );
+
+			assert.areSame( CKEDITOR.POSITION_PRECEDING, node1.getPosition( node2 ) );
+		},
+
+		// Test get previous non-spaces node.
+		test_getPrevious : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			var span1 = new CKEDITOR.dom.element( 'span' );
+			element.append( span1 );
+			element.append( new CKEDITOR.dom.text( ' ' ) );
+			var span2 = new CKEDITOR.dom.element( 'span' );
+			element.append( span2 );
+			var previous = span2.getPrevious( CKEDITOR.dom.walker.whitespaces( true ) );
+			assert.areSame( span1.$, previous.$ );
+		},
+
+		// Test get next non-spaces node.
+		test_getNext : function()
+		{
+			var element = new CKEDITOR.dom.element( document.getElementById( 'append' ) );
+			var span1 = new CKEDITOR.dom.element( 'span' );
+			element.append( span1 );
+			element.append( new CKEDITOR.dom.text( ' ' ) );
+			var span2 = new CKEDITOR.dom.element( 'span' );
+			element.append( span2 );
+			var next = span1.getNext( CKEDITOR.dom.walker.whitespaces( true ) );
+			assert.areSame( span2.$, next.$ );
+		},
+
+		name : document.title
+	};
+})() );
+
+//window.onload = function()
+//{
+//	var node1 = new CKEDITOR.dom.node( document.getElementsByTagName( 'h1' )[0] );
+//	var node2 = new CKEDITOR.dom.node( document.getElementsByTagName( 'p' )[0] );
+//
+//	alert( node1.getPosition( node2 ) );
+//};
+//window.onload =  tc.test_getPosition6;
+	//]]>
+	</script>
+</head>
+<body>
+	<div>
+		<h1>Title</h1>
+		<p><b>Sample</b> <i>Text</i></p>
+	</div>
+	<span>Another</span>
+	<p id="append"></p>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/range.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/range.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/range.html	(revision 4087)
@@ -0,0 +1,2409 @@
+<!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.range</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+var html1, html2;
+var tests;
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local references.
+	var assert			= CKEDITOR.test.assert;
+	var getInnerHtml	= CKEDITOR.test.getInnerHtml;
+
+	var doc = new CKEDITOR.dom.document( document );
+
+	var getRange = function( startId, endId )
+	{
+		var range = new CKEDITOR.dom.range( CKEDITOR.document );
+		range.moveToBookmark( { startNode : startId, endNode : endId, serializable : true } );
+		return range;
+	};
+
+	return tests = {
+		test__constructor : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			assert.isNotNull( range, 'range must not be null' );
+
+			assert.isNull( range.startContainer, 'startContainer must be null' );
+			assert.isNull( range.startOffset, 'startOffset must be null' );
+			assert.isNull( range.endContainer, 'endContainer must be null' );
+			assert.isNull( range.endOffset, 'endOffset must be null' );
+
+			assert.isTrue( range.collapsed, 'range must be collapsed' );
+		},
+
+		test_setStart : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( 'playground' ), 1 );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$ );
+			assert.areSame( 1, range.startOffset );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$ );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed );
+		},
+
+		test_setEnd : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEnd( doc.getById( 'playground' ), 1 );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$ );
+			assert.areSame( 1, range.startOffset );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$ );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed );
+		},
+
+		test_setStartAfter : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAfter( doc.getById( '_B' ) );
+			range.setStartAfter( doc.getById( '_H1' ).getFirst() );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_setStartBefore : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartBefore( doc.getById( '_B' ) );
+			range.setStartBefore( doc.getById( '_H1' ).getFirst() );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_setEndAfter : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEndAfter( doc.getById( '_H1' ).getFirst() );
+			range.setEndAfter( doc.getById( '_B' ) );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_setEndBefore : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEndBefore( doc.getById( '_H1' ).getFirst() );
+			range.setEndBefore( doc.getById( '_B' ) );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_setStartAt_1 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( doc.getById('_Span'), CKEDITOR.POSITION_AFTER_START );
+
+			assert.areSame( document.getElementById('_Span'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_Span'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_setStartAt_2 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( doc.getById('_Span'), CKEDITOR.POSITION_BEFORE_END );
+
+			assert.areSame( document.getElementById('_Span'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_Span'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_setStartAt_3 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( doc.getById('_Span'), CKEDITOR.POSITION_BEFORE_START );
+
+			assert.areSame( document.getElementById('_P'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_P'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_setStartAt_4 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( doc.getById('_Span'), CKEDITOR.POSITION_AFTER_END );
+
+			assert.areSame( document.getElementById('_P'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_P'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_setEndAt_1 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEndAt( doc.getById('_Span'), CKEDITOR.POSITION_AFTER_START );
+
+			assert.areSame( document.getElementById('_Span'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_Span'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_setEndAt_2 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEndAt( doc.getById('_Span'), CKEDITOR.POSITION_BEFORE_END );
+
+			assert.areSame( document.getElementById('_Span'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_Span'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_setEndAt_3 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEndAt( doc.getById('_Span'), CKEDITOR.POSITION_BEFORE_START );
+
+			assert.areSame( document.getElementById('_P'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_P'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_setEndAt_4 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEndAt( doc.getById('_Span'), CKEDITOR.POSITION_AFTER_END );
+
+			assert.areSame( document.getElementById('_P'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_P'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_collapsed : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( doc.getById( '_P' ), CKEDITOR.POSITION_AFTER_START );
+
+			assert.isTrue( range.collapsed );
+		},
+
+		test_collapse : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( doc.getById( '_Para' ), CKEDITOR.POSITION_AFTER_START );
+			range.setEndAt( doc.getById( '_Span' ), CKEDITOR.POSITION_BEFORE_END );
+
+			assert.areSame( document.getElementById('_Para'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_Span'), range.endContainer.$, 'endContainer' );
+			assert.isFalse( range.collapsed, 'collapsed' );
+
+			range.collapse( true );
+
+			assert.areSame( document.getElementById('_Para'), range.startContainer.$, 'startContainer' );
+			assert.areSame( document.getElementById('_Para'), range.endContainer.$, 'endContainer' );
+			assert.isTrue( range.collapsed, 'collapsed' );
+		},
+
+		test_selectNodeContents_Element : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			// Test with an Element node.
+			range.selectNodeContents( doc.getById( '_Para' ) );
+
+			assert.areSame( document.getElementById( '_Para' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 3, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_selectNodeContents_Text : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			// Test with a Text node.
+			range.selectNodeContents( doc.getById( '_Para' ).getFirst() );
+
+			assert.areSame( document.getElementById( '_Para' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ).firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 8, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_collapse_ToStart : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById( '_P' ) );
+			range.collapse( true );
+
+			assert.areSame( document.getElementById( '_P' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_P' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_collapse_ToEnd : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById( '_Para' ) );
+			range.collapse( false );
+
+			assert.areSame( document.getElementById( '_Para' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 3, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 3, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_insertNode_ElementContents : function()
+		{
+			var newNode = new CKEDITOR.dom.element( 'span' );
+			newNode.setHtml( 'test_' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById( '_B' ) );
+			range.insertNode( newNode );
+
+			assert.areSame( document.getElementById( '_B' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_B' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_insertNode_ElementCollapsed : function()
+		{
+			var newNode = new CKEDITOR.dom.element( 'span' );
+			newNode.setHtml( 'test_' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartBefore( doc.getById( '_Para' ) );
+			range.insertNode( newNode );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_insertNode_ElementNotCollapsed : function()
+		{
+			var newNode = new CKEDITOR.dom.element( 'span' );
+			newNode.setHtml( 'test_' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartBefore( doc.getById( '_Para' ) );
+			range.setStartBefore( doc.getById( '_H1' ) );
+			range.insertNode( newNode );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_insertNode_DiffElements : function()
+		{
+			var newNode = new CKEDITOR.dom.element( 'span' );
+			newNode.setHtml( 'test_' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById( '_Para' ) );
+
+			range.setStart( doc.getById( '_H1' ), 0 );
+			range.insertNode( newNode );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 3, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+
+			assert.isTrue( range.startContainer.getChild( range.startOffset ).equals( newNode ), 'Start must be on new node' );
+		},
+
+		test_insertNode_TextCollapsed : function()
+		{
+			var newNode = new CKEDITOR.dom.element( 'span' );
+			newNode.setHtml( 'test_' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( doc.getById( '_H1' ).getFirst(), 3 );
+			range.insertNode( newNode );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_H1' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_insertNode_TextNotCollapsed : function()
+		{
+			var newNode = new CKEDITOR.dom.element( 'span' );
+			newNode.setHtml( 'test_' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( doc.getById( '_H1' ).getFirst(), 3 );
+			range.setEnd( doc.getById( '_H1' ).getFirst(), 5 );
+			range.insertNode( newNode );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_H1' ).childNodes[2], range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_insertNode_Mixed : function()
+		{
+			var newNode = new CKEDITOR.dom.element( 'span' );
+			newNode.setHtml( 'test_' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( doc.getById( '_H1' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_P' ), 1 );
+			range.insertNode( newNode );
+
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_P' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_getCommonAncestor1 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_H1' ).getFirst(), 3 );
+
+			assert.areSame( document.getElementById( '_H1' ).firstChild, range.getCommonAncestor().$ );
+		},
+
+		test_getCommonAncestor2 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_H1' ), 0 );
+
+			assert.areSame( document.getElementById( '_H1' ), range.getCommonAncestor().$ );
+		},
+
+		test_getCommonAncestor3 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_H1' ), 0 );
+			range.setEnd( doc.getById( '_Para' ), 0 );
+
+			assert.areSame( document.getElementById( 'playground' ), range.getCommonAncestor().$ );
+		},
+
+		test_getCommonAncestor4 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_Para' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_B' ), 0 );
+
+			assert.areSame( document.getElementById( '_Para' ), range.getCommonAncestor().$ );
+		},
+
+		test_getCommonAncestor5 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getBody(), 0 );
+			range.setEnd( doc.getById( '_B' ).getFirst(), 1 );
+
+			assert.areSame( document.body, range.getCommonAncestor().$ );
+		},
+
+		test_getCommonAncestor6 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI' ).getFirst(), 2 );
+			range.setEnd( doc.getById( '_EnlargeB' ), 3 );
+
+			assert.areSame( document.getElementById( '_EnlargeB' ), range.getCommonAncestor().$ );
+		},
+
+		test_enlarge_element1 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> Test <b> <i>  [Enlarge]</i> this</b>   </p>
+			// <p> Test <b> [<i>  Enlarge</i>] this</b>   </p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI' ).getFirst(), 2 );
+			range.setEnd( doc.getById( '_EnlargeI' ), 1 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeB' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element1_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p>Test <b><i>[Enlarge]</i> this</b></p>
+			// <p>Test <b>[<i>Enlarge</i>] this</b></p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeI' ), 1 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeB' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element2 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> Test <b> <i>  [Enlarge</i> this]</b>   </p>
+			// <p> Test [<b> <i>  Enlarge</i> this</b>]   </p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI' ).getFirst(), 2 );
+			range.setEnd( doc.getById( '_EnlargeB' ), 3 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element2_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p>Test <b><i>[Enlarge</i> this]</b></p>
+			// <p>Test [<b><i>Enlarge</i> this</b>]</p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeB' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element3 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> [Test <b> <i>  Enlarge]</i> this</b>   </p>
+			// <p> [Test <b> <i>  Enlarge</i>] this</b>   </p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeP' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_EnlargeI' ), 1 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element3_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p>[Test <b><i>Enlarge]</i> this</b></p>
+			// <p>[Test <b><i>Enlarge</i>] this</b></p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeP' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeI' ), 1 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element4 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> [Test <b> <i>  Enlarge</i> this]</b>   </p>
+			// [<p> Test <b> <i>  Enlarge</i> this</b>   </p>]
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeP' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_EnlargeB' ).getChild( 2 ), 5 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ).parentNode, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( doc.getById( '_EnlargeP' ).getIndex(), range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP' ).parentNode, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( doc.getById( '_EnlargeP' ).getIndex() + 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element4_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p>[Test <b><i>Enlarge</i> this]</b></p>
+			// [<p>Test <b><i>Enlarge</i> this</b></p>]
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeP' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeB' ).getChild( 1 ), 5 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ).parentNode, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( doc.getById( '_EnlargeP' ).getIndex(), range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP' ).parentNode, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( doc.getById( '_EnlargeP' ).getIndex() + 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element5 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> Test<b> <i>  [Enlarge</i> this]</b>   </p>
+			// <p> Test<b> [<i>  Enlarge</i> this]</b>   </p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI1' ).getFirst(), 2 );
+			range.setEnd( doc.getById( '_EnlargeB1' ).getChild( 2 ), 5 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeB1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB1' ).childNodes[ 2 ], range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 5, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element5_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p>Test<b> <i>[Enlarge</i> this]</b></p>
+			// <p>Test<b> [<i>Enlarge</i> this]</b></p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI1' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeB1' ).getChild( 2 ), 5 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeB1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB1' ).childNodes[ 2 ], range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 5, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element6 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> <b> <i>  [Enlarge</i>] this</b>   </p>
+			// <p> <b> [<i>  Enlarge</i>] this</b>   </p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI2' ).getFirst(), 2 );
+			range.setEnd( doc.getById( '_EnlargeB2' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeB2' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB2' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element6_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p><b><i>[Enlarge</i>] this</b></p>
+			// <p><b>[<i>Enlarge</i>] this</b></p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI2' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeB2' ), 1 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeB2' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeB2' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element7 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> <b> <i>  [Enlarge</i> this]</b>   </p>
+			// [<p> <b> <i>  Enlarge</i> this</b>   </p>]
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI2' ).getFirst(), 2 );
+			range.setEnd( doc.getById( '_EnlargeB2' ), 3 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP2' ).parentNode, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( doc.getById( '_EnlargeP2' ).getIndex(), range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP2' ).parentNode, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( doc.getById( '_EnlargeP2' ).getIndex() + 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element7_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p><b><i>[Enlarge</i> this]</b></p>
+			// [<p><b><i>Enlarge</i> this</b></p>]
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI2' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeB2' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP2' ).parentNode, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( doc.getById( '_EnlargeP2' ).getIndex(), range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP2' ).parentNode, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( doc.getById( '_EnlargeP2' ).getIndex() + 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element8 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p> Test <b> <i>  [Enlarge</i> this</b>   </p><p> <b> <i>  Enlarge</i> this]</b>   </p>
+			// <p> Test [<b> <i>  Enlarge</i> this</b>   </p><p> <b> <i>  Enlarge</i> this</b>   </p>]
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI' ).getFirst(), 2 );
+			range.setEnd( doc.getById( '_EnlargeB2' ), 3 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP2' ).parentNode, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( doc.getById( '_EnlargeP2' ).getIndex() + 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element8_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p>Test <b><i>[Enlarge</i> this</b></p><p><b><i>Enlarge</i> this]</b></p>
+			// <p>Test [<b><i>Enlarge</i> this</b></p><p><b><i>Enlarge</i> this</b></p>]
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeB2' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP2' ).parentNode, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( doc.getById( '_EnlargeP2' ).getIndex() + 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element9 : function()
+		{
+			// <p>Test<i> [Enlarge</i>]</p>
+			// <p>Test<i> [Enlarge</i>]</p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI3' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_EnlargeP3' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeI3' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP3' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element10 : function()
+		{
+			// For IE, see the next test.
+			if ( CKEDITOR.env.ie )
+				return;
+
+			// <p>Test <i> [Enlarge</i>]</p>
+			// <p>Test [<i> Enlarge</i>]</p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI4' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_EnlargeP4' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP4' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP4' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element10_ie : function()
+		{
+			// IE normalizes whitespaces when parsing the HTML, so we need a
+			// specific test for it.
+			if ( !CKEDITOR.env.ie )
+				return;
+
+			// <p>Test <i>[Enlarge</i>]</p>
+			// <p>Test [<i>Enlarge</i>]</p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI4' ).getFirst(), 0 );
+			range.setEnd( doc.getById( '_EnlargeP4' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP4' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP4' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element11 : function()
+		{
+			// <p>Test <i>[Enlarge]</i></p>
+			// <p>Test [<i>Enlarge</i>]</p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI5' ), 0 );
+			range.setEnd( doc.getById( '_EnlargeI5' ), 1 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP5' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP5' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element12 : function()
+		{
+			// <p>Test <i><b></b>[Enlarge]</i></p>
+			// <p>Test [<i><b></b>Enlarge</i>]</p>
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeI6' ), 1 );
+			range.setEnd( doc.getById( '_EnlargeI6' ), 2 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP6' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP6' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_element13 : function()
+		{
+			// <p>Test <i><b></b>[Enlarge]</i></p>
+			// <p>Test [<i><b></b>Enlarge</i>]</p>
+
+			doc.getById( '_EnlargeP' ).setHtml( 'this <i>is some </i>sample text' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_EnlargeP' ), 0 );
+			range.setEnd( doc.getById( '_EnlargeP' ).getChild( 1 ), 0 );
+
+			range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
+
+			assert.areSame( document.getElementById( '_EnlargeP' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP' ).childNodes[ 1 ], range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_list1 : function()
+		{
+			var range = getRange( 'S1', null );
+			range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP7' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP7' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 3, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_list2 : function()
+		{
+			var range = getRange( 'S2', 'E2' );
+			range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP8' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP8' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 4, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_list3 : function()
+		{
+			var range = getRange( 'S3', null );
+			range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP9' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 2, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP9' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 3, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_list4 : function()
+		{
+			var range = getRange( 'S4', null );
+			range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP10' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 3, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP10' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 5, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_list5 : function()
+		{
+			var range = getRange( 'S9', null );
+			var bookmark = range.createBookmark();
+			range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP15' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP15' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 4, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+			range.moveToBookmark( bookmark );
+		},
+
+		test_enlarge_block1 : function()
+		{
+			var range = getRange( 'S5', null );
+			range.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP11' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP11'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 5, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_block2 : function()
+		{
+			var range = getRange( 'S10', null );
+			var bookmark = range.createBookmark();
+			range.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP16' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP16'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 5, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+			range.moveToBookmark( bookmark );
+		},
+
+		test_enlarge_block3 : function()
+		{
+			var range = getRange( 'S6', null );
+			range.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP12' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP12'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_block4 : function()
+		{
+			var range = getRange( 'S7', null );
+			range.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP13' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_EnlargeP13'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_enlarge_block5 : function()
+		{
+			var range = getRange( 'S8', null );
+			range.enlarge( CKEDITOR.ENLARGE_BLOCK_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP14' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		/**
+		 * Test enlarge list when there's no nodes between
+		 * range start and the block boundary.
+		 */
+		test_enlarge_block6 : function()
+		{
+			var range = getRange( 'S11', null );
+			range.enlarge( CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS );
+
+			assert.areSame( document.getElementById( '_EnlargeP17' ),
+				range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+		},
+
+		test_deleteContents_W3C_1 : function()
+		{
+			// W3C DOM Range Specs - Section 2.6 - Example 1
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_Para' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_Para' ), 2 );
+
+			range.deleteContents();
+
+			assert.areSame( 't text.', getInnerHtml( '_Para' ), 'HTML after deletion' );
+
+			assert.areSame( document.getElementById( '_Para' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ).firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_deleteContents_W3C_2 : function()
+		{
+			// W3C DOM Range Specs - Section 2.6 - Example 2
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_B' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_B' ).getNext(), 1 );
+
+			range.deleteContents();
+
+			assert.areSame( 'this is <b id="_b">s</b>text.', getInnerHtml( '_Para' ) );
+
+			assert.areSame( document.getElementById( '_Para' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 2, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_deleteContents_W3C_3 : function()
+		{
+			// W3C DOM Range Specs - Section 2.6 - Example 3
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_B' ).getPrevious(), 1 );
+			range.setEnd( doc.getById( '_B' ).getFirst(), 1 );
+
+			range.deleteContents();
+
+			assert.areSame( 't<b id="_b">ome</b> text.', getInnerHtml( '_Para' ) );
+
+			assert.areSame( document.getElementById( '_Para' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_deleteContents_W3C_4 : function()
+		{
+			// W3C DOM Range Specs - Section 2.6 - Example 4
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_H1' ).getFirst(), 1 );
+			range.setEnd( doc.getById( 'playground' ).getLast().getFirst(), 1 );
+
+			range.deleteContents();
+
+			assert.areSame( '<h1 id="_h1">f</h1><p>nother paragraph.</p>', getInnerHtml( 'playground' ) );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_deleteContents_Other : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_H1' ), 0 );
+			range.setEnd( doc.getById( 'playground' ).getLast(), 1 );
+
+			range.deleteContents();
+
+			assert.areSame( '<h1 id="_h1"></h1><p></p>', getInnerHtml( 'playground' ) );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_deleteContents_Other_2 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( 'playground' ), 0 );
+			range.setEnd( doc.getById( 'playground' ), 2 );
+
+			range.deleteContents();
+
+			assert.areSame( '<p>another paragraph.</p>', getInnerHtml( 'playground' ) );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame(document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_deleteContents_Other_3 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( doc.getById('_B') );
+
+			range.deleteContents();
+
+			assert.areSame( '', getInnerHtml('_B') );
+
+			assert.areSame( document.getElementById('_B'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('_B'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_deleteContents_Other_4 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( doc.getById('_Para') );
+
+			range.deleteContents();
+
+			assert.areSame( '', getInnerHtml('_Para') );
+
+			assert.areSame( document.getElementById('_Para'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('_Para'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_W3C_1 : function()
+		{
+			// W3C DOM Range Specs - Section 2.7 - Example 1
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_Para' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_Para' ), 2 );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'his is <b id="_b">some</b>', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( 't text.', getInnerHtml( '_Para' ), 'HTML after extraction' );
+
+			assert.areSame( document.getElementById( '_Para' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ).firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_W3C_2 : function()
+		{
+			// W3C DOM Range Specs - Section 2.7 - Example 2
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_B' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_B' ).getNext(), 2 );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<b>ome</b> t', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( 'this is <b id="_b">s</b>ext.', getInnerHtml( '_Para' ), 'HTML after extraction' );
+
+			assert.areSame( document.getElementById( '_Para' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 2, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_W3C_3 : function()
+		{
+			// W3C DOM Range Specs - Section 2.6 - Example 3
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_B' ).getPrevious(), 1 );
+			range.setEnd( doc.getById( '_B' ).getFirst(), 1 );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'his is <b>s</b>', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( 't<b id="_b">ome</b> text.', getInnerHtml( '_Para' ), 'HTML after extraction' );
+
+			assert.areSame( document.getElementById( '_Para' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_W3C_4 : function()
+		{
+			// W3C DOM Range Specs - Section 2.6 - Example 4
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_H1' ).getFirst(), 1 );
+			range.setEnd( doc.getById( 'playground' ).getLast().getFirst(), 1 );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<h1>ckw3crange test</h1><p id="_para">this is <b id="_b">some</b> text.</p><p>a</p>', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( '<h1 id="_h1">f</h1><p>nother paragraph.</p>', getInnerHtml( 'playground' ) );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_Other : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_H1' ), 0 );
+			range.setEnd( doc.getById( 'playground' ).getLast(), 1 );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<h1>fckw3crange test</h1><p id="_para">this is <b id="_b">some</b> text.</p><p>another paragraph.</p>', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( '<h1 id="_h1"></h1><p></p>', getInnerHtml( 'playground' ) );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_Other_2 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( 'playground' ), 0 );
+			range.setEnd( doc.getById( 'playground' ), 2 );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<h1 id="_h1">fckw3crange test</h1><p id="_para">this is <b id="_b">some</b> text.</p>', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( '<p>another paragraph.</p>', getInnerHtml( 'playground' ) );
+
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_Other_3 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById('_B') );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'some', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( '', getInnerHtml('_B'), 'HTML after extraction' );
+
+			assert.areSame( document.getElementById('_B'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('_B'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_Other_4 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById('_Para') );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'this is <b id="_b">some</b> text.', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( '', getInnerHtml('_Para'), 'HTML after extraction' );
+
+			assert.areSame( document.getElementById('_Para'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('_Para'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_Other_5 : function()
+		{
+			document.getElementById( 'playground' ).innerHTML = '<p><b><i>test</i></b></p>';
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAfter( new CKEDITOR.dom.element( document.getElementById( 'playground' ).getElementsByTagName('i')[0] ) );
+			range.setEndAfter( new CKEDITOR.dom.element( document.getElementById( 'playground' ).getElementsByTagName('b')[0] ) );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<b></b>', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( '<p><b><i>test</i></b></p>', getInnerHtml( 'playground' ), 'HTML after extraction' );
+
+			assert.areSame( document.getElementById( 'playground' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ).firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_extractContents_Other_6 : function()
+		{
+			document.getElementById( 'playground' ).innerHTML = '<p><b><i>test</i></b></p>';
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartBefore( new CKEDITOR.dom.element( document.getElementById( 'playground' ).getElementsByTagName('b')[0] ) );
+			range.setEndBefore( new CKEDITOR.dom.element( document.getElementById( 'playground' ).getElementsByTagName('i')[0] ) );
+
+			var docFrag = range.extractContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<b></b>', getInnerHtml( tmpDiv.$ ), 'Extracted HTML' );
+			assert.areSame( '<p><b><i>test</i></b></p>', getInnerHtml( 'playground' ), 'HTML after extraction' );
+
+			assert.areSame( document.getElementById( 'playground' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ).firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 0, range.endOffset, 'range.endOffset' );
+			assert.isTrue( range.collapsed, 'range.collapsed' );
+		},
+
+		test_cloneContents_W3C_1 : function()
+		{
+			// W3C DOM Range Specs - Section 2.7 - Example 1
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_Para' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_Para' ), 2 );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'his is <b>some</b>', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			// The range must also remain unchanged.
+			assert.areSame( document.getElementById( '_Para' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_Para' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_cloneContents_W3C_2 : function()
+		{
+			// W3C DOM Range Specs - Section 2.7 - Example 2
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_B' ).getFirst(), 1 );
+			range.setEnd( doc.getById( '_B' ).getNext(), 2 );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<b>ome</b> t', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			// The range must also remain unchanged.
+			assert.areSame( document.getElementById( '_B' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_B' ).nextSibling, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_cloneContents_W3C_3 : function()
+		{
+			// W3C DOM Range Specs - Section 2.6 - Example 3
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStart( doc.getById( '_B' ).getPrevious(), 1 );
+			range.setEnd( doc.getById( '_B' ).getFirst(), 1 );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'his is <b>s</b>', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			// The range must also remain unchanged.
+			assert.areSame( document.getElementById( '_B' ).previousSibling, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( '_B' ).firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		// W3C DOM Range Specs - Section 2.6 - Example 4
+		test_cloneContents_W3C_4 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( doc.getById( '_H1' ).getFirst(), 1 );
+			range.setEnd( doc.getById( 'playground' ).getLast().getFirst(), 1 );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<h1>ckw3crange test</h1><p>this is <b>some</b> text.</p><p>a</p>', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			// The range must also remain unchanged.
+			assert.areSame( document.getElementById( '_H1' ).firstChild, range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 1, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ).lastChild.firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_cloneContents_Other : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( doc.getById( '_H1' ), 0 );
+			range.setEnd( doc.getById( 'playground' ).getLast(), 1 );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<h1>fckw3crange test</h1><p>this is <b>some</b> text.</p><p>another paragraph.</p>', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			// The range must also remain unchanged.
+			assert.areSame( document.getElementById( '_H1' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ).lastChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_cloneContents_Other_2 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( doc.getById( 'playground' ), 0 );
+			range.setEnd( doc.getById( 'playground' ), 2 );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( '<h1>fckw3crange test</h1><p>this is <b>some</b> text.</p>', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			// The range must also remain unchanged.
+			assert.areSame( document.getElementById( 'playground' ), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById( 'playground' ), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 2, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_cloneContents_Other_3 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById('_B') );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'some', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			assert.areSame( document.getElementById('_B'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('_B'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 1, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_cloneContents_Other_4 : function()
+		{
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.selectNodeContents( doc.getById('_Para') );
+
+			var bodyHtml = document.getElementById( 'playground' ).innerHTML;
+
+			var docFrag = range.cloneContents();
+
+			var tmpDiv = doc.createElement( 'div' );
+			docFrag.appendTo( tmpDiv );
+
+			assert.areSame( 'this is <b>some</b> text.', getInnerHtml( tmpDiv.$ ), 'Cloned HTML' );
+
+			// The body HTML must remain unchanged.
+			assert.areSame( bodyHtml.replace( /\s+_cke_expando=["\d]+/g, '' ), document.getElementById( 'playground' ).innerHTML.replace( /\s+_cke_expando=["\d]+/g, '' ), 'The HTML must remain untouched' );
+
+			assert.areSame( document.getElementById('_Para'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('_Para'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 3, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_createBookmark2_1 : function()
+		{
+			doc.getById( 'playground' ).setHtml( '<p id="P">This is <b id="B">a test</b></p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( doc.getById( 'P' ), 0 );
+			range.setEnd( doc.getById( 'B' ).getFirst(), 3 );
+
+			var bookmark = range.createBookmark2();
+
+			range = new CKEDITOR.dom.range( doc );
+			range.moveToBookmark( bookmark );
+
+			assert.areSame( document.getElementById('P'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 0, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('B').firstChild, range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 3, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		// This test is just like test_createBookmark2_3, but uses a "non
+		// normalized" bookmark.
+		test_createBookmark2_2 : function()
+		{
+			var html = '<p id="P">A B <b>C </b>D E</p>';
+
+			doc.getById( 'playground' ).setHtml( html );
+
+			var p = doc.getById( 'P' );
+
+			// Split the text nodes.
+			p.getFirst().split( 2 );	// Right before "B"
+			p.getChild( 3 ).split( 2 );	// Right before "E"
+
+			assert.areSame( 5, p.getChildCount(), 'The number of nodes after split doesn\'t match' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			// Create a range that enbraces "E".
+			range.setStartBefore( p.getChild( 4 ) );
+			range.setEndAfter( p.getChild( 4 ) );
+
+			var bookmark = range.createBookmark2();
+
+			range = new CKEDITOR.dom.range( doc );
+			range.moveToBookmark( bookmark );
+
+			assert.areSame( document.getElementById('P'), range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 4, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('P'), range.endContainer.$, 'range.endContainer' );
+			assert.areSame( 5, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_createBookmark2_3 : function()
+		{
+			var html = '<p id="P">A B <b>C </b>D E</p>';
+
+			doc.getById( 'playground' ).setHtml( html );
+
+			var p = doc.getById( 'P' );
+
+			// Split the text nodes.
+			p.getFirst().split( 2 );	// Right before "B"
+			p.getChild( 3 ).split( 2 );	// Right before "E"
+
+			assert.areSame( 5, p.getChildCount(), 'The number of nodes after split doesn\'t match' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			// Create a range that enbraces "E".
+			range.setStartBefore( p.getChild( 4 ) );
+			range.setEndAfter( p.getChild( 4 ) );
+
+			var bookmark = range.createBookmark2( true );
+
+			// Normalize the contents.
+			doc.getById( 'playground' ).setHtml( html );
+
+			range = new CKEDITOR.dom.range( doc );
+			range.moveToBookmark( bookmark );
+
+			assert.areSame( document.getElementById('P').childNodes[2], range.startContainer.$, 'range.startContainer' );
+			assert.areSame( 2, range.startOffset, 'range.startOffset' );
+			assert.areSame( document.getElementById('P'), range.endContainer.$, 'range.endContainer' );
+
+			// Note that the endOffset doesn't get normalized as it's not
+			// needed. Any offset pointing over the container size is meant to
+			// be at the end of it.
+			assert.areSame( 5, range.endOffset, 'range.endOffset' );
+			assert.isFalse( range.collapsed, 'range.collapsed' );
+		},
+
+		test_checkStartOfBlock1 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock2 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock3 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock4 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock5 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p> Test </p>' );
+			el = el.getFirst().getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			// IE trims the space in the beginning of text nodes in our case.
+			// So, let's just check it and make it pass.
+			range.setStart( el, ( el.substring( 0, 1 ) == 'T' ) ? 0 : 1 );
+			range.collapse( true );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock6 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p> Test </p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( p.getFirst(), 5 );
+			range.collapse( true );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock7 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p><b>Test</b></p>' );
+			el = el.getFirst().getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock8 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p>A<b>Test</b>B</p>' );
+			el = el.getFirst().getFirst().getNext();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkEndOfBlock1 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock2 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock3 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock4 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock5 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p> Test </p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( p.getFirst(), 1 );
+			range.collapse( true );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock6 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p> Test </p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( p.getFirst(), 5 );
+			range.collapse( true );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock7 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p><b>Test</b></p>' );
+			el = el.getFirst().getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock8 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p>A<b>Test</b>B</p>' );
+			el = el.getFirst().getFirst().getNext();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		test_checkStartOfBlock1 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock2 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock3 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock4 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock5 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p> Test </p>' );
+			el = el.getFirst().getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			// IE trims the space in the beginning of text nodes in our case.
+			// So, let's just check it and make it pass.
+			range.setStart( el, ( el.substring( 0, 1 ) == 'T' ) ? 0 : 1 );
+			range.collapse( true );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock6 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p> Test </p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( p.getFirst(), 5 );
+			range.collapse( true );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock7 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p><b>Test</b></p>' );
+			el = el.getFirst().getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isTrue( range.checkStartOfBlock() );
+		},
+
+		test_checkStartOfBlock8 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p>A<b>Test</b>B</p>' );
+			el = el.getFirst().getFirst().getNext();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isFalse( range.checkStartOfBlock() );
+		},
+
+		test_checkEndOfBlock1 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock2 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p, CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock3 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock4 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p>Test</p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( p.getFirst(), CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock5 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p> Test </p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( p.getFirst(), 1 );
+			range.collapse( true );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock6 : function()
+		{
+			var p = doc.getById( 'playground' );
+			p.setHtml( '<p> Test </p>' );
+			p = p.getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStart( p.getFirst(), 5 );
+			range.collapse( true );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock7 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p><b>Test</b></p>' );
+			el = el.getFirst().getFirst();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isTrue( range.checkEndOfBlock() );
+		},
+
+		test_checkEndOfBlock8 : function()
+		{
+			var el = doc.getById( 'playground' );
+			el.setHtml( '<p>A<b>Test</b>B</p>' );
+			el = el.getFirst().getFirst().getNext();
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( el );
+
+			assert.isFalse( range.checkEndOfBlock() );
+		},
+
+		/**
+		 *  Test trim with text range.
+		 */
+		test_trim : function()
+		{
+			var text = doc.getById( '_trim_ct').getFirst();
+			var range = new CKEDITOR.dom.range();
+			range.setStart(text, 2);
+			range.setEnd(text, 6);
+			range.trim();
+
+			assert.isFalse( range.collapsed );
+			assert.isTrue( range.startContainer.equals( doc.getById( '_trim_ct') ) );
+			assert.areEqual( range.startOffset, 1 );
+			assert.isTrue( range.endContainer.equals( doc.getById( '_trim_ct') ) );
+			assert.areEqual( range.endOffset, 2 );
+		},
+
+		/**
+		 * Trim range which collapsed at text node boundary.
+		 */
+		test_trim_3790 : function()
+		{
+
+			var ct = doc.getById( '_trim_ct');
+			ct.setHtml( '<span id="_SPAN1">text</span>' );
+			var text = doc.getById( '_trim_ct').getFirst();
+
+			// <span id="_SPAN1">text^</span>
+			var range = new CKEDITOR.dom.range();
+			range.setStartAt( doc.getById( '_SPAN1' ).getFirst(), CKEDITOR.POSITION_BEFORE_END );
+			range.collapse( true );
+			range.trim( true );
+
+			// <span id="_SPAN1">text^</span>
+			assert.isTrue( range.collapsed );
+			assert.areEqual( doc.getById( '_SPAN1').$, range.startContainer.$ );
+			assert.areEqual( range.startOffset, 1 );
+		},
+
+		/**
+		 * Trim range which collapsed inside text node.
+		 */
+		test_trim_3790_2 : function()
+		{
+
+			var ct = doc.getById( '_trim_ct');
+			ct.setHtml( '<span id="_SPAN1">text</span>' );
+			var text = doc.getById( '_trim_ct').getFirst();
+
+			// <span id="_SPAN1">te^xt</span>
+			var range = new CKEDITOR.dom.range();
+			range.setStart( doc.getById( '_SPAN1' ).getFirst(), 2 );
+			range.collapse( true );
+			range.trim( true );
+
+			// <span id="_SPAN1">te^xt</span>
+			assert.isTrue( range.collapsed );
+			assert.areEqual( doc.getById( '_SPAN1').$, range.startContainer.$ );
+			assert.areEqual( range.startOffset, 1 );
+		},
+		/////////////
+
+		setUp : function()
+		{
+			 document.getElementById( 'playground' ).innerHTML = html1;
+			 document.getElementById( 'playground2' ).innerHTML = html2;
+		},
+
+		name : document.title
+	};
+})() );
+
+//window.onload = tests.test_trim;
+	//]]>
+	</script>
+</head>
+<body>
+	<div id="playground" style="visibility:hidden"><h1 id="_H1">FCKW3CRange Test</h1><p id="_Para">This is <b id="_B">some</b> text.</p><p>Another paragraph.</p></div>
+	<div id="playground2" style="visibility: hidden">
+		<h1>
+			Test page for CKEditor
+		</h1>
+		<p id="_P">
+			This document contains various markup features commonly used by content editors
+			or "<span id="_Span" lang="fr">r&eacute;dacteurs de contenu</span>" as they are
+			called in <a id="_A" href="http://en.wikipedia.org/wiki/France" title="Wikipedia article about France">
+				France</a>.<br />
+			It is important that a <acronym id="_Acronym" title="what you see is what you get">WYSIWYG</acronym>
+			tool has features that are easily available for the editor. If not, there is a risk
+			that content won't receive <strong id="_Strong">proper</strong> markup. Examples
+			of commonly found content are:</p>
+		<p id="_Pnbsp">
+			&nbsp;
+		</p>
+		<p id="_Pspaces">
+		</p>
+		<ol>
+			<li>Headings</li>
+			<li style="color: Red">Links (with optional title) </li>
+			<li>Lists (like this one)
+				<ul>
+					<li>including nested lists </li>
+				</ul>
+			</li>
+			<li>Tables
+				<ul>
+					<li>caption</li>
+					<li>headers</li>
+					<li>summary</li>
+				</ul>
+			</li>
+			<li>Language information</li>
+			<li>Acronyms and abbreviations</li>
+			<li>Emphasis and strong emphasis </li>
+			<li>Quotes, inline and block </li>
+			<li>Images</li>
+		</ol>
+		<hr />
+		<h2 style="background-color: Silver">
+			Test procedure
+		</h2>
+		This text has no block tag. It should be corrected when working with the enter key
+		set to "p" or "div" tags. The "br" configuration should not make changes instead.
+		<p id="_P2">
+			In the test we will try to recreate this document using the editor tools. To make
+			sure tables can be inserted <em id="_Em">properly</em> we re-visit banana import
+			statistics from 1998.
+		</p>
+		<p id="_P3">
+			This paragraph has and image at the very end of its contents.<img id="_Img" src="img.gif"
+				alt="" />
+		</p>
+		This text has no block tag.<br />It should be corrected when working with the enter key
+		set to "p" or "div" tags. The <strong id="_StrongNoPara">"br" configuration</strong>
+		should not make changes instead.<br />It has three lines separated by BR tags.
+		<p>
+			In the test we will try to recreate this document using the editor tools. To make
+			sure tables can be inserted <em>properly</em> we re-visit banana import statistics
+			from 1998.
+		</p>
+		<table summary="Sweden was the top importing country by far in 1998.">
+			<caption>
+				Top banana importers 1998 (value of banana imports in millions of US dollars per
+				million people)<br />
+				<br />
+			</caption>
+			<tr>
+				<th scope="col">
+					Country</th>
+				<th scope="col">
+					Millions of US dollars per million people</th>
+			</tr>
+			<tr>
+				<td>
+					Sweden</td>
+				<td>
+					17.12</td>
+			</tr>
+			<tr>
+				<td>
+					United&nbsp;Kingdom</td>
+				<td>
+					8.88</td>
+			</tr>
+			<tr>
+				<td>
+					Germany</td>
+				<td>
+					8.36</td>
+			</tr>
+			<tr>
+				<td>
+					Italy</td>
+				<td>
+					5.96</td>
+			</tr>
+			<tr>
+				<td>
+					United States</td>
+				<td>
+					4.78</td>
+			</tr>
+		</table>
+		<p>
+			For block quotes we will have a look at <a href="http://fawny.org/rhcp.html">what Joe
+				Clark says about redheads</a>:</p>
+		<blockquote cite="http://fawny.org/rhcp.html#me">
+			<p>
+				"Since boyhood I&rsquo;ve always believed, at the deepest level, that redheads are
+				standard-bearers of the grandest and most wondrous human beauty."</p>
+		</blockquote>
+		<p>
+			<img src="img.gif" alt="" /></p>
+		<p>
+			The above is the CKEditor logo loaded from the FCKeditor.net web site.</p>
+		<p><b id="_B1">Line 1<br />Line 2<br /><i id="_I1">Line 3</i></b></p>
+		<p id="_EnlargeP"> Test <b id="_EnlargeB"> <i id="_EnlargeI">  Enlarge</i> this</b>   </p>
+		<p id="_EnlargeP1"> Test<b id="_EnlargeB1"> <i id="_EnlargeI1">  Enlarge</i> this</b>   </p>
+		<p id="_EnlargeP2"> <b id="_EnlargeB2"> <i id="_EnlargeI2">  Enlarge</i> this</b>   </p>
+		<p id="_EnlargeP3">Test<i id="_EnlargeI3"> Enlarge</i></p>
+		<p id="_EnlargeP4">Test <i id="_EnlargeI4"> Enlarge</i></p>
+		<p id="_EnlargeP5">Test <i id="_EnlargeI5">Enlarge</i></p>
+		<p id="_EnlargeP6">Test <i id="_EnlargeI6"><b></b>Enlarge</i></p>
+		<p id="_EnlargeP7">Test <span id="S1"></span>List<br/ >Item Enlarge</p>
+		<p id="_EnlargeP8">Test <span id="S2"></span>List<span id="E2"></span> <br /><br />Item Enlarge</p>
+		<p id="_EnlargeP9">Test List <br /><span id="S3"></span><br />Item Enlarge</p>
+		<p id="_EnlargeP10">Test List <br /><br />Item<span id="S4"></span> Enlarge</p>
+		<p id="_EnlargeP11">Test <strong>Block<span id="S5"></span></strong><br /><br />Enlarge</p>
+		<div id="_EnlargeP12">Test<span id="S6"></span> Block <div>Enlarge</div></div>
+		<div>Test <div id="_EnlargeP13">Blo<span id="S7"></span>ck</div> Enlarge</div>
+		<p id="_EnlargeP14"><span id="S8"></span></p>
+		<p id="_EnlargeP15">Test <span id="S9"></span>List<br/ >Item Enlarge</p>
+		<p id="_EnlargeP16">Test <strong>Block<span id="S10"></span></strong><br /><br />Enlarge</p>
+		<p id="_EnlargeP17"><span><span id="S11"></span>Test Block Enlarge<span id="E11"></span></span></p>
+		<p id="_trim_ct">Test trim</p>
+	</div>
+	<script type="text/javascript">
+	//<![CDATA[
+
+html1 = document.getElementById( 'playground' ).innerHTML;
+html2 = document.getElementById( 'playground2' ).innerHTML;
+
+	//]]>
+	</script>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/text.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/text.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/text.html	(revision 4087)
@@ -0,0 +1,126 @@
+<!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.text</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+var tc;
+CKEDITOR.test.addTestCase( tc = (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+
+		test_substring1 : function()
+		{
+			var text = new CKEDITOR.dom.text( '0123456789' );
+
+			assert.areSame( '123', text.substring( 1, 4 ) );
+		},
+
+		test_substring2 : function()
+		{
+			var text = new CKEDITOR.dom.text( '0123456789' );
+
+			assert.areSame( '56789', text.substring( 5 ) );
+		},
+
+		test_substring3 : function()
+		{
+			var text = new CKEDITOR.dom.text( '0123456789' );
+
+			assert.areSame( '', text.substring( 1,1 ) );
+		},
+
+		test_substring4 : function()
+		{
+			var text = new CKEDITOR.dom.text( '0123456789' );
+
+			assert.areSame( '012', text.substring( -10,3 ) );
+		},
+
+		test_substring5 : function()
+		{
+			var text = new CKEDITOR.dom.text( '0123456789' );
+
+			assert.areSame( '89', text.substring( 8,100 ) );
+		},
+
+		test_substring6 : function()
+		{
+			var text = new CKEDITOR.dom.text( '0123456789' );
+
+			assert.areSame( '234', text.substring( 5,2 ) );
+		},
+
+		test_split1 : function()
+		{
+			var div = CKEDITOR.document.getById( 'playground' );
+			div.setHtml( '01234' );
+
+			var text = div.getFirst(),
+				next = text.split( 3 );
+
+			assert.areSame( '012', text.getText(), 'text.getText() is wrong' );
+			assert.areSame( '34', next.getText(), 'next.getText() is wrong' );
+
+			assert.areSame( div.$, next.$.parentNode, 'parentNode is wrong' );
+			assert.areSame( text.$, next.$.previousSibling, 'sibling is wrong' );
+		},
+
+		test_split2 : function()
+		{
+			var div = CKEDITOR.document.getById( 'playground' );
+			div.setHtml( '01234' );
+
+			var text = div.getFirst(),
+				next = text.split( 5 );
+
+			assert.areSame( '01234', text.getText(), 'text.getText() is wrong' );
+			assert.areSame( '', next.getText(), 'next.getText() is wrong' );
+
+			assert.areSame( div.$, next.$.parentNode, 'parentNode is wrong' );
+			assert.areSame( text.$, next.$.previousSibling, 'sibling is wrong' );
+		},
+
+		test_split3 : function()
+		{
+			var div = CKEDITOR.document.getById( 'playground' );
+			div.setHtml( '01234' );
+
+			var text = div.getFirst(),
+				next = text.split( 0 );
+
+			assert.areSame( '', text.getText(), 'text.getText() is wrong' );
+			assert.areSame( '01234', next.getText(), 'next.getText() is wrong' );
+
+			assert.areSame( div.$, next.$.parentNode, 'parentNode is wrong' );
+			assert.areSame( text.$, next.$.previousSibling, 'sibling is wrong' );
+		},
+
+		test_split_3436 : function()
+		{
+			var parent = CKEDITOR.document.getById( 'playground2' );
+			parent.setHtml( 'A B <b>C </b>D E' );
+			parent.getFirst().split( 2 );	// Right before "B"
+			parent.getChildren().getItem( 3 ).split( 2 );	// Right before "E"
+			assert.areSame( 5, parent.getChildren().count(), 'Child nodes num doesn\'t match after split' );
+		},
+
+		name : document.title
+	};
+})() );
+
+//window.onload = tc.test_split_3436;
+
+	//]]>
+	</script>
+</head>
+<body>
+	<p id="playground"></p>
+	<p id="playground2"></p>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/walker.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/walker.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/walker.html	(revision 4087)
@@ -0,0 +1,338 @@
+<!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.walker</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+var tc;
+
+CKEDITOR.test.addTestCase( tc = (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	var doc = new CKEDITOR.dom.document( document );
+
+	function assertNodesList( wanted, nodes )
+	{
+		var simplifiedNodes = [];
+
+		for ( var i = 0 ; i < nodes.length ; i++ )
+			simplifiedNodes.push( nodes[i].type == CKEDITOR.NODE_TEXT ? nodes[i].getText() : ( '<' + nodes[i].getName() + '>' ) );
+
+		assert.areSame( wanted.toString(), simplifiedNodes.toString() );
+	}
+
+	return {
+
+		test_collapsed : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+
+			range.setStartAt( node.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.collapse( true );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			assert.isNull( walker.next() );
+		},
+
+		test_next_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.next() ) )
+				nodes.push( node );
+
+			assertNodesList( [ '<p>', 'This is ', '<b>', 'a ', '<i>', 'simple', ' test' ], nodes );
+		},
+
+		test_next_2 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getFirst(), CKEDITOR.POSITION_AFTER_START );
+			range.setEnd( node.getChild( [0,1,1,0] ), 2 );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.next() ) )
+				nodes.push( node );
+
+			assertNodesList( [ 'This is ', '<b>', 'a ', '<i>', 'si' ], nodes );
+		},
+
+		test_next_3 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 1 ), CKEDITOR.POSITION_BEFORE_START );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.next() ) )
+				nodes.push( node );
+
+			assertNodesList( [ '<h1>' ], nodes );
+		},
+
+		test_next_4 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 0 ), CKEDITOR.POSITION_AFTER_END );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.next() ) )
+				nodes.push( node );
+
+			assertNodesList( [], nodes );
+		},
+
+		test_next_5 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.next() ) )
+				nodes.push( node );
+
+			assertNodesList( [ '<h1>' ], nodes );
+		},
+
+		test_previous_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.previous() ) )
+				nodes.push( node );
+
+			assertNodesList( [ '<p>', ' test', '<b>', '<i>', 'simple', 'a ', 'This is ' ], nodes );
+		},
+
+		test_previous_2 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setEnd( node.getChild( [0,0] ), 2 );
+			range.setEnd( node.getChild( [0,1,1,0] ), 2 );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.previous() ) )
+				nodes.push( node );
+
+			assertNodesList( [ 'si', 'a ', 'is is ' ], nodes );
+		},
+
+		test_previous_3 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 1 ), CKEDITOR.POSITION_BEFORE_START );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.previous() ) )
+				nodes.push( node );
+
+			assertNodesList( [ '' ], nodes );
+		},
+
+		test_previous_4 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 0 ), CKEDITOR.POSITION_AFTER_END );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.previous() ) )
+				nodes.push( node );
+
+			assertNodesList( [ '<p>' ], nodes );
+		},
+
+		test_previous_5 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>Test</p><h1>More</h1>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.setStartAt( node.getChild( 0 ), CKEDITOR.POSITION_BEFORE_END );
+			range.setEndAt( node.getChild( 1 ), CKEDITOR.POSITION_AFTER_START );
+
+			var walker = new CKEDITOR.dom.walker( range );
+
+			var nodes = [];
+			while ( ( node = walker.previous() ) )
+				nodes.push( node );
+
+			assertNodesList( [ '<p>' ], nodes );
+		},
+
+		/**
+		 *  Test guard function is invoked on every move when iterating forward.
+		 */
+		test_guard_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+
+			var walker = new CKEDITOR.dom.walker( range );
+			var nodes = [];
+
+			walker.guard = function( node )
+			{
+				nodes.push( node );
+				return true;
+			};
+
+			while ( ( node = walker.next() ) )
+			{ /*jsl:pass*/ }
+
+			assertNodesList( [ '<p>', 'This is ', '<b>', 'a ', '<i>', 'simple', '<i>', '<b>',' test' , '<p>' ], nodes );
+		},
+
+		/**
+		 *  Test guard function is invoked on every move when iterating backward.
+		 */
+		test_guard_2 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+
+			var walker = new CKEDITOR.dom.walker( range );
+			var nodes = [];
+
+			walker.guard = function( node )
+			{
+				nodes.push( node );
+				return true;
+			};
+
+			while ( ( node = walker.previous() ) )
+			{ /*jsl:pass*/ }
+
+			assertNodesList( [ '<p>', ' test', '<b>', '<i>', 'simple', '<i>', 'a ', '<b>', 'This is ', '<p>' ], nodes );
+		},
+
+		/**
+		 *  Test evaluator function is invoked on every  step when iterating backward.
+		 */
+		test_evaluator_1 : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<p>This is <b>a <i>simple</i></b> test</p>' );
+
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+
+			var walker = new CKEDITOR.dom.walker( range );
+			var nodes = [];
+
+			walker.evaluator = function( node )
+			{
+				nodes.push( node );
+				return true;
+			};
+
+			while ( ( node = walker.previous() ) )
+			{ /*jsl:pass*/ }
+
+			assertNodesList( [ '<p>', ' test', '<b>', '<i>', 'simple', 'a ', 'This is ' ], nodes );
+		},
+		/**
+		 * Test walker stop at empty endContainer.
+		 */
+		test_stopGuard : function()
+		{
+			var node = doc.getById( 'playground' );
+			node.setHtml( '<span></span>afterEnd' );
+			var endContainer = node.getFirst();
+			var range = new CKEDITOR.dom.range( doc );
+			range.selectNodeContents( node );
+			range.setEndAt( endContainer, CKEDITOR.POSITION_AFTER_START );
+
+			var walker = new CKEDITOR.dom.walker( range );
+			var nodes = [];
+
+			walker.evaluator = function( node )
+			{
+				nodes.push( node );
+				return true;
+			};
+
+			while ( ( node = walker.next() ) )
+			{ /*jsl:pass*/ }
+
+			assertNodesList( [ '<span>' ], nodes );
+
+		},
+		name : document.title
+	};
+})() );
+
+//window.onload = tc.test_stopGuard;
+	//]]>
+	</script>
+</head>
+<body>
+	<div id="playground"></div>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/dom/window.html
===================================================================
--- /CKEditor/branches/tests/editor/core/dom/window.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/dom/window.html	(revision 4087)
@@ -0,0 +1,51 @@
+﻿<!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.window</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+var loadCalled;
+
+var testWindow = new CKEDITOR.dom.window( window );
+
+var t;
+
+testWindow.on( 'load', function()
+	{
+		t = document.createElement( 'textarea' );
+		t.id = 'fred';
+
+		document.body.appendChild( t );
+
+		loadCalled = true;
+	});
+
+testWindow.on( 'beforeunload', function()
+	{
+		t.value = new Date();
+	});
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_loadEvent : function()
+		{
+			assert.isTrue( loadCalled );
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+	<div id="test1"></div>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/editor.html
===================================================================
--- /CKEditor/branches/tests/editor/core/editor.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/editor.html	(revision 4087)
@@ -0,0 +1,121 @@
+<!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.editor</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+// Disable 'scayt' plugin due to it may alter editor config after initialized.
+CKEDITOR.config.removePlugins = 'scayt';
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_name : function()
+		{
+			assert.areSame( 'editor1', CKEDITOR.instances.editor1.name );
+		},
+
+		test_element : function()
+		{
+			assert.areSame( document.getElementById( 'editor1' ), CKEDITOR.instances.editor1.element.$ );
+		},
+
+		test_config : function()
+		{
+			// The instance default config must match the CKEDITOR.config.
+
+			var config = CKEDITOR.instances.editor1.config;
+
+			for ( var prop in CKEDITOR.config )
+				assert.areSame( CKEDITOR.config[ prop ], config[ prop ], '"' + prop + '" doesn\'t match' );
+		},
+
+		test_config_inpage : function()
+		{
+			var self = this;
+
+			CKEDITOR.replace( 'editor2',
+				{
+					// The custom setting to be checked.
+					test1 : 'ball',
+					baseHref : 'test',
+
+					on :
+					{
+						instanceReady : function()
+						{
+							self.resume( function()
+							{
+								var config = CKEDITOR.instances.editor2.config;
+
+								assert.areSame( 'ball', config.test1, '"test1" doesn\'t match' );
+								assert.areSame( 'test', config.baseHref, '"baseHref" doesn\'t match' );
+
+								// All other settings must match CKEDITOR.config.
+								for ( var prop in CKEDITOR.config )
+								{
+									if ( prop != 'test1' && prop != 'baseHref' )
+										assert.areSame( CKEDITOR.config[ prop ], config[ prop ], '"' + prop + '" doesn\'t match' );
+								}
+							} );
+						}
+					}
+				});
+
+			this.wait();
+		},
+
+		test_config_customConfig : function()
+		{
+			var testCase = this;
+
+			CKEDITOR.on( 'instanceCreated', function( event )
+				{
+					if ( event.editor.name == 'editor3' )
+					{
+						event.editor.on( 'configLoaded', function()
+							{
+								testCase.resume( function()
+								{
+									var config = event.editor.config;
+
+									assert.areSame( 'Ok', config.test_custom1, '"test_custom1" doesn\'t match' );
+									assert.areSame( 'Ok', config.test_custom2, '"test_custom1" doesn\'t match' );
+									assert.areSame( 'ball', config.test1, '"test1" doesn\'t match' );
+									assert.areSame( 'test', config.baseHref, '"baseHref" doesn\'t match' );
+
+									// All other settings must match CKEDITOR.config.
+									for ( var prop in CKEDITOR.config )
+									{
+										if ( prop != 'customConfig' && prop != 'test_custom1' && prop != 'test_custom2' && prop != 'test1' && prop != 'baseHref' )
+											assert.areSame( CKEDITOR.config[ prop ], config[ prop ], '"' + prop + '" doesn\'t match' );
+									}
+								});
+							});
+					}
+				});
+
+			// Pass in-page settings to the instance.
+			CKEDITOR.replace( 'editor3', { customConfig : '_editor/custom_config_1.js', test1 : 'ball', baseHref : 'test' } );
+
+			this.wait();
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+	<textarea id="editor1" class="ckeditor" cols="80" rows="10"></textarea>
+	<textarea id="editor2" cols="80" rows="10"></textarea>
+	<textarea id="editor3" cols="80" rows="10"></textarea>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/env.html
===================================================================
--- /CKEditor/branches/tests/editor/core/env.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/env.html	(revision 4087)
@@ -0,0 +1,50 @@
+<!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.env</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_ie : function()
+		{
+			if ( window.ActiveXObject )
+			{
+				assert.isTrue( CKEDITOR.env.ie		, 'ie should be true' );
+				assert.isFalse( CKEDITOR.env.opera	, 'opera should be false' );
+				assert.isFalse( CKEDITOR.env.webkit	, 'webkit should be false' );
+				assert.isFalse( CKEDITOR.env.air	, 'air should be false' );
+				assert.isFalse( CKEDITOR.env.gecko	, 'gecko should be false' );
+				assert.isFalse( CKEDITOR.env.mac	, 'ismac should be false' );
+			}
+			else
+				assert.isFalse( CKEDITOR.env.ie );
+		},
+
+		test_isCompatible : function()
+		{
+			assert.isTrue( CKEDITOR.env.isCompatible );
+		},
+
+
+		test_quirks : function()
+		{
+			assert.isFalse( CKEDITOR.env.quirks );
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/event.html
===================================================================
--- /CKEditor/branches/tests/editor/core/event.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/event.html	(revision 4087)
@@ -0,0 +1,485 @@
+<!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.event</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_inherit : function()
+		{
+			// Create a testClass that inherits from CKEDITOR.event.
+			var testClass = function()
+			{
+				CKEDITOR.event.call( this );
+			};
+			testClass.prototype = CKEDITOR.event.prototype;
+
+			var calls = [];
+
+			var testInstance = new testClass();
+
+			testInstance.on( 'someEvent', function( ev )
+				{
+					assert.areSame( testInstance, this, 'Scope 1 is not valid' );
+
+					assert.areSame( 'someEvent', ev.name, 'ev.name (1) is wrong' );
+					assert.areSame( testInstance, ev.sender, 'ev.sender (1) is wrong' );
+					assert.isUndefined( ev.editor, 'ev.editor (1) is wrong' );
+					assert.isUndefined( ev.data, 'ev.data (1) is wrong' );
+					assert.isUndefined( ev.listenerData, 'ev.listenerData (1) is wrong' );
+
+					calls.push( 'a' );
+				} );
+
+			testInstance.on( 'someEvent', function( ev )
+				{
+					assert.areSame( testInstance, this, 'Scope 2 is not valid' );
+
+					assert.areSame( 'someEvent', ev.name, 'ev.name (2) is wrong' );
+					assert.areSame( testInstance, ev.sender, 'ev.sender (2) is wrong' );
+					assert.isUndefined( ev.editor, 'ev.editor (2) is wrong' );
+					assert.isUndefined( ev.data, 'ev.data (2) is wrong' );
+					assert.isUndefined( ev.listenerData, 'ev.listenerData (2) is wrong' );
+
+					calls.push( 'b' );
+				} );
+
+			assert.areSame( false, testInstance.fire( 'someEvent' ) );
+
+			assert.areSame( 2, calls.length, 'number of calls doesn\'t match' );
+			assert.areSame( 'a,b', calls.toString() );
+		},
+
+		test_implementOn : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = { someprop : 'Test' };
+			CKEDITOR.event.implementOn( testObject );
+
+			assert.areSame( 'Test', testObject.someprop );
+
+			var calls = [];
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( testObject, this, 'Scope 1 is not valid' );
+
+					assert.areSame( 'someEvent', ev.name, 'ev.name (1) is wrong' );
+					assert.areSame( testObject, ev.sender, 'ev.sender (1) is wrong' );
+					assert.isUndefined( ev.editor, 'ev.editor (1) is wrong' );
+					assert.isUndefined( ev.data, 'ev.data (1) is wrong' );
+					assert.isUndefined( ev.listenerData, 'ev.listenerData (1) is wrong' );
+
+					calls.push( 'a' );
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( testObject, this, 'Scope 2 is not valid' );
+
+					assert.areSame( 'someEvent', ev.name, 'ev.name (2) is wrong' );
+					assert.areSame( testObject, ev.sender, 'ev.sender (2) is wrong' );
+					assert.isUndefined( ev.editor, 'ev.editor (2) is wrong' );
+					assert.isUndefined( ev.data, 'ev.data (2) is wrong' );
+					assert.isUndefined( ev.listenerData, 'ev.listenerData (2) is wrong' );
+
+					calls.push( 'b' );
+				} );
+
+			assert.areSame( false, testObject.fire( 'someEvent' ) );
+
+			assert.areSame( 2, calls.length, 'number of calls doesn\'t match' );
+			assert.areSame( 'a,b', calls.toString() );
+		},
+
+		test_eventNameCase : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var counter = 0;
+
+			// Event Names are case sensitive.
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'someEvent', ev.name, 'ev.name (someEvent) is wrong' );
+					counter++;
+				} );
+
+			testObject.on( 'SomeEvent', function( ev )
+				{
+					assert.areSame( 'SomeEvent', ev.name, 'ev.name (SomeEvent) is wrong' );
+					counter++;
+				} );
+
+			testObject.fire( 'someEvent' );
+			assert.areSame( 1, counter, '"someEvent" calls doesn\'t match' );
+
+			counter = 0;
+
+			testObject.fire( 'SomeEvent' );
+			assert.areSame( 1, counter, '"SomeEvent" calls doesn\'t match' );
+		},
+
+		test_scope : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			// Counter used just to check that the calls are effectively done.
+			var counter = 0;
+
+			var testScope = {};
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( testObject, this, 'scope (testObject) is wrong' );
+					assert.areSame( testObject, ev.sender, 'sender (testObject) is wrong' );
+					counter++;
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( testScope, this, 'scope (testScope) is wrong' );
+					assert.areSame( testObject, ev.sender, 'sender (testScope) is wrong' );
+					counter++;
+				}, testScope );
+
+			testObject.fire( 'someEvent' );
+
+			assert.areSame( 2, counter, 'wrong number of calls' );
+		},
+
+		test_listenerData : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			// Counter used just to check that the calls are effectively done.
+			var counter = 0;
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'Test1', ev.listenerData, 'listenerData (1) is wrong' );
+					counter++;
+				}, null, 'Test1'  );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'Test2', ev.listenerData, 'listenerData (2) is wrong' );
+					counter++;
+				}, null, 'Test2' );
+
+			testObject.fire( 'someEvent' );
+
+			assert.areSame( 2, counter, 'wrong number of calls' );
+		},
+
+		test_data : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			// Counter used just to check that the calls are effectively done.
+			var counter = 0;
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'Test data', ev.data, 'data (1) is wrong' );
+					counter++;
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'Test data', ev.data, 'data (2) is wrong' );
+					counter++;
+				} );
+
+			testObject.fire( 'someEvent', 'Test data' );
+
+			assert.areSame( 2, counter, 'wrong number of calls' );
+		},
+
+		test_editor : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			// Counter used just to check that the calls are effectively done.
+			var counter = 0;
+
+			var editor = {};
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( editor, ev.editor, 'editor is wrong' );
+					counter++;
+				} );
+
+			testObject.fire( 'someEvent', null, editor );
+
+			assert.areSame( 1, counter, 'wrong number of calls' );
+		},
+
+		test_stop : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var counter = 0;
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					ev.stop();
+					counter++;
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					counter++;
+				} );
+
+			assert.areSame( false, testObject.fire( 'someEvent' ), 'fire must return "false"' );
+			assert.areSame( 1, counter, 'number of calls doesn\'t match' );
+		},
+
+		test_cancel : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var counter = 0;
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					ev.cancel();
+					counter++;
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					counter++;
+				} );
+
+			assert.areSame( true, testObject.fire( 'someEvent' ), 'fire must return "true"' );
+			assert.areSame( 1, counter, 'number of calls doesn\'t match' );
+		},
+
+		test_dataManipulation : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var counter = 0;
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'Test1', ev.data );
+					ev.data = 'Test2';
+					counter++;
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'Test2', ev.data );
+					ev.data = 'Test3';
+					counter++;
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					assert.areSame( 'Test3', ev.data );
+					ev.data = 'Test4';
+					counter++;
+				} );
+
+			assert.areSame( 'Test4', testObject.fire( 'someEvent', 'Test1' ), 'fire must return "Test4"' );
+			assert.areSame( 3, counter, 'number of calls doesn\'t match' );
+		},
+
+		test_priority : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var calls = [];
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					calls.push( 'e' );
+				}, null, null, 11 );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					calls.push( 'c' );
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					calls.push( 'a' );
+				}, null, null, 9 );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					calls.push( 'f' );
+				}, null, null, 11 );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					calls.push( 'd' );
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					calls.push( 'b' );
+				}, null, null, 9 );
+
+			testObject.fire( 'someEvent', 'Test data' );
+			assert.areSame( 'a,b,c,d,e,f', calls.toString() );
+		},
+
+		test_removeListener : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var calls = [];
+
+			var listener = function( ev )
+				{
+					calls.push( 'a' );
+				};
+
+			testObject.on( 'someEvent', listener );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					calls.push( 'b' );
+				} );
+
+			testObject.fire( 'someEvent', 'Test data' );
+			assert.areSame( 'a,b', calls.toString() );
+
+			testObject.removeListener( 'someEvent', listener );
+
+			calls = [];
+
+			testObject.fire( 'someEvent', 'Test data' );
+			assert.areSame( 'b', calls.toString() );
+		},
+
+		test_fireOnce : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var counter = 0;
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					counter++;
+				} );
+
+			testObject.on( 'someEvent', function( ev )
+				{
+					counter++;
+				} );
+
+			assert.areSame( false, testObject.fireOnce( 'someEvent' ), 'fireOnce must return "false"' );
+			assert.areSame( 2, counter, 'number of calls doesn\'t match' );
+
+			counter = 0;
+
+			assert.areSame( false, testObject.fire( 'someEvent' ), 'fire must return "false"' );
+			assert.areSame( 0, counter, 'number of calls doesn\'t match' );
+		},
+
+		test_nestedCancel : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var isCanceledA,
+				isCanceledB,
+				isCanceledC;
+
+			testObject.on( 'A', function( ev )
+				{
+					isCanceledB = testObject.fire( 'B' );
+					isCanceledC = testObject.fire( 'C' );
+				});
+
+			testObject.on( 'B', function( ev )
+				{
+					ev.cancel();
+				});
+
+			testObject.on( 'C', function( ev )
+				{
+				});
+
+			isCanceledA = testObject.fire( 'A' );
+
+			assert.areSame( false, isCanceledA, 'event A must not be canceled' );
+			assert.areSame( true, isCanceledB, 'event B must be canceled' );
+			assert.areSame( false, isCanceledC, 'event C must not be canceled' );
+		},
+
+		test_event_removeListener : function()
+		{
+			// Create a testObject and implement CKEDITOR.event on it.
+			var testObject = {};
+			CKEDITOR.event.implementOn( testObject );
+
+			var counter = 0;
+
+			// Add two listeners for the same event "A".
+
+			testObject.on( 'A', function( ev )
+				{
+					counter++;
+					ev.removeListener();
+				});
+
+			testObject.on( 'A', function( ev )
+				{
+					counter++;
+				});
+
+			// Fire the event twice.
+			testObject.fire( 'A' );
+			testObject.fire( 'A' );
+
+			assert.areSame( 3, counter );
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/htmlparser/fragment.html
===================================================================
--- /CKEditor/branches/tests/editor/core/htmlparser/fragment.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/htmlparser/fragment.html	(revision 4087)
@@ -0,0 +1,186 @@
+﻿<!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.htmlParser.fragment</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+var tc;
+
+CKEDITOR.test.addTestCase( tc = (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	function testParser( input, expected )
+	{
+		var fragment = CKEDITOR.htmlParser.fragment.fromHtml( input, 'p' ),
+			writer = new CKEDITOR.htmlParser.basicWriter();
+
+		fragment.writeHtml( writer );
+
+		assert.areSame( expected, writer.getHtml( true ) );
+	}
+
+	return {
+		test_fromHtml_1 : function()
+		{
+			var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<p>Test</p>' );
+
+			assert.areSame( 1, fragment.children.length, 'Wrong size' );
+			assert.areSame( CKEDITOR.NODE_ELEMENT, fragment.children[0].type, 'Wrong child type' );
+			assert.areSame( 'p', fragment.children[0].name, 'Wrong child name' );
+		},
+
+		test_parser_1 : function()
+		{
+			testParser(	'<table><tr><td>1</td><p><b>2</b> Test</p><td>3</td></tr></table>',
+						'<p><b>2</b> Test</p><table><tr><td>1</td><td>3</td></tr></table>' );
+		},
+
+		test_parser_2 : function()
+		{
+			testParser(	'<b><table><tr><td>1</td><td>2</td></tr></table></b>',
+						'<table><tr><td><b>1</b></td><td><b>2</b></td></tr></table>' );
+		},
+
+		test_parser_3_1 : function()
+		{
+			testParser(	'<b><i>Table:<table><tr><td>1</td><td>2</td></tr></table></i></b>',
+						'<p><b><i>Table:</i></b></p><table><tr><td><b><i>1</i></b></td><td><b><i>2</i></b></td></tr></table>' );
+		},
+
+		test_parser_3_2 : function()
+		{
+			testParser(	'<b><i><table><tr><td>1</td><td>2</td></tr></table>Table</i></b>',
+						'<table><tr><td><b><i>1</i></b></td><td><b><i>2</i></b></td></tr></table><p><b><i>Table</i></b></p>' );
+		},
+
+		test_parser_4 : function()
+		{
+			testParser(	'<b><i>Test',
+						'<p><b><i>Test</i></b></p>' );
+		},
+
+		test_parser_5 : function()
+		{
+			testParser(	'<p>Para 1<p>Para 2<p>Para 3',
+						'<p>Para 1</p><p>Para 2</p><p>Para 3</p>' );
+		},
+
+		test_parser_6 : function()
+		{
+			testParser(	'<b>A</b><i>B</i>',
+						'<p><b>A</b><i>B</i></p>' );
+		},
+
+		test_parser_7 : function()
+		{
+			testParser(	'<p>Para 1<hr>Para 2<h1>Para 3',
+						'<p>Para 1</p><hr /><p>Para 2</p><h1>Para 3</h1>' );
+		},
+
+		/**
+		 * Test remove empty inline element.
+		 */
+		test_parser_8 : function()
+		{
+			testParser(	'<p><b></b>text</p>',
+						'<p>text</p>' );
+		},
+
+		/**
+		 *  Test remove multiple empty inline elements.
+		 */
+		test_parser_8_2 : function()
+		{
+			testParser(	'<p><b><i></b></i>text</p>',
+						'<p>text</p>' );
+		},
+
+		/**
+		 * Test fixing malformed inline element closing.
+		 */
+		test_parser_9 : function()
+		{
+			testParser(	'<p><b>bold<i>ita</b>lic</i></p>',
+						'<p><b>bold<i>ita</i></b><i>lic</i></p>' );
+		},
+
+		test_ticket_10 : function()
+		{
+			testParser(	'<table><tbody><tr><td>A<b></b></td></tr></tbody></table>',
+						'<table><tbody><tr><td>A</td></tr></tbody></table>' );
+		},
+
+		/**
+		 *  Test fixing paragraph inside table row.
+		 */
+		test_ticket_3195 : function()
+		{
+			testParser(	'<table><tr><td>1</td><p>2</p><td>3</td></tr></table>',
+						'<p>2</p><table><tr><td>1</td><td>3</td></tr></table>' );
+		},
+
+		/**
+		 *  Test fixing paragraph inside list.
+		 */
+		test_ticket_3195_2 : function()
+		{
+			testParser(	'<ul><li>1</li><p>2</p><li>3</li></ul>',
+						'<p>2</p><ul><li>1</li><li>3</li></ul>' );
+		},
+
+		/**
+		 *  Test fixing 'div' inside paragraph.
+		 */
+		test_ticket_3195_3 : function()
+		{
+			testParser(	'<p>1<div>2</div><span>3</span></p>',
+						'<p>1</p><div>2</div><p><span>3</span></p>' );
+		},
+
+		test_ticket_3441 : function()
+		{
+			testParser(	'<p><b>Test</b></p><script type="test">var a = "<A Href=xxx>Testing</ A>";\nGo();<\/script>',
+						'<p><b>Test</b></p><script type="test">var a = "<A Href=xxx>Testing</ A>";\nGo();<\/script>' );
+		},
+
+		test_ticket_3585 : function()
+		{
+			testParser(	'<p><br />\t\r\n</p>',
+						'<p><br /></p>' );
+		},
+
+		test_ticket_3585_1 : function()
+		{
+			testParser(	'<p><br />text\t\r\n</p>',
+						'<p><br />text</p>' );
+		},
+
+		test_ticket_3585_2 : function()
+		{
+			testParser(	'<b>inline </b>\n<p>paragraph\t\r\n</p>\t\r\n',
+						'<p><b>inline </b></p><p>paragraph</p>' );
+		},
+
+		test_ticket_3744 : function()
+		{
+			testParser(	'<div><b><font><span>A</font></span></b></div><div>X</div>',
+						'<div><b><font><span>A</span></font></b></div><div>X</div>' );
+		},
+
+		name : document.title
+	};
+})() );
+
+// Uncomment the following to run a single test.
+// window.onload = tc.test_ticket_3585_2;
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/htmlparser/htmlparser.html
===================================================================
--- /CKEditor/branches/tests/editor/core/htmlparser/htmlparser.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/htmlparser/htmlparser.html	(revision 4087)
@@ -0,0 +1,89 @@
+<!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.htmlParser</title>
+	<script type="text/javascript" src="../../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.plugins.load( 'htmlwriter' );
+var tc;
+CKEDITOR.test.addTestCase( tc = ( function()
+{
+	// Local reference to the "assert" object.
+	var assert = YAHOO.util.Assert;
+
+	/**
+	 * Wrapper of the combination of htmlParser with htmlWriter, for convenience of
+	 * testing, formatting of writer has been disabled.
+	 */
+	function htmlParse( htmlString , writerConfig)
+	{
+		var writer = new CKEDITOR.htmlParser.basicWriter();
+		writer.reset();
+		var fragment = CKEDITOR.htmlParser.fragment.fromHtml( htmlString );
+		fragment.writeHtml( writer );
+		return writer.getHtml();
+	}
+
+	/**
+	 * IE always returning CRLF for line-feed, so remove it when retrieving
+	 * pre-formated text from text area.
+	 */
+	function getTextAreaValue( id )
+	{
+		return CKEDITOR.document.getById( id ).getValue().replace( /\r/gi, '' );
+	}
+
+	return {
+		/**
+		 * Test <pre> tag formatting.
+		 */
+		test_fromHtml_3715 : function()
+		{
+			assert.areSame( getTextAreaValue( 'htmlResult1' ),
+				htmlParse( getTextAreaValue( 'htmlOriginal1' ) ),
+				'<pre> parsing result doesn\'t match.' );
+		},
+
+		/**
+		 * Test compress empty spaces within text.
+		 */
+		test_fromHtml_3715_2 : function()
+		{
+			assert.areSame( getTextAreaValue( 'htmlResult2' ),
+				htmlParse( getTextAreaValue( 'htmlOriginal2' ) ),
+				'Spaces compressing result doesn\'t match.' );
+		},
+		name :document.title
+	};
+} )() );
+
+//window.onload = tc.test_fromHtml_3715;
+	//]]>
+	</script>
+</head>
+<body>
+
+	<textarea id="htmlOriginal1"><pre>
+	text<b>
+inside<br /><br /></b>
+
+pre
+</pre></textarea>
+	<textarea id="htmlResult1"><pre>
+	text<b>
+inside
+
+</b>
+
+pre
+</pre></textarea>
+
+<textarea id="htmlOriginal2"><p>
+	para		graph
+</p><b>compress   spaces</b></textarea>
+
+<textarea id="htmlResult2"><p>para graph</p><b>compress spaces</b></textarea>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/plugins.html
===================================================================
--- /CKEditor/branches/tests/editor/core/plugins.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/plugins.html	(revision 4087)
@@ -0,0 +1,42 @@
+<!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.plugins</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+
+		/**
+		 * Test loading self defined external plugin file paths.
+		 */
+		test_addExternal : function()
+		{
+			CKEDITOR.plugins.addExternal( 'myplugin',
+			CKTester.cell.getAbsolutePath( 'plugins/myplugins/sample/' ), 'my_plugin.js' );
+
+			CKEDITOR.plugins.load( 'myplugin', function(){
+				this.resume( function(){
+
+					assert.isTrue( CKEDITOR.plugins.get( 'myplugin' ).definition );
+				} );
+			}, this );
+			this.wait();
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/plugins/myplugins/sample/my_plugin.js
===================================================================
--- /CKEditor/branches/tests/editor/core/plugins/myplugins/sample/my_plugin.js	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/plugins/myplugins/sample/my_plugin.js	(revision 4087)
@@ -0,0 +1,3 @@
+CKEDITOR.plugins.add( 'myplugin' , {
+	definition :  true
+} );
Index: /CKEditor/branches/tests/editor/core/scriptloader.html
===================================================================
--- /CKEditor/branches/tests/editor/core/scriptloader.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/scriptloader.html	(revision 4087)
@@ -0,0 +1,50 @@
+﻿<!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.scriptLoader</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_loadCode : function()
+		{
+			CKEDITOR.scriptLoader.loadCode( 'var test="Testing!";' );
+
+			/*jsl:ignore*/
+			assert.areEqual( 'Testing!', test );
+			/*jsl:end*/
+		},
+
+		test_load : function()
+		{
+			var testCase = this;
+			var callback = function( data )
+			{
+				testCase.resume( function()
+					{
+						/*jsl:ignore*/
+						assert.areSame( 'Test!', testVar );
+						/*jsl:end*/
+					} );
+			};
+
+			CKEDITOR.scriptLoader.load( '../_assets/sample.js', callback );
+			this.wait();
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/tools.html
===================================================================
--- /CKEditor/branches/tests/editor/core/tools.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/tools.html	(revision 4087)
@@ -0,0 +1,168 @@
+<!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.tools</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+var testcase;
+CKEDITOR.test.addTestCase( testcase = (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_extend : function()
+		{
+			var fakeFn = function() {};
+			var fakeObj = { fake1 : 1, fake2 : 2 };
+			var fakeArray = [ 'Test', 10, fakeFn, fakeObj ];
+
+			var target =
+			{
+				prop1 : 'Test',
+				prop2 : 10,
+				prop3 : fakeFn,
+				prop4 : fakeObj,
+				prop5 : fakeArray
+			};
+
+			CKEDITOR.tools.extend( target,
+				{
+					prop3 : 'Wrong',
+					prop6 : 'Good',
+					prop7 : fakeArray
+				} );
+
+			assert.areSame( 'Test'		, target.prop1, 'prop1 doesn\'t match' );
+			assert.areSame( 10			, target.prop2, 'prop2 doesn\'t match' );
+			assert.areSame( fakeFn		, target.prop3, 'prop3 doesn\'t match' );
+			assert.areSame( fakeObj		, target.prop4, 'prop4 doesn\'t match' );
+			assert.areSame( fakeArray	, target.prop5, 'prop5 doesn\'t match' );
+			assert.areSame( 'Good'		, target.prop6, 'prop6 doesn\'t match' );
+			assert.areSame( fakeArray	, target.prop7, 'prop7 doesn\'t match' );
+		},
+
+		test_isArray1 : function()
+		{
+			assert.isTrue( CKEDITOR.tools.isArray( [] ) );
+		},
+
+		test_isArray2 : function()
+		{
+			assert.isFalse( CKEDITOR.tools.isArray( { length:1 } ) );
+		},
+
+		test_isArray3 : function()
+		{
+			assert.isFalse( CKEDITOR.tools.isArray( null ) );
+		},
+
+		test_isArray4 : function()
+		{
+			assert.isFalse( CKEDITOR.tools.isArray( window.x ) );
+		},
+
+		test_htmlEncode1 : function()
+		{
+			assert.areSame( '&lt;b&gt;Test&lt;/b&gt;', CKEDITOR.tools.htmlEncode( '<b>Test</b>' ) );
+		},
+
+		test_htmlEncode2 : function()
+		{
+			assert.areSame( 'Test\'s &amp; "quote"', CKEDITOR.tools.htmlEncode( 'Test\'s & "quote"' ) );
+		},
+
+		test_htmlEncode_3874 : function()
+		{
+			assert.areSame( 'line1\nline2', CKEDITOR.tools.htmlEncode( 'line1\nline2' ) );
+		},
+
+		test_cssStyleToDomStyle1 : function()
+		{
+			assert.areSame( 'backgroundColor', CKEDITOR.tools.cssStyleToDomStyle( 'background-color' ) );
+		},
+
+		test_cssStyleToDomStyle2 : function()
+		{
+			assert.areSame( 'cssFloat', CKEDITOR.tools.cssStyleToDomStyle( 'float' ) );
+		},
+
+		test_getNextNumber : function()
+		{
+			var number = CKEDITOR.tools.getNextNumber();
+			assert.areSame( number +  1, CKEDITOR.tools.getNextNumber() );
+			assert.areSame( number +  2, CKEDITOR.tools.getNextNumber() );
+			assert.areSame( number +  3, CKEDITOR.tools.getNextNumber() );
+		},
+
+		test_trim1 : function()
+		{
+			assert.areSame( 'test', CKEDITOR.tools.trim( '    test   ' ) );
+		},
+
+		test_trim2 : function()
+		{
+			assert.areSame( 'test', CKEDITOR.tools.trim( ' \n \t  test\n  \t ' ) );
+		},
+
+		test_ltrim1 : function()
+		{
+			assert.areSame( 'test   ', CKEDITOR.tools.ltrim( '    test   ' ) );
+		},
+
+		test_ltrim2 : function()
+		{
+			assert.areSame( 'test\n  \t ', CKEDITOR.tools.ltrim( ' \n \t  test\n  \t ' ) );
+		},
+
+		test_rtrim1 : function()
+		{
+			assert.areSame( '    test', CKEDITOR.tools.rtrim( '    test   ' ) );
+		},
+
+		test_rtrim2 : function()
+		{
+			assert.areSame( ' \n \t  test', CKEDITOR.tools.rtrim( ' \n \t  test\n  \t ' ) );
+		},
+
+		test_clone : function()
+		{
+			var obj =
+			{
+				name : 'John',
+				cars :
+				{
+					Mercedes : { color : 'blue' },
+					Porsche : { color : 'red' }
+				}
+			};
+
+			var clone = CKEDITOR.tools.clone( obj );
+
+			clone.name = 'Paul';
+			clone.cars.Porsche.color = 'silver';
+
+			assert.areSame( 'John', obj.name );
+			assert.areSame( 'Paul', clone.name );
+
+			assert.areSame( 'red', obj.cars.Porsche.color );
+			assert.areSame( 'silver', clone.cars.Porsche.color );
+		},
+
+		test_repeat : function()
+		{
+			assert.areSame( '&nbsp;&nbsp;&nbsp;', CKEDITOR.tools.repeat( '&nbsp;', 3 ) );
+		},
+
+		name : document.title
+	};
+})() );
+//window.onload = testcase.test_htmlEncode_3874;
+	//]]>
+	</script>
+</head>
+<body>
+	<iframe></iframe>
+</body>
+</html>
Index: /CKEditor/branches/tests/editor/core/xml.html
===================================================================
--- /CKEditor/branches/tests/editor/core/xml.html	(revision 4087)
+++ /CKEditor/branches/tests/editor/core/xml.html	(revision 4087)
@@ -0,0 +1,147 @@
+<!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.xml</title>
+	<script type="text/javascript" src="../../cktester/cell.js"></script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.loader.load( 'core/xml' );
+
+	//]]>
+	</script>
+	<script type="text/javascript">
+	//<![CDATA[
+
+CKEDITOR.test.addTestCase( (function()
+{
+	// Local reference to the "assert" object.
+	var assert = CKEDITOR.test.assert;
+
+	return {
+		test_baseXml : function()
+		{
+			var xml = new CKEDITOR.xml( '<data />' );
+			assert.isObject( xml.baseXml );
+		},
+
+		test_selectSingleNode1a : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item /></data>' );
+			var node = xml.selectSingleNode( 'data/item' );
+			assert.areEqual( 'item', node.nodeName );
+		},
+
+		test_selectSingleNode1b : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item /></data>' );
+			var node = xml.selectSingleNode( 'item' );
+			assert.isNull( node );
+		},
+
+		test_selectSingleNode2a : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item><subitem/></item></data>' );
+			var contextNode = xml.selectSingleNode( 'data' );
+			var node = xml.selectSingleNode( 'item/subitem', contextNode );
+			assert.areEqual( 'subitem', node.nodeName );
+		},
+
+		test_selectSingleNode2b : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item><subitem/></item></data>' );
+			var contextNode = xml.selectSingleNode( 'data' );
+			var node = xml.selectSingleNode( 'subitem', contextNode );
+			assert.isNull( node );
+		},
+
+		test_selectSingleNode3 : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item id="x1"/><item id="x2"/></data>' );
+			var node = xml.selectSingleNode( '//item[@id="x2"]' );
+			assert.areEqual( 'item', node.nodeName );
+			assert.areEqual( 'x2', node.getAttribute( 'id' ) );
+		},
+
+		test_selectSingleNode4 : function()
+		{
+			// For may results, the first one must be returned.
+
+			var xml = new CKEDITOR.xml( '<data><item id="x1"/><item id="x2"/></data>' );
+			var node = xml.selectSingleNode( '//item' );
+			assert.areEqual( 'item', node.nodeName );
+			assert.areEqual( 'x1', node.getAttribute( 'id' ) );
+		},
+
+		test_selectNodes1 : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item /></data>' );
+			var nodes = xml.selectNodes( 'data/item' );
+			assert.areEqual( 1, nodes.length );
+			assert.areEqual( 'item', nodes[0].nodeName );
+		},
+
+		test_selectNodes2a : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item id="x1"/><item id="x2"/><item id="x3"/></data>' );
+			var nodes = xml.selectNodes( '//item' );
+			assert.areEqual( 3, nodes.length );
+			assert.areEqual( 'x1', nodes[0].getAttribute( 'id' ) );
+			assert.areEqual( 'x2', nodes[1].getAttribute( 'id' ) );
+			assert.areEqual( 'x3', nodes[2].getAttribute( 'id' ) );
+		},
+
+		test_selectNodes2b : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item id="x1"/><item id="x2"/><item id="x3"/></data>' );
+			var nodes = xml.selectNodes( '//itemX' );
+			assert.areEqual( 0, nodes.length );
+		},
+
+		test_selectNodes3a : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item id="x1"/><item id="x2"/><item id="x3"/></data>' );
+			var contextNode = xml.selectSingleNode( 'data' );
+			var nodes = xml.selectNodes( 'item', contextNode );
+			assert.areEqual( 3, nodes.length );
+			assert.areEqual( 'x1', nodes[0].getAttribute( 'id' ) );
+			assert.areEqual( 'x2', nodes[1].getAttribute( 'id' ) );
+			assert.areEqual( 'x3', nodes[2].getAttribute( 'id' ) );
+		},
+
+		test_selectNodes3b : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item id="x1"/><item id="x2"/><item id="x3"/></data>' );
+			var contextNode = xml.selectSingleNode( 'data' );
+			var nodes = xml.selectNodes( 'itemX', contextNode );
+			assert.areEqual( 0, nodes.length );
+		},
+
+		test_getInnerXml1 : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item/></data>' );
+			assert.areEqual( '<item/>', xml.getInnerXml( 'data' ) );
+		},
+
+		test_getInnerXml2 : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item id="x1"><subitem name="sub1"/></item></data>' );
+			assert.areEqual( '<subitem name="sub1"/>', xml.getInnerXml( '//item' ) );
+		},
+
+		test_getInnerXml3 : function()
+		{
+			var xml = new CKEDITOR.xml( '<data><item id="x1"/></data>' );
+			assert.isNull( xml.getInnerXml( '//itemX' ) );
+		},
+
+		name : document.title
+	};
+})() );
+
+	//]]>
+	</script>
+</head>
+<body>
+</body>
+</html>
Index: /CKEditor/branches/tests/index.html
===================================================================
--- /CKEditor/branches/tests/index.html	(revision 4087)
+++ /CKEditor/branches/tests/index.html	(revision 4087)
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+		"http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+	<title>Index Page - CKEditor Tests</title>
+</head>
+<body>
+<h1>Test Runner Links</h1>
+<ul>
+	<li><a href="cktester/forge.html?profile=../profile.js&cells=editor">All tests of CKEditor</a></li>
+	<li><a href="cktester/forge.html?profile=../profile.js&cells=tt">All ticket tests of CKEditor</a></li>
+</ul>
+</body>
+</html>
Index: /CKEditor/branches/tests/profile.js
===================================================================
--- /CKEditor/branches/tests/profile.js	(revision 4087)
+++ /CKEditor/branches/tests/profile.js	(revision 4087)
@@ -0,0 +1,58 @@
+CKTester.runner.getProfile = function ()
+{
+	// Note : All paths specified below should refer to CKTester project root if they are relative.
+	return {
+		cells : [
+			[ '../editor/core/ajax', [  'unit', 'stable' ] ],
+			[ '../editor/core/bootstrap', [  'unit', 'stable', 'editor-ondemand' ] ],
+			[ '../editor/core/ckeditor', [  'unit', 'stable' ] ],
+			[ '../editor/core/editor', [  'unit', 'stable' ] ],
+			[ '../editor/core/env', [  'unit', 'stable' ] ],
+			[ '../editor/core/event', [  'unit', 'stable' ] ],
+			[ '../editor/core/plugins', [  'unit', 'stable' ] ],
+			[ '../editor/core/scriptloader', [  'unit', 'stable' ] ],
+			[ '../editor/core/tools', [  'unit', 'stable' ] ],
+			[ '../editor/core/xml', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/document', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/documentfragment', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/element', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/node', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/range', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/text', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/walker', [  'unit', 'stable' ] ],
+			[ '../editor/core/dom/window', [  'unit', 'stable' ] ],
+			[ '../editor/core/htmlparser/fragment', [  'unit', 'stable' ] ],
+			[ '../editor/core/htmlparser/htmlparser', [  'unit', 'stable' ] ],
+			[ '../editor/plugins/domiterator/domiterator', [  'unit', 'stable' ] ],
+			[ '../editor/plugins/htmldataprocessor/htmldataprocessor', [  'unit', 'stable' ] ],
+			[ '../editor/plugins/link/link', [  'unit', 'stable' ] ],
+			[ '../editor/plugins/list/list', [  'unit', 'stable' ] ],
+			[ '../editor/plugins/styles/styles', [  'unit', 'stable' ] ],
+			[ '../editor/plugins/selection/selection', [  'unit', 'stable' ] ]
+		],
+
+		variables : 
+		{
+			'CKEDITOR_ROOT' : '../../ckeditor'
+		},
+
+		cellResolvers :
+		[
+			function( cell )
+			{
+				var tags = cell.tags, env = cell.environment;
+
+				// Inject CKEditor source.
+				if( ( tags.indexOf( 'editor' ) != -1 )
+					&& ( tags.indexOf( 'editor-ondemand' ) == -1  ) )
+					env.push( '${CKEDITOR_ROOT}/ckeditor_source.js' );
+				else if ( tags.indexOf( 'editor-ondemand' ) )
+					env.push( '${CKEDITOR_ROOT}/ckeditor_basic_source.js' );
+
+				// Inject CKEditor unit test library.
+				if ( tags.indexOf( 'unit' ) != -1  )
+					env.push( '${CKEDITOR_ROOT}/_source/core/test.js' );
+			}
+		]
+	};
+};
