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

Added tests and fixes for treeView.Writer.unwrap method.

Szymon Kupś 9 лет назад
Родитель
Сommit
f23e08b6df

+ 10 - 3
packages/ckeditor5-engine/src/treeview/writer.js

@@ -772,6 +772,12 @@ function wrapAttributeElement( wrapper, toWrap ) {
 	return true;
 }
 
+// Unwraps {@link engine.treeView.AttributeElement AttributeElement} from another by removing corresponding attributes,
+// classes and styles. All attributes, classes and styles from wrapper should be present inside element being unwrapped.
+//
+// @param {engine.treeView.AttributeElement} wrapper Wrapper AttributeElement.
+// @param {engine.treeView.AttributeElement} toUnwrap AttributeElement to unwrap using wrapper element.
+// @returns {Boolean} Returns `true` if elements are unwrapped.
 function unwrapAttributeElement( wrapper, toUnwrap ) {
 	// Can't unwrap if name or priority differs.
 	if ( wrapper.name !== toUnwrap.name || wrapper.priority !== toUnwrap.priority ) {
@@ -785,8 +791,8 @@ function unwrapAttributeElement( wrapper, toUnwrap ) {
 			continue;
 		}
 
-		// If some attributes are different we cannot unwrap.
-		if ( toUnwrap.hasAttribute( key ) && toUnwrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {
+		// If some attributes are missing or different we cannot unwrap.
+		if ( !toUnwrap.hasAttribute( key ) || toUnwrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {
 			return false;
 		}
 	}
@@ -798,7 +804,8 @@ function unwrapAttributeElement( wrapper, toUnwrap ) {
 
 	// Check if AttributeElement has all wrapper styles.
 	for ( let key of wrapper.getStyleNames() ) {
-		if ( toUnwrap.hasStyle( key ) && toUnwrap.getStyle( key ) !== wrapper.getStyle( key ) ) {
+		// If some styles are missing or different we cannot unwrap.
+		if ( !toUnwrap.hasStyle( key ) || toUnwrap.getStyle( key ) !== wrapper.getStyle( key ) ) {
 			return false;
 		}
 	}

+ 217 - 0
packages/ckeditor5-engine/tests/treeview/writer/unwrap.js

@@ -707,5 +707,222 @@ describe( 'Writer', () => {
 				]
 			} );
 		} );
+
+		it( 'should unwrap single element by removing matching attributes', () => {
+			// <p>[<b foo="bar" baz="qux" >test</b>]</p>
+			// unwrap using <b baz="qux">test</b></p>
+			// <p>[<b foo="bar">test</b>]</p>
+			const text = new Text( 'test' );
+			const b = new AttributeElement( 'b', {
+				foo: 'bar',
+				baz: 'qux'
+			}, text );
+			const p = new ContainerElement( 'p', null, b );
+			const wrapper = new AttributeElement( 'b', {
+				baz: 'qux'
+			} );
+			const range = Range.createFromParentsAndOffsets( p, 0, p, 1 );
+
+			const newRange = writer.unwrap( range, wrapper );
+			expect( b.getAttribute( 'foo' ) ).to.equal( 'bar' );
+			expect( b.hasAttribute( 'baz' ) ).to.be.false;
+			expect( b.parent ).to.equal( p );
+			test( writer, newRange, p, {
+				instanceof: ContainerElement,
+				name: 'p',
+				rangeStart: 0,
+				rangeEnd: 1,
+				children: [
+					{
+						instanceof: AttributeElement,
+						name: 'b',
+						children: [
+							{ instanceof: Text, data: 'test' }
+						]
+					}
+				]
+			} );
+		} );
+
+		it( 'should not unwrap single element when attributes are different', () => {
+			// <p>[<b foo="bar" baz="qux">test</b>]</p>
+			// unwrap using <b baz="qux" test="true">test</b></p>
+			// <p>[<b foo="bar" baz="qux">test</b>]</p>
+			const text = new Text( 'test' );
+			const b = new AttributeElement( 'b', {
+				foo: 'bar',
+				baz: 'qux'
+			}, text );
+			const p = new ContainerElement( 'p', null, b );
+			const wrapper = new AttributeElement( 'b', {
+				baz: 'qux',
+				test: 'true'
+			} );
+			const range = Range.createFromParentsAndOffsets( p, 0, p, 1 );
+
+			const newRange = writer.unwrap( range, wrapper );
+			expect( b.getAttribute( 'foo' ) ).to.equal( 'bar' );
+			expect( b.getAttribute( 'baz' ) ).to.equal( 'qux' );
+			expect( b.parent ).to.equal( p );
+			test( writer, newRange, p, {
+				instanceof: ContainerElement,
+				name: 'p',
+				rangeStart: 0,
+				rangeEnd: 1,
+				children: [
+					{
+						instanceof: AttributeElement,
+						name: 'b',
+						children: [
+							{ instanceof: Text, data: 'test' }
+						]
+					}
+				]
+			} );
+		} );
+
+		it( 'should unwrap single element by removing matching classes', () => {
+			// <p>[<b class="foo bar baz">test</b>]</p>
+			// unwrap using <b class="baz foo">test</b></p>
+			// <p>[<b class="bar">test</b>]</p>
+			const text = new Text( 'test' );
+			const b = new AttributeElement( 'b', {
+				class: 'foo bar baz'
+			}, text );
+			const p = new ContainerElement( 'p', null, b );
+			const wrapper = new AttributeElement( 'b', {
+				class: 'baz foo'
+			} );
+			const range = Range.createFromParentsAndOffsets( p, 0, p, 1 );
+
+			const newRange = writer.unwrap( range, wrapper );
+			expect( b.hasClass( 'bar' ) ).to.be.true;
+			expect( b.hasClass( 'foo' ) ).to.be.false;
+			expect( b.hasClass( 'baz' ) ).to.be.false;
+			expect( b.parent ).to.equal( p );
+			test( writer, newRange, p, {
+				instanceof: ContainerElement,
+				name: 'p',
+				rangeStart: 0,
+				rangeEnd: 1,
+				children: [
+					{
+						instanceof: AttributeElement,
+						name: 'b',
+						children: [
+							{ instanceof: Text, data: 'test' }
+						]
+					}
+				]
+			} );
+		} );
+
+		it( 'should not unwrap single element when classes are different', () => {
+			// <p>[<b class="foo bar baz">test</b>]</p>
+			// unwrap using <b class="baz foo qux">test</b></p>
+			// <p>[<b class="foo bar baz">test</b>]</p>
+			const text = new Text( 'test' );
+			const b = new AttributeElement( 'b', {
+				class: 'foo bar baz'
+			}, text );
+			const p = new ContainerElement( 'p', null, b );
+			const wrapper = new AttributeElement( 'b', {
+				class: 'baz foo qux'
+			} );
+			const range = Range.createFromParentsAndOffsets( p, 0, p, 1 );
+
+			const newRange = writer.unwrap( range, wrapper );
+			expect( b.hasClass( 'bar' ) ).to.be.true;
+			expect( b.hasClass( 'foo' ) ).to.be.true;
+			expect( b.hasClass( 'baz' ) ).to.be.true;
+			expect( b.parent ).to.equal( p );
+			test( writer, newRange, p, {
+				instanceof: ContainerElement,
+				name: 'p',
+				rangeStart: 0,
+				rangeEnd: 1,
+				children: [
+					{
+						instanceof: AttributeElement,
+						name: 'b',
+						children: [
+							{ instanceof: Text, data: 'test' }
+						]
+					}
+				]
+			} );
+		} );
+
+		it( 'should unwrap single element by removing matching styles', () => {
+			// <p>[<b style="color:red; position:absolute; top:10px;">test</b>]</p>
+			// unwrap using <b style="position: absolute;">test</b></p>
+			// <p>[<b style="color:red; top:10px;">test</b>]</p>
+			const text = new Text( 'test' );
+			const b = new AttributeElement( 'b', {
+				style: 'color:red; position:absolute; top:10px;'
+			}, text );
+			const p = new ContainerElement( 'p', null, b );
+			const wrapper = new AttributeElement( 'b', {
+				style: 'position: absolute;'
+			} );
+			const range = Range.createFromParentsAndOffsets( p, 0, p, 1 );
+
+			const newRange = writer.unwrap( range, wrapper );
+			expect( b.getStyle( 'color' ) ).to.equal( 'red' );
+			expect( b.getStyle( 'top' ) ).to.equal( '10px' );
+			expect( b.hasStyle( 'position' ) ).to.be.false;
+			expect( b.parent ).to.equal( p );
+			test( writer, newRange, p, {
+				instanceof: ContainerElement,
+				name: 'p',
+				rangeStart: 0,
+				rangeEnd: 1,
+				children: [
+					{
+						instanceof: AttributeElement,
+						name: 'b',
+						children: [
+							{ instanceof: Text, data: 'test' }
+						]
+					}
+				]
+			} );
+		} );
+
+		it( 'should not unwrap single element when styles are different', () => {
+			// <p>[<b style="color:red; position:absolute; top:10px;">test</b>]</p>
+			// unwrap using <b style="position: relative;">test</b></p>
+			// <p>[<b style="color:red; position:absolute; top:10px;">test</b>]</p>
+			const text = new Text( 'test' );
+			const b = new AttributeElement( 'b', {
+				style: 'color:red; position:absolute; top:10px;'
+			}, text );
+			const p = new ContainerElement( 'p', null, b );
+			const wrapper = new AttributeElement( 'b', {
+				style: 'position: relative;'
+			} );
+			const range = Range.createFromParentsAndOffsets( p, 0, p, 1 );
+
+			const newRange = writer.unwrap( range, wrapper );
+			expect( b.getStyle( 'color' ) ).to.equal( 'red' );
+			expect( b.getStyle( 'top' ) ).to.equal( '10px' );
+			expect( b.getStyle( 'position' ) ).to.equal( 'absolute' );
+			expect( b.parent ).to.equal( p );
+			test( writer, newRange, p, {
+				instanceof: ContainerElement,
+				name: 'p',
+				rangeStart: 0,
+				rangeEnd: 1,
+				children: [
+					{
+						instanceof: AttributeElement,
+						name: 'b',
+						children: [
+							{ instanceof: Text, data: 'test' }
+						]
+					}
+				]
+			} );
+		} );
 	} );
 } );