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

Commit

Permalink
Merge pull request #1044 from ckeditor/t/1042
Browse files Browse the repository at this point in the history
Feature: Introduced `Schema#getLimitElement()`. Closes #1042.
  • Loading branch information
Reinmar authored Jul 26, 2017
2 parents 9f7e0a2 + c1479a4 commit 691e53e
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 17 deletions.
19 changes: 2 additions & 17 deletions src/controller/deletecontent.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,21 +168,6 @@ function checkCanBeMerged( leftPos, rightPos ) {
return true;
}

// Returns the lowest limit element defined in `Schema.limits` for passed selection.
function getLimitElement( schema, selection ) {
let element = selection.getFirstRange().getCommonAncestor();

while ( !schema.limits.has( element.name ) ) {
if ( element.parent ) {
element = element.parent;
} else {
break;
}
}

return element;
}

function insertParagraph( batch, position, selection ) {
const paragraph = new Element( 'paragraph' );
batch.insert( position, paragraph );
Expand All @@ -191,7 +176,7 @@ function insertParagraph( batch, position, selection ) {
}

function replaceEntireContentWithParagraph( batch, selection ) {
const limitElement = getLimitElement( batch.document.schema, selection );
const limitElement = batch.document.schema.getLimitElement( selection );

batch.remove( Range.createIn( limitElement ) );
insertParagraph( batch, Position.createAt( limitElement ), selection );
Expand All @@ -202,7 +187,7 @@ function replaceEntireContentWithParagraph( batch, selection ) {
// * selection contains at least two elements,
// * whether the paragraph is allowed in schema in the common ancestor.
function shouldEntireContentBeReplacedWithParagraph( schema, selection ) {
const limitElement = getLimitElement( schema, selection );
const limitElement = schema.getLimitElement( selection );
const limitStartPosition = Position.createAt( limitElement );
const limitEndPosition = Position.createAt( limitElement, 'end' );

Expand Down
29 changes: 29 additions & 0 deletions src/model/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,35 @@ export default class Schema {
return validRanges;
}

/**
* Returns the lowest {@link module:engine/model/schema~Schema#limits limit element} containing the entire
* selection or the root otherwise.
*
* @param {module:engine/model/selection~Selection} selection Selection which returns the common ancestor.
* @returns {module:engine/model/element~Element}
*/
getLimitElement( selection ) {
// Find the common ancestor for all selection's ranges.
let element = Array.from( selection.getRanges() )
.reduce( ( node, range ) => {
if ( !node ) {
return range.getCommonAncestor();
}

return node.getCommonAncestor( range.getCommonAncestor() );
}, null );

while ( !this.limits.has( element.name ) ) {
if ( element.parent ) {
element = element.parent;
} else {
break;
}
}

return element;
}

/**
* Returns {@link module:engine/model/schema~SchemaItem schema item} that was registered in the schema under given name.
* If item has not been found, throws error.
Expand Down
96 changes: 96 additions & 0 deletions tests/model/schema/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -641,4 +641,100 @@ describe( 'Schema', () => {
expect( result[ 1 ].end.path ).to.members( [ 1 ] );
} );
} );

describe( 'getLimitElement()', () => {
let doc, root;

beforeEach( () => {
doc = new Document();
schema = doc.schema;
root = doc.createRoot();

schema.registerItem( 'div', '$block' );
schema.registerItem( 'article', '$block' );
schema.registerItem( 'section', '$block' );
schema.registerItem( 'paragraph', '$block' );
schema.registerItem( 'widget', '$block' );
schema.registerItem( 'image', '$block' );
schema.registerItem( 'caption', '$block' );
schema.allow( { name: 'image', inside: 'widget' } );
schema.allow( { name: 'caption', inside: 'image' } );
schema.allow( { name: 'paragraph', inside: 'article' } );
schema.allow( { name: 'article', inside: 'section' } );
schema.allow( { name: 'section', inside: 'div' } );
schema.allow( { name: 'widget', inside: 'div' } );
} );

it( 'always returns $root element if any other limit was not defined', () => {
schema.limits.clear();

setData( doc, '<div><section><article><paragraph>foo[]bar</paragraph></article></section></div>' );
expect( schema.getLimitElement( doc.selection ) ).to.equal( root );
} );

it( 'returns the limit element which is the closest element to common ancestor for collapsed selection', () => {
schema.limits.add( 'article' );
schema.limits.add( 'section' );

setData( doc, '<div><section><article><paragraph>foo[]bar</paragraph></article></section></div>' );

const article = root.getNodeByPath( [ 0, 0, 0 ] );

expect( schema.getLimitElement( doc.selection ) ).to.equal( article );
} );

it( 'returns the limit element which is the closest element to common ancestor for non-collapsed selection', () => {
schema.limits.add( 'article' );
schema.limits.add( 'section' );

setData( doc, '<div><section><article>[foo</article><article>bar]</article></section></div>' );

const section = root.getNodeByPath( [ 0, 0 ] );

expect( schema.getLimitElement( doc.selection ) ).to.equal( section );
} );

it( 'works fine with multi-range selections', () => {
schema.limits.add( 'article' );
schema.limits.add( 'widget' );
schema.limits.add( 'div' );

setData(
doc,
'<div>' +
'<section>' +
'<article>' +
'<paragraph>[foo]</paragraph>' +
'</article>' +
'</section>' +
'<widget>' +
'<image>' +
'<caption>b[a]r</caption>' +
'</image>' +
'</widget>' +
'</div>'
);

const div = root.getNodeByPath( [ 0 ] );
expect( schema.getLimitElement( doc.selection ) ).to.equal( div );
} );

it( 'works fine with multi-range selections even if limit elements are not defined', () => {
schema.limits.clear();

setData(
doc,
'<div>' +
'<section>' +
'<article>' +
'<paragraph>[foo]</paragraph>' +
'</article>' +
'</section>' +
'</div>' +
'<section>b[]ar</section>'
);

expect( schema.getLimitElement( doc.selection ) ).to.equal( root );
} );
} );
} );

0 comments on commit 691e53e

Please sign in to comment.