Explorar el Código

Simplified DOM to View conversion and spacing normalization.

Krzysztof Krztoń hace 7 años
padre
commit
450247a7ee
Se han modificado 1 ficheros con 60 adiciones y 21 borrados
  1. 60 21
      packages/ckeditor5-paste-from-office/src/filters/utils.js

+ 60 - 21
packages/ckeditor5-paste-from-office/src/filters/utils.js

@@ -9,11 +9,17 @@
 
 /* globals DOMParser */
 
+import ViewText from '@ckeditor/ckeditor5-engine/src/view/text';
+import ViewElement from '@ckeditor/ckeditor5-engine/src/view/element';
+import ViewDocumentFragment from '@ckeditor/ckeditor5-engine/src/view/documentfragment';
 import DomConverter from '@ckeditor/ckeditor5-engine/src/view/domconverter';
+import UpcastWriter from '@ckeditor/ckeditor5-engine/src/view/upcastwriter';
 import { NBSP_FILLER } from '@ckeditor/ckeditor5-engine/src/view/filler';
+import isText from '@ckeditor/ckeditor5-utils/src/dom/istext';
 
 const domParser = new DOMParser();
 const domConverter = new DomConverter( { blockFiller: NBSP_FILLER } );
+const upcastWriter = new UpcastWriter();
 
 /**
  * Parses provided HTML extracting contents of `body` and `style` tags.
@@ -29,9 +35,7 @@ const domConverter = new DomConverter( { blockFiller: NBSP_FILLER } );
  */
 export function parseHtml( htmlString ) {
 	// Parse htmlString as native Document object.
-	const htmlDocument = domParser.parseFromString( normalizeEndTagsPrecedingSpace( htmlString ), 'text/html' );
-
-	normalizeSpacerunSpans( htmlDocument );
+	const htmlDocument = domParser.parseFromString( htmlString, 'text/html' );
 
 	// Get `innerHTML` first as transforming to View modifies the source document.
 	const bodyString = htmlDocument.body.innerHTML;
@@ -62,7 +66,7 @@ function documentToView( htmlDocument ) {
 		fragment.appendChild( nodes[ 0 ] );
 	}
 
-	return domConverter.domToView( fragment );
+	return domToView( fragment );
 }
 
 // Extracts both `CSSStyleSheet` and string representation from all `style` elements available in a provided `htmlDocument`.
@@ -89,25 +93,60 @@ function extractStyles( htmlDocument ) {
 	};
 }
 
-// Replaces last space preceding elements closing tag with ` `. Such operation prevents spaces from being removed
-// during further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).
-// This method also takes into account Word specific `<o:p></o:p>` empty tags.
+// Converts given DOM structure to a View structure.
 //
-// @param {String} htmlString HTML string in which spacing should be normalized.
-// @returns {String} Input HTML with spaces normalized.
-function normalizeEndTagsPrecedingSpace( htmlString ) {
-	return htmlString
-		.replace( / <\//g, '\u00A0</' )
-		.replace( / <o:p><\/o:p>/g, '\u00A0<o:p></o:p>' );
+// @param {Node|DocumentFragment} domNode DOM node or document fragment to transform.
+// @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} Converted node or document fragment
+// or `null` if DOM node is an empty text node or not a `DocumentFragment` or `Element` node type.
+function domToView( domNode ) {
+	if ( isText( domNode ) ) {
+		const textData = normalizeTextNodes( domNode.data );
+
+		return textData === '' ? null : new ViewText( textData );
+	} else if ( domConverter.isDocumentFragment( domNode ) || domConverter.isElement( domNode ) ) {
+		let viewElement;
+
+		if ( domConverter.isDocumentFragment( domNode ) ) {
+			// Create view document fragment.
+			viewElement = new ViewDocumentFragment();
+		} else {
+			// Create view element.
+			const viewName = domNode.tagName.toLowerCase();
+			viewElement = new ViewElement( viewName );
+
+			// Copy element's attributes.
+			const attrs = domNode.attributes;
+
+			for ( let i = attrs.length - 1; i >= 0; i-- ) {
+				upcastWriter.setAttribute( attrs[ i ].name, attrs[ i ].value, viewElement );
+			}
+		}
+
+		const children = [];
+
+		for ( let i = 0; i < domNode.childNodes.length; i++ ) {
+			const viewChild = domToView( domNode.childNodes[ i ] );
+
+			if ( viewChild ) {
+				children.push( viewChild );
+			}
+		}
+		upcastWriter.appendChild( children, viewElement );
+
+		return viewElement;
+	}
+
+	return null;
 }
 
-// Normalizes spacing in special Word `spacerun spans` (`<span style='mso-spacerun:yes'>\s+</span>`) by replacing
-// all spaces with `&nbsp;`'s. This prevents spaces from being removed during further DOM/View processing
-// (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).
+// Normalizes given text nodes by replacing new line characters and non-breaking spaces with regular spaces.
 //
-// @param {Document} htmlDocument Native `Document` object in which spacing should be normalized.
-function normalizeSpacerunSpans( htmlDocument ) {
-	htmlDocument.querySelectorAll( 'span[style*=spacerun]' ).forEach( el => {
-		el.innerHTML = Array( el.innerText.length + 1 ).join( '\u00A0' );
-	} );
+// @param {String} text Text to be normalized.
+// @returns {String} Normalized text.
+function normalizeTextNodes( text ) {
+	const normalizedText = text
+		.replace( /[\n\t\r]{1,}/g, ' ' )
+		.replace( /\u00A0/g, ' ' );
+
+	return normalizedText === ' ' ? '' : normalizedText;
 }