Browse Source

Added setData method to view test utils.

Szymon Kupś 9 years ago
parent
commit
b7513085af

+ 49 - 1
packages/ckeditor5-engine/tests/_utils-tests/view.js

@@ -5,7 +5,7 @@
 
 
 'use strict';
 'use strict';
 
 
-import { getData } from '/tests/engine/_utils/view.js';
+import { getData, setData } from '/tests/engine/_utils/view.js';
 import DocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
 import DocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
 import Element from '/ckeditor5/engine/treeview/element.js';
 import Element from '/ckeditor5/engine/treeview/element.js';
 import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
@@ -170,4 +170,52 @@ describe( 'view test utils', () => {
 			expect( getData( p, selection ) ).to.equal( '<p>[<b>foobar</b>][]{baz}{q}ux</p>' );
 			expect( getData( p, selection ) ).to.equal( '<p>[<b>foobar</b>][]{baz}{q}ux</p>' );
 		} );
 		} );
 	} );
 	} );
+
+	describe( 'setData', () => {
+		it( 'should parse elements and texts', () => {
+			const view = setData( '<b>foobar</b>' );
+			const element = new Element( 'b' );
+
+			expect( view ).to.be.instanceof( Element );
+			expect( view.isSimilar( element ) ).to.be.true;
+			expect( view.getChildCount() ).to.equal( 1 );
+			const text = view.getChild( 0 );
+			expect( text ).to.be.instanceof( Text );
+			expect( text.data ).to.equal( 'foobar' );
+		} );
+
+		it( 'should parse element attributes', () => {
+			const view = setData( '<b name="foo" title="bar" class="foo bar" style="color:red;"></b>' );
+			const element = new Element( 'b', { name: 'foo', title: 'bar', class: 'foo bar', style: 'color:red;' } );
+
+			expect( view ).to.be.instanceof( Element );
+			expect( view.isSimilar( element ) ).to.be.true;
+			expect( view.getChildCount() ).to.equal( 0 );
+		} );
+
+		it( 'should parse element type', () => {
+			const view1 = setData( '<attribute:b></attribute:b>' );
+			const attribute = new AttributeElement( 'b' );
+			const view2 = setData( '<container:p></container:p>' );
+			const container = new ContainerElement( 'p' );
+
+			expect( view1 ).to.be.instanceof( AttributeElement );
+			expect( view1.isSimilar( attribute ) ).to.be.true;
+			expect( view2 ).to.be.instanceof( ContainerElement );
+			expect( view2.isSimilar( container ) ).to.be.true;
+		} );
+
+		it( 'should parse element priority', () => {
+			const parsed1 = setData( '<b:12></b:12>' );
+			const attribute1 = new AttributeElement( 'b' );
+			attribute1.priority = 12;
+			const parsed2 = setData( '<attribute:b:44></attribute:b:44>' );
+			const attribute2 = new AttributeElement( 'b' );
+			attribute2.priority = 44;
+
+			parsed1.isSimilar( attribute1 );
+			expect( parsed1.isSimilar( attribute1 ) ).to.be.true;
+			expect( parsed2.isSimilar( attribute2 ) ).to.be.true;
+		} );
+	} );
 } );
 } );

+ 161 - 7
packages/ckeditor5-engine/tests/_utils/view.js

@@ -7,11 +7,16 @@
 
 
 /* jshint latedef:false */
 /* jshint latedef:false */
 
 
-import DocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
-import Element from '/ckeditor5/engine/treeview/element.js';
+import ViewDocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+import ViewElement from '/ckeditor5/engine/treeview/element.js';
 import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import AttributeElement from '/ckeditor5/engine/treeview/attributeelement.js';
 import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
 import ContainerElement from '/ckeditor5/engine/treeview/containerelement.js';
-import Text from '/ckeditor5/engine/treeview/text.js';
+import ViewText from '/ckeditor5/engine/treeview/text.js';
+
+const DomDocumentFragment = window.DocumentFragment;
+const DomText = window.Text;
+const DomElement = window.Element;
 
 
 const ELEMENT_RANGE_START_TOKEN = '[';
 const ELEMENT_RANGE_START_TOKEN = '[';
 const ELEMENT_RANGE_END_TOKEN = ']';
 const ELEMENT_RANGE_END_TOKEN = ']';
