diff --git a/src/controller/datacontroller.js b/src/controller/datacontroller.js
index 1b480c713..a9cc4644a 100644
--- a/src/controller/datacontroller.js
+++ b/src/controller/datacontroller.js
@@ -201,7 +201,7 @@ export default class DataController {
const modelRoot = this.model.document.getRoot( rootName );
this.model.enqueueChange( 'transparent', writer => {
- writer.insert( this.parse( data, modelRoot ), modelRoot );
+ writer.insert( this.parse( data, modelRoot ), modelRoot, 0 );
} );
return Promise.resolve();
@@ -228,7 +228,7 @@ export default class DataController {
writer.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );
writer.remove( ModelRange.createIn( modelRoot ) );
- writer.insert( this.parse( data, modelRoot ), modelRoot );
+ writer.insert( this.parse( data, modelRoot ), modelRoot, 0 );
} );
}
diff --git a/src/conversion/upcast-converters.js b/src/conversion/upcast-converters.js
index a5e480765..0cc75a4f3 100644
--- a/src/conversion/upcast-converters.js
+++ b/src/conversion/upcast-converters.js
@@ -358,7 +358,7 @@ function _prepareToElementConverter( config ) {
conversionApi.writer.insert( modelElement, splitResult.position );
// Convert children and insert to element.
- const childrenResult = conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( modelElement ) );
+ const childrenResult = conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( modelElement, 0 ) );
// Consume appropriate value from consumable values list.
conversionApi.consumable.consume( data.viewItem, match.match );
@@ -380,7 +380,7 @@ function _prepareToElementConverter( config ) {
// before: []
// after: []
if ( splitResult.cursorParent ) {
- data.modelCursor = ModelPosition.createAt( splitResult.cursorParent );
+ data.modelCursor = ModelPosition.createAt( splitResult.cursorParent, 0 );
// Otherwise just continue after inserted element.
} else {
diff --git a/src/conversion/upcastdispatcher.js b/src/conversion/upcastdispatcher.js
index 8815deaec..a95c10da5 100644
--- a/src/conversion/upcastdispatcher.js
+++ b/src/conversion/upcastdispatcher.js
@@ -71,7 +71,7 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
* conversionApi.writer.insert( paragraph, splitResult.position );
*
* // Convert children to paragraph.
- * const { modelRange } = conversionApi.convertChildren( data.viewItem, Position.createAt( paragraph ) );
+ * const { modelRange } = conversionApi.convertChildren( data.viewItem, Position.createAt( paragraph, 0 ) );
*
* // Set as conversion result, attribute converters may use this property.
* data.modelRange = new Range( Position.createBefore( paragraph ), modelRange.end );
@@ -419,7 +419,7 @@ function createContextTree( contextDefinition, writer ) {
writer.append( current, position );
}
- position = ModelPosition.createAt( current );
+ position = ModelPosition.createAt( current, 0 );
}
return position;
diff --git a/src/dev-utils/model.js b/src/dev-utils/model.js
index e9de58d83..3bb88fdd2 100644
--- a/src/dev-utils/model.js
+++ b/src/dev-utils/model.js
@@ -391,7 +391,7 @@ function convertToModelElement() {
conversionApi.mapper.bindElements( element, data.viewItem );
- conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( element ) );
+ conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( element, 0 ) );
data.modelRange = ModelRange.createOn( element );
data.modelCursor = data.modelRange.end;
diff --git a/src/model/model.js b/src/model/model.js
index f6532d549..73325102a 100644
--- a/src/model/model.js
+++ b/src/model/model.js
@@ -307,6 +307,9 @@ export default class Model {
*
* // Insert text at given position - document selection will not be modified.
* editor.model.change( writer => {
+ * editor.model.insertContent( writer.createText( 'x' ), doc.getRoot(), 2 );
+ *
+ * // Which is a shorthand for:
* editor.model.insertContent( writer.createText( 'x' ), Position.createAt( doc.getRoot(), 2 ) );
* } );
*
@@ -327,12 +330,14 @@ export default class Model {
* @fires insertContent
* @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.
* @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
- * module:engine/model/position~Position|module:engine/model/element~Element|
+ * module:engine/model/position~Position|module:engine/model/item~Item|
* Iterable.|module:engine/model/range~Range|null} [selectable=model.document.selection]
* Selection into which the content should be inserted. If not provided the current model document selection will be used.
+ * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] To be used when a model item was passed as `selectable`.
+ * This param defines a position in relation to that item.
*/
- insertContent( content, selectable ) {
- insertContent( this, content, selectable );
+ insertContent( content, selectable, placeOrOffset ) {
+ insertContent( this, content, selectable, placeOrOffset );
}
/**
diff --git a/src/model/position.js b/src/model/position.js
index 274f54d6b..eef73ce79 100644
--- a/src/model/position.js
+++ b/src/model/position.js
@@ -816,7 +816,7 @@ export default class Position {
* * {@link module:engine/model/position~Position.createFromPosition}.
*
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/model/item~Item model item}.
*/
static createAt( itemOrPosition, offset ) {
@@ -831,8 +831,16 @@ export default class Position {
return this.createBefore( node );
} else if ( offset == 'after' ) {
return this.createAfter( node );
- } else if ( !offset ) {
- offset = 0;
+ } else if ( offset !== 0 && !offset ) {
+ /**
+ * {@link module:engine/model/position~Position.createAt `Position.createAt()`}
+ * requires the offset to be specified when the first parameter is a model item.
+ *
+ * @error model-position-createAt-offset-required
+ */
+ throw new CKEditorError(
+ 'model-position-createAt-offset-required: ' +
+ 'Position.createAt() requires the offset when the first parameter is a model item.' );
}
return this.createFromParentAndOffset( node, offset );
diff --git a/src/model/range.js b/src/model/range.js
index 61b3d340e..3ccb520b9 100644
--- a/src/model/range.js
+++ b/src/model/range.js
@@ -835,7 +835,7 @@ export default class Range {
* or on the given {@link module:engine/model/item~Item item}.
*
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/model/item~Item model item}.
*/
static createCollapsedAt( itemOrPosition, offset ) {
diff --git a/src/model/schema.js b/src/model/schema.js
index f7fef73f8..53cb22dc7 100644
--- a/src/model/schema.js
+++ b/src/model/schema.js
@@ -1162,7 +1162,7 @@ export class SchemaContext {
* schema.checkChild( contextDefinition, childToCheck );
*
* // Also check in [ rootElement, blockQuoteElement, paragraphElement ].
- * schema.checkChild( Position.createAt( paragraphElement ), 'foo' );
+ * schema.checkChild( Position.createAt( paragraphElement, 0 ), 'foo' );
*
* // Check in [ rootElement, paragraphElement ].
* schema.checkChild( [ rootElement, paragraphElement ], 'foo' );
diff --git a/src/model/selection.js b/src/model/selection.js
index 8524f7e88..d800538a1 100644
--- a/src/model/selection.js
+++ b/src/model/selection.js
@@ -485,7 +485,7 @@ export default class Selection {
*
* @fires change:range
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/model/item~Item model item}.
*/
setFocus( itemOrPosition, offset ) {
@@ -665,7 +665,7 @@ export default class Selection {
const endBlock = getParentBlock( range.end, visited );
// #984. Don't return the end block if the range ends right at its beginning.
- if ( endBlock && !range.end.isTouching( Position.createAt( endBlock ) ) ) {
+ if ( endBlock && !range.end.isTouching( Position.createAt( endBlock, 0 ) ) ) {
yield endBlock;
}
}
@@ -683,7 +683,7 @@ export default class Selection {
* @returns {Boolean}
*/
containsEntireContent( element = this.anchor.root ) {
- const limitStartPosition = Position.createAt( element );
+ const limitStartPosition = Position.createAt( element, 0 );
const limitEndPosition = Position.createAt( element, 'end' );
return limitStartPosition.isTouching( this.getFirstPosition() ) &&
diff --git a/src/model/utils/deletecontent.js b/src/model/utils/deletecontent.js
index 7dfa28579..2828f8365 100644
--- a/src/model/utils/deletecontent.js
+++ b/src/model/utils/deletecontent.js
@@ -208,7 +208,7 @@ function replaceEntireContentWithParagraph( writer, selection ) {
const limitElement = writer.model.schema.getLimitElement( selection );
writer.remove( Range.createIn( limitElement ) );
- insertParagraph( writer, Position.createAt( limitElement ), selection );
+ insertParagraph( writer, Position.createAt( limitElement, 0 ), selection );
}
// We want to replace the entire content with a paragraph when:
diff --git a/src/model/utils/getselectedcontent.js b/src/model/utils/getselectedcontent.js
index 995074aa4..037db1a55 100644
--- a/src/model/utils/getselectedcontent.js
+++ b/src/model/utils/getselectedcontent.js
@@ -99,7 +99,7 @@ export default function getSelectedContent( model, selection ) {
// Find the position of the original range in the cloned fragment.
const newRange = range._getTransformedByMove( flatSubtreeRange.start, Position.createAt( frag, 0 ), howMany )[ 0 ];
- const leftExcessRange = new Range( Position.createAt( frag ), newRange.start );
+ const leftExcessRange = new Range( Position.createAt( frag, 0 ), newRange.start );
const rightExcessRange = new Range( newRange.end, Position.createAt( frag, 'end' ) );
removeRangeContent( rightExcessRange, writer );
diff --git a/src/model/utils/insertcontent.js b/src/model/utils/insertcontent.js
index 17a8fd864..b9db0e9dd 100644
--- a/src/model/utils/insertcontent.js
+++ b/src/model/utils/insertcontent.js
@@ -33,8 +33,9 @@ import Selection from '../selection';
* module:engine/model/position~Position|module:engine/model/element~Element|
* Iterable.|module:engine/model/range~Range|null} [selectable=model.document.selection]
* Selection into which the content should be inserted.
+ * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.
*/
-export default function insertContent( model, content, selectable ) {
+export default function insertContent( model, content, selectable, placeOrOffset ) {
model.change( writer => {
let selection;
@@ -43,7 +44,7 @@ export default function insertContent( model, content, selectable ) {
} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {
selection = selectable;
} else {
- selection = new Selection( selectable );
+ selection = new Selection( selectable, placeOrOffset );
}
if ( !selection.isCollapsed ) {
diff --git a/src/model/utils/selection-post-fixer.js b/src/model/utils/selection-post-fixer.js
index e63cc39ab..bd651509d 100644
--- a/src/model/utils/selection-post-fixer.js
+++ b/src/model/utils/selection-post-fixer.js
@@ -199,8 +199,11 @@ function tryFixingNonCollapsedRage( range, schema ) {
if ( isStartInLimit || isEndInLimit ) {
// Although we've already found limit element on start/end positions we must find the outer-most limit element.
// as limit elements might be nested directly inside (ie table > tableRow > tableCell).
- const fixedStart = isStartInLimit ? expandSelectionOnIsLimitNode( Position.createAt( startLimitElement ), schema, 'start' ) : start;
- const fixedEnd = isEndInLimit ? expandSelectionOnIsLimitNode( Position.createAt( endLimitElement ), schema, 'end' ) : end;
+ const startPosition = Position.createAt( startLimitElement, 0 );
+ const endPosition = Position.createAt( endLimitElement, 0 );
+
+ const fixedStart = isStartInLimit ? expandSelectionOnIsLimitNode( startPosition, schema, 'start' ) : start;
+ const fixedEnd = isEndInLimit ? expandSelectionOnIsLimitNode( endPosition, schema, 'end' ) : end;
return new Range( fixedStart, fixedEnd );
}
diff --git a/src/model/writer.js b/src/model/writer.js
index 9ba588455..9717e72d9 100644
--- a/src/model/writer.js
+++ b/src/model/writer.js
@@ -153,10 +153,10 @@ export default class Writer {
* @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment} item Item or document
* fragment to insert.
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* second parameter is a {@link module:engine/model/item~Item model item}.
*/
- insert( item, itemOrPosition, offset ) {
+ insert( item, itemOrPosition, offset = 0 ) {
this._assertWriterUsedCorrectly();
const position = Position.createAt( itemOrPosition, offset );
@@ -198,7 +198,7 @@ export default class Writer {
if ( item instanceof DocumentFragment ) {
for ( const [ markerName, markerRange ] of item.markers ) {
// We need to migrate marker range from DocumentFragment to Document.
- const rangeRootPosition = Position.createAt( markerRange.root );
+ const rangeRootPosition = Position.createAt( markerRange.root, 0 );
const range = new Range(
markerRange.start._getCombined( rangeRootPosition, position ),
markerRange.end._getCombined( rangeRootPosition, position )
@@ -230,7 +230,7 @@ export default class Writer {
* @param {String} data Text data.
* @param {Object} [attributes] Text attributes.
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* third parameter is a {@link module:engine/model/item~Item model item}.
*/
insertText( text, attributes, itemOrPosition, offset ) {
@@ -262,7 +262,7 @@ export default class Writer {
* @param {String} name Name of the element.
* @param {Object} [attributes] Elements attributes.
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* third parameter is a {@link module:engine/model/item~Item model item}.
*/
insertElement( name, attributes, itemOrPosition, offset ) {
@@ -440,7 +440,7 @@ export default class Writer {
*
* @param {module:engine/model/range~Range} range Source range.
* @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* second parameter is a {@link module:engine/model/item~Item model item}.
*/
move( range, itemOrPosition, offset ) {
@@ -668,7 +668,7 @@ export default class Writer {
return {
position,
- range: new Range( Position.createAt( firstSplitElement, 'end' ), Position.createAt( firstCopyElement ) )
+ range: new Range( Position.createAt( firstSplitElement, 'end' ), Position.createAt( firstCopyElement, 0 ) )
};
}
diff --git a/src/view/documentselection.js b/src/view/documentselection.js
index 9774cb977..9497949d9 100644
--- a/src/view/documentselection.js
+++ b/src/view/documentselection.js
@@ -357,7 +357,7 @@ export default class DocumentSelection {
* @protected
* @fires change
* @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/view/item~Item view item}.
*/
_setFocus( itemOrPosition, offset ) {
diff --git a/src/view/downcastwriter.js b/src/view/downcastwriter.js
index 9645683e1..62d6f64ef 100644
--- a/src/view/downcastwriter.js
+++ b/src/view/downcastwriter.js
@@ -123,7 +123,7 @@ export default class DowncastWriter {
* The location can be specified in the same form as {@link module:engine/view/position~Position.createAt} parameters.
*
* @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/view/item~Item view item}.
*/
setSelectionFocus( itemOrPosition, offset ) {
@@ -915,7 +915,7 @@ export default class DowncastWriter {
const newElement = new ContainerElement( newName, viewElement.getAttributes() );
this.insert( Position.createAfter( viewElement ), newElement );
- this.move( Range.createIn( viewElement ), Position.createAt( newElement ) );
+ this.move( Range.createIn( viewElement ), Position.createAt( newElement, 0 ) );
this.remove( Range.createOn( viewElement ) );
return newElement;
diff --git a/src/view/position.js b/src/view/position.js
index 1ccdd16db..c62eeb225 100644
--- a/src/view/position.js
+++ b/src/view/position.js
@@ -288,8 +288,8 @@ export default class Position {
* * {@link module:engine/view/position~Position.createAfter},
* * {@link module:engine/view/position~Position.createFromPosition}.
*
- * @param {module:engine/view/item~Item|module:engine/model/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/view/item~Item view item}.
*/
static createAt( itemOrPosition, offset ) {
@@ -304,8 +304,16 @@ export default class Position {
return this.createBefore( node );
} else if ( offset == 'after' ) {
return this.createAfter( node );
- } else if ( !offset ) {
- offset = 0;
+ } else if ( offset !== 0 && !offset ) {
+ /**
+ * {@link module:engine/view/position~Position.createAt `Position.createAt()`}
+ * requires the offset to be specified when the first parameter is a view item.
+ *
+ * @error view-position-createAt-offset-required
+ */
+ throw new CKEditorError(
+ 'view-position-createAt-offset-required: ' +
+ 'Position.createAt() requires the offset when the first parameter is a view item.' );
}
return new Position( node, offset );
diff --git a/src/view/range.js b/src/view/range.js
index 3cd170765..75572ca94 100644
--- a/src/view/range.js
+++ b/src/view/range.js
@@ -454,7 +454,7 @@ export default class Range {
* or on the given {@link module:engine/view/item~Item item}.
*
* @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/view/item~Item view item}.
*/
static createCollapsedAt( itemOrPosition, offset ) {
diff --git a/src/view/selection.js b/src/view/selection.js
index e8b00e75a..f6d1190ee 100644
--- a/src/view/selection.js
+++ b/src/view/selection.js
@@ -548,7 +548,7 @@ export default class Selection {
*
* @fires change
* @param {module:engine/view/item~Item|module:engine/view/position~Position} itemOrPosition
- * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when
+ * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when
* first parameter is a {@link module:engine/view/item~Item view item}.
*/
setFocus( itemOrPosition, offset ) {
diff --git a/tests/conversion/upcast-converters.js b/tests/conversion/upcast-converters.js
index 171fed14a..44ed080f3 100644
--- a/tests/conversion/upcast-converters.js
+++ b/tests/conversion/upcast-converters.js
@@ -841,7 +841,7 @@ describe( 'upcast-converters', () => {
const paragraph = conversionApi.writer.createElement( 'paragraph' );
conversionApi.writer.insert( paragraph, data.modelCursor );
- conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( paragraph ) );
+ conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( paragraph, 0 ) );
data.modelRange = ModelRange.createOn( paragraph );
data.modelCursor = data.modelRange.end;
@@ -863,7 +863,7 @@ describe( 'upcast-converters', () => {
new ViewContainerElement( 'div', null, [ new ViewText( 'abc' ), new ViewContainerElement( 'foo' ) ] ),
new ViewContainerElement( 'bar' )
] );
- const position = ModelPosition.createAt( new ModelElement( 'element' ) );
+ const position = ModelPosition.createAt( new ModelElement( 'element' ), 0 );
dispatcher.on( 'documentFragment', convertToModelFragment() );
dispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } );
diff --git a/tests/conversion/upcastdispatcher.js b/tests/conversion/upcastdispatcher.js
index 278077ef1..da6e162c3 100644
--- a/tests/conversion/upcastdispatcher.js
+++ b/tests/conversion/upcastdispatcher.js
@@ -501,7 +501,7 @@ describe( 'UpcastDispatcher', () => {
dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => {
spy();
- const result = conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( rootMock ) );
+ const result = conversionApi.convertChildren( data.viewItem, ModelPosition.createAt( rootMock, 0 ) );
expect( result.modelRange ).to.be.instanceof( ModelRange );
expect( result.modelRange.start.path ).to.deep.equal( [ 0 ] );
@@ -540,7 +540,7 @@ describe( 'UpcastDispatcher', () => {
dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => {
const paragraph = conversionApi.writer.createElement( 'paragraph' );
const span = conversionApi.writer.createElement( 'span' );
- const position = ModelPosition.createAt( paragraph );
+ const position = ModelPosition.createAt( paragraph, 0 );
const result = conversionApi.splitToAllowedParent( span, position );
@@ -572,7 +572,7 @@ describe( 'UpcastDispatcher', () => {
conversionApi.writer.insert( paragraph, section );
conversionApi.writer.insert( span, paragraph );
- const position = ModelPosition.createAt( span );
+ const position = ModelPosition.createAt( span, 0 );
const paragraph2 = conversionApi.writer.createElement( 'paragraph' );
const result = conversionApi.splitToAllowedParent( paragraph2, position );
@@ -597,7 +597,7 @@ describe( 'UpcastDispatcher', () => {
dispatcher.on( 'documentFragment', ( evt, data, conversionApi ) => {
const paragraph = conversionApi.writer.createElement( 'paragraph' );
const span = conversionApi.writer.createElement( 'span' );
- const position = ModelPosition.createAt( paragraph );
+ const position = ModelPosition.createAt( paragraph, 0 );
const result = conversionApi.splitToAllowedParent( span, position );
diff --git a/tests/model/position.js b/tests/model/position.js
index 066f47500..03e7da8ab 100644
--- a/tests/model/position.js
+++ b/tests/model/position.js
@@ -158,17 +158,21 @@ describe( 'Position', () => {
} );
describe( 'createAt()', () => {
+ it( 'should throw if no offset is passed', () => {
+ expect( () => Position.createAt( ul ) ).to.throw( CKEditorError, /model-position-createAt-offset-required/ );
+ } );
+
it( 'should create positions from positions', () => {
const spy = testUtils.sinon.spy( Position, 'createFromPosition' );
- expect( Position.createAt( Position.createAt( ul ) ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
+ expect( Position.createAt( Position.createAt( ul, 0 ) ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
expect( spy.calledOnce ).to.be.true;
} );
it( 'should create positions from node and offset', () => {
- expect( Position.createAt( ul ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
- expect( Position.createAt( li1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 0 ] );
+ expect( Position.createAt( ul, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0 ] );
+ expect( Position.createAt( li1, 0 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 0, 0 ] );
expect( Position.createAt( ul, 1 ) ).to.have.property( 'path' ).that.deep.equals( [ 1, 1 ] );
} );
diff --git a/tests/model/range.js b/tests/model/range.js
index 75883b1a4..87686d599 100644
--- a/tests/model/range.js
+++ b/tests/model/range.js
@@ -176,7 +176,7 @@ describe( 'Range', () => {
describe( 'createCollapsedAt()', () => {
it( 'should return new collapsed range at the given item position', () => {
const item = new Element( 'p', null, new Text( 'foo' ) );
- const range = Range.createCollapsedAt( item );
+ const range = Range.createCollapsedAt( item, 0 );
expect( range.start.parent ).to.equal( item );
expect( range.start.offset ).to.equal( 0 );
diff --git a/tests/model/schema.js b/tests/model/schema.js
index b79a16de7..826ae96d8 100644
--- a/tests/model/schema.js
+++ b/tests/model/schema.js
@@ -394,8 +394,8 @@ describe( 'Schema', () => {
} );
it( 'accepts a schemaContext instance as a context', () => {
- const rootContext = new SchemaContext( Position.createAt( root1 ) );
- const paragraphContext = new SchemaContext( Position.createAt( r1p1 ) );
+ const rootContext = new SchemaContext( Position.createAt( root1, 0 ) );
+ const paragraphContext = new SchemaContext( Position.createAt( r1p1, 0 ) );
expect( schema.checkChild( rootContext, 'paragraph' ) ).to.be.true;
expect( schema.checkChild( rootContext, '$text' ) ).to.be.false;
@@ -405,8 +405,8 @@ describe( 'Schema', () => {
} );
it( 'accepts a position as a context', () => {
- const posInRoot = Position.createAt( root1 );
- const posInParagraph = Position.createAt( r1p1 );
+ const posInRoot = Position.createAt( root1, 0 );
+ const posInParagraph = Position.createAt( r1p1, 0 );
expect( schema.checkChild( posInRoot, 'paragraph' ) ).to.be.true;
expect( schema.checkChild( posInRoot, '$text' ) ).to.be.false;
@@ -486,16 +486,16 @@ describe( 'Schema', () => {
} );
it( 'accepts a position as a context', () => {
- const posInRoot = Position.createAt( root1 );
- const posInParagraph = Position.createAt( r1p1 );
+ const posInRoot = Position.createAt( root1, 0 );
+ const posInParagraph = Position.createAt( r1p1, 0 );
expect( schema.checkAttribute( posInRoot, 'align' ) ).to.be.false;
expect( schema.checkAttribute( posInParagraph, 'align' ) ).to.be.true;
} );
it( 'accepts a schemaContext instance as a context', () => {
- const rootContext = new SchemaContext( Position.createAt( root1 ) );
- const paragraphContext = new SchemaContext( Position.createAt( r1p1 ) );
+ const rootContext = new SchemaContext( Position.createAt( root1, 0 ) );
+ const paragraphContext = new SchemaContext( Position.createAt( r1p1, 0 ) );
expect( schema.checkAttribute( rootContext, 'align' ) ).to.be.false;
expect( schema.checkAttribute( paragraphContext, 'align' ) ).to.be.true;
@@ -1575,7 +1575,7 @@ describe( 'Schema', () => {
it( 'should return position ancestor that allows to insert given node to it', () => {
const node = new Element( 'paragraph' );
- const allowedParent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+ const allowedParent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
expect( allowedParent ).to.equal( r1bQ );
} );
@@ -1583,7 +1583,7 @@ describe( 'Schema', () => {
it( 'should return position ancestor that allows to insert given node to it when position is already i such an element', () => {
const node = new Text( 'text' );
- const parent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+ const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
expect( parent ).to.equal( r1bQp );
} );
@@ -1597,7 +1597,7 @@ describe( 'Schema', () => {
} );
const node = new Element( 'div' );
- const parent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+ const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
expect( parent ).to.null;
} );
@@ -1611,7 +1611,7 @@ describe( 'Schema', () => {
} );
const node = new Element( 'div' );
- const parent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+ const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
expect( parent ).to.null;
} );
@@ -1619,7 +1619,7 @@ describe( 'Schema', () => {
it( 'should return null when there is no allowed ancestor for given position', () => {
const node = new Element( 'section' );
- const parent = schema.findAllowedParent( node, Position.createAt( r1bQp ) );
+ const parent = schema.findAllowedParent( node, Position.createAt( r1bQp, 0 ) );
expect( parent ).to.null;
} );
@@ -2866,7 +2866,7 @@ describe( 'SchemaContext', () => {
} );
it( 'creates context based on a position', () => {
- const pos = Position.createAt( root.getChild( 0 ).getChild( 0 ) );
+ const pos = Position.createAt( root.getChild( 0 ).getChild( 0 ), 0 );
const ctx = new SchemaContext( pos );
expect( ctx.length ).to.equal( 3 );
diff --git a/tests/model/utils/insertcontent.js b/tests/model/utils/insertcontent.js
index b5d451594..0a490cbbc 100644
--- a/tests/model/utils/insertcontent.js
+++ b/tests/model/utils/insertcontent.js
@@ -18,11 +18,13 @@ describe( 'DataController utils', () => {
let model, doc;
describe( 'insertContent', () => {
- it( 'should use parent batch', () => {
+ beforeEach( () => {
model = new Model();
doc = model.document;
doc.createRoot();
+ } );
+ it( 'should use parent batch', () => {
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'x[]x' );
@@ -33,10 +35,6 @@ describe( 'DataController utils', () => {
} );
it( 'should be able to insert content at custom selection', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'a[]bc' );
@@ -49,10 +47,6 @@ describe( 'DataController utils', () => {
} );
it( 'should modify passed selection instance', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'a[]bc' );
@@ -72,10 +66,6 @@ describe( 'DataController utils', () => {
} );
it( 'should be able to insert content at custom position', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'a[]bc' );
@@ -88,10 +78,6 @@ describe( 'DataController utils', () => {
} );
it( 'should be able to insert content at custom range', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'a[]bc' );
@@ -104,10 +90,6 @@ describe( 'DataController utils', () => {
} );
it( 'should be able to insert content at model selection if document selection is passed', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'a[]bc' );
@@ -118,10 +100,6 @@ describe( 'DataController utils', () => {
} );
it( 'should be able to insert content at model selection if none passed', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'a[]bc' );
@@ -131,11 +109,72 @@ describe( 'DataController utils', () => {
} );
} );
- it( 'accepts DocumentFragment', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
+ it( 'should be able to insert content at model element (numeric offset)', () => {
+ model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+
+ setData( model, 'foo[]bar' );
+
+ const element = doc.getRoot().getNodeByPath( [ 1 ] );
+
+ model.change( writer => {
+ const text = writer.createText( 'x' );
+
+ insertContent( model, text, element, 2 );
+
+ expect( getData( model ) ).to.equal( 'foo[]baxr' );
+ } );
+ } );
+
+ it( 'should be able to insert content at model element (offset="in")', () => {
+ model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+
+ setData( model, 'foo[]bar' );
+
+ const element = doc.getRoot().getNodeByPath( [ 1 ] );
+
+ model.change( writer => {
+ const text = writer.createText( 'x' );
+
+ insertContent( model, text, element, 'in' );
+
+ expect( getData( model ) ).to.equal( 'foo[]x' );
+ } );
+ } );
+
+ it( 'should be able to insert content at model element (offset="on")', () => {
+ model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+ model.schema.register( 'foo', { inheritAllFrom: '$block' } );
+
+ setData( model, 'foo[]bar' );
+
+ const element = doc.getRoot().getNodeByPath( [ 1 ] );
+
+ model.change( writer => {
+ const insertElement = writer.createElement( 'foo' );
+
+ insertContent( model, insertElement, element, 'on' );
+
+ expect( getData( model ) ).to.equal( 'foo[]' );
+ } );
+ } );
+
+ it( 'should be able to insert content at model element (offset="end")', () => {
+ model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
+
+ setData( model, 'foo[]bar' );
+
+ const element = doc.getRoot().getNodeByPath( [ 1 ] );
+
+ model.change( writer => {
+ const text = writer.createText( 'x' );
+
+ insertContent( model, text, element, 'end' );
+
+ expect( getData( model ) ).to.equal( 'foo[]barx' );
+ } );
+ } );
+ it( 'accepts DocumentFragment', () => {
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'x[]x' );
@@ -146,10 +185,6 @@ describe( 'DataController utils', () => {
} );
it( 'accepts Text', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
model.schema.extend( '$text', { allowIn: '$root' } );
setData( model, 'x[]x' );
@@ -160,10 +195,6 @@ describe( 'DataController utils', () => {
} );
it( 'should save the reference to the original object', () => {
- model = new Model();
- doc = model.document;
- doc.createRoot();
-
const content = new Element( 'image' );
model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
diff --git a/tests/model/writer.js b/tests/model/writer.js
index 109d78788..c2b400a37 100644
--- a/tests/model/writer.js
+++ b/tests/model/writer.js
@@ -1476,7 +1476,7 @@ describe( 'Writer', () => {
const docFrag = createDocumentFragment();
expect( () => {
- move( range, docFrag );
+ move( range, docFrag, 0 );
} ).to.throw( CKEditorError, /^writer-move-different-document/ );
} );
@@ -2385,7 +2385,7 @@ describe( 'Writer', () => {
const firstParagraph = root.getNodeByPath( [ 1 ] );
const setFocusSpy = sinon.spy( DocumentSelection.prototype, '_setFocus' );
- setSelectionFocus( firstParagraph );
+ setSelectionFocus( firstParagraph, 0 );
expect( setFocusSpy.calledOnce ).to.be.true;
setFocusSpy.restore();
diff --git a/tests/tickets/1281.js b/tests/tickets/1281.js
index e5785fe2a..b45e0b78d 100644
--- a/tests/tickets/1281.js
+++ b/tests/tickets/1281.js
@@ -47,10 +47,10 @@ describe( 'Bug ckeditor5-engine#1281', () => {
expect( selRanges.length ).to.equal( 2 );
- assertPositions( Position.createAt( thirdParagraph ), selRanges[ 0 ].start );
+ assertPositions( Position.createAt( thirdParagraph, 0 ), selRanges[ 0 ].start );
assertPositions( Position.createAt( thirdParagraph, 'end' ), selRanges[ 0 ].end );
- assertPositions( Position.createAt( fourthParagraph ), selRanges[ 1 ].start );
+ assertPositions( Position.createAt( fourthParagraph, 0 ), selRanges[ 1 ].start );
assertPositions( Position.createAt( fourthParagraph, 'end' ), selRanges[ 1 ].end );
} );
diff --git a/tests/view/downcastwriter/writer.js b/tests/view/downcastwriter/writer.js
index 7b24d9778..b9b6a477a 100644
--- a/tests/view/downcastwriter/writer.js
+++ b/tests/view/downcastwriter/writer.js
@@ -22,7 +22,7 @@ describe( 'DowncastWriter', () => {
describe( 'setSelection()', () => {
it( 'should set document view selection', () => {
- const position = ViewPosition.createAt( root );
+ const position = ViewPosition.createAt( root, 0 );
writer.setSelection( position );
const ranges = Array.from( doc.selection.getRanges() );
@@ -33,7 +33,7 @@ describe( 'DowncastWriter', () => {
} );
it( 'should be able to set fake selection', () => {
- const position = ViewPosition.createAt( root );
+ const position = ViewPosition.createAt( root, 0 );
writer.setSelection( position, { fake: true, label: 'foo' } );
expect( doc.selection.isFake ).to.be.true;
@@ -43,7 +43,7 @@ describe( 'DowncastWriter', () => {
describe( 'setSelectionFocus()', () => {
it( 'should use selection._setFocus method internally', () => {
- const position = ViewPosition.createAt( root );
+ const position = ViewPosition.createAt( root, 0 );
writer.setSelection( position );
const spy = sinon.spy( writer.document.selection, '_setFocus' );
diff --git a/tests/view/position.js b/tests/view/position.js
index 9427a32be..70785c04e 100644
--- a/tests/view/position.js
+++ b/tests/view/position.js
@@ -152,12 +152,18 @@ describe( 'Position', () => {
} );
describe( 'createAt', () => {
+ it( 'should throw if no offset is passed', () => {
+ const element = new Element( 'p' );
+
+ expect( () => Position.createAt( element ) ).to.throw( CKEditorError, /view-position-createAt-offset-required/ );
+ } );
+
it( 'should create positions from positions', () => {
const spy = sinon.spy( Position, 'createFromPosition' );
const p = new Element( 'p' );
const position = new Position( p, 0 );
- const created = Position.createAt( position );
+ const created = Position.createAt( position, 0 );
expect( created.isEqual( position ) ).to.be.true;
expect( spy.calledOnce ).to.be.true;
@@ -167,8 +173,8 @@ describe( 'Position', () => {
const foo = new Text( 'foo' );
const p = new Element( 'p', null, foo );
- expect( Position.createAt( foo ).parent ).to.equal( foo );
- expect( Position.createAt( foo ).offset ).to.equal( 0 );
+ expect( Position.createAt( foo, 0 ).parent ).to.equal( foo );
+ expect( Position.createAt( foo, 0 ).offset ).to.equal( 0 );
expect( Position.createAt( foo, 2 ).parent ).to.equal( foo );
expect( Position.createAt( foo, 2 ).offset ).to.equal( 2 );
@@ -572,7 +578,7 @@ describe( 'Position', () => {
} );
it( 'for two positions in the same element returns the element', () => {
- const startMaecenasPosition = Position.createAt( liOl2 );
+ const startMaecenasPosition = Position.createAt( liOl2, 0 );
const beforeTellusPosition = new Position( liOl2, 18 );
test( startMaecenasPosition, beforeTellusPosition, liOl2 );
diff --git a/tests/view/range.js b/tests/view/range.js
index c6c54dd6e..b58a9208c 100644
--- a/tests/view/range.js
+++ b/tests/view/range.js
@@ -690,7 +690,7 @@ describe( 'Range', () => {
describe( 'createCollapsedAt()', () => {
it( 'should return new collapsed range at the given item position', () => {
const item = new Element( 'p', null, new Text( 'foo' ) );
- const range = Range.createCollapsedAt( item );
+ const range = Range.createCollapsedAt( item, 0 );
expect( range.start.parent ).to.equal( item );
expect( range.start.offset ).to.equal( 0 );
diff --git a/tests/view/view/view.js b/tests/view/view/view.js
index 258eeca2e..57647ee1c 100644
--- a/tests/view/view/view.js
+++ b/tests/view/view/view.js
@@ -478,8 +478,8 @@ describe( 'view', () => {
return element;
} );
- writer.insert( ViewPosition.createAt( p ), ui );
- writer.insert( ViewPosition.createAt( viewRoot ), p );
+ writer.insert( ViewPosition.createAt( p, 0 ), ui );
+ writer.insert( ViewPosition.createAt( viewRoot, 0 ), p );
} );
expect( renderingCalled ).to.be.true;