{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/operation/utils.js"],"names":["_insert","position","nodes","_normalizeNodes","offset","reduce","sum","node","offsetSize","parent","_splitNodeAtPosition","index","_insertChild","_mergeNodesAtIndex","length","Range","getShiftedBy","_remove","range","isFlat","CKEditorError","this","start","end","removed","_removeChildren","_move","sourceRange","targetPosition","_getTransformedByDeletion","_setAttribute","key","value","_step","_iterator","_createForOfIteratorHelper","getItems","shallow","s","n","done","item","is","textNode","_removeAttribute","err","e","f","normalized","Array","i","push","Text","TextProxy","data","getAttributes","DocumentFragment","NodeList","_step2","_iterator2","child","Node","prev","_haveSameAttributes","splice","element","nodeBefore","getChild","nodeAfter","mergedNode","offsetDiff","startOffset","firstPart","substr","secondPart","nodeA","nodeB","_step3","iteratorA","iteratorB","_iterator3","attr","getAttribute","next"],"mappings":"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","file":"js/chunk-2d22a163.1d073f69.js","sourcesContent":["/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/utils\n */\n\nimport Node from '../node';\nimport Text from '../text';\nimport TextProxy from '../textproxy';\nimport Range from '../range';\nimport DocumentFragment from '../documentfragment';\nimport NodeList from '../nodelist';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Contains functions used for composing model tree by {@link module:engine/model/operation/operation~Operation operations}.\n * Those functions are built on top of {@link module:engine/model/node~Node node}, and it's child classes', APIs.\n *\n * @protected\n * @namespace utils\n */\n\n/**\n * Inserts given nodes at given position.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.insert\n * @param {module:engine/model/position~Position} position Position at which nodes should be inserted.\n * @param {module:engine/model/node~NodeSet} nodes Nodes to insert.\n * @returns {module:engine/model/range~Range} Range spanning over inserted elements.\n */\nexport function _insert( position, nodes ) {\n\tnodes = _normalizeNodes( nodes );\n\n\t// We have to count offset before inserting nodes because they can get merged and we would get wrong offsets.\n\tconst offset = nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\tconst parent = position.parent;\n\n\t// Insertion might be in a text node, we should split it if that's the case.\n\t_splitNodeAtPosition( position );\n\tconst index = position.index;\n\n\t// Insert nodes at given index. After splitting we have a proper index and insertion is between nodes,\n\t// using basic `Element` API.\n\tparent._insertChild( index, nodes );\n\n\t// Merge text nodes, if possible. Merging is needed only at points where inserted nodes \"touch\" \"old\" nodes.\n\t_mergeNodesAtIndex( parent, index + nodes.length );\n\t_mergeNodesAtIndex( parent, index );\n\n\treturn new Range( position, position.getShiftedBy( offset ) );\n}\n\n/**\n * Removed nodes in given range. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._remove\n * @param {module:engine/model/range~Range} range Range containing nodes to remove.\n * @returns {Array.}\n */\nexport function _remove( range ) {\n\tif ( !range.isFlat ) {\n\t\t/**\n\t\t * Trying to remove a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-remove-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-remove-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst parent = range.start.parent;\n\n\t// Range may be inside text nodes, we have to split them if that's the case.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Remove the text nodes using basic `Element` API.\n\tconst removed = parent._removeChildren( range.start.index, range.end.index - range.start.index );\n\n\t// Merge text nodes, if possible. After some nodes were removed, node before and after removed range will be\n\t// touching at the position equal to the removed range beginning. We check merging possibility there.\n\t_mergeNodesAtIndex( parent, range.start.index );\n\n\treturn removed;\n}\n\n/**\n * Moves nodes in given range to given target position. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.move\n * @param {module:engine/model/range~Range} sourceRange Range containing nodes to move.\n * @param {module:engine/model/position~Position} targetPosition Position to which nodes should be moved.\n * @returns {module:engine/model/range~Range} Range containing moved nodes.\n */\nexport function _move( sourceRange, targetPosition ) {\n\tif ( !sourceRange.isFlat ) {\n\t\t/**\n\t\t * Trying to move a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-move-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-move-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst nodes = _remove( sourceRange );\n\n\t// We have to fix `targetPosition` because model changed after nodes from `sourceRange` got removed and\n\t// that change might have an impact on `targetPosition`.\n\ttargetPosition = targetPosition._getTransformedByDeletion( sourceRange.start, sourceRange.end.offset - sourceRange.start.offset );\n\n\treturn _insert( targetPosition, nodes );\n}\n\n/**\n * Sets given attribute on nodes in given range. The attributes are only set on top-level nodes of the range, not on its children.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._setAttribute\n * @param {module:engine/model/range~Range} range Range containing nodes that should have the attribute set. Must be a flat range.\n * @param {String} key Key of attribute to set.\n * @param {*} value Attribute value.\n */\nexport function _setAttribute( range, key, value ) {\n\t// Range might start or end in text nodes, so we have to split them.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Iterate over all items in the range.\n\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t// Iterator will return `TextProxy` instances but we know that those text proxies will\n\t\t// always represent full text nodes (this is guaranteed thanks to splitting we did before).\n\t\t// So, we can operate on those text proxies' text nodes.\n\t\tconst node = item.is( '$textProxy' ) ? item.textNode : item;\n\n\t\tif ( value !== null ) {\n\t\t\tnode._setAttribute( key, value );\n\t\t} else {\n\t\t\tnode._removeAttribute( key );\n\t\t}\n\n\t\t// After attributes changing it may happen that some text nodes can be merged. Try to merge with previous node.\n\t\t_mergeNodesAtIndex( node.parent, node.index );\n\t}\n\n\t// Try to merge last changed node with it's previous sibling (not covered by the loop above).\n\t_mergeNodesAtIndex( range.end.parent, range.end.index );\n}\n\n/**\n * Normalizes given object or an array of objects to an array of {@link module:engine/model/node~Node nodes}. See\n * {@link module:engine/model/node~NodeSet NodeSet} for details on how normalization is performed.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.normalizeNodes\n * @param {module:engine/model/node~NodeSet} nodes Objects to normalize.\n * @returns {Array.} Normalized nodes.\n */\nexport function _normalizeNodes( nodes ) {\n\tconst normalized = [];\n\n\tif ( !( nodes instanceof Array ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Convert instances of classes other than Node.\n\tfor ( let i = 0; i < nodes.length; i++ ) {\n\t\tif ( typeof nodes[ i ] == 'string' ) {\n\t\t\tnormalized.push( new Text( nodes[ i ] ) );\n\t\t} else if ( nodes[ i ] instanceof TextProxy ) {\n\t\t\tnormalized.push( new Text( nodes[ i ].data, nodes[ i ].getAttributes() ) );\n\t\t} else if ( nodes[ i ] instanceof DocumentFragment || nodes[ i ] instanceof NodeList ) {\n\t\t\tfor ( const child of nodes[ i ] ) {\n\t\t\t\tnormalized.push( child );\n\t\t\t}\n\t\t} else if ( nodes[ i ] instanceof Node ) {\n\t\t\tnormalized.push( nodes[ i ] );\n\t\t}\n\t\t// Skip unrecognized type.\n\t}\n\n\t// Merge text nodes.\n\tfor ( let i = 1; i < normalized.length; i++ ) {\n\t\tconst node = normalized[ i ];\n\t\tconst prev = normalized[ i - 1 ];\n\n\t\tif ( node instanceof Text && prev instanceof Text && _haveSameAttributes( node, prev ) ) {\n\t\t\t// Doing this instead changing `prev.data` because `data` is readonly.\n\t\t\tnormalized.splice( i - 1, 2, new Text( prev.data + node.data, prev.getAttributes() ) );\n\t\t\ti--;\n\t\t}\n\t}\n\n\treturn normalized;\n}\n\n// Checks if nodes before and after given index in given element are {@link module:engine/model/text~Text text nodes} and\n// merges them into one node if they have same attributes.\n//\n// Merging is done by removing two text nodes and inserting a new text node containing data from both merged text nodes.\n//\n// @private\n// @param {module:engine/model/element~Element} element Parent element of nodes to merge.\n// @param {Number} index Index between nodes to merge.\nfunction _mergeNodesAtIndex( element, index ) {\n\tconst nodeBefore = element.getChild( index - 1 );\n\tconst nodeAfter = element.getChild( index );\n\n\t// Check if both of those nodes are text objects with same attributes.\n\tif ( nodeBefore && nodeAfter && nodeBefore.is( '$text' ) && nodeAfter.is( '$text' ) && _haveSameAttributes( nodeBefore, nodeAfter ) ) {\n\t\t// Append text of text node after index to the before one.\n\t\tconst mergedNode = new Text( nodeBefore.data + nodeAfter.data, nodeBefore.getAttributes() );\n\n\t\t// Remove separate text nodes.\n\t\telement._removeChildren( index - 1, 2 );\n\n\t\t// Insert merged text node.\n\t\telement._insertChild( index - 1, mergedNode );\n\t}\n}\n\n// Checks if given position is in a text node, and if so, splits the text node in two text nodes, each of them\n// containing a part of original text node.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position at which node should be split.\nfunction _splitNodeAtPosition( position ) {\n\tconst textNode = position.textNode;\n\tconst element = position.parent;\n\n\tif ( textNode ) {\n\t\tconst offsetDiff = position.offset - textNode.startOffset;\n\t\tconst index = textNode.index;\n\n\t\telement._removeChildren( index, 1 );\n\n\t\tconst firstPart = new Text( textNode.data.substr( 0, offsetDiff ), textNode.getAttributes() );\n\t\tconst secondPart = new Text( textNode.data.substr( offsetDiff ), textNode.getAttributes() );\n\n\t\telement._insertChild( index, [ firstPart, secondPart ] );\n\t}\n}\n\n// Checks whether two given nodes have same attributes.\n//\n// @private\n// @param {module:engine/model/node~Node} nodeA Node to check.\n// @param {module:engine/model/node~Node} nodeB Node to check.\n// @returns {Boolean} `true` if nodes have same attributes, `false` otherwise.\nfunction _haveSameAttributes( nodeA, nodeB ) {\n\tconst iteratorA = nodeA.getAttributes();\n\tconst iteratorB = nodeB.getAttributes();\n\n\tfor ( const attr of iteratorA ) {\n\t\tif ( attr[ 1 ] !== nodeB.getAttribute( attr[ 0 ] ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\titeratorB.next();\n\t}\n\n\treturn iteratorB.next().done;\n}\n\n/**\n * Value that can be normalized to an array of {@link module:engine/model/node~Node nodes}.\n *\n * Non-arrays are normalized as follows:\n * * {@link module:engine/model/node~Node Node} is left as is,\n * * {@link module:engine/model/textproxy~TextProxy TextProxy} and `String` are normalized to {@link module:engine/model/text~Text Text},\n * * {@link module:engine/model/nodelist~NodeList NodeList} is normalized to an array containing all nodes that are in that node list,\n * * {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment} is normalized to an array containing all of it's\n * * children.\n *\n * Arrays are processed item by item like non-array values and flattened to one array. Normalization always results in\n * a flat array of {@link module:engine/model/node~Node nodes}. Consecutive text nodes (or items normalized to text nodes) will be\n * merged if they have same attributes.\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/textproxy~TextProxy|String|\n * module:engine/model/nodelist~NodeList|module:engine/model/documentfragment~DocumentFragment|Iterable}\n * module:engine/model/node~NodeSet\n */\n"],"sourceRoot":""}