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

Commit bcdaaa9

Browse files
author
Piotr Jasiun
authored
Merge pull request #1545 from ckeditor/t/ckeditor5/1243
Other: The `model.insertContent()` accepts range and position. Closes ckeditor/ckeditor5#1243.
2 parents 925b799 + 3cb0b59 commit bcdaaa9

File tree

5 files changed

+179
-39
lines changed

5 files changed

+179
-39
lines changed

src/model/model.js

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -275,12 +275,12 @@ export default class Model {
275275
*
276276
* // insertContent() doesn't have to be used in a change() block. It can, though,
277277
* // so this code could be moved to the callback defined above.
278-
* editor.model.insertContent( docFrag, editor.model.document.selection );
278+
* editor.model.insertContent( docFrag );
279279
*
280280
* Using `insertContent()` with HTML string converted to a model document fragment (similar to the pasting mechanism):
281281
*
282282
* // You can create your own HtmlDataProcessor instance or use editor.data.processor
283-
* // if you haven't overriden the default one (which is HtmlDataProcessor instance).
283+
* // if you haven't overridden the default one (which is HtmlDataProcessor instance).
284284
* const htmlDP = new HtmlDataProcessor();
285285
*
286286
* // Convert an HTML string to a view document fragment.
@@ -296,15 +296,43 @@ export default class Model {
296296
* // which has a loosened schema.
297297
* const modelFragment = editor.data.toModel( viewFragment );
298298
*
299-
* editor.model.insertContent( modelFragment, editor.model.document.selection );
299+
* editor.model.insertContent( modelFragment );
300+
*
301+
* By default this method will use the document selection but it can also be used with a position, range or selection instance.
302+
*
303+
* // Insert text at the current document selection position.
304+
* editor.model.change( writer => {
305+
* editor.model.insertContent( writer.createText( 'x' ) );
306+
* } );
307+
*
308+
* // Insert text at given position - document selection will not be modified.
309+
* editor.model.change( writer => {
310+
* editor.model.insertContent( writer.createText( 'x' ), Position.createAt( doc.getRoot(), 2 ) );
311+
* } );
312+
*
313+
* If an instance of {module:engine/model/selection~Selection} is passed as `selectable`
314+
* it will be moved to the target position (where the document selection should be moved after the insertion).
315+
*
316+
* // Insert text replacing given selection instance.
317+
* const selection = new Selection( paragraph, 'in' );
318+
*
319+
* editor.model.change( writer => {
320+
* editor.model.insertContent( writer.createText( 'x' ), selection );
321+
*
322+
* // insertContent() modifies the passed selection instance so it can be used to set the document selection.
323+
* // Note: This is not necessary when you passed document selection to insertContent().
324+
* writer.setSelection( selection );
325+
* } );
300326
*
301327
* @fires insertContent
302328
* @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.
303-
* @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection
304-
* Selection into which the content should be inserted.
329+
* @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
330+
* module:engine/model/position~Position|module:engine/model/element~Element|
331+
* Iterable.<module:engine/model/range~Range>|module:engine/model/range~Range|null} [selectable=model.document.selection]
332+
* Selection into which the content should be inserted. If not provided the current model document selection will be used.
305333
*/
306-
insertContent( content, selection ) {
307-
insertContent( this, content, selection );
334+
insertContent( content, selectable ) {
335+
insertContent( this, content, selectable );
308336
}
309337

310338
/**
@@ -534,6 +562,9 @@ export default class Model {
534562
* The {@link #insertContent default action of that method} is implemented as a
535563
* listener to this event so it can be fully customized by the features.
536564
*
565+
* **Note** The `selectable` parameter for the {@link #insertContent} is optional. When `undefined` value is passed the method uses
566+
* `model.document.selection`.
567+
*
537568
* @event insertContent
538569
* @param {Array} args The arguments passed to the original method.
539570
*/

src/model/selection.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,46 +35,46 @@ export default class Selection {
3535
* or on the given {@link module:engine/model/element~Element element},
3636
* or creates an empty selection if no arguments were passed.
3737
*
38-
* // Creates empty selection without ranges.
38+
* // Creates empty selection without ranges.
3939
* const selection = new Selection();
4040
*
4141
* // Creates selection at the given range.
4242
* const range = new Range( start, end );
4343
* const selection = new Selection( range );
4444
*
4545
* // Creates selection at the given ranges
46-
* const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
46+
* const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
4747
* const selection = new Selection( ranges );
4848
*
4949
* // Creates selection from the other selection.
5050
* // Note: It doesn't copies selection attributes.
5151
* const otherSelection = new Selection();
5252
* const selection = new Selection( otherSelection );
5353
*
54-
* // Creates selection from the given document selection.
54+
* // Creates selection from the given document selection.
5555
* // Note: It doesn't copies selection attributes.
5656
* const documentSelection = new DocumentSelection( doc );
5757
* const selection = new Selection( documentSelection );
5858
*
59-
* // Creates selection at the given position.
59+
* // Creates selection at the given position.
6060
* const position = new Position( root, path );
6161
* const selection = new Selection( position );
6262
*
63-
* // Creates selection at the start position of the given element.
63+
* // Creates selection at the start position of the given element.
6464
* const paragraph = writer.createElement( 'paragraph' );
6565
* const selection = new Selection( paragraph, offset );
6666
*
67-
* // Creates a range inside an {@link module:engine/model/element~Element element} which starts before the
68-
* // first child of that element and ends after the last child of that element.
67+
* // Creates a range inside an {@link module:engine/model/element~Element element} which starts before the
68+
* // first child of that element and ends after the last child of that element.
6969
* const selection = new Selection( paragraph, 'in' );
7070
*
71-
* // Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends
72-
* // just after the item.
71+
* // Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends
72+
* // just after the item.
7373
* const selection = new Selection( paragraph, 'on' );
7474
*
7575
* Selection's constructor allow passing additional options (`'backward'`) as the last argument.
7676
*
77-
* // Creates backward selection.
77+
* // Creates backward selection.
7878
* const selection = new Selection( range, { backward: true } );
7979
*
8080
* @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
@@ -326,32 +326,32 @@ export default class Selection {
326326
* {@link module:engine/model/element~Element element}, {@link module:engine/model/position~Position position},
327327
* {@link module:engine/model/range~Range range}, an iterable of {@link module:engine/model/range~Range ranges} or null.
328328
*
329-
* // Removes all selection's ranges.
329+
* // Removes all selection's ranges.
330330
* selection.setTo( null );
331331
*
332332
* // Sets selection to the given range.
333333
* const range = new Range( start, end );
334334
* selection.setTo( range );
335335
*
336336
* // Sets selection to given ranges.
337-
* const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
337+
* const ranges = [ new Range( start1, end2 ), new Range( star2, end2 ) ];
338338
* selection.setTo( ranges );
339339
*
340340
* // Sets selection to other selection.
341341
* // Note: It doesn't copies selection attributes.
342342
* const otherSelection = new Selection();
343343
* selection.setTo( otherSelection );
344344
*
345-
* // Sets selection to the given document selection.
345+
* // Sets selection to the given document selection.
346346
* // Note: It doesn't copies selection attributes.
347347
* const documentSelection = new DocumentSelection( doc );
348348
* selection.setTo( documentSelection );
349349
*
350-
* // Sets collapsed selection at the given position.
350+
* // Sets collapsed selection at the given position.
351351
* const position = new Position( root, path );
352352
* selection.setTo( position );
353353
*
354-
* // Sets collapsed selection at the position of the given node and an offset.
354+
* // Sets collapsed selection at the position of the given node and an offset.
355355
* selection.setTo( paragraph, offset );
356356
*
357357
* Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of
@@ -365,7 +365,7 @@ export default class Selection {
365365
*
366366
* `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.
367367
*
368-
* // Sets backward selection.
368+
* // Sets backward selection.
369369
* const selection = new Selection( range, { backward: true } );
370370
*
371371
* @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|

src/model/utils/insertcontent.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,39 @@ import Element from '../element';
1313
import Range from '../range';
1414
import log from '@ckeditor/ckeditor5-utils/src/log';
1515
import DocumentSelection from '../documentselection';
16+
import Selection from '../selection';
1617

1718
/**
1819
* Inserts content into the editor (specified selection) as one would expect the paste
1920
* functionality to work.
2021
*
22+
* If an instance of {module:engine/model/selection~Selection} is passed as `selectable` it will be modified
23+
* to the insertion selection (equal to a range to be selected after insertion).
24+
*
2125
* **Note:** Use {@link module:engine/model/model~Model#insertContent} instead of this function.
22-
* This function is only exposed to be reusable in algorithms
23-
* which change the {@link module:engine/model/model~Model#insertContent}
26+
* This function is only exposed to be reusable in algorithms which change the {@link module:engine/model/model~Model#insertContent}
2427
* method's behavior.
2528
*
2629
* @param {module:engine/model/model~Model} model The model in context of which the insertion
2730
* should be performed.
2831
* @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.
29-
* @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection
32+
* @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|
33+
* module:engine/model/position~Position|module:engine/model/element~Element|
34+
* Iterable.<module:engine/model/range~Range>|module:engine/model/range~Range|null} [selectable=model.document.selection]
3035
* Selection into which the content should be inserted.
3136
*/
32-
export default function insertContent( model, content, selection ) {
37+
export default function insertContent( model, content, selectable ) {
3338
model.change( writer => {
39+
let selection;
40+
41+
if ( !selectable ) {
42+
selection = model.document.selection;
43+
} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {
44+
selection = selectable;
45+
} else {
46+
selection = new Selection( selectable );
47+
}
48+
3449
if ( !selection.isCollapsed ) {
3550
model.deleteContent( selection );
3651
}

tests/model/model.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ describe( 'Model', () => {
347347

348348
model.on( 'insertContent', spy );
349349

350-
model.insertContent( new ModelText( 'a' ), model.document.selection );
350+
model.insertContent( new ModelText( 'a' ) );
351351

352352
expect( spy.calledOnce ).to.be.true;
353353
} );
@@ -357,7 +357,7 @@ describe( 'Model', () => {
357357

358358
setData( model, '<paragraph>fo[]ar</paragraph>' );
359359

360-
model.insertContent( new ModelText( 'ob' ), model.document.selection );
360+
model.insertContent( new ModelText( 'ob' ) );
361361

362362
expect( getData( model ) ).to.equal( '<paragraph>foob[]ar</paragraph>' );
363363
} );
@@ -367,7 +367,17 @@ describe( 'Model', () => {
367367

368368
setData( model, '<paragraph>fo[]ar</paragraph>' );
369369

370-
model.insertContent( new ModelDocumentFragment( [ new ModelText( 'ob' ) ] ), model.document.selection );
370+
model.insertContent( new ModelDocumentFragment( [ new ModelText( 'ob' ) ] ) );
371+
372+
expect( getData( model ) ).to.equal( '<paragraph>foob[]ar</paragraph>' );
373+
} );
374+
375+
it( 'should use current model selection if no selectable passed', () => {
376+
schema.register( 'paragraph', { inheritAllFrom: '$block' } );
377+
378+
setData( model, '<paragraph>fo[]ar</paragraph>' );
379+
380+
model.insertContent( new ModelText( 'ob' ) );
371381

372382
expect( getData( model ) ).to.equal( '<paragraph>foob[]ar</paragraph>' );
373383
} );
@@ -377,7 +387,7 @@ describe( 'Model', () => {
377387
setData( model, '<paragraph>[]</paragraph>' );
378388

379389
model.change( writer => {
380-
model.insertContent( new ModelText( 'abc' ), model.document.selection );
390+
model.insertContent( new ModelText( 'abc' ) );
381391
expect( writer.batch.operations ).to.length( 1 );
382392
} );
383393
} );

0 commit comments

Comments
 (0)