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

Commit 712ccfc

Browse files
authored
Merge pull request #1115 from ckeditor/t/1114
Feature: Introduced `controller.DataController#hasContent`. Closes #1114.
2 parents e6c5bcf + 37be714 commit 712ccfc

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

src/controller/datacontroller.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import ViewDocumentFragment from '../view/documentfragment';
2222

2323
import ModelRange from '../model/range';
2424
import ModelPosition from '../model/position';
25+
import ModelElement from '../model/element';
2526

2627
import insertContent from './insertcontent';
2728
import deleteContent from './deletecontent';
@@ -297,6 +298,34 @@ export default class DataController {
297298
getSelectedContent( selection ) {
298299
return getSelectedContent( selection );
299300
}
301+
302+
/**
303+
* Checks whether given {@link module:engine/model/range~Range range} or {@link module:engine/model/element~Element element}
304+
* has any content.
305+
*
306+
* Content is any text node or element which is registered in {@link module:engine/model/schema~Schema schema}.
307+
*
308+
* @param {module:engine/model/range~Range|module:engine/model/element~Element} rangeOrElement Range or element to check.
309+
* @returns {Boolean}
310+
*/
311+
hasContent( rangeOrElement ) {
312+
if ( rangeOrElement instanceof ModelElement ) {
313+
rangeOrElement = ModelRange.createIn( rangeOrElement );
314+
}
315+
316+
if ( rangeOrElement.isCollapsed ) {
317+
return false;
318+
}
319+
320+
for ( const item of rangeOrElement.getItems() ) {
321+
// Remember, `TreeWalker` returns always `textProxy` nodes.
322+
if ( item.is( 'textProxy' ) || this.model.schema.objects.has( item.name ) ) {
323+
return true;
324+
}
325+
}
326+
327+
return false;
328+
}
300329
}
301330

302331
mix( DataController, ObservableMixin );

tests/controller/datacontroller.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import buildModelConverter from '../../src/conversion/buildmodelconverter';
1212

1313
import ModelDocumentFragment from '../../src/model/documentfragment';
1414
import ModelText from '../../src/model/text';
15+
import ModelRange from '../../src/model/range';
1516
import ModelSelection from '../../src/model/selection';
1617

1718
import ViewDocumentFragment from '../../src/view/documentfragment';
@@ -439,4 +440,87 @@ describe( 'DataController', () => {
439440
expect( stringify( content ) ).to.equal( 'ob' );
440441
} );
441442
} );
443+
444+
describe( 'hasContent', () => {
445+
let root;
446+
447+
beforeEach( () => {
448+
schema.registerItem( 'paragraph', '$block' );
449+
schema.registerItem( 'div', '$block' );
450+
schema.allow( { name: '$block', inside: 'div' } );
451+
schema.registerItem( 'image' );
452+
schema.allow( { name: 'image', inside: 'div' } );
453+
schema.objects.add( 'image' );
454+
455+
setData(
456+
modelDocument,
457+
458+
'<div>' +
459+
'<paragraph></paragraph>' +
460+
'</div>' +
461+
'<paragraph>foo</paragraph>' +
462+
'<div>' +
463+
'<image></image>' +
464+
'</div>'
465+
);
466+
467+
root = modelDocument.getRoot();
468+
} );
469+
470+
it( 'should return true if given element has text node', () => {
471+
const pFoo = root.getChild( 1 );
472+
473+
expect( data.hasContent( pFoo ) ).to.be.true;
474+
} );
475+
476+
it( 'should return true if given element has element that is an object', () => {
477+
const divImg = root.getChild( 2 );
478+
479+
expect( data.hasContent( divImg ) ).to.be.true;
480+
} );
481+
482+
it( 'should return false if given element has no elements', () => {
483+
const pEmpty = root.getChild( 0 ).getChild( 0 );
484+
485+
expect( data.hasContent( pEmpty ) ).to.be.false;
486+
} );
487+
488+
it( 'should return false if given element has only elements that are not objects', () => {
489+
const divP = root.getChild( 0 );
490+
491+
expect( data.hasContent( divP ) ).to.be.false;
492+
} );
493+
494+
it( 'should return true if there is a text node in given range', () => {
495+
const range = ModelRange.createFromParentsAndOffsets( root, 1, root, 2 );
496+
497+
expect( data.hasContent( range ) ).to.be.true;
498+
} );
499+
500+
it( 'should return true if there is a part of text node in given range', () => {
501+
const pFoo = root.getChild( 1 );
502+
const range = ModelRange.createFromParentsAndOffsets( pFoo, 1, pFoo, 2 );
503+
504+
expect( data.hasContent( range ) ).to.be.true;
505+
} );
506+
507+
it( 'should return true if there is element that is an object in given range', () => {
508+
const divImg = root.getChild( 2 );
509+
const range = ModelRange.createFromParentsAndOffsets( divImg, 0, divImg, 1 );
510+
511+
expect( data.hasContent( range ) ).to.be.true;
512+
} );
513+
514+
it( 'should return false if range is collapsed', () => {
515+
const range = ModelRange.createFromParentsAndOffsets( root, 1, root, 1 );
516+
517+
expect( data.hasContent( range ) ).to.be.false;
518+
} );
519+
520+
it( 'should return false if range has only elements that are not objects', () => {
521+
const range = ModelRange.createFromParentsAndOffsets( root, 0, root, 1 );
522+
523+
expect( data.hasContent( range ) ).to.be.false;
524+
} );
525+
} );
442526
} );

0 commit comments

Comments
 (0)