Browse Source

Changed: inline style attribute parser changed from RegExp-based to linear-loop based.

Szymon Cofalik 8 years ago
parent
commit
881a4f622e

+ 54 - 4
packages/ckeditor5-engine/src/view/element.js

@@ -685,12 +685,62 @@ export default class Element extends Node {
 // @param {Map.<String, String>} stylesMap Map to insert parsed properties and values.
 // @param {Map.<String, String>} stylesMap Map to insert parsed properties and values.
 // @param {String} stylesString Styles to parse.
 // @param {String} stylesString Styles to parse.
 function parseInlineStyles( stylesMap, stylesString ) {
 function parseInlineStyles( stylesMap, stylesString ) {
-	const regex = /\s*([^:;\s]+)\s*:\s*([^;]+)\s*(?=;|$)/g;
-	let matchStyle;
+	let quoteType = null;
+	let propertyNameStart = 0;
+	let propertyValueStart = 0;
+	let propertyName = null;
+
+	const tokens = [];
+
 	stylesMap.clear();
 	stylesMap.clear();
 
 
-	while ( ( matchStyle = regex.exec( stylesString ) ) !== null ) {
-		stylesMap.set( matchStyle[ 1 ], matchStyle[ 2 ].trim() );
+	if ( stylesString === '' ) {
+		return;
+	}
+
+	if ( stylesString.charAt( stylesString.length - 1 ) != ';' ) {
+		stylesString = stylesString + ';';
+	}
+
+	for ( let i = 0; i < stylesString.length; i++ ) {
+		const char = stylesString.charAt( i );
+
+		if ( quoteType === null ) {
+			switch ( char ) {
+				case ':':
+					if ( !propertyName ) {
+						propertyName = stylesString.substr( propertyNameStart, i - propertyNameStart );
+						propertyValueStart = i + 1;
+					}
+
+					break;
+
+				case '"':
+				case '\'':
+					quoteType = char;
+
+					break;
+
+				case ';':
+					let propertyValue = stylesString.substr( propertyValueStart, i - propertyValueStart );
+
+					tokens.push( {
+						name: propertyName,
+						value: propertyValue
+					} );
+
+					propertyName = null;
+					propertyNameStart = i + 1;
+
+					break;
+			}
+		} else if ( char === quoteType ) {
+			quoteType = null;
+		}
+	}
+
+	for ( let token of tokens ) {
+		stylesMap.set( token.name.trim(), token.value.trim() );
 	}
 	}
 }
 }
 
 

File diff suppressed because it is too large
+ 1 - 0
packages/ckeditor5-engine/tests/view/_utils/encodedimage.js


+ 29 - 0
packages/ckeditor5-engine/tests/view/element.js

@@ -7,6 +7,8 @@ import count from '@ckeditor/ckeditor5-utils/src/count';
 import Node from '../../src/view/node';
 import Node from '../../src/view/node';
 import Element from '../../src/view/element';
 import Element from '../../src/view/element';
 
 
+import encodedImage from './_utils/encodedimage.js';
+
 describe( 'Element', () => {
 describe( 'Element', () => {
 	describe( 'constructor()', () => {
 	describe( 'constructor()', () => {
 		it( 'should create element without attributes', () => {
 		it( 'should create element without attributes', () => {
@@ -767,10 +769,12 @@ describe( 'Element', () => {
 		describe( 'getStyleNames', () => {
 		describe( 'getStyleNames', () => {
 			it( 'should return iterator with all style names', () => {
 			it( 'should return iterator with all style names', () => {
 				const names = [ 'color', 'position' ];
 				const names = [ 'color', 'position' ];
+
 				el.setStyle( {
 				el.setStyle( {
 					color: 'red',
 					color: 'red',
 					position: 'absolute'
 					position: 'absolute'
 				} );
 				} );
+
 				const iterator = el.getStyleNames();
 				const iterator = el.getStyleNames();
 				let i = 0;
 				let i = 0;
 
 
@@ -832,6 +836,31 @@ describe( 'Element', () => {
 				expect( el.hasStyle( 'color' ) ).to.be.true;
 				expect( el.hasStyle( 'color' ) ).to.be.true;
 			} );
 			} );
 		} );
 		} );
+
+		describe( 'styles parsing edge cases', () => {
+			it( 'should not crash and not add any styles if styles attribute was empty', () => {
+				const element = new Element( 'div', { style: '' } );
+				const styles = Array.from( element.getStyleNames() );
+
+				expect( styles ).to.deep.equal( [] );
+			} );
+
+			it( 'should be able to parse big styles definition', () => {
+				expect( () => {
+					new Element( 'div', { style: `background-image:url('data:image/jpeg;base64,${ encodedImage }')` } );
+				} ).not.to.throw();
+			} );
+
+			it( 'should work with both types of quotes and ignore values inside quotes', () => {
+				let element;
+
+				element = new Element( 'div', { style: 'background-image:url("im;color:g.jpg")' } );
+				expect( element.getStyle( 'background-image' ) ).to.equal( 'url("im;color:g.jpg")' );
+
+				element = new Element( 'div', { style: 'background-image:url(\'im;color:g.jpg\')' } );
+				expect( element.getStyle( 'background-image' ) ).to.equal( 'url(\'im;color:g.jpg\')' );
+			} );
+		} );
 	} );
 	} );
 
 
 	describe( 'findAncestor', () => {
 	describe( 'findAncestor', () => {