Sfoglia il codice sorgente

Merge pull request #1173 from ckeditor/t/1170

Fix: Prevent adding inline filler to non-editable content. Closes #1170.
Piotr Jasiun 8 anni fa
parent
commit
443b5c052e

+ 21 - 0
packages/ckeditor5-engine/src/view/renderer.js

@@ -381,6 +381,12 @@ export default class Renderer {
 			return false;
 		}
 
+		// Prevent adding inline filler inside elements with contenteditable=false.
+		// https://github.com/ckeditor/ckeditor5-engine/issues/1170
+		if ( !_isEditable( selectionParent ) ) {
+			return false;
+		}
+
 		// We have block filler, we do not need inline one.
 		if ( selectionOffset === selectionParent.getFillerOffset() ) {
 			return false;
@@ -708,3 +714,18 @@ export default class Renderer {
 }
 
 mix( Renderer, ObservableMixin );
+
+// Checks if provided element is editable.
+//
+// @private
+// @param {module:engine/view/element~Element} element
+// @returns {Boolean}
+function _isEditable( element ) {
+	if ( element.getAttribute( 'contenteditable' ) == 'false' ) {
+		return false;
+	}
+
+	const parent = element.findAncestor( element => element.hasAttribute( 'contenteditable' ) );
+
+	return !parent || parent.getAttribute( 'contenteditable' ) == 'true';
+}

+ 44 - 0
packages/ckeditor5-engine/tests/view/renderer.js

@@ -410,6 +410,50 @@ describe( 'Renderer', () => {
 			expect( viewRoot ).to.be.ok;
 		} );
 
+		it( 'should not add filler when inside contenteditable=false parent', () => {
+			const { view: viewP, selection: newSelection } = parse(
+				'<container:p>foo<attribute:b contenteditable="false">[]</attribute:b>bar</container:p>' );
+
+			viewRoot.appendChildren( viewP );
+			selection.setTo( newSelection );
+
+			renderer.markToSync( 'children', viewRoot );
+			renderer.render();
+
+			expect( domRoot.childNodes.length ).to.equal( 1 );
+			expect( domRoot.childNodes[ 0 ].tagName.toLowerCase() ).to.equal( 'p' );
+
+			const domP = domRoot.childNodes[ 0 ];
+
+			expect( domP.childNodes.length ).to.equal( 3 );
+			expect( domP.childNodes[ 0 ].data ).to.equal( 'foo' );
+			expect( domP.childNodes[ 2 ].data ).to.equal( 'bar' );
+			expect( domP.childNodes[ 1 ].tagName.toLowerCase() ).to.equal( 'b' );
+			expect( domP.childNodes[ 1 ].childNodes.length ).to.equal( 0 );
+		} );
+
+		it( 'should not add filler when inside contenteditable=false ancestor', () => {
+			const { view: viewP, selection: newSelection } = parse(
+				'<container:p contenteditable="false">foo<attribute:b>[]</attribute:b>bar</container:p>' );
+
+			viewRoot.appendChildren( viewP );
+			selection.setTo( newSelection );
+
+			renderer.markToSync( 'children', viewRoot );
+			renderer.render();
+
+			expect( domRoot.childNodes.length ).to.equal( 1 );
+			expect( domRoot.childNodes[ 0 ].tagName.toLowerCase() ).to.equal( 'p' );
+
+			const domP = domRoot.childNodes[ 0 ];
+
+			expect( domP.childNodes.length ).to.equal( 3 );
+			expect( domP.childNodes[ 0 ].data ).to.equal( 'foo' );
+			expect( domP.childNodes[ 2 ].data ).to.equal( 'bar' );
+			expect( domP.childNodes[ 1 ].tagName.toLowerCase() ).to.equal( 'b' );
+			expect( domP.childNodes[ 1 ].childNodes.length ).to.equal( 0 );
+		} );
+
 		it( 'should add and remove inline filler in case <p>foo<b>[]</b>bar</p>', () => {
 			const domSelection = document.getSelection();