{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/range.js"],"names":["Range","start","end","arguments","length","undefined","Object","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_classCallCheck_js__WEBPACK_IMPORTED_MODULE_10__","this","Position","_createAt","stickiness","isCollapsed","value","regeneratorRuntime","wrap","_context","prev","next","delegateYield","TreeWalker","boundaries","ignoreElementEnd","stop","isEqual","startParentPath","getParentPath","endParentPath","compareArrays","root","position","isAfter","isBefore","otherRange","loose","containsStart","containsPosition","containsEnd","item","pos","_createBefore","type","ranges","isIntersecting","push","commonRangeStart","commonRangeEnd","shouldJoin","isTouching","startPosition","endPosition","diffAt","getCommonPath","posParent","parent","path","howMany","maxOffset","offset","getShiftedBy","slice","options","getItems","treeWalker","_iterator","_step","_value","_args2","_context2","_createForOfIteratorHelper","s","n","done","t0","e","f","finish","getPositions","_iterator2","_step2","_value2","_args3","_context3","nextPosition","operation","_getTransformedByInsertOperation","_getTransformedByMoveOperation","_getTransformedBySplitOperation","_getTransformedByMergeOperation","operations","_step3","_iterator3","i","result","getTransformedByOperation","splice","apply","concat","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_toConsumableArray_js__WEBPACK_IMPORTED_MODULE_7__","err","range","j","containsRange","getCommonAncestor","nodeAfterStart","nodeAfter","nodeBeforeEnd","nodeBefore","is","toJSON","constructor","spread","_getTransformedByInsertion","sourcePosition","targetPosition","_getTransformedByMove","insertionPosition","deletionPosition","insertPosition","newPos","moveRange","_createFromPositionAndShift","_getTransformedByDeletion","differenceSet","getDifference","difference","common","getIntersection","transformedCommon","_getCombined","deletePosition","newStart","newEnd","shift","element","offsetSize","CKEditorError","clone","ref","sort","a","b","refIndex","indexOf","json","doc","fromJSON","Symbol","iterator"],"mappings":"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","file":"js/chunk-2d213745.fa4f0de6.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\n/**\n * Represents a range in the model tree.\n *\n * A range is defined by its {@link module:engine/model/range~Range#start} and {@link module:engine/model/range~Range#end}\n * positions.\n *\n * You can create range instances via its constructor or the `createRange*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * @param {module:engine/model/position~Position} start The start position.\n\t * @param {module:engine/model/position~Position} [end] The end position. If not set,\n\t * the range will be collapsed at the `start` position.\n\t */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.start = Position._createAt( start );\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.end = end ? Position._createAt( end ) : Position._createAt( start );\n\n\t\t// If the range is collapsed, treat in a similar way as a position and set its boundaries stickiness to 'toNone'.\n\t\t// In other case, make the boundaries stick to the \"inside\" of the range.\n\t\tthis.start.stickiness = this.isCollapsed ? 'toNone' : 'toNext';\n\t\tthis.end.stickiness = this.isCollapsed ? 'toNone' : 'toPrevious';\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/model/position~Position positions},\n\t * grouped as {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t * It iterates over all {@link module:engine/model/textproxy~TextProxy text contents} that are inside the range\n\t * and all the {@link module:engine/model/element~Element}s that are entered into when iterating over this range.\n\t *\n\t * This iterator uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range\n\t * and `ignoreElementEnd` option set to `true`.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is if {@link #start} and\n\t * {@link #end} positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link #start} position and\n\t * {@link #end} position are in the same {@link module:engine/model/position~Position#parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\tconst startParentPath = this.start.getParentPath();\n\t\tconst endParentPath = this.end.getParentPath();\n\n\t\treturn compareArrays( startParentPath, endParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/model/position~Position position} is contained\n\t * in this range,`false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link ~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link ~Range range} boundaries are contained by this range, `false` otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Checks whether given {@link module:engine/model/item~Item} is inside this range.\n\t *\n\t * @param {module:engine/model/item~Item} item Model item to check.\n\t */\n\tcontainsItem( item ) {\n\t\tconst pos = Position._createBefore( item );\n\n\t\treturn this.containsPosition( pos ) || this.start.isEqual( pos );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'model:range' ); // -> true\n\t *\n\t *\t\trange.is( 'view:range' ); // -> false\n\t *\t\trange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'range' || type === 'model:range';\n\t}\n\n\t/**\n\t * Two ranges are equal if their {@link #start} and {@link #end} positions are equal.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise.\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end );\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with given range.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges intersect, `false` otherwise.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link ~Range range} is not a part of given {@link ~Range range}.\n\t * Returned array contains zero, one or two {@link ~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 3 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 4 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( new Range( this.start, this.end ) );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link ~Range range} and given {@link ~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 2 ] ) );\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\ttransformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/model/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns a range created by joining this {@link ~Range range} with the given {@link ~Range range}.\n\t * If ranges have no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 1 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2 ] )\n \t *\t\t);\n\t *\t\tlet transformed = range.getJoined( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 3 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 5 ] )\n\t *\t\t);\n\t *\t\ttransformed = range.getJoined( otherRange ); // range from [ 2, 7 ] to [ 5 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to be joined.\n\t * @param {Boolean} [loose=false] Whether the intersection check is loose or strict. If the check is strict (`false`),\n\t * ranges are tested for intersection or whether start/end positions are equal. If the check is loose (`true`),\n\t * compared range is also checked if it's {@link module:engine/model/position~Position#isTouching touching} current range.\n\t * @returns {module:engine/model/range~Range|null} A sum of given ranges or `null` if ranges have no common part.\n\t */\n\tgetJoined( otherRange, loose = false ) {\n\t\tlet shouldJoin = this.isIntersecting( otherRange );\n\n\t\tif ( !shouldJoin ) {\n\t\t\tif ( this.start.isBefore( otherRange.start ) ) {\n\t\t\t\tshouldJoin = loose ? this.end.isTouching( otherRange.start ) : this.end.isEqual( otherRange.start );\n\t\t\t} else {\n\t\t\t\tshouldJoin = loose ? otherRange.end.isTouching( this.start ) : otherRange.end.isEqual( this.start );\n\t\t\t}\n\t\t}\n\n\t\tif ( !shouldJoin ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet startPosition = this.start;\n\t\tlet endPosition = this.end;\n\n\t\tif ( otherRange.start.isBefore( startPosition ) ) {\n\t\t\tstartPosition = otherRange.start;\n\t\t}\n\n\t\tif ( otherRange.end.isAfter( endPosition ) ) {\n\t\t\tendPosition = otherRange.end;\n\t\t}\n\n\t\treturn new Range( startPosition, endPosition );\n\t}\n\n\t/**\n\t * Computes and returns the smallest set of {@link #isFlat flat} ranges, that covers this range in whole.\n\t *\n\t * See an example of a model structure (`[` and `]` are range boundaries):\n\t *\n\t *\t\troot root\n\t *\t\t |- element DIV DIV P2 P3 DIV\n\t *\t\t | |- element H H P1 f o o b a r H P4\n\t *\t\t | | |- \"fir[st\" fir[st lorem se]cond ipsum\n\t *\t\t | |- element P1\n\t *\t\t | | |- \"lorem\" ||\n\t *\t\t |- element P2 ||\n\t *\t\t | |- \"foo\" VV\n\t *\t\t |- element P3\n\t *\t\t | |- \"bar\" root\n\t *\t\t |- element DIV DIV [P2 P3] DIV\n\t *\t\t | |- element H H [P1] f o o b a r H P4\n\t *\t\t | | |- \"se]cond\" fir[st] lorem [se]cond ipsum\n\t *\t\t | |- element P4\n\t *\t\t | | |- \"ipsum\"\n\t *\n\t * As it can be seen, letters contained in the range are: `stloremfoobarse`, spread across different parents.\n\t * We are looking for minimal set of flat ranges that contains the same nodes.\n\t *\n\t * Minimal flat ranges for above range `( [ 0, 0, 3 ], [ 3, 0, 2 ] )` will be:\n\t *\n\t *\t\t( [ 0, 0, 3 ], [ 0, 0, 5 ] ) = \"st\"\n\t *\t\t( [ 0, 1 ], [ 0, 2 ] ) = element P1 (\"lorem\")\n\t *\t\t( [ 1 ], [ 3 ] ) = element P2, element P3 (\"foobar\")\n\t *\t\t( [ 3, 0, 0 ], [ 3, 0, 2 ] ) = \"se\"\n\t *\n\t * **Note:** if an {@link module:engine/model/element~Element element} is not wholly contained in this range, it won't be returned\n\t * in any of the returned flat ranges. See in the example how `H` elements at the beginning and at the end of the range\n\t * were omitted. Only their parts that were wholly in the range were returned.\n\t *\n\t * **Note:** this method is not returning flat ranges that contain no nodes.\n\t *\n\t * @returns {Array.} Array of flat ranges covering this range.\n\t */\n\tgetMinimalFlatRanges() {\n\t\tconst ranges = [];\n\t\tconst diffAt = this.start.getCommonPath( this.end ).length;\n\n\t\tconst pos = Position._createAt( this.start );\n\t\tlet posParent = pos.parent;\n\n\t\t// Go up.\n\t\twhile ( pos.path.length > diffAt + 1 ) {\n\t\t\tconst howMany = posParent.maxOffset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.path = pos.path.slice( 0, -1 );\n\t\t\tpos.offset++;\n\t\t\tposParent = posParent.parent;\n\t\t}\n\n\t\t// Go down.\n\t\twhile ( pos.path.length <= this.end.path.length ) {\n\t\t\tconst offset = this.end.path[ pos.path.length - 1 ];\n\t\t\tconst howMany = offset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.offset = offset;\n\t\t\tpos.path.push( 0 );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * For example, to iterate over all items in the entire document root:\n\t *\n\t *\t\t// Create a range spanning over the entire root content:\n\t *\t\tconst range = editor.model.createRangeIn( editor.model.document.getRoot() );\n\t *\n\t *\t\t// Iterate over all items in this range:\n\t *\t\tfor ( const value of range.getWalker() ) {\n\t *\t\t\tconsole.log( value.item );\n\t *\t\t}\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @param {module:engine/model/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t * @returns {module:engine/model/treewalker~TreeWalker}\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/model/item~Item model items},\n\t * not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/model/position~Position positions}, not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by given `operation`.\n\t *\n\t * **Note:** transformation may break one range into multiple ranges (for example, when a part of the range is\n\t * moved to a different part of document tree). For this reason, an array is returned by this method and it\n\t * may contain one or more `Range` instances.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform range by.\n\t * @returns {Array.} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\treturn this._getTransformedByInsertOperation( operation );\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\treturn this._getTransformedByMoveOperation( operation );\n\t\t\tcase 'split':\n\t\t\t\treturn [ this._getTransformedBySplitOperation( operation ) ];\n\t\t\tcase 'merge':\n\t\t\t\treturn [ this._getTransformedByMergeOperation( operation ) ];\n\t\t}\n\n\t\treturn [ new Range( this.start, this.end ) ];\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by multiple `operations`.\n\t *\n\t * @see ~Range#getTransformedByOperation\n\t * @param {Iterable.} operations Operations to transform the range by.\n\t * @returns {Array.} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperations( operations ) {\n\t\tconst ranges = [ new Range( this.start, this.end ) ];\n\n\t\tfor ( const operation of operations ) {\n\t\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\t\tconst result = ranges[ i ].getTransformedByOperation( operation );\n\n\t\t\t\tranges.splice( i, 1, ...result );\n\t\t\t\ti += result.length - 1;\n\t\t\t}\n\t\t}\n\n\t\t// It may happen that a range is split into two, and then the part of second \"piece\" is moved into first\n\t\t// \"piece\". In this case we will have incorrect third range, which should not be included in the result --\n\t\t// because it is already included in the first \"piece\". In this loop we are looking for all such ranges that\n\t\t// are inside other ranges and we simply remove them.\n\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\tconst range = ranges[ i ];\n\n\t\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t\tconst next = ranges[ j ];\n\n\t\t\t\tif ( range.containsRange( next ) || next.containsRange( range ) || range.isEqual( next ) ) {\n\t\t\t\t\tranges.splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of the range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element Element} contained by the range.\n\t * The element will be returned when it is the **only** node within the range and **fully–contained**\n\t * at the same time.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetContainedElement() {\n\t\tif ( this.isCollapsed ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst nodeAfterStart = this.start.nodeAfter;\n\t\tconst nodeBeforeEnd = this.end.nodeBefore;\n\n\t\tif ( nodeAfterStart && nodeAfterStart.is( 'element' ) && nodeAfterStart === nodeBeforeEnd ) {\n\t\t\treturn nodeAfterStart;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts `Range` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\tstart: this.start.toJSON(),\n\t\t\tend: this.end.toJSON()\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new range that is equal to current range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by insert operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {Array.}\n\t */\n\t_getTransformedByInsertOperation( operation, spread = false ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by move operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {Array.}\n\t */\n\t_getTransformedByMoveOperation( operation, spread = false ) {\n\t\tconst sourcePosition = operation.sourcePosition;\n\t\tconst howMany = operation.howMany;\n\t\tconst targetPosition = operation.targetPosition;\n\n\t\treturn this._getTransformedByMove( sourcePosition, targetPosition, howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by split operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst start = this.start._getTransformedBySplitOperation( operation );\n\t\tlet end = this.end._getTransformedBySplitOperation( operation );\n\n\t\tif ( this.end.isEqual( operation.insertionPosition ) ) {\n\t\t\tend = this.end.getShiftedBy( 1 );\n\t\t}\n\n\t\t// Below may happen when range contains graveyard element used by split operation.\n\t\tif ( start.root != end.root ) {\n\t\t\t// End position was next to the moved graveyard element and was moved with it.\n\t\t\t// Fix it by using old `end` which has proper `root`.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by merge operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\t// Special case when the marker is set on \"the closing tag\" of an element. Marker can be set like that during\n\t\t// transformations, especially when a content of a few block elements were removed. For example:\n\t\t//\n\t\t// {} is the transformed range, [] is the removed range.\n\t\t//

F[o{o

B}ar

Xy]z

\n\t\t//\n\t\t//

Fo{o

B}ar

z

\n\t\t//

F{

B}ar

z

\n\t\t//

F{

}

z

\n\t\t//

F{}z

\n\t\t//\n\t\tif ( this.start.isEqual( operation.targetPosition ) && this.end.isEqual( operation.deletionPosition ) ) {\n\t\t\treturn new Range( this.start );\n\t\t}\n\n\t\tlet start = this.start._getTransformedByMergeOperation( operation );\n\t\tlet end = this.end._getTransformedByMergeOperation( operation );\n\n\t\tif ( start.root != end.root ) {\n\t\t\t// This happens when the end position was next to the merged (deleted) element.\n\t\t\t// Then, the end position was moved to the graveyard root. In this case we need to fix\n\t\t\t// the range cause its boundaries would be in different roots.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\tif ( start.isAfter( end ) ) {\n\t\t\t// This happens in three following cases:\n\t\t\t//\n\t\t\t// Case 1: Merge operation source position is before the target position (due to some transformations, OT, etc.)\n\t\t\t// This means that start can be moved before the end of the range.\n\t\t\t//\n\t\t\t// Before:

a{a

b}b

cc

\n\t\t\t// Merge:

b}b