@@ -19,7 +24,7 @@ const TEXT_RANGE_START_TOKEN = '{';
 const TEXT_RANGE_END_TOKEN = '}';
 const TEXT_RANGE_END_TOKEN = '}';
 
 
 /**
 /**
- * Converts view elements to its string representation.
+ * Converts view elements to its string representation, an HTML-like string.
  * Root element can be provided as {@link engine.treeView.Element Element} or
  * Root element can be provided as {@link engine.treeView.Element Element} or
  * {@link engine.treeView.DocumentFragment DocumentFragment}.
  * {@link engine.treeView.DocumentFragment DocumentFragment}.
  *
  *
@@ -82,6 +87,155 @@ export function getData( root, selection, options ) {
 	return viewStringify.stringify();
 	return viewStringify.stringify();
 }
 }
 
 
+export function setData( data ) {
+	const viewParser = new ViewParser();
+
+	return viewParser.parse( data );
+}
+
+class ViewParser {
+
+	parse( data ) {
+		const htmlProcessor = new HtmlDataProcessor();
+		const domRoot = htmlProcessor.toDom( data );
+
+		return this._walkDom( domRoot );
+	}
+
+	_walkDom( domNode ) {
+		const isDomElement = domNode instanceof DomElement;
+
+		if ( isDomElement || domNode instanceof DomDocumentFragment ) {
+			const children = domNode.childNodes;
+			const length = children.length;
+
+			// If there is only one element inside DOM DocumentFragment - use it as root.
+			if ( !isDomElement && length == 1 ) {
+				return this._walkDom( domNode.childNodes[ 0 ] );
+			}
+
+			let viewElement;
+
+			if ( isDomElement ) {
+				viewElement = this._convertElement( domNode );
+			} else {
+				viewElement = new ViewDocumentFragment();
+			}
+
+			for ( let i = 0; i < children.length; i++ ) {
+				const child = children[ i ];
+				viewElement.appendChildren( this._walkDom( child ) );
+			}
+
+			return viewElement;
+		}
+
+		if ( domNode instanceof DomText ) {
+			return new ViewText( domNode.textContent );
+		}
+	}
+
+	_convertElement( domElement ) {
+		const info = this._convertElementName( domElement );
+		let viewElement;
+
+		if ( info.type == 'attribute' ) {
+			viewElement = new AttributeElement( info.name );
+
+			if ( info.priority !== null ) {
+				viewElement.priority = info.priority;
+			}
+		} else if ( info.type == 'container' ) {
+			viewElement = new ContainerElement( info.name );
+		} else {
+			viewElement = new ViewElement( info.name );
+		}
+
+		const attributes = domElement.attributes;
+		const attributesCount = attributes.length;
+
+		for ( let i = 0; i < attributesCount; i++ ) {
+			const attribute = attributes[ i ];
+			viewElement.setAttribute( attribute.name, attribute.value );
+		}
+
+		return viewElement;
+	}
+
+	_convertElementName( element ) {
+		const parts = element.tagName.toLowerCase().split( ':' );
+
+		if ( parts.length == 1 ) {
+			return {
+				name: parts[ 0 ],
+				type: null,
+				priority: null
+			};
+		}
+
+		if ( parts.length == 2 ) {
+			// Check if type and name: container:div.
+			const type = this._convertType( parts[ 0 ] );
+
+			if ( type ) {
+				return {
+					name: parts[ 1 ],
+					type: type,
+					priority: null
+				};
+			}
+
+			// Check if name and priority: span:10.
+			const priority = this._convertPriority( parts[ 1 ] );
+
+			if ( priority !== null ) {
+				return {
+					name: parts[ 0 ],
+					type: 'attribute',
+					priority: priority
+				};
+			}
+
+			throw new Error( `Cannot parse element's tag name: ${ element.tagName }.` );
+		}
+
+		// Check if name is in format type:name:priority.
+		if ( parts.length === 3 ) {
+			const type = this._convertType( parts[ 0 ] );
+			const priority = this._convertPriority( parts[ 2 ] );
+
+			if ( type && priority !== null ) {
+				return {
+					name: parts[ 1 ],
+					type: type,
+					priority: priority
+				};
+			}
+		}
+
+		throw new Error( `Cannot parse element's tag name: ${ element.tagName }.` );
+	}
+
+	_convertType( type ) {
+		if ( type == 'container' || type == 'attribute' ) {
+			return type;
+		}
+
+		return null;
+	}
+
+	_convertPriority( priorityString ) {
+		const priority = parseInt( priorityString, 10 );
+
+		if ( !isNaN( priority ) ) {
+			return priority;
+		}
+
+		return null;
+	}
+
+}
+
 /**
 /**
  * Private helper class used for converting view tree to string.
  * Private helper class used for converting view tree to string.
  *
  *
@@ -133,9 +287,9 @@ class ViewStringify {
 	 * @param {Function} callback
 	 * @param {Function} callback
 	 */
 	 */
 	_walkView( root, callback ) {
 	_walkView( root, callback ) {
-		const isElement = root instanceof Element;
+		const isElement = root instanceof ViewElement;
 
 
-		if ( isElement || root instanceof DocumentFragment ) {
+		if ( isElement || root instanceof ViewDocumentFragment ) {
 			if ( isElement ) {
 			if ( isElement ) {
 				callback( this._stringifyElementOpen( root ) );
 				callback( this._stringifyElementOpen( root ) );
 			}
 			}
@@ -154,7 +308,7 @@ class ViewStringify {
 			}
 			}
 		}
 		}
 
 
-		if ( root instanceof Text ) {
+		if ( root instanceof ViewText ) {
 			callback( this._stringifyTextRanges( root ) );
 			callback( this._stringifyTextRanges( root ) );
 		}
 		}
 	}
 	}