@@ -150,6 +150,8 @@ export default class Writer {
150150 * second parameter is a {@link module:engine/model/item~Item model item}.
151151 */
152152 insert ( item , itemOrPosition , offset ) {
153+ this . _assertWriterUsageCorrectness ( ) ;
154+
153155 const position = Position . createAt ( itemOrPosition , offset ) ;
154156
155157 // For text that has no parent we need to make a WeakInsert.
@@ -315,6 +317,8 @@ export default class Writer {
315317 * Model item or range on which the attribute will be set.
316318 */
317319 setAttribute ( key , value , itemOrRange ) {
320+ this . _assertWriterUsageCorrectness ( ) ;
321+
318322 if ( itemOrRange instanceof Range ) {
319323 setAttributeToRange ( this , key , value , itemOrRange ) ;
320324 } else {
@@ -350,6 +354,8 @@ export default class Writer {
350354 * Model item or range from which the attribute will be removed.
351355 */
352356 removeAttribute ( key , itemOrRange ) {
357+ this . _assertWriterUsageCorrectness ( ) ;
358+
353359 if ( itemOrRange instanceof Range ) {
354360 setAttributeToRange ( this , key , null , itemOrRange ) ;
355361 } else {
@@ -364,6 +370,8 @@ export default class Writer {
364370 * Model item or range from which all attributes will be removed.
365371 */
366372 clearAttributes ( itemOrRange ) {
373+ this . _assertWriterUsageCorrectness ( ) ;
374+
367375 const removeAttributesFromItem = item => {
368376 for ( const attribute of item . getAttributeKeys ( ) ) {
369377 this . removeAttribute ( attribute , item ) ;
@@ -404,6 +412,8 @@ export default class Writer {
404412 * second parameter is a {@link module:engine/model/item~Item model item}.
405413 */
406414 move ( range , itemOrPosition , offset ) {
415+ this . _assertWriterUsageCorrectness ( ) ;
416+
407417 if ( ! ( range instanceof Range ) ) {
408418 /**
409419 * Invalid range to move.
@@ -448,6 +458,8 @@ export default class Writer {
448458 * @param {module:engine/model/item~Item|module:engine/model/range~Range } itemOrRange Model item or range to remove.
449459 */
450460 remove ( itemOrRange ) {
461+ this . _assertWriterUsageCorrectness ( ) ;
462+
451463 const addRemoveDelta = ( position , howMany ) => {
452464 const delta = new RemoveDelta ( ) ;
453465 this . batch . addDelta ( delta ) ;
@@ -489,6 +501,8 @@ export default class Writer {
489501 * @param {module:engine/model/position~Position } position Position of merge.
490502 */
491503 merge ( position ) {
504+ this . _assertWriterUsageCorrectness ( ) ;
505+
492506 const delta = new MergeDelta ( ) ;
493507 this . batch . addDelta ( delta ) ;
494508
@@ -542,6 +556,8 @@ export default class Writer {
542556 * @param {String } newName New element name.
543557 */
544558 rename ( element , newName ) {
559+ this . _assertWriterUsageCorrectness ( ) ;
560+
545561 if ( ! ( element instanceof Element ) ) {
546562 /**
547563 * Trying to rename an object which is not an instance of Element.
@@ -570,6 +586,8 @@ export default class Writer {
570586 * @param {module:engine/model/position~Position } position Position of split.
571587 */
572588 split ( position ) {
589+ this . _assertWriterUsageCorrectness ( ) ;
590+
573591 const delta = new SplitDelta ( ) ;
574592 this . batch . addDelta ( delta ) ;
575593
@@ -616,6 +634,8 @@ export default class Writer {
616634 * @param {module:engine/model/element~Element|String } elementOrString Element or name of element to wrap the range with.
617635 */
618636 wrap ( range , elementOrString ) {
637+ this . _assertWriterUsageCorrectness ( ) ;
638+
619639 if ( ! range . isFlat ) {
620640 /**
621641 * Range to wrap is not flat.
@@ -670,6 +690,8 @@ export default class Writer {
670690 * @param {module:engine/model/element~Element } element Element to unwrap.
671691 */
672692 unwrap ( element ) {
693+ this . _assertWriterUsageCorrectness ( ) ;
694+
673695 if ( element . parent === null ) {
674696 /**
675697 * Trying to unwrap an element which has no parent.
@@ -722,6 +744,8 @@ export default class Writer {
722744 * @param {module:engine/model/range~Range } [newRange] Marker range.
723745 */
724746 setMarker ( markerOrName , newRange ) {
747+ this . _assertWriterUsageCorrectness ( ) ;
748+
725749 const name = typeof markerOrName == 'string' ? markerOrName : markerOrName . name ;
726750 const currentMarker = this . model . markers . get ( name ) ;
727751
@@ -752,6 +776,8 @@ export default class Writer {
752776 * @param {module:engine/model/markercollection~Marker|String } markerOrName Marker or marker name to remove.
753777 */
754778 removeMarker ( markerOrName ) {
779+ this . _assertWriterUsageCorrectness ( ) ;
780+
755781 const name = typeof markerOrName == 'string' ? markerOrName : markerOrName . name ;
756782
757783 if ( ! this . model . markers . has ( name ) ) {
@@ -767,6 +793,23 @@ export default class Writer {
767793
768794 addMarkerOperation ( this , name , oldRange , null ) ;
769795 }
796+
797+ /**
798+ * Throws `writer-detached-writer-tries-to-modify-model` error when the writer is used outside of the `change()` block.
799+ *
800+ * @private
801+ */
802+ _assertWriterUsageCorrectness ( ) {
803+ /**
804+ * Detached writer tries to modify the model. Be sure, that your Writer is used
805+ * within the `model.change()` or `model.enqueueChange()` block.
806+ *
807+ * @error writer-detached-writer-tries-to-modify-model
808+ */
809+ if ( this . model . _currentWriter !== this ) {
810+ throw new CKEditorError ( 'writer-detached-writer-tries-to-modify-model: Detached writer tries to modify the model.' ) ;
811+ }
812+ }
770813}
771814
772815// Sets given attribute to each node in given range. When attribute value is null then attribute will be removed.
0 commit comments