cca{a

\n\t\t\t// Fix:

{b}b

ccaa

\n\t\t\t//\n\t\t\t// Case 2: Range start is before merged node but not directly.\n\t\t\t// Result should include all nodes that were in the original range.\n\t\t\t//\n\t\t\t// Before:

aa

{

cc

b}b

\n\t\t\t// Merge:

aab}b

{

cc

\n\t\t\t// Fix:

aa{bb

cc

}\n\t\t\t//\n\t\t\t// The range is expanded by an additional `b` letter but it is better than dropping the whole `cc` paragraph.\n\t\t\t//\n\t\t\t// Case 3: Range start is directly before merged node.\n\t\t\t// Resulting range should include only nodes from the merged element:\n\t\t\t//\n\t\t\t// Before:

aa

{

b}b

cc

\n\t\t\t// Merge:

aab}b

{

cc

\n\t\t\t// Fix:

aa{b}b

cc

\n\t\t\t//\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Case 1.\n\t\t\t\tstart = Position._createAt( end );\n\t\t\t\tstart.offset = 0;\n\t\t\t} else {\n\t\t\t\tif ( !operation.deletionPosition.isEqual( start ) ) {\n\t\t\t\t\t// Case 2.\n\t\t\t\t\tend = operation.deletionPosition;\n\t\t\t\t}\n\n\t\t\t\t// In both case 2 and 3 start is at the end of the merge-to element.\n\t\t\t\tstart = operation.targetPosition;\n\t\t\t}\n\n\t\t\treturn new Range( start, end );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns an array containing one or two {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link ~Range ranges} are\n\t * returned if the insertion was inside this {@link ~Range range} and `spread` is set to `true`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 1 ] ), 2 );\n\t *\t\t// transformed array has one range from [ 4, 7 ] to [ 6, 0, 1 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 4, 0, 0 ] ), 4 );\n\t *\t\t// transformed array has one range from [ 2, 7 ] to [ 4, 0, 5 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4 );\n\t *\t\t// transformed array has one range, which is equal to original range\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4, true );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3, 2 ] and from [ 3, 6 ] to [ 4, 0, 1 ]\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @param {Boolean} [spread] Flag indicating whether this {~Range range} should be spread if insertion\n\t * was inside the range. Defaults to `false`.\n\t * @returns {Array.} Result of the transformation.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany, spread = false ) {\n\t\tif ( spread && this.containsPosition( insertPosition ) ) {\n\t\t\t// Range has to be spread. The first part is from original start to the spread point.\n\t\t\t// The other part is from spread point to the original end, but transformed by\n\t\t\t// insertion to reflect insertion changes.\n\n\t\t\treturn [\n\t\t\t\tnew Range( this.start, insertPosition ),\n\t\t\t\tnew Range(\n\t\t\t\t\tinsertPosition.getShiftedBy( howMany ),\n\t\t\t\t\tthis.end._getTransformedByInsertion( insertPosition, howMany )\n\t\t\t\t)\n\t\t\t];\n\t\t} else {\n\t\t\tconst range = new Range( this.start, this.end );\n\n\t\t\trange.start = range.start._getTransformedByInsertion( insertPosition, howMany );\n\t\t\trange.end = range.end._getTransformedByInsertion( insertPosition, howMany );\n\n\t\t\treturn [ range ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns an array containing {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position from which nodes are moved.\n\t * @param {module:engine/model/position~Position} targetPosition Position to where nodes are moved.\n\t * @param {Number} howMany How many nodes are moved.\n\t * @param {Boolean} [spread=false] Whether the range should be spread if the move points inside the range.\n\t * @returns {Array.} Result of the transformation.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany, spread = false ) {\n\t\t// Special case for transforming a collapsed range. Just transform it like a position.\n\t\tif ( this.isCollapsed ) {\n\t\t\tconst newPos = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\treturn [ new Range( newPos ) ];\n\t\t}\n\n\t\t// Special case for transformation when a part of the range is moved towards the range.\n\t\t//\n\t\t// Examples:\n\t\t//\n\t\t//

ab

c[d

e]f

-->

ab

c[d

e]f

\n\t\t//

e[f

a]b

cd

-->

e[f

a]b

cd

\n\t\t//\n\t\t// Without this special condition, the default algorithm leaves an \"artifact\" range from one of `differenceSet` parts:\n\t\t//\n\t\t//

ab

c[d

e]f

-->

ab

{
}

c[d

e]f

\n\t\t//\n\t\t// This special case is applied only if the range is to be kept together (not spread).\n\t\tconst moveRange = Range._createFromPositionAndShift( sourcePosition, howMany );\n\t\tconst insertPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( this.containsPosition( targetPosition ) && !spread ) {\n\t\t\tif ( moveRange.containsPosition( this.start ) || moveRange.containsPosition( this.end ) ) {\n\t\t\t\tconst start = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\t\t\t\tconst end = this.end._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\t\treturn [ new Range( start, end ) ];\n\t\t\t}\n\t\t}\n\n\t\t// Default algorithm.\n\t\tlet result;\n\n\t\tconst differenceSet = this.getDifference( moveRange );\n\t\tlet difference = null;\n\n\t\tconst common = this.getIntersection( moveRange );\n\n\t\tif ( differenceSet.length == 1 ) {\n\t\t\t// `moveRange` and this range may intersect but may be separate.\n\t\t\tdifference = new Range(\n\t\t\t\tdifferenceSet[ 0 ].start._getTransformedByDeletion( sourcePosition, howMany ),\n\t\t\t\tdifferenceSet[ 0 ].end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} else if ( differenceSet.length == 2 ) {\n\t\t\t// `moveRange` is inside this range.\n\t\t\tdifference = new Range(\n\t\t\t\tthis.start,\n\t\t\t\tthis.end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} // else, `moveRange` contains this range.\n\n\t\tif ( difference ) {\n\t\t\tresult = difference._getTransformedByInsertion( insertPosition, howMany, common !== null || spread );\n\t\t} else {\n\t\t\tresult = [];\n\t\t}\n\n\t\tif ( common ) {\n\t\t\tconst transformedCommon = new Range(\n\t\t\t\tcommon.start._getCombined( moveRange.start, insertPosition ),\n\t\t\t\tcommon.end._getCombined( moveRange.start, insertPosition )\n\t\t\t);\n\n\t\t\tif ( result.length == 2 ) {\n\t\t\t\tresult.splice( 1, 0, transformedCommon );\n\t\t\t} else {\n\t\t\t\tresult.push( transformedCommon );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this range that is transformed by deletion of `howMany` nodes from `deletePosition`.\n\t *\n\t * If the deleted range is intersecting with the transformed range, the transformed range will be shrank.\n\t *\n\t * If the deleted range contains transformed range, `null` will be returned.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletionPosition Position from which nodes are removed.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/range~Range|null} Result of the transformation.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tlet newStart = this.start._getTransformedByDeletion( deletePosition, howMany );\n\t\tlet newEnd = this.end._getTransformedByDeletion( deletePosition, howMany );\n\n\t\tif ( newStart == null && newEnd == null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( newStart == null ) {\n\t\t\tnewStart = deletePosition;\n\t\t}\n\n\t\tif ( newEnd == null ) {\n\t\t\tnewEnd = deletePosition;\n\t\t}\n\n\t\treturn new Range( newStart, newEnd );\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/model/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn new this( Position._createAt( element, 0 ), Position._createAt( element, element.maxOffset ) );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), item.offsetSize );\n\t}\n\n\t/**\n\t * Combines all ranges from the passed array into a one range. At least one range has to be passed.\n\t * Passed ranges must not have common parts.\n\t *\n\t * The first range from the array is a reference range. If other ranges start or end on the exactly same position where\n\t * the reference range, they get combined into one range.\n\t *\n\t *\t\t[ ][] [ ][ ][ ][ ][] [ ] // Passed ranges, shown sorted\n\t *\t\t[ ] // The result of the function if the first range was a reference range.\n\t *\t [ ] // The result of the function if the third-to-seventh range was a reference range.\n\t *\t [ ] // The result of the function if the last range was a reference range.\n\t *\n\t * @param {Array.} ranges Ranges to combine.\n\t * @returns {module:engine/model/range~Range} Combined range.\n\t */\n\tstatic _createFromRanges( ranges ) {\n\t\tif ( ranges.length === 0 ) {\n\t\t\t/**\n\t\t\t * At least one range has to be passed to\n\t\t\t * {@link module:engine/model/range~Range._createFromRanges `Range._createFromRanges()`}.\n\t\t\t *\n\t\t\t * @error range-create-from-ranges-empty-array\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'range-create-from-ranges-empty-array',\n\t\t\t\tnull\n\t\t\t);\n\t\t} else if ( ranges.length == 1 ) {\n\t\t\treturn ranges[ 0 ].clone();\n\t\t}\n\n\t\t// 1. Set the first range in `ranges` array as a reference range.\n\t\t// If we are going to return just a one range, one of the ranges need to be the reference one.\n\t\t// Other ranges will be stuck to that range, if possible.\n\t\tconst ref = ranges[ 0 ];\n\n\t\t// 2. Sort all the ranges so it's easier to process them.\n\t\tranges.sort( ( a, b ) => {\n\t\t\treturn a.start.isAfter( b.start ) ? 1 : -1;\n\t\t} );\n\n\t\t// 3. Check at which index the reference range is now.\n\t\tconst refIndex = ranges.indexOf( ref );\n\n\t\t// 4. At this moment we don't need the original range.\n\t\t// We are going to modify the result and we need to return a new instance of Range.\n\t\t// We have to create a copy of the reference range.\n\t\tconst result = new this( ref.start, ref.end );\n\n\t\t// 5. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tif ( refIndex > 0 ) {\n\t\t\tfor ( let i = refIndex - 1; true; i++ ) {\n\t\t\t\tif ( ranges[ i ].end.isEqual( result.start ) ) {\n\t\t\t\t\tresult.start = Position._createAt( ranges[ i ].start );\n\t\t\t\t} else {\n\t\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 6. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tfor ( let i = refIndex + 1; i < ranges.length; i++ ) {\n\t\t\tif ( ranges[ i ].start.isEqual( result.end ) ) {\n\t\t\t\tresult.end = Position._createAt( ranges[ i ].end );\n\t\t\t} else {\n\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates a `Range` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Range`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be range owner.\n\t * @returns {module:engine/model/range~Range} `Range` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\treturn new this( Position.fromJSON( json.start, doc ), Position.fromJSON( json.end, doc ) );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.start.path.join( ', ' ) } ] - [ ${ this.end.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n"],"sourceRoot":""}