diff --git a/src/entercommand.js b/src/entercommand.js index db5478b..b267717 100644 --- a/src/entercommand.js +++ b/src/entercommand.js @@ -8,6 +8,7 @@ */ import Command from '@ckeditor/ckeditor5-core/src/command'; +import { getCopyOnEnterAttributes } from './utils'; /** * Enter command. It is used by the {@link module:enter/enter~Enter Enter feature} to handle the Enter key. @@ -56,7 +57,9 @@ function enterBlock( model, writer, selection, schema ) { } if ( isSelectionEmpty ) { + const attributesToCopy = getCopyOnEnterAttributes( writer.model.schema, selection.getAttributes() ); splitBlock( writer, range.start ); + writer.setSelectionAttribute( attributesToCopy ); } else { const leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd ); const isContainedWithinOneElement = ( startElement == endElement ); diff --git a/src/shiftentercommand.js b/src/shiftentercommand.js index 5944238..ceb6d22 100644 --- a/src/shiftentercommand.js +++ b/src/shiftentercommand.js @@ -8,6 +8,7 @@ */ import Command from '@ckeditor/ckeditor5-core/src/command'; +import { getCopyOnEnterAttributes } from './utils'; /** * ShiftEnter command. It is used by the {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature} to handle @@ -81,7 +82,11 @@ function softBreakAction( model, writer, selection ) { const isContainedWithinOneElement = ( startElement == endElement ); if ( isSelectionEmpty ) { + const attributesToCopy = getCopyOnEnterAttributes( model.schema, selection.getAttributes() ); insertBreak( writer, range.end ); + + writer.removeSelectionAttribute( selection.getAttributeKeys() ); + writer.setSelectionAttribute( attributesToCopy ); } else { const leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd ); model.deleteContent( selection, { leaveUnmerged } ); diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..66a68ac --- /dev/null +++ b/src/utils.js @@ -0,0 +1,26 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module enter/utils + */ + +/** + * Returns attributes that should be preserved on the enter key. + * + * Filtering is realized based on `copyOnEnter` attribute property. Read more about attribute properties + * {@link module:engine/model/schema~Schema#setAttributeProperties here}. + * + * @param {module:engine/model/schema~Schema} schema + * @param {Iterable.<*>} allAttributes attributes to filter. + * @returns {Iterable.<*>} + */ +export function* getCopyOnEnterAttributes( schema, allAttributes ) { + for ( const attribute of allAttributes ) { + if ( attribute && schema.getAttributeProperties( attribute[ 0 ] ).copyOnEnter ) { + yield attribute; + } + } +} diff --git a/tests/entercommand.js b/tests/entercommand.js index d8e7217..3d5f52c 100644 --- a/tests/entercommand.js +++ b/tests/entercommand.js @@ -87,6 +87,31 @@ describe( 'EnterCommand', () => { '

x

[]

y

', '

x

[]

y

' ); + + describe( 'copyOnEnter', () => { + beforeEach( () => { + schema.extend( '$text', { allowAttributes: [ 'foo', 'bar' ] } ); + schema.setAttributeProperties( 'foo', { copyOnEnter: true } ); + } ); + + test( + 'allowed attributes are copied', + '

<$text foo="true">test[]

', + '

<$text foo="true">test

<$text foo="true">[]

' + ); + + test( + 'unknown attributes are not copied', + '

<$text bar="true">test[]

', + '

<$text bar="true">test

[]

' + ); + + test( + 'only allowed attributes are copied from mix set', + '

<$text bar="true" foo="true">test[]

', + '

<$text bar="true" foo="true">test

<$text foo="true">[]

' + ); + } ); } ); describe( 'non-collapsed selection', () => { diff --git a/tests/shiftentercommand.js b/tests/shiftentercommand.js index ca12217..08b5be6 100644 --- a/tests/shiftentercommand.js +++ b/tests/shiftentercommand.js @@ -101,6 +101,31 @@ describe( 'ShiftEnterCommand', () => { '

x

[]foo

y

', '

x

[]foo

y

' ); + + describe( 'copyOnEnter', () => { + beforeEach( () => { + schema.extend( '$text', { allowAttributes: [ 'foo', 'bar' ] } ); + schema.setAttributeProperties( 'foo', { copyOnEnter: true } ); + } ); + + test( + 'allowed attributes are copied', + '

<$text foo="true">test[]

', + '

<$text foo="true">test<$text foo="true">[]

' + ); + + test( + 'unknown attributes are not copied', + '

<$text bar="true">test[]

', + '

<$text bar="true">test[]

' + ); + + test( + 'only allowed attributes are copied from mix set', + '

<$text bar="true" foo="true">test[]

', + '

<$text bar="true" foo="true">test<$text foo="true">[]

' + ); + } ); } ); describe( 'non-collapsed selection', () => { diff --git a/tests/utils.js b/tests/utils.js new file mode 100644 index 0000000..e1a5831 --- /dev/null +++ b/tests/utils.js @@ -0,0 +1,38 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import { getCopyOnEnterAttributes } from '../src/utils'; +import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; + +describe( 'utils', () => { + describe( 'getCopyOnEnterAttributes()', () => { + it( 'filters attributes with copyOnEnter property', () => { + return ModelTestEditor.create() + .then( editor => { + const schema = editor.model.schema; + + schema.extend( '$text', { + allowAttributes: [ 'foo', 'bar', 'baz' ] + } ); + + schema.setAttributeProperties( 'foo', { copyOnEnter: true } ); + schema.setAttributeProperties( 'baz', { copyOnEnter: true } ); + + const allAttributes = ( new Map( [ + [ 'foo', true ], + [ 'bar', true ], + [ 'baz', true ] + ] ) )[ Symbol.iterator ](); + + expect( Array.from( getCopyOnEnterAttributes( schema, allAttributes ) ) ).to.deep.equal( + [ + [ 'foo', true ], + [ 'baz', true ] + ] + ); + } ); + } ); + } ); +} );