8
0
Просмотр исходного кода

Removed ViewParser internall class from view test utilities.

Szymon Kupś 9 лет назад
Родитель
Сommit
f095f7e29f
1 измененных файлов с 167 добавлено и 215 удалено
  1. 167 215
      packages/ckeditor5-engine/tests/_utils/view.js

+ 167 - 215
packages/ckeditor5-engine/tests/_utils/view.js

@@ -260,16 +260,28 @@ export function stringify( node, selectionOrPositionOrRange = null, options = {}
  */
 export function parse( data, options = {} ) {
 	options.order = options.order || [];
-	const viewParser = new ViewParser();
 	const rangeParser = new RangeParser();
+	const processor = new HtmlDataProcessor();
 
-	let view = viewParser.parse( data, options.rootElement );
+	// let view = viewParser.parse( data, options.rootElement );
+	let view = processor.toView( data );
 
-	// If single Element or Text is returned - move it to the DocumentFragment.
-	if ( !options.rootElement && ( view instanceof ViewText || view instanceof ViewElement ) ) {
-		view = new ViewDocumentFragment( view );
+	// At this point we have a view tree with Elements that could have names like `attribute:b:1`. In the next step
+	// we need to parse Element's names and convert them to AttributeElements and ContainerElements.
+	view = _convertViewElements( view );
+
+	// If custom root is provided - move all nodes there.
+	if ( options.rootElement ) {
+		const root = options.rootElement;
+		const nodes = view.removeChildren( 0, view.getChildCount() );
+
+		root.removeChildren( 0, root.getChildCount() );
+		root.appendChildren( nodes );
+
+		view = root;
 	}
 
+	// Parse ranges included in the view text nodes.
 	const ranges = rangeParser.parse( view, options.order );
 
 	// If only one element is returned inside DocumentFragment - return that element.
@@ -492,216 +504,6 @@ class RangeParser {
 }
 
 /**
- * Private helper class used to convert given HTML-like string to view tree.
- *
- * @private
- */
-class ViewParser {
-	/**
-	 * Parses HTML-like string to view tree elements.
-	 *
-	 * @param {String} data
-	 * @param {engine.view.Element|engine.view.DocumentFragment} [rootElement=null] Default root to use when parsing elements.
-	 * When set to `null` root element will be created automatically. If set to
-	 * {@link engine.view.Element Element} or {@link engine.view.DocumentFragment DocumentFragment} - this node
-	 * will be used as root for all parsed nodes.
-	 * @returns {engine.view.Node|engine.view.DocumentFragment}
-	 */
-	parse( data, rootElement = null ) {
-		const htmlProcessor = new HtmlDataProcessor();
-
-		// Convert HTML string to DOM.
-		const domRoot = htmlProcessor.toDom( data );
-
-		// If root element is provided - remove all children from it.
-		if ( rootElement ) {
-			rootElement.removeChildren( 0, rootElement.getChildCount() );
-		}
-
-		// Convert DOM to View.
-		return this._walkDom( domRoot, rootElement );
-	}
-
-	/**
-	 * Walks through DOM elements and converts them to tree view elements.
-	 *
-	 * @private
-	 * @param {Node} domNode
-	 * @param {engine.view.Element|engine.view.DocumentFragment} [rootElement=null] Default root element to use
-	 * when parsing elements.
-	 * @returns {engine.view.Node|engine.view.DocumentFragment}
-	 */
-	_walkDom( domNode, rootElement = null ) {
-		const isDomElement = domNode instanceof window.Element;
-
-		if ( isDomElement || domNode instanceof window.DocumentFragment ) {
-			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 ], rootElement );
-			}
-
-			let viewElement;
-
-			if ( isDomElement ) {
-				viewElement = this._convertElement( domNode );
-
-				if ( rootElement ) {
-					rootElement.appendChildren( viewElement );
-				}
-			} else {
-				viewElement = rootElement ? rootElement : new ViewDocumentFragment();
-			}
-
-			for ( let i = 0; i < children.length; i++ ) {
-				const child = children[ i ];
-				viewElement.appendChildren( this._walkDom( child ) );
-			}
-
-			return rootElement ? rootElement : viewElement;
-		}
-
-		return new ViewText( domNode.textContent );
-	}
-
-	/**
-	 * Converts DOM Element to {engine.view.Element view Element}.
-	 *
-	 * @private
-	 * @param {Element} domElement DOM element to convert.
-	 * @returns {engine.view.Element|engine.view.AttributeElement|engine.view.ContainerElement} Tree view
-	 * element converted from DOM element.
-	 */
-	_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;
-	}
-
-	/**
-	 * Converts DOM element tag name to information needed for creating {@link engine.view.Element view Element} instance.
-	 * Name can be provided in couple formats: as a simple element's name (`div`), as a type and name (`container:div`,
-	 * `attribute:span`), as a name and priority (`span:12`) and as a type, priority, name trio (`attribute:span:12`);
-	 *
-	 * @private
-	 * @param {Element} element DOM Element which tag name should be converted.
-	 * @returns {Object} info Object with parsed information.
-	 * @returns {String} info.name Parsed name of the element.
-	 * @returns {String|null} info.type Parsed type of the element, can be `attribute` or `container`.
-	 * @returns {Number|null} info.priority Parsed priority of the element.
-	 */
-	_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( `Parse error - cannot parse element's tag name: ${ element.tagName.toLowerCase() }.` );
-		}
-
-		// 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( `Parse error - cannot parse element's tag name: ${ element.tagName.toLowerCase() }.` );
-	}
-
-	/**
-	 * Checks if element's type is allowed. Returns `attribute`, `container` or `null`.
-	 *
-	 * @private
-	 * @param {String} type
-	 * @returns {String|null}
-	 */
-	_convertType( type ) {
-		if ( type == 'container' || type == 'attribute' ) {
-			return type;
-		}
-
-		return null;
-	}
-
-	/**
-	 * Checks if given priority is allowed. Returns null if priority cannot be converted.
-	 *
-	 * @private
-	 * @param {String} priorityString
-	 * @returns {Number|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
@@ -956,3 +758,153 @@ class ViewStringify {
 		return attributes.join( ' ' );
 	}
 }
+
+// Converts {@link engine.view.Element Elements} to {@link engine.view.AttributeElement AttributeElements} and
+// {@link engine.view.ContainerElement ContainerElements}. It converts all tree starting from the `rootNode`.
+// Conversion is based on element names. See `_convertElement` method for more details.
+//
+// @param {engine.view.Element|engine.view.DocumentFragment|engine.view.Text} rootNode Root node to convert.
+// @returns {engine.view.Element|engine.view.DocumentFragment|engine.view.Text|engine.view.AttributeElement|
+// engine.view.ContainerElement} Root node of converted elements.
+function _convertViewElements( rootNode ) {
+	const isFragment = rootNode instanceof ViewDocumentFragment;
+
+	if ( rootNode instanceof ViewElement || isFragment ) {
+		// Convert element or leave document fragment.
+		const convertedElement = isFragment ? new ViewDocumentFragment() : _convertElement( rootNode );
+
+		// Convert all child nodes.
+		for ( let child of rootNode.getChildren() ) {
+			convertedElement.appendChildren( _convertViewElements( child ) );
+		}
+
+		return convertedElement;
+	}
+
+	return rootNode;
+}
+
+// Converts {@link engine.view.Element Element} to {@link engine.view.AttributeElement AttributeElement} or
+// {@link engine.view.ContainerElement ContainerElement}.
+// If element's name is in format `attribute:b:1` or `b:11` it will be converted to
+// {@link engine.view.AttributeElement AttributeElement} with priority 11.
+// If element's name is in format `container:p` - it will be converted to
+// {@link engine.view.ContainerElement ContainerElement}.
+// If element's name will not contain any information - {@link engine.view.Element view Element} will be returned.
+//
+// @param {engine.view.Element} viewElement View element to convert.
+// @returns {engine.view.Element|engine.view.AttributeElement|engine.view.ContainerElement} Tree view
+// element converted according to it's name.
+function _convertElement( viewElement ) {
+	const info = _convertElementName( viewElement );
+	let newElement;
+
+	if ( info.type == 'attribute' ) {
+		newElement = new AttributeElement( info.name );
+
+		if ( info.priority !== null ) {
+			newElement.priority = info.priority;
+		}
+	} else if ( info.type == 'container' ) {
+		newElement = new ContainerElement( info.name );
+	} else {
+		newElement = new ViewElement( info.name );
+	}
+
+	// Move attributes.
+	for ( let attributeKey of viewElement.getAttributeKeys() ) {
+		newElement.setAttribute( attributeKey, viewElement.getAttribute( attributeKey ) );
+	}
+
+	return newElement;
+}
+
+// Converts {@link engine.view.Element#name Element's name} information needed for creating
+// {@link engine.view.AttributeElement AttributeElement} or {@link engine.view.ContainerElement ContainerElement} instance.
+// Name can be provided in couple formats: as a simple element's name (`div`), as a type and name (`container:div`,
+// `attribute:span`), as a name and priority (`span:12`) and as a type, priority, name trio (`attribute:span:12`);
+//
+// @param {engine.view.Element} element Element which name should be converted.
+// @returns {Object} info Object with parsed information.
+// @returns {String} info.name Parsed name of the element.
+// @returns {String|null} info.type Parsed type of the element, can be `attribute` or `container`.
+// returns {Number|null} info.priority Parsed priority of the element.
+function _convertElementName( viewElement ) {
+	const parts = viewElement.name.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 = _convertType( parts[ 0 ] );
+
+		if ( type ) {
+			return {
+				name: parts[ 1 ],
+				type: type,
+				priority: null
+			};
+		}
+
+		// Check if name and priority: span:10.
+		const priority = _convertPriority( parts[ 1 ] );
+
+		if ( priority !== null ) {
+			return {
+				name: parts[ 0 ],
+				type: 'attribute',
+				priority: priority
+			};
+		}
+
+		throw new Error( `Parse error - cannot parse element's name: ${ viewElement.name }.` );
+	}
+
+	// Check if name is in format type:name:priority.
+	if ( parts.length === 3 ) {
+		const type = _convertType( parts[ 0 ] );
+		const priority = _convertPriority( parts[ 2 ] );
+
+		if ( type && priority !== null ) {
+			return {
+				name: parts[ 1 ],
+				type: type,
+				priority: priority
+			};
+		}
+	}
+
+	throw new Error( `Parse error - cannot parse element's tag name: ${ viewElement.name }.` );
+}
+
+// Checks if element's type is allowed. Returns `attribute`, `container` or `null`.
+//
+// @param {String} type
+// @returns {String|null}
+function _convertType( type ) {
+	if ( type == 'container' || type == 'attribute' ) {
+		return type;
+	}
+
+	return null;
+}
+
+// Checks if given priority is allowed. Returns null if priority cannot be converted.
+//
+// @param {String} priorityString
+// returns {Number|Null}
+function _convertPriority( priorityString ) {
+	const priority = parseInt( priorityString, 10 );
+
+	if ( !isNaN( priority ) ) {
+		return priority;
+	}
+
+	return null;
+}