{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/splitoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/insertoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/operationfactory.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/moveoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/rootattributeoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/operation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/detachoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/attributeoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/nooperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/transform.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/renameoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/mergeoperation.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/utils.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/markeroperation.js"],"names":["SplitOperation","splitPosition","howMany","insertionPosition","graveyardPosition","baseVersion","clone","stickiness","this","constructor","graveyard","root","document","Position","MergeOperation","moveTargetPosition","element","parent","offset","maxOffset","CKEditorError","nodeAfter","splitElement","_move","Range","_createFromPositionAndShift","newElement","_clone","_insert","sourceRange","_createAt","json","toJSON","path","slice","push","end","getShiftedBy","Number","POSITIVE_INFINITY","length","fromJSON","Operation","InsertOperation","position","nodes","NodeList","_normalizeNodes","shouldReceiveAttributes","map","node","insert","gyPosition","MoveOperation","targetElement","originalNodes","children","child","name","Element","Text","operations","AttributeOperation","className","MarkerOperation","NoOperation","RenameOperation","RootAttributeOperation","OperationFactory","__className","sourcePosition","targetPosition","_getTransformedByDeletion","newTargetPosition","_getTransformedByInsertion","getMovedRangeStart","sourceElement","sourceOffset","targetOffset","compareArrays","getParentPath","i","rootName","key","oldValue","newValue","is","getAttribute","hasAttribute","_setAttribute","_removeAttribute","getRoot","isDocumentOperation","batch","Object","assign","DetachOperation","_remove","range","undefined","isFlat","getItems","shallow","item","isEqual","value","transformations","Map","setTransformation","OperationA","OperationB","transformationFunction","aGroup","get","set","getTransformation","has","noUpdateTransformation","a","transform","b","context","e","transformSets","operationsA","operationsB","options","contextFactory","ContextFactory","useRelations","forceWeakRemove","setOriginalOperations","originalOperations","nextTransformIndex","WeakMap","op","data","nextBaseVersionA","nextBaseVersionB","originalOperationsACount","originalOperationsBCount","opA","indexB","opB","newOpsA","getContext","newOpsB","updateRelation","newOpA","splice","padWithNoOps","brokenOperationsACount","brokenOperationsBCount","updateBaseVersions","_history","history","_useRelations","_forceWeakRemove","_relations","takeFrom","originalOperation","operation","movedRange","containsPosition","_setRelation","deletionPosition","isAfter","isBefore","hasSameParentAs","start","markerRange","newRange","affectedLeft","affectedRight","containsRange","side","wasInLeftElement","wasStartBeforeMergedElement","wasEndBeforeMergedElement","wasInRightElement","aIsStrong","aWasUndone","_wasUndone","bWasUndone","abRelation","_getRelation","baRelation","originalOp","wasUndone","isUndoneOperation","origB","undoneB","getUndoneOperation","origA","relationsA","relation","_getComplementaryAttributeOperations","insertOperation","insertValue","getNode","_breakRangeByMoveOperation","moveOp","moveRange","common","difference","getDifference","getIntersection","result","diff","spread","_getTransformedByMove","_moveTargetIntoMovedRange","_makeMoveOperationsFromRanges","ranges","j","r","unshift","_getTransformedByMergeOperation","isCollapsed","secondPart","_getCombined","_getTransformedBySplitOperation","_getTransformedByInsertOperation","_getTransformedByMoveOperation","oldRange","_createFromRanges","aNewRange","aToGraveyard","bToGraveyard","aIsWeak","bIsWeak","forceMove","removedRange","type","mergeInside","mergeSplittingElement","transformed","rangeA","rangeB","insertBefore","getReversed","bTargetsToA","aTargetsToB","aCompB","shouldSpread","newRanges","rightRange","movesGraveyardElement","results","gyMoveSource","splitNodesMoveSource","gyMoveTarget","gyMove","splitNodesMoveTargetPath","splitNodesMoveTarget","splitNodesMove","oldName","newName","renamePath","splitPath","extraRename","getInsertionPosition","additionalSplit","rangeToMove","gyElementMoved","newParentPosition","newTargetPath","splitAtTarget","howManyRemoved","aInGraveyard","bInGraveyard","newPositionPath","newPosition","mergedElement","_createIn","_createOn","reduce","sum","offsetSize","_splitNodeAtPosition","index","_insertChild","_mergeNodesAtIndex","removed","_removeChildren","textNode","normalized","Array","TextProxy","getAttributes","DocumentFragment","Node","prev","_haveSameAttributes","nodeBefore","getChild","mergedNode","offsetDiff","startOffset","firstPart","substr","nodeA","nodeB","iteratorA","iteratorB","attr","next","done","markers","affectsData","_markers","model"],"mappings":"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","file":"js/chunk-vendors~63d7cf05.d8d5f3ef.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/splitoperation\n */\n\nimport Operation from './operation';\nimport MergeOperation from './mergeoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _insert, _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to split {@link module:engine/model/element~Element an element} at given\n * {@link module:engine/model/operation/splitoperation~SplitOperation#splitPosition split position} into two elements,\n * both containing a part of the element's original content.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class SplitOperation extends Operation {\n\t/**\n\t * Creates a split operation.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition Position at which an element should be split.\n\t * @param {Number} howMany Total offset size of elements that are in the split element after `position`.\n\t * @param {module:engine/model/position~Position} insertionPosition Position at which the clone of split element\n\t * (or element from graveyard) will be inserted.\n\t * @param {module:engine/model/position~Position|null} graveyardPosition Position in the graveyard root before the element which\n\t * should be used as a parent of the nodes after `position`. If it is not set, a copy of the the `position` parent will be used.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( splitPosition, howMany, insertionPosition, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position at which an element should be split.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#splitPosition\n\t\t */\n\t\tthis.splitPosition = splitPosition.clone();\n\t\t// Keep position sticking to the next node. This way any new content added at the place where the element is split\n\t\t// will be left in the original element.\n\t\tthis.splitPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Total offset size of elements that are in the split element after `position`.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/splitoperation~SplitOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which the clone of split element (or element from graveyard) will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#insertionPosition\n\t\t */\n\t\tthis.insertionPosition = insertionPosition;\n\n\t\t/**\n\t\t * Position in the graveyard root before the element which should be used as a parent of the nodes after `position`.\n\t\t * If it is not set, a copy of the the `position` parent will be used.\n\t\t *\n\t\t * The default behavior is to clone the split element. Element from graveyard is used during undo.\n\t\t *\n\t\t * @member {module:engine/model/position~Position|null} #graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition ? graveyardPosition.clone() : null;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tthis.graveyardPosition.stickiness = 'toNext';\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'split';\n\t}\n\n\t/**\n\t * Position inside the new clone of a split element.\n\t *\n\t * This is a position where nodes that are after the split position will be moved to.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget moveTargetPosition() {\n\t\tconst path = this.insertionPosition.path.slice();\n\t\tpath.push( 0 );\n\n\t\treturn new Position( this.insertionPosition.root, path );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the split element that will be moved to the new element.\n\t * The range starts at {@link ~#splitPosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.splitPosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.splitPosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.splitPosition, this.howMany, this.insertionPosition, this.graveyardPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.splitPosition.root.document.graveyard;\n\t\tconst graveyardPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MergeOperation( this.moveTargetPosition, this.howMany, this.splitPosition, graveyardPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.splitPosition.parent;\n\t\tconst offset = this.splitPosition.offset;\n\n\t\t// Validate whether split operation has correct parameters.\n\t\tif ( !element || element.maxOffset < offset ) {\n\t\t\t/**\n\t\t\t * Split position is invalid.\n\t\t\t *\n\t\t\t * @error split-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-position-invalid', this );\n\t\t} else if ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Cannot split root element.\n\t\t\t *\n\t\t\t * @error split-operation-split-in-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-split-in-root', this );\n\t\t} else if ( this.howMany != element.maxOffset - this.splitPosition.offset ) {\n\t\t\t/**\n\t\t\t * Split operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error split-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-how-many-invalid', this );\n\t\t} else if ( this.graveyardPosition && !this.graveyardPosition.nodeAfter ) {\n\t\t\t/**\n\t\t\t * Graveyard position invalid.\n\t\t\t *\n\t\t\t * @error split-operation-graveyard-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-graveyard-position-invalid', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst splitElement = this.splitPosition.parent;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\t_move( Range._createFromPositionAndShift( this.graveyardPosition, 1 ), this.insertionPosition );\n\t\t} else {\n\t\t\tconst newElement = splitElement._clone();\n\n\t\t\t_insert( this.insertionPosition, newElement );\n\t\t}\n\n\t\tconst sourceRange = new Range(\n\t\t\tPosition._createAt( splitElement, this.splitPosition.offset ),\n\t\t\tPosition._createAt( splitElement, splitElement.maxOffset )\n\t\t);\n\n\t\t_move( sourceRange, this.moveTargetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.splitPosition = this.splitPosition.toJSON();\n\t\tjson.insertionPosition = this.insertionPosition.toJSON();\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tjson.graveyardPosition = this.graveyardPosition.toJSON();\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'SplitOperation';\n\t}\n\n\t/**\n\t * Helper function that returns a default insertion position basing on given `splitPosition`. The default insertion\n\t * position is after the split element.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tstatic getInsertionPosition( splitPosition ) {\n\t\tconst path = splitPosition.path.slice( 0, -1 );\n\t\tpath[ path.length - 1 ]++;\n\n\t\treturn new Position( splitPosition.root, path, 'toPrevious' );\n\t}\n\n\t/**\n\t * Creates `SplitOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst splitPosition = Position.fromJSON( json.splitPosition, document );\n\t\tconst insertionPosition = Position.fromJSON( json.insertionPosition, document );\n\t\tconst graveyardPosition = json.graveyardPosition ? Position.fromJSON( json.graveyardPosition, document ) : null;\n\n\t\treturn new this( splitPosition, json.howMany, insertionPosition, graveyardPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `SplitOperation( ${ this.baseVersion } ): ${ this.splitPosition } ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`( ${ this.howMany } ) -> ${ this.insertionPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.graveyardPosition ? ' with ' + this.graveyardPosition : '' }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/insertoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport NodeList from '../nodelist';\nimport MoveOperation from './moveoperation';\nimport { _insert, _normalizeNodes } from './utils';\nimport Text from '../text';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to insert one or more nodes at given position in the model.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class InsertOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} position Position of insertion.\n\t * @param {module:engine/model/node~NodeSet} nodes The list of nodes to be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, nodes, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position of insertion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/insertoperation~InsertOperation#position\n\t\t */\n\t\tthis.position = position.clone();\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * List of nodes to insert.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/operation/insertoperation~InsertOperation#nodeList\n\t\t */\n\t\tthis.nodes = new NodeList( _normalizeNodes( nodes ) );\n\n\t\t/**\n\t\t * Flag deciding how the operation should be transformed. If set to `true`, nodes might get additional attributes\n\t\t * during operational transformation. This happens when the operation insertion position is inside of a range\n\t\t * where attributes have changed.\n\t\t *\n\t\t * @member {Boolean} module:engine/model/operation/insertoperation~InsertOperation#shouldReceiveAttributes\n\t\t */\n\t\tthis.shouldReceiveAttributes = false;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'insert';\n\t}\n\n\t/**\n\t * Total offset size of inserted nodes.\n\t *\n\t * @returns {Number}\n\t */\n\tget howMany() {\n\t\treturn this.nodes.maxOffset;\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\tconst nodes = new NodeList( [ ...this.nodes ].map( node => node._clone( true ) ) );\n\t\tconst insert = new InsertOperation( this.position, nodes, this.baseVersion );\n\n\t\tinsert.shouldReceiveAttributes = this.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.position.root.document.graveyard;\n\t\tconst gyPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MoveOperation( this.position, this.nodes.maxOffset, gyPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst targetElement = this.position.parent;\n\n\t\tif ( !targetElement || targetElement.maxOffset < this.position.offset ) {\n\t\t\t/**\n\t\t\t * Insertion position is invalid.\n\t\t\t *\n\t\t\t * @error insert-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'insert-operation-position-invalid',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// What happens here is that we want original nodes be passed to writer because we want original nodes\n\t\t// to be inserted to the model. But in InsertOperation, we want to keep those nodes as they were added\n\t\t// to the operation, not modified. For example, text nodes can get merged or cropped while Elements can\n\t\t// get children. It is important that InsertOperation has the copy of original nodes in intact state.\n\t\tconst originalNodes = this.nodes;\n\t\tthis.nodes = new NodeList( [ ...originalNodes ].map( node => node._clone( true ) ) );\n\n\t\t_insert( this.position, originalNodes );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\t\tjson.nodes = this.nodes.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'InsertOperation';\n\t}\n\n\t/**\n\t * Creates `InsertOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst children = [];\n\n\t\tfor ( const child of json.nodes ) {\n\t\t\tif ( child.name ) {\n\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t} else {\n\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t}\n\t\t}\n\n\t\tconst insert = new InsertOperation( Position.fromJSON( json.position, document ), children, json.baseVersion );\n\t\tinsert.shouldReceiveAttributes = json.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst nodeString = this.nodes.length > 1 ? `[ ${ this.nodes.length } ]` : this.nodes.getNode( 0 );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `InsertOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ this.position }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/operationfactory\n */\n\nimport AttributeOperation from '../operation/attributeoperation';\nimport InsertOperation from '../operation/insertoperation';\nimport MarkerOperation from '../operation/markeroperation';\nimport MoveOperation from '../operation/moveoperation';\nimport NoOperation from '../operation/nooperation';\nimport Operation from '../operation/operation';\nimport RenameOperation from '../operation/renameoperation';\nimport RootAttributeOperation from '../operation/rootattributeoperation';\nimport SplitOperation from '../operation/splitoperation';\nimport MergeOperation from '../operation/mergeoperation';\n\nconst operations = {};\noperations[ AttributeOperation.className ] = AttributeOperation;\noperations[ InsertOperation.className ] = InsertOperation;\noperations[ MarkerOperation.className ] = MarkerOperation;\noperations[ MoveOperation.className ] = MoveOperation;\noperations[ NoOperation.className ] = NoOperation;\noperations[ Operation.className ] = Operation;\noperations[ RenameOperation.className ] = RenameOperation;\noperations[ RootAttributeOperation.className ] = RootAttributeOperation;\noperations[ SplitOperation.className ] = SplitOperation;\noperations[ MergeOperation.className ] = MergeOperation;\n\n/**\n * A factory class for creating operations.\n *\n * @abstract\n */\nexport default class OperationFactory {\n\t/**\n\t * Creates an operation instance from a JSON object (parsed JSON string).\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn operations[ json.__className ].fromJSON( json, document );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/moveoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport { _move } from './utils';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to move a range of {@link module:engine/model/item~Item model items}\n * to given {@link module:engine/model/position~Position target position}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MoveOperation extends Operation {\n\t/**\n\t * Creates a move operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t * @param {module:engine/model/position~Position} targetPosition Position at which moved nodes will be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// `'toNext'` because `sourcePosition` is a bit like a start of the moved range.\n\t\tthis.sourcePosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/moveoperation~MoveOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which moved nodes will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\tthis.targetPosition.stickiness = 'toNone';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.targetPosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'remove';\n\t\t} else if ( this.sourcePosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'reinsert';\n\t\t}\n\n\t\treturn 'move';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * Returns the start position of the moved range after it got moved. This may be different than\n\t * {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition} in some cases, i.e. when a range is moved\n\t * inside the same parent but {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition targetPosition}\n\t * is after {@link module:engine/model/operation/moveoperation~MoveOperation#sourcePosition sourcePosition}.\n\t *\n\t *\t\t vv vv\n\t *\t\tabcdefg ===> adefbcg\n\t *\t\t ^ ^\n\t *\t\t targetPos\tmovedRangeStart\n\t *\t\t offset 6\toffset 4\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetMovedRangeStart() {\n\t\treturn this.targetPosition._getTransformedByDeletion( this.sourcePosition, this.howMany );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst newTargetPosition = this.sourcePosition._getTransformedByInsertion( this.targetPosition, this.howMany );\n\n\t\treturn new this.constructor( this.getMovedRangeStart(), this.howMany, newTargetPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\t\tconst sourceOffset = this.sourcePosition.offset;\n\t\tconst targetOffset = this.targetPosition.offset;\n\n\t\t// Validate whether move operation has correct parameters.\n\t\t// Validation is pretty complex but move operation is one of the core ways to manipulate the document state.\n\t\t// We expect that many errors might be connected with one of scenarios described below.\n\t\tif ( sourceOffset + this.howMany > sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * The nodes which should be moved do not exist.\n\t\t\t *\n\t\t\t * @error move-operation-nodes-do-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-nodes-do-not-exist', this\n\t\t\t);\n\t\t} else if ( sourceElement === targetElement && sourceOffset < targetOffset && targetOffset < sourceOffset + this.howMany ) {\n\t\t\t/**\n\t\t\t * Trying to move a range of nodes into the middle of that range.\n\t\t\t *\n\t\t\t * @error move-operation-range-into-itself\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-range-into-itself', this\n\t\t\t);\n\t\t} else if ( this.sourcePosition.root == this.targetPosition.root ) {\n\t\t\tif ( compareArrays( this.sourcePosition.getParentPath(), this.targetPosition.getParentPath() ) == 'prefix' ) {\n\t\t\t\tconst i = this.sourcePosition.path.length - 1;\n\n\t\t\t\tif ( this.targetPosition.path[ i ] >= sourceOffset && this.targetPosition.path[ i ] < sourceOffset + this.howMany ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Trying to move a range of nodes into one of nodes from that range.\n\t\t\t\t\t *\n\t\t\t\t\t * @error move-operation-node-into-itself\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'move-operation-node-into-itself', this\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_move( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\t\tjson.targetPosition = this.targetPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MoveOperation';\n\t}\n\n\t/**\n\t * Creates `MoveOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `MoveOperation( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/rootattributeoperation\n */\n\nimport Operation from './operation';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to change root element's attribute. Using this class you can add, remove or change value of the attribute.\n *\n * This operation is needed, because root elements can't be changed through\n * @link module:engine/model/operation/attributeoperation~AttributeOperation}.\n * It is because {@link module:engine/model/operation/attributeoperation~AttributeOperation}\n * requires a range to change and root element can't\n * be a part of range because every {@link module:engine/model/position~Position} has to be inside a root.\n * {@link module:engine/model/position~Position} can't be created before a root element.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RootAttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes on root element.\n\t *\n\t * @see module:engine/model/operation/attributeoperation~AttributeOperation\n\t * @param {module:engine/model/rootelement~RootElement} root Root element to change.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null` if adding a new attribute.\n\t * @param {*} newValue New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( root, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Root element to change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/rootelement~RootElement}\n\t\t */\n\t\tthis.root = root;\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null` if adding a new attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue;\n\n\t\t/**\n\t\t * New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addRootAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeRootAttribute';\n\t\t} else {\n\t\t\treturn 'changeRootAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.root != this.root.root || this.root.is( 'documentFragment' ) ) {\n\t\t\t/**\n\t\t\t * The element to change is not a root element.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-not-a-root\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-not-a-root',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue !== null && this.root.getAttribute( this.key ) !== this.oldValue ) {\n\t\t\t/**\n\t\t\t * The attribute which should be removed does not exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-wrong-old-value\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-wrong-old-value',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue === null && this.newValue !== null && this.root.hasAttribute( this.key ) ) {\n\t\t\t/**\n\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-attribute-exists\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-attribute-exists',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tif ( this.newValue !== null ) {\n\t\t\tthis.root._setAttribute( this.key, this.newValue );\n\t\t} else {\n\t\t\tthis.root._removeAttribute( this.key );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.root = this.root.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RootAttributeOperation';\n\t}\n\n\t/**\n\t * Creates RootAttributeOperation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tif ( !document.getRoot( json.root ) ) {\n\t\t\t/**\n\t\t\t * Cannot create RootAttributeOperation for document. Root with specified name does not exist.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-fromjson-no-root\n\t\t\t * @param {String} rootName\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'rootattribute-operation-fromjson-no-root', this, { rootName: json.root } );\n\t\t}\n\n\t\treturn new RootAttributeOperation( document.getRoot( json.root ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RootAttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.root.rootName }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/operation\n */\n\n/**\n * Abstract base operation class.\n *\n * @abstract\n */\nexport default class Operation {\n\t/**\n\t * Base operation constructor.\n\t *\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( baseVersion ) {\n\t\t/**\n\t\t * {@link module:engine/model/document~Document#version} on which operation can be applied. If you try to\n\t\t * {@link module:engine/model/model~Model#applyOperation apply} operation with different base version than the\n\t\t * {@link module:engine/model/document~Document#version document version} the\n\t\t * {@link module:utils/ckeditorerror~CKEditorError model-document-applyOperation-wrong-version} error is thrown.\n\t\t *\n\t\t * @member {Number}\n\t\t */\n\t\tthis.baseVersion = baseVersion;\n\n\t\t/**\n\t\t * Defines whether operation is executed on attached or detached {@link module:engine/model/item~Item items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isDocumentOperation\n\t\t */\n\t\tthis.isDocumentOperation = this.baseVersion !== null;\n\n\t\t/**\n\t\t * {@link module:engine/model/batch~Batch Batch} to which the operation is added or `null` if the operation is not\n\t\t * added to any batch yet.\n\t\t *\n\t\t * @member {module:engine/model/batch~Batch|null} #batch\n\t\t */\n\t\tthis.batch = null;\n\n\t\t/**\n\t\t * Operation type.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #type\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns an operation that has the same parameters as this operation.\n\t\t *\n\t\t * @method #clone\n\t\t * @returns {module:engine/model/operation/operation~Operation} Clone of this operation.\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns a reverse operation. Reverse operation when executed right after\n\t\t * the original operation will bring back tree model state to the point before the original\n\t\t * operation execution. In other words, it reverses changes done by the original operation.\n\t\t *\n\t\t * Keep in mind that tree model state may change since executing the original operation,\n\t\t * so reverse operation will be \"outdated\". In that case you will need to transform it by\n\t\t * all operations that were executed after the original operation.\n\t\t *\n\t\t * @method #getReversed\n\t\t * @returns {module:engine/model/operation/operation~Operation} Reversed operation.\n\t\t */\n\n\t\t/**\n\t\t * Executes the operation - modifications described by the operation properties will be applied to the model tree.\n\t\t *\n\t\t * @protected\n\t\t * @method #_execute\n\t\t */\n\t}\n\n\t/**\n\t * Checks whether the operation's parameters are correct and the operation can be correctly executed. Throws\n\t * an error if operation is not valid.\n\t *\n\t * @protected\n\t * @method #_validate\n\t */\n\t_validate() {\n\t}\n\n\t/**\n\t * Custom toJSON method to solve child-parent circular dependencies.\n\t *\n\t * @method #toJSON\n\t * @returns {Object} Clone of this object with the operation property replaced with string.\n\t */\n\ttoJSON() {\n\t\t// This method creates only a shallow copy, all nested objects should be defined separately.\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1477.\n\t\tconst json = Object.assign( {}, this );\n\n\t\tjson.__className = this.constructor.className;\n\n\t\t// Remove reference to the parent `Batch` to avoid circular dependencies.\n\t\tdelete json.batch;\n\n\t\t// Only document operations are shared with other clients so it is not necessary to keep this information.\n\t\tdelete json.isDocumentOperation;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Name of the operation class used for serialization.\n\t *\n\t * @type {String}\n\t */\n\tstatic get className() {\n\t\treturn 'Operation';\n\t}\n\n\t/**\n\t * Creates Operation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} doc Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new this( json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.toString() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/detachoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport { _remove } from './utils';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to permanently remove node from detached root.\n * Note this operation is only a local operation and won't be send to the other clients.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class DetachOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t */\n\tconstructor( sourcePosition, howMany ) {\n\t\tsuper( null );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to detach.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} #sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} #howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'detach';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.sourcePosition.root.document ) {\n\t\t\t/**\n\t\t\t * Cannot detach document node.\n\t\t\t *\n\t\t\t * @error detach-operation-on-document-node\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'detach-operation-on-document-node', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_remove( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'DetachOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\t// @if CK_DEBUG_ENGINE //\tconst nodes = Array.from( range.getItems() );\n\t// @if CK_DEBUG_ENGINE //\tconst nodeString = nodes.length > 1 ? `[ ${ nodes.length } ]` : nodes[ 0 ];\n\n\t// @if CK_DEBUG_ENGINE //\treturn `DetachOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/attributeoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport { _setAttribute } from './utils';\nimport { isEqual } from 'lodash-es';\n\n/**\n * Operation to change nodes' attribute.\n *\n * Using this class you can add, remove or change value of the attribute.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class AttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes.\n\t *\n\t * If only `newValue` is set, attribute will be added on a node. Note that all nodes in operation's range must not\n\t * have an attribute with the same key as the added attribute.\n\t *\n\t * If only `oldValue` is set, then attribute with given key will be removed. Note that all nodes in operation's range\n\t * must have an attribute with that key added.\n\t *\n\t * If both `newValue` and `oldValue` are set, then the operation will change the attribute value. Note that all nodes in\n\t * operation's ranges must already have an attribute with given key and `oldValue` as value\n\t *\n\t * @param {module:engine/model/range~Range} range Range on which the operation should be applied. Must be a flat range.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null`, if attribute was not set before.\n\t * @param {*} newValue New value of the attribute with given key or `null`, if operation should remove attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( range, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Range on which operation should be applied.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.range = range.clone();\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null`, if attribute was not set before.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue === undefined ? null : oldValue;\n\n\t\t/**\n\t\t * New value of the attribute with given key or `null`, if operation should remove attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue === undefined ? null : newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeAttribute';\n\t\t} else {\n\t\t\treturn 'changeAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new AttributeOperation( this.range, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new AttributeOperation( this.range, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.range = this.range.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( !this.range.isFlat ) {\n\t\t\t/**\n\t\t\t * The range to change is not flat.\n\t\t\t *\n\t\t\t * @error attribute-operation-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'attribute-operation-range-not-flat', this );\n\t\t}\n\n\t\tfor ( const item of this.range.getItems( { shallow: true } ) ) {\n\t\t\tif ( this.oldValue !== null && !isEqual( item.getAttribute( this.key ), this.oldValue ) ) {\n\t\t\t\t/**\n\t\t\t\t * Changed node has different attribute value than operation's old attribute value.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-wrong-old-value\n\t\t\t\t * @param {module:engine/model/item~Item} item\n\t\t\t\t * @param {String} key\n\t\t\t\t * @param {*} value\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-wrong-old-value',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ item, key: this.key, value: this.oldValue }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( this.oldValue === null && this.newValue !== null && item.hasAttribute( this.key ) ) {\n\t\t\t\t/**\n\t\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-attribute-exists\n\t\t\t\t * @param {module:engine/model/node~Node} node\n\t\t\t\t * @param {String} key\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-attribute-exists',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ node: item, key: this.key }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// If value to set is same as old value, don't do anything.\n\t\tif ( !isEqual( this.oldValue, this.newValue ) ) {\n\t\t\t// Execution.\n\t\t\t_setAttribute( this.range, this.key, this.newValue );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'AttributeOperation';\n\t}\n\n\t/**\n\t * Creates `AttributeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new AttributeOperation( Range.fromJSON( json.range, document ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `AttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/nooperation\n */\n\nimport Operation from './operation';\n\n/**\n * Operation which is doing nothing (\"empty operation\", \"do-nothing operation\", \"noop\"). This is an operation,\n * which when executed does not change the tree model. It still has some parameters defined for transformation purposes.\n *\n * In most cases this operation is a result of transforming operations. When transformation returns\n * {@link module:engine/model/operation/nooperation~NoOperation} it means that changes done by the transformed operation\n * have already been applied.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class NoOperation extends Operation {\n\tget type() {\n\t\treturn 'noop';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new NoOperation( this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation}\n\t */\n\tgetReversed() {\n\t\treturn new NoOperation( this.baseVersion + 1 );\n\t}\n\n\t_execute() {\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'NoOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `NoOperation( ${ this.baseVersion } )`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport InsertOperation from './insertoperation';\nimport AttributeOperation from './attributeoperation';\nimport RenameOperation from './renameoperation';\nimport MarkerOperation from './markeroperation';\nimport MoveOperation from './moveoperation';\nimport RootAttributeOperation from './rootattributeoperation';\nimport MergeOperation from './mergeoperation';\nimport SplitOperation from './splitoperation';\nimport NoOperation from './nooperation';\nimport Range from '../range';\nimport Position from '../position';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\nconst transformations = new Map();\n\n/**\n * @module engine/model/operation/transform\n */\n\n/**\n * Sets a transformation function to be be used to transform instances of class `OperationA` by instances of class `OperationB`.\n *\n * The `transformationFunction` is passed three parameters:\n *\n * * `a` - operation to be transformed, an instance of `OperationA`,\n * * `b` - operation to be transformed by, an instance of `OperationB`,\n * * {@link module:engine/model/operation/transform~TransformationContext `context`} - object with additional information about\n * transformation context.\n *\n * The `transformationFunction` should return transformation result, which is an array with one or multiple\n * {@link module:engine/model/operation/operation~Operation operation} instances.\n *\n * @protected\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @param {Function} transformationFunction Function to use for transforming.\n */\nfunction setTransformation( OperationA, OperationB, transformationFunction ) {\n\tlet aGroup = transformations.get( OperationA );\n\n\tif ( !aGroup ) {\n\t\taGroup = new Map();\n\t\ttransformations.set( OperationA, aGroup );\n\t}\n\n\taGroup.set( OperationB, transformationFunction );\n}\n\n/**\n * Returns a previously set transformation function for transforming an instance of `OperationA` by an instance of `OperationB`.\n *\n * If no transformation was set for given pair of operations, {@link module:engine/model/operation/transform~noUpdateTransformation}\n * is returned. This means that if no transformation was set, the `OperationA` instance will not change when transformed\n * by the `OperationB` instance.\n *\n * @private\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @returns {Function} Function set to transform an instance of `OperationA` by an instance of `OperationB`.\n */\nfunction getTransformation( OperationA, OperationB ) {\n\tconst aGroup = transformations.get( OperationA );\n\n\tif ( aGroup && aGroup.has( OperationB ) ) {\n\t\treturn aGroup.get( OperationB );\n\t}\n\n\treturn noUpdateTransformation;\n}\n\n/**\n * A transformation function that only clones operation to transform, without changing it.\n *\n * @private\n * @param {module:engine/model/operation/operation~Operation} a Operation to transform.\n * @returns {Array.}\n */\nfunction noUpdateTransformation( a ) {\n\treturn [ a ];\n}\n\n/**\n * Transforms operation `a` by operation `b`.\n *\n * @param {module:engine/model/operation/operation~Operation} a Operation to be transformed.\n * @param {module:engine/model/operation/operation~Operation} b Operation to transform by.\n * @param {module:engine/model/operation/transform~TransformationContext} context Transformation context for this transformation.\n * @returns {Array.} Transformation result.\n */\nexport function transform( a, b, context = {} ) {\n\tconst transformationFunction = getTransformation( a.constructor, b.constructor );\n\n\t/* eslint-disable no-useless-catch */\n\ttry {\n\t\ta = a.clone();\n\n\t\treturn transformationFunction( a, b, context );\n\t} catch ( e ) {\n\t\t// @if CK_DEBUG // console.warn( 'Error during operation transformation!', e.message );\n\t\t// @if CK_DEBUG // console.warn( 'Transformed operation', a );\n\t\t// @if CK_DEBUG // console.warn( 'Operation transformed by', b );\n\t\t// @if CK_DEBUG // console.warn( 'context.aIsStrong', context.aIsStrong );\n\t\t// @if CK_DEBUG // console.warn( 'context.aWasUndone', context.aWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.bWasUndone', context.bWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.abRelation', context.abRelation );\n\t\t// @if CK_DEBUG // console.warn( 'context.baRelation', context.baRelation );\n\n\t\tthrow e;\n\t}\n\t/* eslint-enable no-useless-catch */\n}\n\n/**\n * Performs a transformation of two sets of operations - `operationsA` and `operationsB`. The transformation is two-way -\n * both transformed `operationsA` and transformed `operationsB` are returned.\n *\n * Note, that the first operation in each set should base on the same document state (\n * {@link module:engine/model/document~Document#version document version}).\n *\n * It is assumed that `operationsA` are \"more important\" during conflict resolution between two operations.\n *\n * New copies of both passed arrays and operations inside them are returned. Passed arguments are not altered.\n *\n * Base versions of the transformed operations sets are updated accordingly. For example, assume that base versions are `4`\n * and there are `3` operations in `operationsA` and `5` operations in `operationsB`. Then:\n *\n * * transformed `operationsA` will start from base version `9` (`4` base version + `5` operations B),\n * * transformed `operationsB` will start from base version `7` (`4` base version + `3` operations A).\n *\n * If no operation was broken into two during transformation, then both sets will end up with an operation that bases on version `11`:\n *\n * * transformed `operationsA` start from `9` and there are `3` of them, so the last will have `baseVersion` equal to `11`,\n * * transformed `operationsB` start from `7` and there are `5` of them, so the last will have `baseVersion` equal to `11`.\n *\n * @param {Array.} operationsA\n * @param {Array.} operationsB\n * @param {Object} options Additional transformation options.\n * @param {module:engine/model/document~Document|null} options.document Document which the operations change.\n * @param {Boolean} [options.useRelations=false] Whether during transformation relations should be used (used during undo for\n * better conflict resolution).\n * @param {Boolean} [options.padWithNoOps=false] Whether additional {@link module:engine/model/operation/nooperation~NoOperation}s\n * should be added to the transformation results to force the same last base version for both transformed sets (in case\n * if some operations got broken into multiple operations during transformation).\n * @returns {Object} Transformation result.\n * @returns {Array.} return.operationsA Transformed `operationsA`.\n * @returns {Array.} return.operationsB Transformed `operationsB`.\n * @returns {Map} return.originalOperations A map that links transformed operations to original operations. The keys are the transformed\n * operations and the values are the original operations from the input (`operationsA` and `operationsB`).\n */\nexport function transformSets( operationsA, operationsB, options ) {\n\t// Create new arrays so the originally passed arguments are not changed.\n\t// No need to clone operations, they are cloned as they are transformed.\n\toperationsA = operationsA.slice();\n\toperationsB = operationsB.slice();\n\n\tconst contextFactory = new ContextFactory( options.document, options.useRelations, options.forceWeakRemove );\n\tcontextFactory.setOriginalOperations( operationsA );\n\tcontextFactory.setOriginalOperations( operationsB );\n\n\tconst originalOperations = contextFactory.originalOperations;\n\n\t// If one of sets is empty there is simply nothing to transform, so return sets as they are.\n\tif ( operationsA.length == 0 || operationsB.length == 0 ) {\n\t\treturn { operationsA, operationsB, originalOperations };\n\t}\n\t//\n\t// Following is a description of transformation process:\n\t//\n\t// There are `operationsA` and `operationsB` to be transformed, both by both.\n\t//\n\t// So, suppose we have sets of two operations each: `operationsA` = `[ a1, a2 ]`, `operationsB` = `[ b1, b2 ]`.\n\t//\n\t// Remember, that we can only transform operations that base on the same context. We assert that `a1` and `b1` base on\n\t// the same context and we transform them. Then, we get `a1'` and `b1'`. `a2` bases on a context with `a1` -- `a2`\n\t// is an operation that followed `a1`. Similarly, `b2` bases on a context with `b1`.\n\t//\n\t// However, since `a1'` is a result of transformation by `b1`, `a1'` now also has a context with `b1`. This means that\n\t// we can safely transform `a1'` by `b2`. As we finish transforming `a1`, we also transformed all `operationsB`.\n\t// All `operationsB` also have context including `a1`. Now, we can properly transform `a2` by those operations.\n\t//\n\t// The transformation process can be visualized on a transformation diagram (\"diamond diagram\"):\n\t//\n\t// [the initial state]\n\t// [common for a1 and b1]\n\t//\n\t// *\n\t// / \\\n\t// / \\\n\t// b1 a1\n\t// / \\\n\t// / \\\n\t// * *\n\t// / \\ / \\\n\t// / \\ / \\\n\t// b2 a1' b1' a2\n\t// / \\ / \\\n\t// / \\ / \\\n\t// * * *\n\t// \\ / \\ /\n\t// \\ / \\ /\n\t// a1'' b2' a2' b1''\n\t// \\ / \\ /\n\t// \\ / \\ /\n\t// * *\n\t// \\ /\n\t// \\ /\n\t// a2'' b2''\n\t// \\ /\n\t// \\ /\n\t// *\n\t//\n\t// [the final state]\n\t//\n\t// The final state can be reached from the initial state by applying `a1`, `a2`, `b1''` and `b2''`, as well as by\n\t// applying `b1`, `b2`, `a1''`, `a2''`. Note how the operations get to a proper common state before each pair is\n\t// transformed.\n\t//\n\t// Another thing to consider is that an operation during transformation can be broken into multiple operations.\n\t// Suppose that `a1` * `b1` = `[ a11', a12' ]` (instead of `a1'` that we considered previously).\n\t//\n\t// In that case, we leave `a12'` for later and we continue transforming `a11'` until it is transformed by all `operationsB`\n\t// (in our case it is just `b2`). At this point, `b1` is transformed by \"whole\" `a1`, while `b2` is only transformed\n\t// by `a11'`. Similarly, `a12'` is only transformed by `b1`. This leads to a conclusion that we need to start transforming `a12'`\n\t// from the moment just after it was broken. So, `a12'` is transformed by `b2`. Now, \"the whole\" `a1` is transformed\n\t// by `operationsB`, while all `operationsB` are transformed by \"the whole\" `a1`. This means that we can continue with\n\t// following `operationsA` (in our case it is just `a2`).\n\t//\n\t// Of course, also `operationsB` can be broken. However, since we focus on transforming operation `a` to the end,\n\t// the only thing to do is to store both pieces of operation `b`, so that the next transformed operation `a` will\n\t// be transformed by both of them.\n\t//\n\t// *\n\t// / \\\n\t// / \\\n\t// / \\\n\t// b1 a1\n\t// / \\\n\t// / \\\n\t// / \\\n\t// * *\n\t// / \\ / \\\n\t// / a11' / \\\n\t// / \\ / \\\n\t// b2 * b1' a2\n\t// / / \\ / \\\n\t// / / a12' / \\\n\t// / / \\ / \\\n\t// * b2' * *\n\t// \\ / / \\ /\n\t// a11'' / b21'' \\ /\n\t// \\ / / \\ /\n\t// * * a2' b1''\n\t// \\ / \\ \\ /\n\t// a12'' b22''\\ \\ /\n\t// \\ / \\ \\ /\n\t// * a2'' *\n\t// \\ \\ /\n\t// \\ \\ b21'''\n\t// \\ \\ /\n\t// a2''' *\n\t// \\ /\n\t// \\ b22'''\n\t// \\ /\n\t// *\n\t//\n\t// Note, how `a1` is broken and transformed into `a11'` and `a12'`, while `b2'` got broken and transformed into `b21''` and `b22''`.\n\t//\n\t// Having all that on mind, here is an outline for the transformation process algorithm:\n\t//\n\t// 1. We have `operationsA` and `operationsB` array, which we dynamically update as the transformation process goes.\n\t//\n\t// 2. We take next (or first) operation from `operationsA` and check from which operation `b` we need to start transforming it.\n\t// All original `operationsA` are set to be transformed starting from the first operation `b`.\n\t//\n\t// 3. We take operations from `operationsB`, one by one, starting from the correct one, and transform operation `a`\n\t// by operation `b` (and vice versa). We update `operationsA` and `operationsB` by replacing the original operations\n\t// with the transformation results.\n\t//\n\t// 4. If operation is broken into multiple operations, we save all the new operations in the place of the\n\t// original operation.\n\t//\n\t// 5. Additionally, if operation `a` was broken, for the \"new\" operation, we remember from which operation `b` it should\n\t// be transformed by.\n\t//\n\t// 6. We continue transforming \"current\" operation `a` until it is transformed by all `operationsB`. Then, go to 2.\n\t// unless the last operation `a` was transformed.\n\t//\n\t// The actual implementation of the above algorithm is slightly different, as only one loop (while) is used.\n\t// The difference is that we have \"current\" `a` operation to transform and we store the index of the next `b` operation\n\t// to transform by. Each loop operates on two indexes then: index pointing to currently processed `a` operation and\n\t// index pointing to next `b` operation. Each loop is just one `a * b` + `b * a` transformation. After each loop\n\t// operation `b` index is updated. If all `b` operations were visited for the current `a` operation, we change\n\t// current `a` operation index to the next one.\n\t//\n\n\t// For each operation `a`, keeps information what is the index in `operationsB` from which the transformation should start.\n\tconst nextTransformIndex = new WeakMap();\n\n\t// For all the original `operationsA`, set that they should be transformed starting from the first of `operationsB`.\n\tfor ( const op of operationsA ) {\n\t\tnextTransformIndex.set( op, 0 );\n\t}\n\n\t// Additional data that is used for some postprocessing after the main transformation process is done.\n\tconst data = {\n\t\tnextBaseVersionA: operationsA[ operationsA.length - 1 ].baseVersion + 1,\n\t\tnextBaseVersionB: operationsB[ operationsB.length - 1 ].baseVersion + 1,\n\t\toriginalOperationsACount: operationsA.length,\n\t\toriginalOperationsBCount: operationsB.length\n\t};\n\n\t// Index of currently transformed operation `a`.\n\tlet i = 0;\n\n\t// While not all `operationsA` are transformed...\n\twhile ( i < operationsA.length ) {\n\t\t// Get \"current\" operation `a`.\n\t\tconst opA = operationsA[ i ];\n\n\t\t// For the \"current\" operation `a`, get the index of the next operation `b` to transform by.\n\t\tconst indexB = nextTransformIndex.get( opA );\n\n\t\t// If operation `a` was already transformed by every operation `b`, change \"current\" operation `a` to the next one.\n\t\tif ( indexB == operationsB.length ) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst opB = operationsB[ indexB ];\n\n\t\t// Transform `a` by `b` and `b` by `a`.\n\t\tconst newOpsA = transform( opA, opB, contextFactory.getContext( opA, opB, true ) );\n\t\tconst newOpsB = transform( opB, opA, contextFactory.getContext( opB, opA, false ) );\n\t\t// As a result we get one or more `newOpsA` and one or more `newOpsB` operations.\n\n\t\t// Update contextual information about operations.\n\t\tcontextFactory.updateRelation( opA, opB );\n\n\t\tcontextFactory.setOriginalOperations( newOpsA, opA );\n\t\tcontextFactory.setOriginalOperations( newOpsB, opB );\n\n\t\t// For new `a` operations, update their index of the next operation `b` to transform them by.\n\t\t//\n\t\t// This is needed even if there was only one result (`a` was not broken) because that information is used\n\t\t// at the beginning of this loop every time.\n\t\tfor ( const newOpA of newOpsA ) {\n\t\t\t// Acknowledge, that operation `b` also might be broken into multiple operations.\n\t\t\t//\n\t\t\t// This is why we raise `indexB` not just by 1. If `newOpsB` are multiple operations, they will be\n\t\t\t// spliced in the place of `opB`. So we need to change `transformBy` accordingly, so that an operation won't\n\t\t\t// be transformed by the same operation (part of it) again.\n\t\t\tnextTransformIndex.set( newOpA, indexB + newOpsB.length );\n\t\t}\n\n\t\t// Update `operationsA` and `operationsB` with the transformed versions.\n\t\toperationsA.splice( i, 1, ...newOpsA );\n\t\toperationsB.splice( indexB, 1, ...newOpsB );\n\t}\n\n\tif ( options.padWithNoOps ) {\n\t\t// If no-operations padding is enabled, count how many extra `a` and `b` operations were generated.\n\t\tconst brokenOperationsACount = operationsA.length - data.originalOperationsACount;\n\t\tconst brokenOperationsBCount = operationsB.length - data.originalOperationsBCount;\n\n\t\t// Then, if that number is not the same, pad `operationsA` or `operationsB` with correct number of no-ops so\n\t\t// that the base versions are equalled.\n\t\t//\n\t\t// Note that only one array will be updated, as only one of those subtractions can be greater than zero.\n\t\tpadWithNoOps( operationsA, brokenOperationsBCount - brokenOperationsACount );\n\t\tpadWithNoOps( operationsB, brokenOperationsACount - brokenOperationsBCount );\n\t}\n\n\t// Finally, update base versions of transformed operations.\n\tupdateBaseVersions( operationsA, data.nextBaseVersionB );\n\tupdateBaseVersions( operationsB, data.nextBaseVersionA );\n\n\treturn { operationsA, operationsB, originalOperations };\n}\n\n// Gathers additional data about operations processed during transformation. Can be used to obtain contextual information\n// about two operations that are about to be transformed. This contextual information can be used for better conflict resolution.\nclass ContextFactory {\n\t// Creates `ContextFactory` instance.\n\t//\n\t// @param {module:engine/model/document~Document} document Document which the operations change.\n\t// @param {Boolean} useRelations Whether during transformation relations should be used (used during undo for\n\t// better conflict resolution).\n\t// @param {Boolean} [forceWeakRemove=false] If set to `false`, remove operation will be always stronger than move operation,\n\t// so the removed nodes won't end up back in the document root. When set to `true`, context data will be used.\n\tconstructor( document, useRelations, forceWeakRemove = false ) {\n\t\t// For each operation that is created during transformation process, we keep a reference to the original operation\n\t\t// which it comes from. The original operation works as a kind of \"identifier\". Every contextual information\n\t\t// gathered during transformation that we want to save for given operation, is actually saved for the original operation.\n\t\t// This way no matter if operation `a` is cloned, then transformed, even breaks, we still have access to the previously\n\t\t// gathered data through original operation reference.\n\t\tthis.originalOperations = new Map();\n\n\t\t// `model.History` instance which information about undone operations will be taken from.\n\t\tthis._history = document.history;\n\n\t\t// Whether additional context should be used.\n\t\tthis._useRelations = useRelations;\n\n\t\tthis._forceWeakRemove = !!forceWeakRemove;\n\n\t\t// Relations is a double-map structure (maps in map) where for two operations we store how those operations were related\n\t\t// to each other. Those relations are evaluated during transformation process. For every transformated pair of operations\n\t\t// we keep relations between them.\n\t\tthis._relations = new Map();\n\t}\n\n\t// Sets \"original operation\" for given operations.\n\t//\n\t// During transformation process, operations are cloned, then changed, then processed again, sometimes broken into two\n\t// or multiple operations. When gathering additional data it is important that all operations can be somehow linked\n\t// so a cloned and transformed \"version\" still kept track of the data assigned earlier to it.\n\t//\n\t// The original operation object will be used as such an universal linking id. Throughout the transformation process\n\t// all cloned operations will refer to \"the original operation\" when storing and reading additional data.\n\t//\n\t// If `takeFrom` is not set, each operation from `operations` array will be assigned itself as \"the original operation\".\n\t// This should be used as an initialization step.\n\t//\n\t// If `takeFrom` is set, each operation from `operations` will be assigned the same original operation as assigned\n\t// for `takeFrom` operation. This should be used to update original operations. It should be used in a way that\n\t// `operations` are the result of `takeFrom` transformation to ensure proper \"original operation propagation\".\n\t//\n\t// @param {Array.} operations\n\t// @param {module:engine/model/operation/operation~Operation|null} [takeFrom=null]\n\tsetOriginalOperations( operations, takeFrom = null ) {\n\t\tconst originalOperation = takeFrom ? this.originalOperations.get( takeFrom ) : null;\n\n\t\tfor ( const operation of operations ) {\n\t\t\tthis.originalOperations.set( operation, originalOperation || operation );\n\t\t}\n\t}\n\n\t// Saves a relation between operations `opA` and `opB`.\n\t//\n\t// Relations are then later used to help solve conflicts when operations are transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\tupdateRelation( opA, opB ) {\n\t\t// The use of relations is described in a bigger detail in transformation functions.\n\t\t//\n\t\t// In brief, this function, for specified pairs of operation types, checks how positions defined in those operations relate.\n\t\t// Then those relations are saved. For example, for two move operations, it is saved if one of those operations target\n\t\t// position is before the other operation source position. This kind of information gives contextual information when\n\t\t// transformation is used during undo. Similar checks are done for other pairs of operations.\n\t\t//\n\t\tswitch ( opA.constructor ) {\n\t\t\tcase MoveOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opB.movedRange.containsPosition( opA.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAtSource' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isEqual( opB.deletionPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBetween' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isAfter( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'moveTargetAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opA.targetPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBefore' );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase SplitOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isEqual( opB.sourcePosition ) || opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst range = Range._createFromPositionAndShift( opB.sourcePosition, opB.howMany );\n\n\t\t\t\t\t\t\tif ( opA.splitPosition.hasSameParentAs( opB.sourcePosition ) && range.containsPosition( opA.splitPosition ) ) {\n\t\t\t\t\t\t\t\tconst howMany = range.end.offset - opA.splitPosition.offset;\n\t\t\t\t\t\t\t\tconst offset = opA.splitPosition.offset - range.start.offset;\n\n\t\t\t\t\t\t\t\tthis._setRelation( opA, opB, { howMany, offset } );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MergeOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( !opA.targetPosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeTargetNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSourceNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSameElement' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase SplitOperation: {\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.splitPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitAtSource' );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MarkerOperation: {\n\t\t\t\tconst markerRange = opA.newRange;\n\n\t\t\t\tif ( !markerRange ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tconst movedRange = Range._createFromPositionAndShift( opB.sourcePosition, opB.howMany );\n\n\t\t\t\t\t\tconst affectedLeft = movedRange.containsPosition( markerRange.start ) ||\n\t\t\t\t\t\t\tmovedRange.start.isEqual( markerRange.start );\n\n\t\t\t\t\t\tconst affectedRight = movedRange.containsPosition( markerRange.end ) ||\n\t\t\t\t\t\t\tmovedRange.end.isEqual( markerRange.end );\n\n\t\t\t\t\t\tif ( ( affectedLeft || affectedRight ) && !movedRange.containsRange( markerRange ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\tside: affectedLeft ? 'left' : 'right',\n\t\t\t\t\t\t\t\tpath: affectedLeft ? markerRange.start.path.slice() : markerRange.end.path.slice()\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tconst wasInLeftElement = markerRange.start.isEqual( opB.targetPosition );\n\t\t\t\t\t\tconst wasStartBeforeMergedElement = markerRange.start.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasEndBeforeMergedElement = markerRange.end.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasInRightElement = markerRange.end.isEqual( opB.sourcePosition );\n\n\t\t\t\t\t\tif ( wasInLeftElement || wasStartBeforeMergedElement || wasEndBeforeMergedElement || wasInRightElement ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\twasInLeftElement,\n\t\t\t\t\t\t\t\twasStartBeforeMergedElement,\n\t\t\t\t\t\t\t\twasEndBeforeMergedElement,\n\t\t\t\t\t\t\t\twasInRightElement\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Evaluates and returns contextual information about two given operations `opA` and `opB` which are about to be transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {module:engine/model/operation/transform~TransformationContext}\n\tgetContext( opA, opB, aIsStrong ) {\n\t\treturn {\n\t\t\taIsStrong,\n\t\t\taWasUndone: this._wasUndone( opA ),\n\t\t\tbWasUndone: this._wasUndone( opB ),\n\t\t\tabRelation: this._useRelations ? this._getRelation( opA, opB ) : null,\n\t\t\tbaRelation: this._useRelations ? this._getRelation( opB, opA ) : null,\n\t\t\tforceWeakRemove: this._forceWeakRemove\n\t\t};\n\t}\n\n\t// Returns whether given operation `op` has already been undone.\n\t//\n\t// Information whether an operation was undone gives more context when making a decision when two operations are in conflict.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} op\n\t// @returns {Boolean}\n\t_wasUndone( op ) {\n\t\t// For `op`, get its original operation. After all, if `op` is a clone (or even transformed clone) of another\n\t\t// operation, literally `op` couldn't be undone. It was just generated. If anything, it was the operation it origins\n\t\t// from which was undone. So get that original operation.\n\t\tconst originalOp = this.originalOperations.get( op );\n\n\t\t// And check with the document if the original operation was undone.\n\t\treturn originalOp.wasUndone || this._history.isUndoneOperation( originalOp );\n\t}\n\n\t// Returns a relation between `opA` and an operation which is undone by `opB`. This can be `String` value if a relation\n\t// was set earlier or `null` if there was no relation between those operations.\n\t//\n\t// This is a little tricky to understand, so let's compare it to `ContextFactory#_wasUndone`.\n\t//\n\t// When `wasUndone( opB )` is used, we check if the `opB` has already been undone. It is obvious, that the\n\t// undoing operation must happen after the undone operation. So, essentially, we have `opB`, we take document history,\n\t// we look forward in the future and ask if in that future `opB` was undone.\n\t//\n\t// Relations is a backward process to `wasUndone()`.\n\t//\n\t// Long story short - using relations is asking what happened in the past. Looking back. This time we have an undoing\n\t// operation `opB` which has undone some other operation. When there is a transformation `opA` x `opB` and there is\n\t// a conflict to solve and `opB` is an undoing operation, we can look back in the history and see what was a relation\n\t// between `opA` and the operation which `opB` undone. Basing on that relation from the past, we can now make\n\t// a better decision when resolving a conflict between two operations, because we know more about the context of\n\t// those two operations.\n\t//\n\t// This is why this function does not return a relation directly between `opA` and `opB` because we need to look\n\t// back to search for a meaningful contextual information.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {String|null}\n\t_getRelation( opA, opB ) {\n\t\t// Get the original operation. Similarly as in `wasUndone()` it is used as an universal identifier for stored data.\n\t\tconst origB = this.originalOperations.get( opB );\n\t\tconst undoneB = this._history.getUndoneOperation( origB );\n\n\t\t// If `opB` is not undoing any operation, there is no relation.\n\t\tif ( !undoneB ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst relationsA = this._relations.get( origA );\n\n\t\t// Get all relations for `opA`, and check if there is a relation with `opB`-undone-counterpart. If so, return it.\n\t\tif ( relationsA ) {\n\t\t\treturn relationsA.get( undoneB ) || null;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t// Helper function for `ContextFactory#updateRelations`.\n\t//\n\t// @private\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @param {String} relation\n\t_setRelation( opA, opB, relation ) {\n\t\t// As always, setting is for original operations, not the clones/transformed operations.\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst origB = this.originalOperations.get( opB );\n\n\t\tlet relationsA = this._relations.get( origA );\n\n\t\tif ( !relationsA ) {\n\t\t\trelationsA = new Map();\n\t\t\tthis._relations.set( origA, relationsA );\n\t\t}\n\n\t\trelationsA.set( origB, relation );\n\t}\n}\n\n/**\n * Holds additional contextual information about a transformed pair of operations (`a` and `b`). Those information\n * can be used for better conflict resolving.\n *\n * @typedef {Object} module:engine/model/operation/transform~TransformationContext\n *\n * @property {Boolean} aIsStrong Whether `a` is strong operation in this transformation, or weak.\n * @property {Boolean} aWasUndone Whether `a` operation was undone.\n * @property {Boolean} bWasUndone Whether `b` operation was undone.\n * @property {String|null} abRelation The relation between `a` operation and an operation undone by `b` operation.\n * @property {String|null} baRelation The relation between `b` operation and an operation undone by `a` operation.\n */\n\n/**\n * An utility function that updates {@link module:engine/model/operation/operation~Operation#baseVersion base versions}\n * of passed operations.\n *\n * The function simply sets `baseVersion` as a base version of the first passed operation and then increments it for\n * each following operation in `operations`.\n *\n * @private\n * @param {Array.} operations Operations to update.\n * @param {Number} baseVersion Base version to set for the first operation in `operations`.\n */\nfunction updateBaseVersions( operations, baseVersion ) {\n\tfor ( const operation of operations ) {\n\t\toperation.baseVersion = baseVersion++;\n\t}\n}\n\n/**\n * Adds `howMany` instances of {@link module:engine/model/operation/nooperation~NoOperation} to `operations` set.\n *\n * @private\n * @param {Array.} operations\n * @param {Number} howMany\n */\nfunction padWithNoOps( operations, howMany ) {\n\tfor ( let i = 0; i < howMany; i++ ) {\n\t\toperations.push( new NoOperation( 0 ) );\n\t}\n}\n\n// -----------------------\n\nsetTransformation( AttributeOperation, AttributeOperation, ( a, b, context ) => {\n\t// If operations in conflict, check if their ranges intersect and manage them properly.\n\t//\n\t// Operations can be in conflict only if:\n\t//\n\t// * their key is the same (they change the same attribute), and\n\t// * they are in the same parent (operations for ranges [ 1 ] - [ 3 ] and [ 2, 0 ] - [ 2, 5 ] change different\n\t// elements and can't be in conflict).\n\tif ( a.key === b.key && a.range.start.hasSameParentAs( b.range.start ) ) {\n\t\t// First, we want to apply change to the part of a range that has not been changed by the other operation.\n\t\tconst operations = a.range.getDifference( b.range ).map( range => {\n\t\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, 0 );\n\t\t} );\n\n\t\t// Then we take care of the common part of ranges.\n\t\tconst common = a.range.getIntersection( b.range );\n\n\t\tif ( common ) {\n\t\t\t// If this operation is more important, we also want to apply change to the part of the\n\t\t\t// original range that has already been changed by the other operation. Since that range\n\t\t\t// got changed we also have to update `oldValue`.\n\t\t\tif ( context.aIsStrong ) {\n\t\t\t\toperations.push( new AttributeOperation( common, b.key, b.newValue, a.newValue, 0 ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( operations.length == 0 ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\treturn operations;\n\t} else {\n\t\t// If operations don't conflict, simply return an array containing just a clone of this operation.\n\t\treturn [ a ];\n\t}\n} );\n\nsetTransformation( AttributeOperation, InsertOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.position ) && a.range.containsPosition( b.position ) ) {\n\t\t// If new nodes should not receive attributes, two separated ranges will be returned.\n\t\t// Otherwise, one expanded range will be returned.\n\t\tconst range = a.range._getTransformedByInsertion( b.position, b.howMany, !b.shouldReceiveAttributes );\n\t\tconst result = range.map( r => {\n\t\t\treturn new AttributeOperation( r, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t\t} );\n\n\t\tif ( b.shouldReceiveAttributes ) {\n\t\t\t// `AttributeOperation#range` includes some newly inserted text.\n\t\t\t// The operation should also change the attribute of that text. An example:\n\t\t\t//\n\t\t\t// Bold should be applied on the following range:\n\t\t\t//

Fo[zb]ar

\n\t\t\t//\n\t\t\t// In meantime, new text is typed:\n\t\t\t//

Fozxxbar

\n\t\t\t//\n\t\t\t// Bold should be applied also on the new text:\n\t\t\t//

Fo[zxxb]ar

\n\t\t\t//

Fo<$text bold=\"true\">zxxbar

\n\t\t\t//\n\t\t\t// There is a special case to consider here to consider.\n\t\t\t//\n\t\t\t// Consider setting an attribute with multiple possible values, for example `highlight`. The inserted text might\n\t\t\t// have already an attribute value applied and the `oldValue` property of the attribute operation might be wrong:\n\t\t\t//\n\t\t\t// Attribute `highlight=\"yellow\"` should be applied on the following range:\n\t\t\t//

Fo[zb]ar

\n\t\t\t//\n\t\t\t// In meantime, character `x` with `highlight=\"red\"` is typed:\n\t\t\t//

Fo[z<$text highlight=\"red\">xb]ar

\n\t\t\t//\n\t\t\t// In this case we cannot simply apply operation changing the attribute value from `null` to `\"yellow\"` for the whole range\n\t\t\t// because that would lead to an exception (`oldValue` is incorrect for `x`).\n\t\t\t//\n\t\t\t// We also cannot break the original range as this would mess up a scenario when there are multiple following\n\t\t\t// insert operations, because then only the first inserted character is included in those ranges:\n\t\t\t//

Fo[z][x][b]ar

-->

Fo[z][x]x[b]ar

-->

Fo[z][x]xx[b]ar

\n\t\t\t//\n\t\t\t// So, the attribute range needs be expanded, no matter what attributes are set on the inserted nodes:\n\t\t\t//\n\t\t\t//

Fo[z<$text highlight=\"red\">xb]ar

<--- Change from `null` to `yellow`, throwing an exception.\n\t\t\t//\n\t\t\t// But before that operation would be applied, we will add an additional attribute operation that will change\n\t\t\t// attributes on the inserted nodes in a way which would make the original operation correct:\n\t\t\t//\n\t\t\t//

Fo[z{<$text highlight=\"red\">}xb]ar

<--- Change range `{}` from `red` to `null`.\n\t\t\t//

Fo[zxb]ar

<--- Now change from `null` to `yellow` is completely fine.\n\t\t\t//\n\n\t\t\t// Generate complementary attribute operation. Be sure to add it before the original operation.\n\t\t\tconst op = _getComplementaryAttributeOperations( b, a.key, a.oldValue );\n\n\t\t\tif ( op ) {\n\t\t\t\tresult.unshift( op );\n\t\t\t}\n\t\t}\n\n\t\t// If nodes should not receive new attribute, we are done here.\n\t\treturn result;\n\t}\n\n\t// If insert operation is not expanding the attribute operation range, simply transform the range.\n\ta.range = a.range._getTransformedByInsertion( b.position, b.howMany, false )[ 0 ];\n\n\treturn [ a ];\n} );\n\n/**\n * Helper function for `AttributeOperation` x `InsertOperation` (and reverse) transformation.\n *\n * For given `insertOperation` it checks the inserted node if it has an attribute `key` set to a value different\n * than `newValue`. If so, it generates an `AttributeOperation` which changes the value of `key` attribute to `newValue`.\n *\n * @private\n * @param {module:engine/model/operation/insertoperation~InsertOperation} insertOperation\n * @param {String} key\n * @param {*} newValue\n * @returns {module:engine/model/operation/attributeoperation~AttributeOperation|null}\n */\nfunction _getComplementaryAttributeOperations( insertOperation, key, newValue ) {\n\tconst nodes = insertOperation.nodes;\n\n\t// At the beginning we store the attribute value from the first node.\n\tconst insertValue = nodes.getNode( 0 ).getAttribute( key );\n\n\tif ( insertValue == newValue ) {\n\t\treturn null;\n\t}\n\n\tconst range = new Range( insertOperation.position, insertOperation.position.getShiftedBy( insertOperation.howMany ) );\n\n\treturn new AttributeOperation( range, key, insertValue, newValue, 0 );\n}\n\nsetTransformation( AttributeOperation, MergeOperation, ( a, b ) => {\n\tconst ranges = [];\n\n\t// Case 1:\n\t//\n\t// Attribute change on the merged element. In this case, the merged element was moved to the graveyard.\n\t// An additional attribute operation that will change the (re)moved element needs to be generated.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.deletionPosition ) ) {\n\t\tif ( a.range.containsPosition( b.deletionPosition ) || a.range.start.isEqual( b.deletionPosition ) ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.graveyardPosition, 1 ) );\n\t\t}\n\t}\n\n\tconst range = a.range._getTransformedByMergeOperation( b );\n\n\t// Do not add empty (collapsed) ranges to the result. `range` may be collapsed if it contained only the merged element.\n\tif ( !range.isCollapsed ) {\n\t\tranges.push( range );\n\t}\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => {\n\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t} );\n} );\n\nsetTransformation( AttributeOperation, MoveOperation, ( a, b ) => {\n\tconst ranges = _breakRangeByMoveOperation( a.range, b );\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion ) );\n} );\n\n// Helper function for `AttributeOperation` x `MoveOperation` transformation.\n//\n// Takes the passed `range` and transforms it by move operation `moveOp` in a specific way. Only top-level nodes of `range`\n// are considered to be in the range. If move operation moves nodes deep from inside of the range, those nodes won't\n// be included in the result. In other words, top-level nodes of the ranges from the result are exactly the same as\n// top-level nodes of the original `range`.\n//\n// This is important for `AttributeOperation` because, for its range, it changes only the top-level nodes. So we need to\n// track only how those nodes have been affected by `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/operation/moveoperation~MoveOperation} moveOp\n// @returns {Array.}\nfunction _breakRangeByMoveOperation( range, moveOp ) {\n\tconst moveRange = Range._createFromPositionAndShift( moveOp.sourcePosition, moveOp.howMany );\n\n\t// We are transforming `range` (original range) by `moveRange` (range moved by move operation). As usual when it comes to\n\t// transforming a ranges, we may have a common part of the ranges and we may have a difference part (zero to two ranges).\n\tlet common = null;\n\tlet difference = [];\n\n\t// Let's compare the ranges.\n\tif ( moveRange.containsRange( range, true ) ) {\n\t\t// If the whole original range is moved, treat it whole as a common part. There's also no difference part.\n\t\tcommon = range;\n\t} else if ( range.start.hasSameParentAs( moveRange.start ) ) {\n\t\t// If the ranges are \"on the same level\" (in the same parent) then move operation may move exactly those nodes\n\t\t// that are changed by the attribute operation. In this case we get common part and difference part in the usual way.\n\t\tdifference = range.getDifference( moveRange );\n\t\tcommon = range.getIntersection( moveRange );\n\t} else {\n\t\t// In any other situation we assume that original range is different than move range, that is that move operation\n\t\t// moves other nodes that attribute operation change. Even if the moved range is deep inside in the original range.\n\t\t//\n\t\t// Note that this is different than in `.getIntersection` (we would get a common part in that case) and different\n\t\t// than `.getDifference` (we would get two ranges).\n\t\tdifference = [ range ];\n\t}\n\n\tconst result = [];\n\n\t// The default behaviour of `_getTransformedByMove` might get wrong results for difference part, though, so\n\t// we do it by hand.\n\tfor ( let diff of difference ) {\n\t\t// First, transform the range by removing moved nodes. Since this is a difference, this is safe, `null` won't be returned\n\t\t// as the range is different than the moved range.\n\t\tdiff = diff._getTransformedByDeletion( moveOp.sourcePosition, moveOp.howMany );\n\n\t\t// Transform also `targetPosition`.\n\t\tconst targetPosition = moveOp.getMovedRangeStart();\n\n\t\t// Spread the range only if moved nodes are inserted only between the top-level nodes of the `diff` range.\n\t\tconst spread = diff.start.hasSameParentAs( targetPosition );\n\n\t\t// Transform by insertion of moved nodes.\n\t\tdiff = diff._getTransformedByInsertion( targetPosition, moveOp.howMany, spread );\n\n\t\tresult.push( ...diff );\n\t}\n\n\t// Common part can be simply transformed by the move operation. This is because move operation will not target to\n\t// that common part (the operation would have to target inside its own moved range).\n\tif ( common ) {\n\t\tresult.push(\n\t\t\tcommon._getTransformedByMove( moveOp.sourcePosition, moveOp.targetPosition, moveOp.howMany, false )[ 0 ]\n\t\t);\n\t}\n\n\treturn result;\n}\n\nsetTransformation( AttributeOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Split node is the last node in `AttributeOperation#range`.\n\t// `AttributeOperation#range` needs to be expanded to include the new (split) node.\n\t//\n\t// Attribute `type` to be changed to `numbered` but the `listItem` is split.\n\t// foobar\n\t//\n\t// After split:\n\t// foobar\n\t//\n\t// After attribute change:\n\t// foofoo\n\t//\n\tif ( a.range.end.isEqual( b.insertionPosition ) ) {\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.range.end.offset++;\n\t\t}\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split position is inside `AttributeOperation#range`, at the same level, so the nodes to change are\n\t// not going to make a flat range.\n\t//\n\t// Content with range-to-change and split position:\n\t//

Fo[zb^a]r

\n\t//\n\t// After split:\n\t//

Fozb

ar

\n\t//\n\t// Make two separate ranges containing all nodes to change:\n\t//

Fo[zb]

[a]r

\n\t//\n\tif ( a.range.start.hasSameParentAs( b.splitPosition ) && a.range.containsPosition( b.splitPosition ) ) {\n\t\tconst secondPart = a.clone();\n\n\t\tsecondPart.range = new Range(\n\t\t\tb.moveTargetPosition.clone(),\n\t\t\ta.range.end._getCombined( b.splitPosition, b.moveTargetPosition )\n\t\t);\n\n\t\ta.range.end = b.splitPosition.clone();\n\t\ta.range.end.stickiness = 'toPrevious';\n\n\t\treturn [ a, secondPart ];\n\t}\n\n\t// The default case.\n\t//\n\ta.range = a.range._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, AttributeOperation, ( a, b ) => {\n\tconst result = [ a ];\n\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\t// This is a mirror scenario to the one described in `AttributeOperation` x `InsertOperation` transformation,\n\t// although this case is a little less complicated. In this case we simply need to change attributes of the\n\t// inserted nodes and that's it.\n\t//\n\tif ( a.shouldReceiveAttributes && a.position.hasSameParentAs( b.range.start ) && b.range.containsPosition( a.position ) ) {\n\t\tconst op = _getComplementaryAttributeOperations( a, b.key, b.newValue );\n\n\t\tif ( op ) {\n\t\t\tresult.push( op );\n\t\t}\n\t}\n\n\t// The default case is: do nothing.\n\t// `AttributeOperation` does not change the model tree structure so `InsertOperation` does not need to be changed.\n\t//\n\treturn result;\n} );\n\nsetTransformation( InsertOperation, InsertOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Two insert operations insert nodes at the same position. Since they are the same, it needs to be decided\n\t// what will be the order of inserted nodes. However, there is no additional information to help in that\n\t// decision. Also, when `b` will be transformed by `a`, the same order must be maintained.\n\t//\n\t// To achieve that, we will check if the operation is strong.\n\t// If it is, it won't get transformed. If it is not, it will be moved.\n\t//\n\tif ( a.position.isEqual( b.position ) && context.aIsStrong ) {\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MoveOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, SplitOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MergeOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MarkerOperation, InsertOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MarkerOperation, ( a, b, context ) => {\n\tif ( a.name == b.name ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldRange = b.newRange ? b.newRange.clone() : null;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MergeOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByMergeOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MoveOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = Range._createFromRanges( a.oldRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\n\t\t\tif ( context.abRelation.side == 'left' && b.targetPosition.isEqual( a.newRange.start ) ) {\n\t\t\t\ta.newRange.start.path = context.abRelation.path;\n\t\t\t\ta.newRange.end = aNewRange.end;\n\n\t\t\t\treturn [ a ];\n\t\t\t} else if ( context.abRelation.side == 'right' && b.targetPosition.isEqual( a.newRange.end ) ) {\n\t\t\t\ta.newRange.start = aNewRange.start;\n\t\t\t\ta.newRange.end.path = context.abRelation.path;\n\n\t\t\t\treturn [ a ];\n\t\t\t}\n\t\t}\n\n\t\ta.newRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, SplitOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedBySplitOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = a.newRange._getTransformedBySplitOperation( b );\n\n\t\t\tif ( a.newRange.start.isEqual( b.splitPosition ) && context.abRelation.wasStartBeforeMergedElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.insertionPosition );\n\t\t\t} else if ( a.newRange.start.isEqual( b.splitPosition ) && !context.abRelation.wasInLeftElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.moveTargetPosition );\n\t\t\t}\n\n\t\t\tif ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasInRightElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.moveTargetPosition );\n\t\t\t} else if ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasEndBeforeMergedElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.insertionPosition );\n\t\t\t} else {\n\t\t\t\ta.newRange.end = aNewRange.end;\n\t\t\t}\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\ta.newRange = a.newRange._getTransformedBySplitOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MergeOperation, InsertOperation, ( a, b ) => {\n\tif ( a.sourcePosition.hasSameParentAs( b.position ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByInsertOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Same merge operations.\n\t//\n\t// Both operations have same source and target positions. So the element already got merged and there is\n\t// theoretically nothing to do.\n\t//\n\tif ( a.sourcePosition.isEqual( b.sourcePosition ) && a.targetPosition.isEqual( b.targetPosition ) ) {\n\t\t// There are two ways that we can provide a do-nothing operation.\n\t\t//\n\t\t// First is simply a NoOperation instance. We will use it if `b` operation was not undone.\n\t\t//\n\t\t// Second is a merge operation that has the source operation in the merged element - in the graveyard -\n\t\t// same target position and `howMany` equal to `0`. So it is basically merging an empty element from graveyard\n\t\t// which is almost the same as NoOperation.\n\t\t//\n\t\t// This way the merge operation can be later transformed by split operation\n\t\t// to provide correct undo. This will be used if `b` operation was undone (only then it is correct).\n\t\t//\n\t\tif ( !context.bWasUndone ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\tconst path = b.graveyardPosition.path.slice();\n\t\t\tpath.push( 0 );\n\n\t\t\ta.sourcePosition = new Position( b.graveyardPosition.root, path );\n\t\t\ta.howMany = 0;\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same merge source position but different target position.\n\t//\n\t// This can happen during collaboration. For example, if one client merged a paragraph to the previous paragraph\n\t// and the other person removed that paragraph and merged the same paragraph to something before:\n\t//\n\t// Client A:\n\t//

Foo

Bar

[]Xyz

\n\t//

Foo

BarXyz

\n\t//\n\t// Client B:\n\t//

Foo

[

Bar

]

Xyz

\n\t//

Foo

[]Xyz

\n\t//

FooXyz

\n\t//\n\t// In this case we need to decide where finally \"Xyz\" will land:\n\t//\n\t//

FooXyz

graveyard:

Bar

\n\t//

Foo

graveyard:

BarXyz

\n\t//\n\t// Let's move it in a way so that a merge operation that does not target to graveyard is more important so that\n\t// nodes does not end up in the graveyard. It makes sense. Both for Client A and for Client B \"Xyz\" finally did not\n\t// end up in the graveyard (see above).\n\t//\n\t// If neither or both operations point to graveyard, then let `aIsStrong` decide.\n\t//\n\tif (\n\t\ta.sourcePosition.isEqual( b.sourcePosition ) && !a.targetPosition.isEqual( b.targetPosition ) &&\n\t\t!context.bWasUndone && context.abRelation != 'splitAtSource'\n\t) {\n\t\tconst aToGraveyard = a.targetPosition.root.rootName == '$graveyard';\n\t\tconst bToGraveyard = b.targetPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aToGraveyard && !bToGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bToGraveyard && !aToGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst sourcePosition = b.targetPosition._getTransformedByMergeOperation( b );\n\t\t\tconst targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\treturn [ new MoveOperation( sourcePosition, a.howMany, targetPosition, 0 ) ];\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMergeOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t// Handle positions in graveyard.\n\t// If graveyard positions are same and `a` operation is strong - do not transform.\n\tif ( !a.graveyardPosition.isEqual( b.graveyardPosition ) || !context.aIsStrong ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MoveOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// The element to merge got removed.\n\t//\n\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t// from technical point of view. However, if the element was removed, the intention of the user deleting it\n\t// was to have it all deleted, together with its children. From user experience point of view, moving back the\n\t// removed nodes might be unexpected. This means that in this scenario we will block the merging.\n\t//\n\t// The exception of this rule would be if the remove operation was later undone.\n\t//\n\tconst removedRange = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\tif ( a.deletionPosition.hasSameParentAs( b.sourcePosition ) && removedRange.containsPosition( a.sourcePosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\tif ( a.sourcePosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMoveOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMoveOperation( b );\n\n\t// `MergeOperation` graveyard position is like `MoveOperation` target position. It is a position where element(s) will\n\t// be moved. Like in other similar cases, we need to consider the scenario when those positions are same.\n\t// Here, we will treat `MergeOperation` like it is always strong (see `InsertOperation` x `InsertOperation` for comparison).\n\t// This means that we won't transform graveyard position if it is equal to move operation target position.\n\tif ( !a.graveyardPosition.isEqual( b.targetPosition ) ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, SplitOperation, ( a, b, context ) => {\n\tif ( b.graveyardPosition ) {\n\t\t// If `b` operation defines graveyard position, a node from graveyard will be moved. This means that we need to\n\t\t// transform `a.graveyardPosition` accordingly.\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByDeletion( b.graveyardPosition, 1 );\n\n\t\t// This is a scenario foreseen in `MergeOperation` x `MergeOperation`, with two identical merge operations.\n\t\t//\n\t\t// So, there was `MergeOperation` x `MergeOperation` transformation earlier. Now, `a` is a merge operation which\n\t\t// source position is in graveyard. Interestingly, split operation wants to use the node to be merged by `a`. This\n\t\t// means that `b` is undoing that merge operation from earlier, which caused `a` to be in graveyard.\n\t\t//\n\t\t// If that's the case, at this point, we will only \"fix\" `a.howMany`. It was earlier set to `0` in\n\t\t// `MergeOperation` x `MergeOperation` transformation. Later transformations in this function will change other\n\t\t// properties.\n\t\t//\n\t\tif ( a.deletionPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\ta.howMany = b.howMany;\n\t\t}\n\t}\n\n\t// Case 1:\n\t//\n\t// Merge operation moves nodes to the place where split happens.\n\t// This is a classic situation when there are two paragraphs, and there is a split (enter) after the first\n\t// paragraph and there is a merge (delete) at the beginning of the second paragraph:\n\t//\n\t//

Foo{}

[]Bar

.\n\t//\n\t// Split is after `Foo`, while merge is from `Bar` to the end of `Foo`.\n\t//\n\t// State after split:\n\t//

Foo

Bar

\n\t//\n\t// Now, `Bar` should be merged to the new paragraph:\n\t//

Foo

Bar

\n\t//\n\t// Instead of merging it to the original paragraph:\n\t//

FooBar

\n\t//\n\t// This means that `targetPosition` needs to be transformed. This is the default case though.\n\t// For example, if the split would be after `F`, `targetPosition` should also be transformed.\n\t//\n\t// There are three exceptions, though, when we want to keep `targetPosition` as it was.\n\t//\n\t// First exception is when the merge target position is inside an element (not at the end, as usual). This\n\t// happens when the merge operation earlier was transformed by \"the same\" merge operation. If merge operation\n\t// targets inside the element we want to keep the original target position (and not transform it) because\n\t// we have additional context telling us that we want to merge to the original element. We can check if the\n\t// merge operation points inside element by checking what is `SplitOperation#howMany`. Since merge target position\n\t// is same as split position, if `howMany` is non-zero, it means that the merge target position is inside an element.\n\t//\n\t// Second exception is when the element to merge is in the graveyard and split operation uses it. In that case\n\t// if target position would be transformed, the merge operation would target at the source position:\n\t//\n\t// root:

Foo

\t\t\t\tgraveyard:

\n\t//\n\t// SplitOperation: root [ 0, 3 ] using graveyard [ 0 ] (howMany = 0)\n\t// MergeOperation: graveyard [ 0, 0 ] -> root [ 0, 3 ] (howMany = 0)\n\t//\n\t// Since split operation moves the graveyard node back to the root, the merge operation source position changes.\n\t// We would like to merge from the empty

to the \"Foo\"

:\n\t//\n\t// root:

Foo

\t\t\tgraveyard:\n\t//\n\t// MergeOperation#sourcePosition = root [ 1, 0 ]\n\t//\n\t// If `targetPosition` is transformed, it would become root [ 1, 0 ] as well. It has to be kept as it was.\n\t//\n\t// Third exception is connected with relations. If this happens during undo and we have explicit information\n\t// that target position has not been affected by the operation which is undone by this split then this split should\n\t// not move the target position either.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) ) {\n\t\tconst mergeInside = b.howMany != 0;\n\t\tconst mergeSplittingElement = b.graveyardPosition && a.deletionPosition.isEqual( b.graveyardPosition );\n\n\t\tif ( mergeInside || mergeSplittingElement || context.abRelation == 'mergeTargetNotMoved' ) {\n\t\t\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Merge source is at the same position as split position. This sometimes happen, mostly during undo.\n\t// The decision here is mostly to choose whether merge source position should stay where it is (so it will be at the end of the\n\t// split element) or should be move to the beginning of the new element.\n\t//\n\tif ( a.sourcePosition.isEqual( b.splitPosition ) ) {\n\t\t// Use context to check if `SplitOperation` is not undoing a merge operation, that didn't change the `a` operation.\n\t\t// This scenario happens the undone merge operation moved nodes at the source position of `a` operation.\n\t\t// In that case `a` operation source position should stay where it is.\n\t\tif ( context.abRelation == 'mergeSourceNotMoved' ) {\n\t\t\ta.howMany = 0;\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\t// This merge operation might have been earlier transformed by a merge operation which both merged the same element.\n\t\t// See that case in `MergeOperation` x `MergeOperation` transformation. In that scenario, if the merge operation has been undone,\n\t\t// the special case is not applied.\n\t\t//\n\t\t// Now, the merge operation is transformed by the split which has undone that previous merge operation.\n\t\t// So now we are fixing situation which was skipped in `MergeOperation` x `MergeOperation` case.\n\t\t//\n\t\tif ( context.abRelation == 'mergeSameElement' || a.sourcePosition.offset > 0 ) {\n\t\t\ta.sourcePosition = b.moveTargetPosition.clone();\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.splitPosition ) ) {\n\t\ta.howMany = b.splitPosition.offset;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MoveOperation, InsertOperation, ( a, b ) => {\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByInsertOperation( b, false )[ 0 ];\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\n\t// See `InsertOperation` x `MoveOperation` transformation for details on this case.\n\t//\n\t// In summary, both operations point to the same place, so the order of nodes needs to be decided.\n\t// `MoveOperation` is considered weaker, so it is always transformed, unless there was a certain relation\n\t// between operations.\n\t//\n\tif ( !a.targetPosition.isEqual( b.position ) ) {\n\t\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MoveOperation, MoveOperation, ( a, b, context ) => {\n\t//\n\t// Setting and evaluating some variables that will be used in special cases and default algorithm.\n\t//\n\t// Create ranges from `MoveOperations` properties.\n\tconst rangeA = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst rangeB = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\t// Assign `context.aIsStrong` to a different variable, because the value may change during execution of\n\t// this algorithm and we do not want to override original `context.aIsStrong` that will be used in later transformations.\n\tlet aIsStrong = context.aIsStrong;\n\n\t// This will be used to decide the order of nodes if both operations target at the same position.\n\t// By default, use strong/weak operation mechanism.\n\tlet insertBefore = !context.aIsStrong;\n\n\t// If the relation is set, then use it to decide nodes order.\n\tif ( context.abRelation == 'insertBefore' || context.baRelation == 'insertAfter' ) {\n\t\tinsertBefore = true;\n\t} else if ( context.abRelation == 'insertAfter' || context.baRelation == 'insertBefore' ) {\n\t\tinsertBefore = false;\n\t}\n\n\t// `a.targetPosition` could be affected by the `b` operation. We will transform it.\n\tlet newTargetPosition;\n\n\tif ( a.targetPosition.isEqual( b.targetPosition ) && insertBefore ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByDeletion(\n\t\t\tb.sourcePosition,\n\t\t\tb.howMany\n\t\t);\n\t} else {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByMove(\n\t\t\tb.sourcePosition,\n\t\t\tb.targetPosition,\n\t\t\tb.howMany\n\t\t);\n\t}\n\n\t//\n\t// Special case #1 + mirror.\n\t//\n\t// Special case when both move operations' target positions are inside nodes that are\n\t// being moved by the other move operation. So in other words, we move ranges into inside of each other.\n\t// This case can't be solved reasonably (on the other hand, it should not happen often).\n\tif ( _moveTargetIntoMovedRange( a, b ) && _moveTargetIntoMovedRange( b, a ) ) {\n\t\t// Instead of transforming operation, we return a reverse of the operation that we transform by.\n\t\t// So when the results of this \"transformation\" will be applied, `b` MoveOperation will get reversed.\n\t\treturn [ b.getReversed() ];\n\t}\n\t//\n\t// End of special case #1.\n\t//\n\n\t//\n\t// Special case #2.\n\t//\n\t// Check if `b` operation targets inside `rangeA`.\n\tconst bTargetsToA = rangeA.containsPosition( b.targetPosition );\n\n\t// If `b` targets to `rangeA` and `rangeA` contains `rangeB`, `b` operation has no influence on `a` operation.\n\t// You might say that operation `b` is captured inside operation `a`.\n\tif ( bTargetsToA && rangeA.containsRange( rangeB, true ) ) {\n\t\t// There is a mini-special case here, where `rangeB` is on other level than `rangeA`. That's why\n\t\t// we need to transform `a` operation anyway.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\n\t//\n\t// Special case #2 mirror.\n\t//\n\tconst aTargetsToB = rangeB.containsPosition( a.targetPosition );\n\n\tif ( aTargetsToB && rangeB.containsRange( rangeA, true ) ) {\n\t\t// `a` operation is \"moved together\" with `b` operation.\n\t\t// Here, just move `rangeA` \"inside\" `rangeB`.\n\t\trangeA.start = rangeA.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\trangeA.end = rangeA.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #2.\n\t//\n\n\t//\n\t// Special case #3 + mirror.\n\t//\n\t// `rangeA` has a node which is an ancestor of `rangeB`. In other words, `rangeB` is inside `rangeA`\n\t// but not on the same tree level. In such case ranges have common part but we have to treat it\n\t// differently, because in such case those ranges are not really conflicting and should be treated like\n\t// two separate ranges. Also we have to discard two difference parts.\n\tconst aCompB = compareArrays( a.sourcePosition.getParentPath(), b.sourcePosition.getParentPath() );\n\n\tif ( aCompB == 'prefix' || aCompB == 'extension' ) {\n\t\t// Transform `rangeA` by `b` operation and make operation out of it, and that's all.\n\t\t// Note that this is a simplified version of default case, but here we treat the common part (whole `rangeA`)\n\t\t// like a one difference part.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #3.\n\t//\n\n\t//\n\t// Default case - ranges are on the same level or are not connected with each other.\n\t//\n\t// Modifier for default case.\n\t// Modifies `aIsStrong` flag in certain conditions.\n\t//\n\t// If only one of operations is a remove operation, we force remove operation to be the \"stronger\" one\n\t// to provide more expected results.\n\tif ( a.type == 'remove' && b.type != 'remove' && !context.aWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = true;\n\t} else if ( a.type != 'remove' && b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = false;\n\t}\n\n\t// Handle operation's source ranges - check how `rangeA` is affected by `b` operation.\n\t// This will aggregate transformed ranges.\n\tconst ranges = [];\n\n\t// Get the \"difference part\" of `a` operation source range.\n\t// This is an array with one or two ranges. Two ranges if `rangeB` is inside `rangeA`.\n\tconst difference = rangeA.getDifference( rangeB );\n\n\tfor ( const range of difference ) {\n\t\t// Transform those ranges by `b` operation. For example if `b` moved range from before those ranges, fix those ranges.\n\t\trange.start = range.start._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\trange.end = range.end._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\n\t\t// If `b` operation targets into `rangeA` on the same level, spread `rangeA` into two ranges.\n\t\tconst shouldSpread = compareArrays( range.start.getParentPath(), b.getMovedRangeStart().getParentPath() ) == 'same';\n\t\tconst newRanges = range._getTransformedByInsertion( b.getMovedRangeStart(), b.howMany, shouldSpread );\n\n\t\tranges.push( ...newRanges );\n\t}\n\n\t// Then, we have to manage the \"common part\" of both move ranges.\n\tconst common = rangeA.getIntersection( rangeB );\n\n\tif ( common !== null && aIsStrong ) {\n\t\t// Calculate the new position of that part of original range.\n\t\tcommon.start = common.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\tcommon.end = common.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\t// Take care of proper range order.\n\t\t//\n\t\t// Put `common` at appropriate place. Keep in mind that we are interested in original order.\n\t\t// Basically there are only three cases: there is zero, one or two difference ranges.\n\t\t//\n\t\t// If there is zero difference ranges, just push `common` in the array.\n\t\tif ( ranges.length === 0 ) {\n\t\t\tranges.push( common );\n\t\t}\n\t\t// If there is one difference range, we need to check whether common part was before it or after it.\n\t\telse if ( ranges.length == 1 ) {\n\t\t\tif ( rangeB.start.isBefore( rangeA.start ) || rangeB.start.isEqual( rangeA.start ) ) {\n\t\t\t\tranges.unshift( common );\n\t\t\t} else {\n\t\t\t\tranges.push( common );\n\t\t\t}\n\t\t}\n\t\t// If there are more ranges (which means two), put common part between them. This is the only scenario\n\t\t// where there could be two difference ranges so we don't have to make any comparisons.\n\t\telse {\n\t\t\tranges.splice( 1, 0, common );\n\t\t}\n\t}\n\n\tif ( ranges.length === 0 ) {\n\t\t// If there are no \"source ranges\", nothing should be changed.\n\t\t// Note that this can happen only if `aIsStrong == false` and `rangeA.isEqual( rangeB )`.\n\t\treturn [ new NoOperation( a.baseVersion ) ];\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {\n\tlet newTargetPosition = a.targetPosition.clone();\n\n\t// Do not transform if target position is same as split insertion position and this split comes from undo.\n\t// This should be done on relations but it is too much work for now as it would require relations working in collaboration.\n\t// We need to make a decision how we will resolve such conflict and this is less harmful way.\n\tif ( !a.targetPosition.isEqual( b.insertionPosition ) || !b.graveyardPosition || context.abRelation == 'moveTargetAfter' ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 1:\n\t//\n\t// Last element in the moved range got split.\n\t//\n\t// In this case the default range transformation will not work correctly as the element created by\n\t// split operation would be outside the range. The range to move needs to be fixed manually.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( moveRange.end.isEqual( b.insertionPosition ) ) {\n\t\t// Do it only if this is a \"natural\" split, not a one that comes from undo.\n\t\t// If this is undo split, only `targetPosition` needs to be changed (if the move is a remove).\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.howMany++;\n\t\t}\n\n\t\ta.targetPosition = newTargetPosition;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split happened between the moved nodes. In this case two ranges to move need to be generated.\n\t//\n\t// Characters `ozba` are moved to the end of paragraph `Xyz` but split happened.\n\t//

F[oz|ba]r

Xyz

\n\t//\n\t// After split:\n\t//

F[oz

ba]r

Xyz

\n\t//\n\t// Correct ranges:\n\t//

F[oz]

[ba]r

Xyz

\n\t//\n\t// After move:\n\t//

F

r

Xyzozba

\n\t//\n\tif ( moveRange.start.hasSameParentAs( b.splitPosition ) && moveRange.containsPosition( b.splitPosition ) ) {\n\t\tlet rightRange = new Range( b.splitPosition, moveRange.end );\n\t\trightRange = rightRange._getTransformedBySplitOperation( b );\n\n\t\tconst ranges = [\n\t\t\tnew Range( moveRange.start, b.splitPosition ),\n\t\t\trightRange\n\t\t];\n\n\t\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n\t}\n\n\t// Case 3:\n\t//\n\t// Move operation targets at the split position. We need to decide if the nodes should be inserted\n\t// at the end of the split element or at the beginning of the new element.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) && context.abRelation == 'insertAtSource' ) {\n\t\tnewTargetPosition = b.moveTargetPosition;\n\t}\n\n\t// Case 4:\n\t//\n\t// Move operation targets just after the split element. We need to decide if the nodes should be inserted\n\t// between two parts of split element, or after the new element.\n\t//\n\t// Split at `|`, while move operation moves `

Xyz

` and targets at `^`:\n\t//

Foo|bar

^

baz

\n\t//

Foo

^

bar

baz

or

Foo

bar

^

baz

?\n\t//\n\t// If there is no contextual information between operations (for example, they come from collaborative\n\t// editing), we don't want to put some unrelated content (move) between parts of related content (split parts).\n\t// However, if the split is from undo, in the past, the moved content might be targeting between the\n\t// split parts, meaning that was exactly user's intention:\n\t//\n\t//

Foo

^

bar

\t\t<--- original situation, in \"past\".\n\t//

Foobar

^\t\t\t\t<--- after merge target position is transformed.\n\t//

Foo|bar

^\t\t\t\t<--- then the merge is undone, and split happens, which leads us to current situation.\n\t//\n\t// In this case it is pretty clear that the intention was to put new paragraph between those nodes,\n\t// so we need to transform accordingly. We can detect this scenario thanks to relations.\n\t//\n\tif ( a.targetPosition.isEqual( b.insertionPosition ) && context.abRelation == 'insertBetween' ) {\n\t\tnewTargetPosition = a.targetPosition;\n\t}\n\n\t// The default case.\n\t//\n\tconst transformed = moveRange._getTransformedBySplitOperation( b );\n\tconst ranges = [ transformed ];\n\n\t// Case 5:\n\t//\n\t// Moved range contains graveyard element used by split operation. Add extra move operation to the result.\n\t//\n\tif ( b.graveyardPosition ) {\n\t\tconst movesGraveyardElement = moveRange.start.isEqual( b.graveyardPosition ) || moveRange.containsPosition( b.graveyardPosition );\n\n\t\tif ( a.howMany > 1 && movesGraveyardElement && !context.aWasUndone ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.insertionPosition, 1 ) );\n\t\t}\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {\n\tconst movedRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( b.deletionPosition.hasSameParentAs( a.sourcePosition ) && movedRange.containsPosition( b.sourcePosition ) ) {\n\t\tif ( a.type == 'remove' && !context.forceWeakRemove ) {\n\t\t\t// Case 1:\n\t\t\t//\n\t\t\t// The element to remove got merged.\n\t\t\t//\n\t\t\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t\t\t// from technical point of view. However, if the element was removed, the intention of the user\n\t\t\t// deleting it was to have it all deleted. From user experience point of view, moving back the\n\t\t\t// removed nodes might be unexpected. This means that in this scenario we will reverse merging and remove the element.\n\t\t\t//\n\t\t\tif ( !context.aWasUndone ) {\n\t\t\t\tconst results = [];\n\n\t\t\t\tlet gyMoveSource = b.graveyardPosition.clone();\n\t\t\t\tlet splitNodesMoveSource = b.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\tif ( a.howMany > 1 ) {\n\t\t\t\t\tresults.push( new MoveOperation( a.sourcePosition, a.howMany - 1, a.targetPosition, 0 ) );\n\n\t\t\t\t\tgyMoveSource = gyMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t}\n\n\t\t\t\tconst gyMoveTarget = b.deletionPosition._getCombined( a.sourcePosition, a.targetPosition );\n\t\t\t\tconst gyMove = new MoveOperation( gyMoveSource, 1, gyMoveTarget, 0 );\n\n\t\t\t\tconst splitNodesMoveTargetPath = gyMove.getMovedRangeStart().path.slice();\n\t\t\t\tsplitNodesMoveTargetPath.push( 0 );\n\n\t\t\t\tconst splitNodesMoveTarget = new Position( gyMove.targetPosition.root, splitNodesMoveTargetPath );\n\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( gyMoveSource, gyMoveTarget, 1 );\n\t\t\t\tconst splitNodesMove = new MoveOperation( splitNodesMoveSource, b.howMany, splitNodesMoveTarget, 0 );\n\n\t\t\t\tresults.push( gyMove );\n\t\t\t\tresults.push( splitNodesMove );\n\n\t\t\t\treturn results;\n\t\t\t}\n\t\t} else {\n\t\t\t// Case 2:\n\t\t\t//\n\t\t\t// The element to move got merged and it was the only element to move.\n\t\t\t// In this case just don't do anything, leave the node in the graveyard. Without special case\n\t\t\t// it would be a move operation that moves 0 nodes, so maybe it is better just to return no-op.\n\t\t\t//\n\t\t\tif ( a.howMany == 1 ) {\n\t\t\t\tif ( !context.bWasUndone ) {\n\t\t\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t\t\t} else {\n\t\t\t\t\ta.sourcePosition = b.graveyardPosition.clone();\n\t\t\t\t\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\t\treturn [ a ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByMergeOperation( b );\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RenameOperation, InsertOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MergeOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Element to rename got merged, so it was moved to `b.graveyardPosition`.\n\t//\n\tif ( a.position.isEqual( b.deletionPosition ) ) {\n\t\ta.position = b.graveyardPosition.clone();\n\t\ta.position.stickiness = 'toNext';\n\n\t\treturn [ a ];\n\t}\n\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MoveOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, RenameOperation, ( a, b, context ) => {\n\tif ( a.position.isEqual( b.position ) ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldName = b.newName;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The element to rename has been split. In this case, the new element should be also renamed.\n\t//\n\t// User decides to change the paragraph to a list item:\n\t// Foobar\n\t//\n\t// However, in meantime, split happens:\n\t// Foobar\n\t//\n\t// As a result, rename both elements:\n\t// Foobar\n\t//\n\tconst renamePath = a.position.path;\n\tconst splitPath = b.splitPosition.getParentPath();\n\n\tif ( compareArrays( renamePath, splitPath ) == 'same' && !b.graveyardPosition ) {\n\t\tconst extraRename = new RenameOperation( a.position.getShiftedBy( 1 ), a.oldName, a.newName, 0 );\n\n\t\treturn [ a, extraRename ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RootAttributeOperation, RootAttributeOperation, ( a, b, context ) => {\n\tif ( a.root === b.root && a.key === b.key ) {\n\t\tif ( !context.aIsStrong || a.newValue === b.newValue ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\ta.oldValue = b.newValue;\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( SplitOperation, InsertOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.position ) && a.splitPosition.offset < b.position.offset ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByInsertOperation( b );\n\ta.insertionPosition = a.insertionPosition._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split element got merged. If two different elements were merged, clients will have different content.\n\t//\n\t// Example. Merge at `{}`, split at `[]`:\n\t// Foo{}B[]ar\n\t//\n\t// On merge side it will look like this:\n\t// FooB[]ar\n\t// FooBar\n\t//\n\t// On split side it will look like this:\n\t// Foo{}Bar\n\t// FooBar\n\t//\n\t// Clearly, the second element is different for both clients.\n\t//\n\t// We could use the removed merge element from graveyard as a split element but then clients would have a different\n\t// model state (in graveyard), because the split side client would still have an element in graveyard (removed by merge).\n\t//\n\t// To overcome this, in `SplitOperation` x `MergeOperation` transformation we will add additional `SplitOperation`\n\t// in the graveyard, which will actually clone the merged-and-deleted element. Then, that cloned element will be\n\t// used for splitting. Example below.\n\t//\n\t// Original state:\n\t// Foo{}B[]ar\n\t//\n\t// Merge side client:\n\t//\n\t// After merge:\n\t// FooB[]ar graveyard: \n\t//\n\t// Extra split:\n\t// FooB[]ar graveyard: \n\t//\n\t// Use the \"cloned\" element from graveyard:\n\t// FooBar graveyard: \n\t//\n\t// Split side client:\n\t//\n\t// After split:\n\t// Foo{}Bar\n\t//\n\t// After merge:\n\t// FooBar graveyard: \n\t//\n\t// This special case scenario only applies if the original split operation clones the split element.\n\t// If the original split operation has `graveyardPosition` set, it all doesn't have sense because split operation\n\t// knows exactly which element it should use. So there would be no original problem with different contents.\n\t//\n\t// Additionally, the special case applies only if the merge wasn't already undone.\n\t//\n\tif ( !a.graveyardPosition && !context.bWasUndone && a.splitPosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\tconst splitPath = b.graveyardPosition.path.slice();\n\t\tsplitPath.push( 0 );\n\n\t\tconst splitPosition = new Position( b.graveyardPosition.root, splitPath );\n\t\tconst insertionPosition = SplitOperation.getInsertionPosition( new Position( b.graveyardPosition.root, splitPath ) );\n\n\t\tconst additionalSplit = new SplitOperation( splitPosition, 0, insertionPosition, null, 0 );\n\n\t\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t\ta.graveyardPosition = additionalSplit.insertionPosition.clone();\n\t\ta.graveyardPosition.stickiness = 'toNext';\n\n\t\treturn [ additionalSplit, a ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.deletionPosition ) && !a.splitPosition.isAfter( b.deletionPosition ) ) {\n\t\ta.howMany--;\n\t}\n\n\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MoveOperation, ( a, b, context ) => {\n\tconst rangeToMove = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( a.graveyardPosition ) {\n\t\t// Case 1:\n\t\t//\n\t\t// Split operation graveyard node was moved. In this case move operation is stronger. Since graveyard element\n\t\t// is already moved to the correct position, we need to only move the nodes after the split position.\n\t\t// This will be done by `MoveOperation` instead of `SplitOperation`.\n\t\t//\n\t\tconst gyElementMoved = rangeToMove.start.isEqual( a.graveyardPosition ) || rangeToMove.containsPosition( a.graveyardPosition );\n\n\t\tif ( !context.bWasUndone && gyElementMoved ) {\n\t\t\tconst sourcePosition = a.splitPosition._getTransformedByMoveOperation( b );\n\n\t\t\tconst newParentPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t\t\tconst newTargetPath = newParentPosition.path.slice();\n\t\t\tnewTargetPath.push( 0 );\n\n\t\t\tconst newTargetPosition = new Position( newParentPosition.root, newTargetPath );\n\t\t\tconst moveOp = new MoveOperation( sourcePosition, a.howMany, newTargetPosition, 0 );\n\n\t\t\treturn [ moveOp ];\n\t\t}\n\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\t// Case 2:\n\t//\n\t// Split is at a position where nodes were moved.\n\t//\n\t// This is a scenario described in `MoveOperation` x `SplitOperation` transformation but from the\n\t// \"split operation point of view\".\n\t//\n\tconst splitAtTarget = a.splitPosition.isEqual( b.targetPosition );\n\n\tif ( splitAtTarget && ( context.baRelation == 'insertAtSource' || context.abRelation == 'splitBefore' ) ) {\n\t\ta.howMany += b.howMany;\n\t\ta.splitPosition = a.splitPosition._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\tif ( splitAtTarget && context.abRelation && context.abRelation.howMany ) {\n\t\tconst { howMany, offset } = context.abRelation;\n\n\t\ta.howMany += howMany;\n\t\ta.splitPosition = a.splitPosition.getShiftedBy( offset );\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 3:\n\t//\n\t// If the split position is inside the moved range, we need to shift the split position to a proper place.\n\t// The position cannot be moved together with moved range because that would result in splitting of an incorrect element.\n\t//\n\t// Characters `bc` should be moved to the second paragraph while split position is between them:\n\t// A[b|c]dXyz\n\t//\n\t// After move, new split position is incorrect:\n\t// AdXb|cyz\n\t//\n\t// Correct split position:\n\t// A|dXbcyz\n\t//\n\t// After split:\n\t// AdXbcyz\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && rangeToMove.containsPosition( a.splitPosition ) ) {\n\t\tconst howManyRemoved = b.howMany - ( a.splitPosition.offset - b.sourcePosition.offset );\n\t\ta.howMany -= howManyRemoved;\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\n\t\ta.splitPosition = b.sourcePosition.clone();\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t// Don't change `howMany` if move operation does not really move anything.\n\t//\n\tif ( !b.sourcePosition.isEqual( b.targetPosition ) ) {\n\t\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && a.splitPosition.offset <= b.sourcePosition.offset ) {\n\t\t\ta.howMany -= b.howMany;\n\t\t}\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\t}\n\n\t// Change position stickiness to force a correct transformation.\n\ta.splitPosition.stickiness = 'toNone';\n\ta.splitPosition = a.splitPosition._getTransformedByMoveOperation( b );\n\ta.splitPosition.stickiness = 'toNext';\n\n\tif ( a.graveyardPosition ) {\n\t\ta.insertionPosition = a.insertionPosition._getTransformedByMoveOperation( b );\n\t} else {\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, SplitOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split at the same position.\n\t//\n\t// If there already was a split at the same position as in `a` operation, it means that the intention\n\t// conveyed by `a` operation has already been fulfilled and `a` should not do anything (to avoid double split).\n\t//\n\t// However, there is a difference if these are new splits or splits created by undo. These have different\n\t// intentions. Also splits moving back different elements from graveyard have different intentions. They\n\t// are just different operations.\n\t//\n\t// So we cancel split operation only if it was really identical.\n\t//\n\t// Also, there is additional case, where split operations aren't identical and should not be cancelled, however the\n\t// default transformation is incorrect too.\n\t//\n\tif ( a.splitPosition.isEqual( b.splitPosition ) ) {\n\t\tif ( !a.graveyardPosition && !b.graveyardPosition ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\t// Use context to know that the `a.splitPosition` should stay where it is.\n\t\t// This happens during undo when first a merge operation moved nodes to `a.splitPosition` and now `b` operation undoes that merge.\n\t\tif ( context.abRelation == 'splitBefore' ) {\n\t\t\t// Since split is at the same position, there are no nodes left to split.\n\t\t\ta.howMany = 0;\n\n\t\t\t// Note: there was `if ( a.graveyardPosition )` here but it was uncovered in tests and I couldn't find any scenarios for now.\n\t\t\t// That would have to be a `SplitOperation` that didn't come from undo but is transformed by operations that were undone.\n\t\t\t// It could happen if `context` is enabled in collaboration.\n\t\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same node is using to split different elements. This happens in undo when previously same element was merged to\n\t// two different elements. This is described in `MergeOperation` x `MergeOperation` transformation.\n\t//\n\t// In this case we will follow the same logic. We will assume that `insertionPosition` is same for both\n\t// split operations. This might not always be true but in the real cases that were experienced it was. After all,\n\t// if these splits are reverses of merge operations that were merging the same element, then the `insertionPosition`\n\t// should be same for both of those splits.\n\t//\n\t// Again, we will decide which operation is stronger by checking if split happens in graveyard or in non-graveyard root.\n\t//\n\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\tconst aInGraveyard = a.splitPosition.root.rootName == '$graveyard';\n\t\tconst bInGraveyard = b.splitPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aInGraveyard && !bInGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bInGraveyard && !aInGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst result = [];\n\n\t\t\t// First we need to move any nodes split by `b` back to where they were.\n\t\t\t// Do it only if `b` actually moved something.\n\t\t\tif ( b.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( b.moveTargetPosition, b.howMany, b.splitPosition, 0 ) );\n\t\t\t}\n\n\t\t\t// Then we need to move nodes from `a` split position to their new element.\n\t\t\t// Do it only if `a` actually should move something.\n\t\t\tif ( a.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( a.splitPosition, a.howMany, a.moveTargetPosition, 0 ) );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 3:\n\t//\n\t// Position where operation `b` inserted a new node after split is the same as the operation `a` split position.\n\t// As in similar cases, there is ambiguity if the split should be before the new node (created by `b`) or after.\n\t//\n\tif ( a.splitPosition.isEqual( b.insertionPosition ) && context.abRelation == 'splitBefore' ) {\n\t\ta.howMany++;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 4:\n\t//\n\t// This is a mirror to the case 2. above.\n\t//\n\tif ( b.splitPosition.isEqual( a.insertionPosition ) && context.baRelation == 'splitBefore' ) {\n\t\tconst newPositionPath = b.insertionPosition.path.slice();\n\t\tnewPositionPath.push( 0 );\n\n\t\tconst newPosition = new Position( b.insertionPosition.root, newPositionPath );\n\t\tconst moveOp = new MoveOperation( a.insertionPosition, 1, newPosition, 0 );\n\n\t\treturn [ a, moveOp ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.splitPosition ) && a.splitPosition.offset < b.splitPosition.offset ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedBySplitOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\treturn [ a ];\n} );\n\n// Checks whether `MoveOperation` `targetPosition` is inside a node from the moved range of the other `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/operation/moveoperation~MoveOperation} a\n// @param {module:engine/model/operation/moveoperation~MoveOperation} b\n// @returns {Boolean}\nfunction _moveTargetIntoMovedRange( a, b ) {\n\treturn a.targetPosition._getTransformedByDeletion( b.sourcePosition, b.howMany ) === null;\n}\n\n// Helper function for `MoveOperation` x `MoveOperation` transformation. Converts given ranges and target position to\n// move operations and returns them.\n//\n// Ranges and target position will be transformed on-the-fly when generating operations.\n//\n// Given `ranges` should be in the order of how they were in the original transformed operation.\n//\n// Given `targetPosition` is the target position of the first range from `ranges`.\n//\n// @private\n// @param {Array.} ranges\n// @param {module:engine/model/position~Position} targetPosition\n// @returns {Array.}\nfunction _makeMoveOperationsFromRanges( ranges, targetPosition ) {\n\t// At this moment we have some ranges and a target position, to which those ranges should be moved.\n\t// Order in `ranges` array is the go-to order of after transformation.\n\t//\n\t// We are almost done. We have `ranges` and `targetPosition` to make operations from.\n\t// Unfortunately, those operations may affect each other. Precisely, first operation after move\n\t// may affect source range and target position of second and third operation. Same with second\n\t// operation affecting third.\n\t//\n\t// We need to fix those source ranges and target positions once again, before converting `ranges` to operations.\n\tconst operations = [];\n\n\t// Keep in mind that nothing will be transformed if there is just one range in `ranges`.\n\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t// Create new operation out of a range and target position.\n\t\tconst range = ranges[ i ];\n\t\tconst op = new MoveOperation(\n\t\t\trange.start,\n\t\t\trange.end.offset - range.start.offset,\n\t\t\ttargetPosition,\n\t\t\t0\n\t\t);\n\n\t\toperations.push( op );\n\n\t\t// Transform other ranges by the generated operation.\n\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t// All ranges in `ranges` array should be:\n\t\t\t//\n\t\t\t// * non-intersecting (these are part of original operation source range), and\n\t\t\t// * `targetPosition` does not target into them (opposite would mean that transformed operation targets \"inside itself\").\n\t\t\t//\n\t\t\t// This means that the transformation will be \"clean\" and always return one result.\n\t\t\tranges[ j ] = ranges[ j ]._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany )[ 0 ];\n\t\t}\n\n\t\ttargetPosition = targetPosition._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany );\n\t}\n\n\treturn operations;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/renameoperation\n */\n\nimport Operation from './operation';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Position from '../position';\n\n/**\n * Operation to change element's name.\n *\n * Using this class you can change element's name.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RenameOperation extends Operation {\n\t/**\n\t * Creates an operation that changes element's name.\n\t *\n\t * @param {module:engine/model/position~Position} position Position before an element to change.\n\t * @param {String} oldName Current name of the element.\n\t * @param {String} newName New name for the element.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, oldName, newName, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before an element to change.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/renameoperation~RenameOperation#position\n\t\t */\n\t\tthis.position = position;\n\t\t// This position sticks to the next node because it is a position before the node that we want to change.\n\t\tthis.position.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Current name of the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#oldName\n\t\t */\n\t\tthis.oldName = oldName;\n\n\t\t/**\n\t\t * New name for the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#newName\n\t\t */\n\t\tthis.newName = newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'rename';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RenameOperation( this.position.clone(), this.oldName, this.newName, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RenameOperation( this.position.clone(), this.newName, this.oldName, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\tif ( !( element instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Given position is invalid or node after it is not instance of Element.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-position',\n\t\t\t\tthis\n\t\t\t);\n\t\t} else if ( element.name !== this.oldName ) {\n\t\t\t/**\n\t\t\t * Element to change has different name than operation's old name.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-name\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-name',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\telement.name = this.newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RenameOperation';\n\t}\n\n\t/**\n\t * Creates `RenameOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new RenameOperation( Position.fromJSON( json.position, document ), json.oldName, json.newName, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RenameOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.position }: \"${ this.oldName }\" -> \"${ this.newName }\"`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/mergeoperation\n */\n\nimport Operation from './operation';\nimport SplitOperation from './splitoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to merge two {@link module:engine/model/element~Element elements}.\n *\n * The merged element is the parent of {@link ~MergeOperation#sourcePosition} and it is merged into the parent of\n * {@link ~MergeOperation#targetPosition}. All nodes from the merged element are moved to {@link ~MergeOperation#targetPosition}.\n *\n * The merged element is moved to the graveyard at {@link ~MergeOperation#graveyardPosition}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MergeOperation extends Operation {\n\t/**\n\t * Creates a merge operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition Position inside the merged element. All nodes from that\n\t * element after that position will be moved to {@link ~#targetPosition}.\n\t * @param {Number} howMany Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t * @param {module:engine/model/position~Position} targetPosition Position which the nodes from the merged elements will be moved to.\n\t * @param {module:engine/model/position~Position} graveyardPosition Position in graveyard to which the merged element will be moved.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position inside the merged element. All nodes from that element after that position will be moved to {@link ~#targetPosition}.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// This is, and should always remain, the first position in its parent.\n\t\tthis.sourcePosition.stickiness = 'toPrevious';\n\n\t\t/**\n\t\t * Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/mergeoperation~MergeOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position which the nodes from the merged elements will be moved to.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\t// Except of a rare scenario in `MergeOperation` x `MergeOperation` transformation,\n\t\t// this is, and should always remain, the last position in its parent.\n\t\tthis.targetPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Position in graveyard to which the merged element will be moved.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition.clone();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'merge';\n\t}\n\n\t/**\n\t * Position before the merged element (which will be deleted).\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget deletionPosition() {\n\t\treturn new Position( this.sourcePosition.root, this.sourcePosition.path.slice( 0, -1 ) );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the merged element that will be moved to {@link ~MergeOperation#sourcePosition}.\n\t * The range starts at {@link ~MergeOperation#sourcePosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.sourcePosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.sourcePosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.graveyardPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tgetReversed() {\n\t\t// Positions in this method are transformed by this merge operation because the split operation bases on\n\t\t// the context after this merge operation happened (because split operation reverses it).\n\t\t// So we need to acknowledge that the merge operation happened and those positions changed a little.\n\t\tconst targetPosition = this.targetPosition._getTransformedByMergeOperation( this );\n\n\t\tconst path = this.sourcePosition.path.slice( 0, -1 );\n\t\tconst insertionPosition = new Position( this.sourcePosition.root, path )._getTransformedByMergeOperation( this );\n\n\t\treturn new SplitOperation( targetPosition, this.howMany, insertionPosition, this.graveyardPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\n\t\t// Validate whether merge operation has correct parameters.\n\t\tif ( !sourceElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge source position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-source-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-source-position-invalid', this );\n\t\t} else if ( !targetElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge target position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-target-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-target-position-invalid', this );\n\t\t} else if ( this.howMany != sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * Merge operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error merge-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-how-many-invalid', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst mergedElement = this.sourcePosition.parent;\n\t\tconst sourceRange = Range._createIn( mergedElement );\n\n\t\t_move( sourceRange, this.targetPosition );\n\t\t_move( Range._createOn( mergedElement ), this.graveyardPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = json.sourcePosition.toJSON();\n\t\tjson.targetPosition = json.targetPosition.toJSON();\n\t\tjson.graveyardPosition = json.graveyardPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MergeOperation';\n\t}\n\n\t/**\n\t * Creates `MergeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\t\tconst graveyardPosition = Position.fromJSON( json.graveyardPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, graveyardPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MergeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.sourcePosition } -> ${ this.targetPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` ( ${ this.howMany } ), ${ this.graveyardPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/utils\n */\n\nimport Node from '../node';\nimport Text from '../text';\nimport TextProxy from '../textproxy';\nimport Range from '../range';\nimport DocumentFragment from '../documentfragment';\nimport NodeList from '../nodelist';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Contains functions used for composing model tree by {@link module:engine/model/operation/operation~Operation operations}.\n * Those functions are built on top of {@link module:engine/model/node~Node node}, and it's child classes', APIs.\n *\n * @protected\n * @namespace utils\n */\n\n/**\n * Inserts given nodes at given position.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.insert\n * @param {module:engine/model/position~Position} position Position at which nodes should be inserted.\n * @param {module:engine/model/node~NodeSet} nodes Nodes to insert.\n * @returns {module:engine/model/range~Range} Range spanning over inserted elements.\n */\nexport function _insert( position, nodes ) {\n\tnodes = _normalizeNodes( nodes );\n\n\t// We have to count offset before inserting nodes because they can get merged and we would get wrong offsets.\n\tconst offset = nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\tconst parent = position.parent;\n\n\t// Insertion might be in a text node, we should split it if that's the case.\n\t_splitNodeAtPosition( position );\n\tconst index = position.index;\n\n\t// Insert nodes at given index. After splitting we have a proper index and insertion is between nodes,\n\t// using basic `Element` API.\n\tparent._insertChild( index, nodes );\n\n\t// Merge text nodes, if possible. Merging is needed only at points where inserted nodes \"touch\" \"old\" nodes.\n\t_mergeNodesAtIndex( parent, index + nodes.length );\n\t_mergeNodesAtIndex( parent, index );\n\n\treturn new Range( position, position.getShiftedBy( offset ) );\n}\n\n/**\n * Removed nodes in given range. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._remove\n * @param {module:engine/model/range~Range} range Range containing nodes to remove.\n * @returns {Array.}\n */\nexport function _remove( range ) {\n\tif ( !range.isFlat ) {\n\t\t/**\n\t\t * Trying to remove a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-remove-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-remove-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst parent = range.start.parent;\n\n\t// Range may be inside text nodes, we have to split them if that's the case.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Remove the text nodes using basic `Element` API.\n\tconst removed = parent._removeChildren( range.start.index, range.end.index - range.start.index );\n\n\t// Merge text nodes, if possible. After some nodes were removed, node before and after removed range will be\n\t// touching at the position equal to the removed range beginning. We check merging possibility there.\n\t_mergeNodesAtIndex( parent, range.start.index );\n\n\treturn removed;\n}\n\n/**\n * Moves nodes in given range to given target position. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.move\n * @param {module:engine/model/range~Range} sourceRange Range containing nodes to move.\n * @param {module:engine/model/position~Position} targetPosition Position to which nodes should be moved.\n * @returns {module:engine/model/range~Range} Range containing moved nodes.\n */\nexport function _move( sourceRange, targetPosition ) {\n\tif ( !sourceRange.isFlat ) {\n\t\t/**\n\t\t * Trying to move a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-move-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-move-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst nodes = _remove( sourceRange );\n\n\t// We have to fix `targetPosition` because model changed after nodes from `sourceRange` got removed and\n\t// that change might have an impact on `targetPosition`.\n\ttargetPosition = targetPosition._getTransformedByDeletion( sourceRange.start, sourceRange.end.offset - sourceRange.start.offset );\n\n\treturn _insert( targetPosition, nodes );\n}\n\n/**\n * Sets given attribute on nodes in given range. The attributes are only set on top-level nodes of the range, not on its children.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._setAttribute\n * @param {module:engine/model/range~Range} range Range containing nodes that should have the attribute set. Must be a flat range.\n * @param {String} key Key of attribute to set.\n * @param {*} value Attribute value.\n */\nexport function _setAttribute( range, key, value ) {\n\t// Range might start or end in text nodes, so we have to split them.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Iterate over all items in the range.\n\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t// Iterator will return `TextProxy` instances but we know that those text proxies will\n\t\t// always represent full text nodes (this is guaranteed thanks to splitting we did before).\n\t\t// So, we can operate on those text proxies' text nodes.\n\t\tconst node = item.is( '$textProxy' ) ? item.textNode : item;\n\n\t\tif ( value !== null ) {\n\t\t\tnode._setAttribute( key, value );\n\t\t} else {\n\t\t\tnode._removeAttribute( key );\n\t\t}\n\n\t\t// After attributes changing it may happen that some text nodes can be merged. Try to merge with previous node.\n\t\t_mergeNodesAtIndex( node.parent, node.index );\n\t}\n\n\t// Try to merge last changed node with it's previous sibling (not covered by the loop above).\n\t_mergeNodesAtIndex( range.end.parent, range.end.index );\n}\n\n/**\n * Normalizes given object or an array of objects to an array of {@link module:engine/model/node~Node nodes}. See\n * {@link module:engine/model/node~NodeSet NodeSet} for details on how normalization is performed.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.normalizeNodes\n * @param {module:engine/model/node~NodeSet} nodes Objects to normalize.\n * @returns {Array.} Normalized nodes.\n */\nexport function _normalizeNodes( nodes ) {\n\tconst normalized = [];\n\n\tif ( !( nodes instanceof Array ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Convert instances of classes other than Node.\n\tfor ( let i = 0; i < nodes.length; i++ ) {\n\t\tif ( typeof nodes[ i ] == 'string' ) {\n\t\t\tnormalized.push( new Text( nodes[ i ] ) );\n\t\t} else if ( nodes[ i ] instanceof TextProxy ) {\n\t\t\tnormalized.push( new Text( nodes[ i ].data, nodes[ i ].getAttributes() ) );\n\t\t} else if ( nodes[ i ] instanceof DocumentFragment || nodes[ i ] instanceof NodeList ) {\n\t\t\tfor ( const child of nodes[ i ] ) {\n\t\t\t\tnormalized.push( child );\n\t\t\t}\n\t\t} else if ( nodes[ i ] instanceof Node ) {\n\t\t\tnormalized.push( nodes[ i ] );\n\t\t}\n\t\t// Skip unrecognized type.\n\t}\n\n\t// Merge text nodes.\n\tfor ( let i = 1; i < normalized.length; i++ ) {\n\t\tconst node = normalized[ i ];\n\t\tconst prev = normalized[ i - 1 ];\n\n\t\tif ( node instanceof Text && prev instanceof Text && _haveSameAttributes( node, prev ) ) {\n\t\t\t// Doing this instead changing `prev.data` because `data` is readonly.\n\t\t\tnormalized.splice( i - 1, 2, new Text( prev.data + node.data, prev.getAttributes() ) );\n\t\t\ti--;\n\t\t}\n\t}\n\n\treturn normalized;\n}\n\n// Checks if nodes before and after given index in given element are {@link module:engine/model/text~Text text nodes} and\n// merges them into one node if they have same attributes.\n//\n// Merging is done by removing two text nodes and inserting a new text node containing data from both merged text nodes.\n//\n// @private\n// @param {module:engine/model/element~Element} element Parent element of nodes to merge.\n// @param {Number} index Index between nodes to merge.\nfunction _mergeNodesAtIndex( element, index ) {\n\tconst nodeBefore = element.getChild( index - 1 );\n\tconst nodeAfter = element.getChild( index );\n\n\t// Check if both of those nodes are text objects with same attributes.\n\tif ( nodeBefore && nodeAfter && nodeBefore.is( '$text' ) && nodeAfter.is( '$text' ) && _haveSameAttributes( nodeBefore, nodeAfter ) ) {\n\t\t// Append text of text node after index to the before one.\n\t\tconst mergedNode = new Text( nodeBefore.data + nodeAfter.data, nodeBefore.getAttributes() );\n\n\t\t// Remove separate text nodes.\n\t\telement._removeChildren( index - 1, 2 );\n\n\t\t// Insert merged text node.\n\t\telement._insertChild( index - 1, mergedNode );\n\t}\n}\n\n// Checks if given position is in a text node, and if so, splits the text node in two text nodes, each of them\n// containing a part of original text node.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position at which node should be split.\nfunction _splitNodeAtPosition( position ) {\n\tconst textNode = position.textNode;\n\tconst element = position.parent;\n\n\tif ( textNode ) {\n\t\tconst offsetDiff = position.offset - textNode.startOffset;\n\t\tconst index = textNode.index;\n\n\t\telement._removeChildren( index, 1 );\n\n\t\tconst firstPart = new Text( textNode.data.substr( 0, offsetDiff ), textNode.getAttributes() );\n\t\tconst secondPart = new Text( textNode.data.substr( offsetDiff ), textNode.getAttributes() );\n\n\t\telement._insertChild( index, [ firstPart, secondPart ] );\n\t}\n}\n\n// Checks whether two given nodes have same attributes.\n//\n// @private\n// @param {module:engine/model/node~Node} nodeA Node to check.\n// @param {module:engine/model/node~Node} nodeB Node to check.\n// @returns {Boolean} `true` if nodes have same attributes, `false` otherwise.\nfunction _haveSameAttributes( nodeA, nodeB ) {\n\tconst iteratorA = nodeA.getAttributes();\n\tconst iteratorB = nodeB.getAttributes();\n\n\tfor ( const attr of iteratorA ) {\n\t\tif ( attr[ 1 ] !== nodeB.getAttribute( attr[ 0 ] ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\titeratorB.next();\n\t}\n\n\treturn iteratorB.next().done;\n}\n\n/**\n * Value that can be normalized to an array of {@link module:engine/model/node~Node nodes}.\n *\n * Non-arrays are normalized as follows:\n * * {@link module:engine/model/node~Node Node} is left as is,\n * * {@link module:engine/model/textproxy~TextProxy TextProxy} and `String` are normalized to {@link module:engine/model/text~Text Text},\n * * {@link module:engine/model/nodelist~NodeList NodeList} is normalized to an array containing all nodes that are in that node list,\n * * {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment} is normalized to an array containing all of it's\n * * children.\n *\n * Arrays are processed item by item like non-array values and flattened to one array. Normalization always results in\n * a flat array of {@link module:engine/model/node~Node nodes}. Consecutive text nodes (or items normalized to text nodes) will be\n * merged if they have same attributes.\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/textproxy~TextProxy|String|\n * module:engine/model/nodelist~NodeList|module:engine/model/documentfragment~DocumentFragment|Iterable}\n * module:engine/model/node~NodeSet\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/markeroperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\n\n/**\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MarkerOperation extends Operation {\n\t/**\n\t * @param {String} name Marker name.\n\t * @param {module:engine/model/range~Range} oldRange Marker range before the change.\n\t * @param {module:engine/model/range~Range} newRange Marker range after the change.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Marker collection on which change should be executed.\n\t * @param {Boolean} affectsData Specifies whether the marker operation affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( name, oldRange, newRange, markers, affectsData, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Marker name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Marker range before the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.oldRange = oldRange ? oldRange.clone() : null;\n\n\t\t/**\n\t\t * Marker range after the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.newRange = newRange ? newRange.clone() : null;\n\n\t\t/**\n\t\t * Specifies whether the marker operation affects the data produced by the data pipeline\n\t\t * (is persisted in the editor's data).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.affectsData = affectsData;\n\n\t\t/**\n\t\t * Marker collection on which change should be executed.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis._markers = markers;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'marker';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new MarkerOperation( this.name, this.oldRange, this.newRange, this._markers, this.affectsData, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tgetReversed() {\n\t\treturn new MarkerOperation( this.name, this.newRange, this.oldRange, this._markers, this.affectsData, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst type = this.newRange ? '_set' : '_remove';\n\n\t\tthis._markers[ type ]( this.name, this.newRange, true, this.affectsData );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tif ( this.oldRange ) {\n\t\t\tjson.oldRange = this.oldRange.toJSON();\n\t\t}\n\n\t\tif ( this.newRange ) {\n\t\t\tjson.newRange = this.newRange.toJSON();\n\t\t}\n\n\t\tdelete json._markers;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MarkerOperation';\n\t}\n\n\t/**\n\t * Creates `MarkerOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new MarkerOperation(\n\t\t\tjson.name,\n\t\t\tjson.oldRange ? Range.fromJSON( json.oldRange, document ) : null,\n\t\t\tjson.newRange ? Range.fromJSON( json.newRange, document ) : null,\n\t\t\tdocument.model.markers,\n\t\t\tjson.affectsData,\n\t\t\tjson.baseVersion\n\t\t);\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MarkerOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.name }\": ${ this.oldRange } -> ${ this.newRange }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n"],"sourceRoot":""}