Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Add support for preserving text attributes on enter #63

Merged
merged 10 commits into from
Jul 16, 2019
3 changes: 3 additions & 0 deletions src/entercommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 <kbd>Enter</kbd> key.
Expand Down Expand Up @@ -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 );
Expand Down
5 changes: 5 additions & 0 deletions src/shiftentercommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 } );
Expand Down
26 changes: 26 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
25 changes: 25 additions & 0 deletions tests/entercommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,31 @@ describe( 'EnterCommand', () => {
'<p>x</p><p>[]</p><p>y</p>',
'<p>x</p><p></p><p>[]</p><p>y</p>'
);

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

test(
'allowed attributes are copied',
'<p><$text foo="true">test[]</$text></p>',
'<p><$text foo="true">test</$text></p><p selection:foo="true"><$text foo="true">[]</$text></p>'
);

test(
'unknown attributes are not copied',
'<p><$text bar="true">test[]</$text></p>',
'<p><$text bar="true">test</$text></p><p>[]</p>'
);

test(
'only allowed attributes are copied from mix set',
'<p><$text bar="true" foo="true">test[]</$text></p>',
'<p><$text bar="true" foo="true">test</$text></p><p selection:foo="true"><$text foo="true">[]</$text></p>'
);
} );
} );

describe( 'non-collapsed selection', () => {
Expand Down
25 changes: 25 additions & 0 deletions tests/shiftentercommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,31 @@ describe( 'ShiftEnterCommand', () => {
'<p>x</p><p>[]foo</p><p>y</p>',
'<p>x</p><p><softBreak></softBreak>[]foo</p><p>y</p>'
);

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

test(
'allowed attributes are copied',
'<p><$text foo="true">test[]</$text></p>',
'<p><$text foo="true">test</$text><softBreak></softBreak><$text foo="true">[]</$text></p>'
);

test(
'unknown attributes are not copied',
'<p><$text bar="true">test[]</$text></p>',
'<p><$text bar="true">test</$text><softBreak></softBreak>[]</p>'
);

test(
'only allowed attributes are copied from mix set',
'<p><$text bar="true" foo="true">test[]</$text></p>',
'<p><$text bar="true" foo="true">test</$text><softBreak></softBreak><$text foo="true">[]</$text></p>'
);
} );
} );

describe( 'non-collapsed selection', () => {
Expand Down
38 changes: 38 additions & 0 deletions tests/utils.js
Original file line number Diff line number Diff line change
@@ -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 ]
]
);
} );
} );
} );
} );