Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed handling of whitespaces inside inline objects. #17197

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/ckeditor5-engine/src/view/domconverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export default class DomConverter {
this.document = document;
this.renderingMode = renderingMode;
this.blockFillerMode = blockFillerMode || ( renderingMode === 'editing' ? 'br' : 'nbsp' );
this.preElements = [ 'pre' ];
this.preElements = [ 'pre', 'textarea' ];
this.blockElements = [
'address', 'article', 'aside', 'blockquote', 'caption', 'center', 'dd', 'details', 'dir', 'div',
'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header',
Expand Down Expand Up @@ -1473,6 +1473,9 @@ export default class DomConverter {
// for inline objects can verify if the element is empty.
if ( this._isInlineObjectElement( viewElement ) ) {
inlineNodes.push( viewElement );

// Inline object content should be handled as a flow-root.
this._processDomInlineNodes( null, nestedInlineNodes, options );
} else {
// It's an inline element that is not an object (like <b>, <i>) or a block element.
for ( const inlineNode of nestedInlineNodes ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ describe( 'DomConverter – whitespace handling – integration', () => {
expect( editor.getData() ).to.equal( '<p>foo <img src="/assets/sample.png"> bar</p>' );
} );

it( 'white space around (and inside) inline object elements should not be trimmed', () => {
it( 'white space around inline object elements should not be trimmed', () => {
editor.model.schema.register( 'button', {
allowWhere: '$text',
isInline: true,
Expand All @@ -362,12 +362,53 @@ describe( 'DomConverter – whitespace handling – integration', () => {
editor.setData( '<p>foo <button> Button </button> bar</p>' );

expect( getData( editor.model, { withoutSelection: true } ) )
.to.equal( '<paragraph>foo <button> Button </button> bar</paragraph>' );
.to.equal( '<paragraph>foo <button>Button</button> bar</paragraph>' );

expect( editor.getData() ).to.equal( '<p>foo <button> Button </button> bar</p>' );
expect( editor.getData() ).to.equal( '<p>foo <button>Button</button> bar</p>' );
} );

it( 'white spaces around (and inside) successive inline object elements should not be trimmed', () => {
it( 'white spaces inside an inline object elements should be trimmed', () => {
editor.model.schema.register( 'button', {
allowWhere: '$text',
isInline: true,
allowChildren: [ '$text' ]
} );

editor.conversion.elementToElement( {
model: 'button',
view: 'button'
} );

editor.setData( '<p>foo <button>\n\t\t\t\t Some button \n\t\t</button> bar</p>' );

expect( getData( editor.model, { withoutSelection: true } ) )
.to.equal( '<paragraph>foo <button>Some button</button> bar</paragraph>' );

expect( editor.getData() ).to.equal( '<p>foo <button>Some button</button> bar</p>' );
} );

it( 'white spaces inside a textarea (as inline object element) should not be trimmed', () => {
editor.model.schema.register( 'textarea', {
allowWhere: '$text',
isInline: true,
allowChildren: [ '$text' ]
} );

editor.conversion.elementToElement( {
model: 'textarea',
view: 'textarea'
} );

editor.setData( '<p>foo <textarea>\n\t\t\t\t Some textarea \n\t\t</textarea> bar</p>' );

// Note that the first \n is trimmed by the DOMParser.
expect( getData( editor.model, { withoutSelection: true } ) )
.to.equal( '<paragraph>foo <textarea>\t\t\t\t Some textarea \n\t\t</textarea> bar</paragraph>' );

expect( editor.getData() ).to.equal( '<p>foo <textarea>\t\t\t\t Some textarea \n\t\t</textarea> bar</p>' );
} );

it( 'white spaces around successive inline object elements should not be trimmed', () => {
editor.model.schema.register( 'button', {
allowWhere: '$text',
isInline: true,
Expand All @@ -382,12 +423,12 @@ describe( 'DomConverter – whitespace handling – integration', () => {
editor.setData( '<p>foo <button> Button </button> <button> Another </button> bar</p>' );

expect( getData( editor.model, { withoutSelection: true } ) )
.to.equal( '<paragraph>foo <button> Button </button> <button> Another </button> bar</paragraph>' );
.to.equal( '<paragraph>foo <button>Button</button> <button>Another</button> bar</paragraph>' );

expect( editor.getData() ).to.equal( '<p>foo <button> Button </button> <button> Another </button> bar</p>' );
expect( editor.getData() ).to.equal( '<p>foo <button>Button</button> <button>Another</button> bar</p>' );
} );

it( 'white spaces around (and inside) nested inline object elements should not be trimmed', () => {
it( 'white spaces around nested inline object elements should not be trimmed', () => {
editor.model.schema.register( 'select', {
allowWhere: '$text',
isInline: true,
Expand Down Expand Up @@ -434,17 +475,29 @@ describe( 'DomConverter – whitespace handling – integration', () => {
.to.equal( '<paragraph>select ' +
'<select name="things">' +
'<optgroup label="FoosAndBars">' +
'<option value="foo"> Foo </option>' +
'<option value="bar"> Bar </option>' +
'<option value="foo">Foo</option>' +
'<option value="bar">Bar</option>' +
'</optgroup>' +
'<optgroup label="letters">' +
'<option value="a"> A </option>' +
'<option value="b"> B </option>' +
'<option value="a">A</option>' +
'<option value="b">B</option>' +
'</optgroup>' +
'</select>' +
' with some text</paragraph>' );

expect( editor.getData() ).to.equal( initialData );
expect( editor.getData() ).to.equal(
'<p>select <select name="things">' +
'<optgroup label="FoosAndBars">' +
'<option value="foo">Foo</option>' +
'<option value="bar">Bar</option>' +
'</optgroup>' +
'<optgroup label="letters">' +
'<option value="a">A</option>' +
'<option value="b">B</option>' +
'</optgroup>' +
'</select> with some text' +
'</p>'
);
} );

// All possible cases have been checked 👆. These are dummy tests only to verify this will work for all elements in the list.
Expand Down