{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/transform.js"],"names":["transformations","Map","setTransformation","OperationA","OperationB","transformationFunction","aGroup","get","set","getTransformation","has","noUpdateTransformation","a","transform","b","context","arguments","length","undefined","constructor","clone","e","transformSets","operationsA","operationsB","options","slice","contextFactory","ContextFactory","document","useRelations","forceWeakRemove","setOriginalOperations","originalOperations","_step","nextTransformIndex","WeakMap","_iterator","_createForOfIteratorHelper","s","n","done","op","value","err","f","data","nextBaseVersionA","baseVersion","nextBaseVersionB","originalOperationsACount","originalOperationsBCount","i","_operationsA","_operationsB","opA","indexB","opB","newOpsA","getContext","newOpsB","updateRelation","_step2","_iterator2","newOpA","splice","apply","concat","Object","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_toConsumableArray_js__WEBPACK_IMPORTED_MODULE_7__","padWithNoOps","brokenOperationsACount","brokenOperationsBCount","updateBaseVersions","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_classCallCheck_js__WEBPACK_IMPORTED_MODULE_5__","this","_history","history","_useRelations","_forceWeakRemove","_relations","operations","_step3","takeFrom","originalOperation","_iterator3","operation","MoveOperation","MergeOperation","targetPosition","isEqual","sourcePosition","movedRange","containsPosition","_setRelation","deletionPosition","isAfter","isBefore","SplitOperation","splitPosition","range","Range","_createFromPositionAndShift","howMany","hasSameParentAs","end","offset","start","MarkerOperation","markerRange","newRange","affectedLeft","affectedRight","containsRange","side","path","wasInLeftElement","wasStartBeforeMergedElement","wasEndBeforeMergedElement","wasInRightElement","aIsStrong","aWasUndone","_wasUndone","bWasUndone","abRelation","_getRelation","baRelation","originalOp","wasUndone","isUndoneOperation","origB","undoneB","getUndoneOperation","origA","relationsA","relation","_step4","_iterator4","push","NoOperation","_getComplementaryAttributeOperations","insertOperation","key","newValue","nodes","insertValue","getNode","getAttribute","position","getShiftedBy","AttributeOperation","_breakRangeByMoveOperation","moveOp","moveRange","common","difference","getDifference","getIntersection","_step5","result","_iterator5","diff","_getTransformedByDeletion","getMovedRangeStart","spread","_getTransformedByInsertion","_getTransformedByMove","_moveTargetIntoMovedRange","_makeMoveOperationsFromRanges","ranges","j","map","oldValue","InsertOperation","shouldReceiveAttributes","r","unshift","graveyardPosition","_getTransformedByMergeOperation","isCollapsed","insertionPosition","secondPart","moveTargetPosition","_getCombined","stickiness","_getTransformedBySplitOperation","_getTransformedByInsertOperation","_getTransformedByMoveOperation","oldRange","name","_createFromRanges","aNewRange","Position","_createAt","root","aToGraveyard","rootName","bToGraveyard","aIsWeak","bIsWeak","forceMove","removedRange","type","mergeInside","mergeSplittingElement","transformed","newTargetPosition","rangeA","rangeB","insertBefore","getReversed","bTargetsToA","aTargetsToB","aCompB","compareArrays","getParentPath","_step6","_iterator6","shouldSpread","newRanges","rightRange","movesGraveyardElement","results","gyMoveSource","splitNodesMoveSource","gyMoveTarget","gyMove","splitNodesMoveTargetPath","splitNodesMoveTarget","splitNodesMove","RenameOperation","oldName","newName","renamePath","splitPath","extraRename","RootAttributeOperation","getInsertionPosition","additionalSplit","rangeToMove","gyElementMoved","newParentPosition","newTargetPath","splitAtTarget","_context$abRelation","howManyRemoved","aInGraveyard","bInGraveyard","newPositionPath","newPosition"],"mappings":"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","file":"js/chunk-2d0e8dee.10838131.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\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"],"sourceRoot":""}