浏览代码

Make sure any content after closing body tag is removed before parsing.

Krzysztof Krztoń 7 年之前
父节点
当前提交
bffab8e9cf

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

@@ -27,8 +27,10 @@ import { NBSP_FILLER } from '@ckeditor/ckeditor5-engine/src/view/filler';
 export function parseHtml( htmlString ) {
 	const domParser = new DOMParser();
 
+	const normalizedHtml = normalizeSpacing( cleanContentAfterBody( htmlString ) );
+
 	// Parse htmlString as native Document object.
-	const htmlDocument = domParser.parseFromString( normalizeSpacing( htmlString ), 'text/html' );
+	const htmlDocument = domParser.parseFromString( normalizedHtml, 'text/html' );
 
 	normalizeSpacerunSpans( htmlDocument );
 
@@ -90,6 +92,24 @@ function extractStyles( htmlDocument ) {
 	};
 }
 
+// Removes leftover content from between closing </body> and closing </html> tag:
+//
+// 		<html><body><p>Foo Bar</p></body><span>Fo</span></html> -> <html><body><p>Foo Bar</p></body></html>
+//
+// This function is used as specific browsers (Edge) add some random content after `body` tag when pasting from Word.
+// @param {String} htmlString The HTML string to be cleaned.
+// @returns {String} The HTML string with leftover content removed.
+function cleanContentAfterBody( htmlString ) {
+	const regexp = /<\/body>(.*?)(<\/html>|$)/;
+	const match = htmlString.match( regexp );
+
+	if ( match && match[ 1 ] ) {
+		htmlString = htmlString.slice( 0, match.index ) + htmlString.slice( match.index ).replace( match[ 1 ], '' );
+	}
+
+	return htmlString;
+}
+
 // Replaces last space preceding elements closing tag with `&nbsp;`. 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.

+ 70 - 0
packages/ckeditor5-paste-from-office/tests/filters/utils.js

@@ -77,6 +77,76 @@ describe( 'Filters', () => {
 
 				expect( stylesString ).to.equal( '' );
 			} );
+
+			it( 'should remove any content after body closing tag - plain', () => {
+				const html = '<html><head></head><body><p>Foo Bar</p></body>Ba</html>';
+				const { body, bodyString, styles, stylesString } = parseHtml( html );
+
+				expect( body ).to.instanceof( DocumentFragment );
+				expect( body.childCount ).to.equal( 1, 'body.childCount' );
+
+				expect( bodyString ).to.equal( '<p>Foo Bar</p>' );
+
+				expect( styles.length ).to.equal( 0 );
+
+				expect( stylesString ).to.equal( '' );
+			} );
+
+			it( 'should remove any content after body closing tag - inline', () => {
+				const html = '<html><head></head><body><p>Foo Bar</p></body><span>Fo</span></html>';
+				const { body, bodyString, styles, stylesString } = parseHtml( html );
+
+				expect( body ).to.instanceof( DocumentFragment );
+				expect( body.childCount ).to.equal( 1, 'body.childCount' );
+
+				expect( bodyString ).to.equal( '<p>Foo Bar</p>' );
+
+				expect( styles.length ).to.equal( 0 );
+
+				expect( stylesString ).to.equal( '' );
+			} );
+
+			it( 'should remove any content after body closing tag - block', () => {
+				const html = '<html><head></head><body><p>Foo Bar</p></body><p>ar</p></html>';
+				const { body, bodyString, styles, stylesString } = parseHtml( html );
+
+				expect( body ).to.instanceof( DocumentFragment );
+				expect( body.childCount ).to.equal( 1, 'body.childCount' );
+
+				expect( bodyString ).to.equal( '<p>Foo Bar</p>' );
+
+				expect( styles.length ).to.equal( 0 );
+
+				expect( stylesString ).to.equal( '' );
+			} );
+
+			it( 'should remove any content after body closing tag - no html tag', () => {
+				const html = '<head></head><body><p>Foo Bar</p></body>oo';
+				const { body, bodyString, styles, stylesString } = parseHtml( html );
+
+				expect( body ).to.instanceof( DocumentFragment );
+				expect( body.childCount ).to.equal( 1, 'body.childCount' );
+
+				expect( bodyString ).to.equal( '<p>Foo Bar</p>' );
+
+				expect( styles.length ).to.equal( 0 );
+
+				expect( stylesString ).to.equal( '' );
+			} );
+
+			it( 'should not remove any content if no body tag', () => {
+				const html = '<p>Foo Bar</p>Baz';
+				const { body, bodyString, styles, stylesString } = parseHtml( html );
+
+				expect( body ).to.instanceof( DocumentFragment );
+				expect( body.childCount ).to.equal( 2, 'body.childCount' );
+
+				expect( bodyString ).to.equal( '<p>Foo Bar</p>Baz' );
+
+				expect( styles.length ).to.equal( 0 );
+
+				expect( stylesString ).to.equal( '' );
+			} );
 		} );
 
 		it( 'correctly parses HTML with body contents and empty style tag', () => {