{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/writer.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/textproxy.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/modifyselection.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/text.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/deletecontent.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/treewalker.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/insertcontent.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/getselectedcontent.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/autoparagraphing.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/selection-post-fixer.js"],"names":["Writer","model","batch","this","data","attributes","Text","name","Element","DocumentFragment","element","deep","_clone","item","itemOrPosition","offset","_assertWriterUsedCorrectly","position","Position","_createAt","parent","isSameTree","root","move","Range","_createOn","document","CKEditorError","remove","version","insert","InsertOperation","shouldReceiveAttributes","addOperation","applyOperation","markers","markerName","markerRange","rangeRootPosition","range","start","_getCombined","end","options","usingOperation","affectsData","has","updateMarker","addMarker","text","createText","createElement","key","value","itemOrRange","ranges","getMinimalFlatRanges","setAttributeOnRange","setAttributeOnItem","toMap","val","setAttribute","removeAttributesFromItem","getAttributeKeys","attribute","removeAttribute","getItems","isFlat","isEqual","_addOperationForAffectedMarkers","operation","MoveOperation","rangeToRemove","reverse","flat","applyRemoveOperation","nodeBefore","nodeAfter","_merge","_mergeDetached","path","stickiness","createPositionFromPath","createPositionAt","createPositionAfter","createPositionBefore","createRange","createRangeIn","createRangeOn","selectable","placeOrOffset","createSelection","_createIn","targetPosition","sourcePosition","graveyard","graveyardPosition","merge","MergeOperation","maxOffset","newName","renameOperation","RenameOperation","_createBefore","limitElement","firstSplitElement","firstCopyElement","splitElement","getAncestors","includeSelf","includes","howMany","insertionPosition","SplitOperation","getInsertionPosition","split","nextSibling","elementOrString","childCount","shiftedRange","getShiftedBy","undefined","applyMarkerOperation","get","_set","markerOrName","currentMarker","hasUsingOperationDefined","affectsDataDefined","currentRange","getRange","updatedRange","managedUsingOperations","_refresh","marker","oldRange","_remove","selection","_setTo","_setFocus","keyOrObjectOrIterable","_setSelectionAttribute","keyOrIterableOfKeys","_removeSelectionAttribute","_overrideGravity","uid","_restoreGravity","isCollapsed","anchor","isEmpty","storeKey","DocumentSelection","_getStoreAttributeKey","_setAttribute","_removeAttribute","_currentWriter","type","positionOrRange","isAffected","containsPosition","elementBefore","elementAfter","affectedInLeftElement","isAtEnd","affectedInRightElement","affectedAfterLeftElement","affectedBeforeRightElement","writer","valueBefore","valueAfter","doc","lastSplitPosition","getWalker","shallow","getAttribute","nextPosition","AttributeOperation","previousValue","isRootChanged","RootAttributeOperation","newRange","MarkerOperation","DetachOperation","rootA","rootB","RootElement","TextProxy","textNode","offsetInText","length","offsetSize","substring","getPath","parentFirst","ancestors","hasAttribute","getAttributes","startOffset","wordBoundaryCharacters","modifySelection","next","schema","isForward","direction","unit","focus","walker","TreeWalker","boundaries","getSearchRange","singleCharacters","done","tryExtendingTo","change","setSelectionFocus","setFocus","getCorrectWordBreakPosition","getCorrectPosition","isSelectable","checkChild","isLimit","skip","isInsideSurrogatePair","isInsideCombinedSymbol","isAtWordBoundary","isAtNodeBoundary","nextNode","is","boundaryChar","charAt","searchEnd","offsetToCheck","endOffset","attrs","_data","json","Node","deleteContent","selRange","getFirstRange","rootName","doNotResetEntireContent","shouldEntireContentBeReplacedWithParagraph","getLivePositionsForSelectedBlocks","startPosition","endPosition","isTouching","leaveUnmerged","mergeBranches","removeDisallowedAttributes","getChildren","collapseSelectionAt","doNotAutoparagraph","shouldAutoparagraph","insertParagraph","detach","replaceEntireContentWithParagraph","hasContent","ignoreMarkers","endBlock","getParentBlock","getLastPosition","LivePosition","fromPosition","isBlock","checkShouldMerge","getAncestorsJustBelowCommonAncestor","startAncestor","endAncestor","mergeBranchesRight","mergeBranchesLeft","commonAncestor","startElement","endElement","parentToRemove","mergeRight","rename","clearAttributes","setAttributes","Object","fromEntries","isCrossingLimitElement","positionA","positionB","ancestorsA","ancestorsB","i","isTextAllowed","isParagraphAllowed","leftPos","rightPos","rangeToCheck","paragraph","getLimitElement","containsEntireContent","setSelection","setTo","clone","ignoreElementEnd","_boundaryStartParent","_boundaryEndParent","_visitedParent","Symbol","iterator","prevPosition","prevVisitedParent","_next","_previous","previousPosition","positionParent","textNodeAtPosition","getTextNodeAtPosition","node","getNodeAfterPosition","push","formatReturnValue","charactersCount","offsetInTextNode","pop","getNodeBeforePosition","insertContent","content","Selection","nodesToInsert","insertion","Insertion","handleNodes","getSelectionRange","affectedRange","getAffectedRange","destroy","canMergeWith","Set","_documentFragment","createDocumentFragment","_documentFragmentPosition","_firstNode","_lastNode","_lastAutoParagraph","_filterAttributesOf","_affectedStart","_affectedEnd","nodes","Array","from","_handleNode","_insertPartialFragment","_updateLastNodeFromAutoParagraph","_mergeOnRight","positionAfterLastNode","positionAfterNode","isAfter","_setAffectedBoundaries","nodeToSelect","getNearestSelectionRange","isObject","_handleObject","isAllowed","_checkAndAutoParagraphToAllowedPosition","_checkAndSplitToAllowedPosition","_appendToFragment","_handleDisallowedNode","livePosition","getChild","_mergeOnLeft","toPosition","_tryAutoparagraphing","isBefore","_canMergeLeft","mergePosLeft","_canMergeRight","mergePosRight","_createAfter","previousSibling","checkMerge","_getAllowedIn","_appendChild","allowedIn","isAtStart","tempPos","add","getSelectedContent","frag","flatSubtreeRange","commonPath","getCommonPath","commonParent","getNodeByPath","appendText","append","cloneElement","_getTransformedByMove","leftExcessRange","rightExcessRange","removeRangeContent","parentsToCheck","map","filter","itemRange","contained","forEach","parentToCheck","removeRange","autoParagraphEmptyRoots","getRootNames","getRoot","insertElement","isParagraphable","nodeOrType","context","createContext","wrapInParagraph","injectSelectionPostFixer","registerPostFixer","selectionPostFixer","wasFixed","getRanges","modelRange","correctedRange","tryFixingRange","mergeIntersectingRanges","backward","isBackward","tryFixingCollapsedRange","tryFixingNonCollapsedRage","originalPosition","nearestSelectionRange","fixedPosition","isTextAllowedOnStart","isTextAllowedOnEnd","startLimitElement","endLimitElement","checkSelectionOnNonLimitElements","isStartBeforeSelectable","fixedStart","isEndAfterSelectable","fixedEnd","rangeStart","rangeEnd","isStartInLimit","isEndInLimit","bothInSameParent","expandStart","expandEnd","findOutermostLimitAncestor","startingNode","isLimitNode","startIsOnBlock","endIsOnBlock","nonIntersectingRanges","shift","previousRange","isIntersecting","merged"],"mappings":"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","file":"js/chunk-vendors~3525d194.c9c71816.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/writer\n */\n\nimport AttributeOperation from './operation/attributeoperation';\nimport DetachOperation from './operation/detachoperation';\nimport InsertOperation from './operation/insertoperation';\nimport MarkerOperation from './operation/markeroperation';\nimport MoveOperation from './operation/moveoperation';\nimport RenameOperation from './operation/renameoperation';\nimport RootAttributeOperation from './operation/rootattributeoperation';\nimport SplitOperation from './operation/splitoperation';\nimport MergeOperation from './operation/mergeoperation';\n\nimport DocumentFragment from './documentfragment';\nimport Text from './text';\nimport Element from './element';\nimport RootElement from './rootelement';\nimport Position from './position';\nimport Range from './range.js';\nimport DocumentSelection from './documentselection';\n\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The model can only be modified by using the writer. It should be used whenever you want to create a node, modify\n * child nodes, attributes or text, set the selection's position and its attributes.\n *\n * The instance of the writer is only available in the {@link module:engine/model/model~Model#change `change()`} or\n * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()`}.\n *\n *\t\tmodel.change( writer => {\n *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n *\t\t} );\n *\n * Note that the writer should never be stored and used outside of the `change()` and\n * `enqueueChange()` blocks.\n *\n * Note that writer's methods do not check the {@link module:engine/model/schema~Schema}. It is possible\n * to create incorrect model structures by using the writer. Read more about in\n * {@glink framework/guides/deep-dive/schema#who-checks-the-schema \"Who checks the schema?\"}.\n *\n * @see module:engine/model/model~Model#change\n * @see module:engine/model/model~Model#enqueueChange\n */\nexport default class Writer {\n\t/**\n\t * Creates a writer instance.\n\t *\n\t * **Note:** It is not recommended to use it directly. Use {@link module:engine/model/model~Model#change `Model#change()`} or\n\t * {@link module:engine/model/model~Model#enqueueChange `Model#enqueueChange()`} instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/model~Model} model\n\t * @param {module:engine/model/batch~Batch} batch\n\t */\n\tconstructor( model, batch ) {\n\t\t/**\n\t\t * Instance of the model on which this writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The batch to which this writer will add changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/batch~Batch}\n\t\t */\n\t\tthis.batch = batch;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/text~Text text node}.\n\t *\n\t *\t\twriter.createText( 'foo' );\n\t *\t\twriter.createText( 'foo', { bold: true } );\n\t *\n\t * @param {String} data Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @returns {module:engine/model/text~Text} Created text node.\n\t */\n\tcreateText( data, attributes ) {\n\t\treturn new Text( data, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/element~Element element}.\n\t *\n\t *\t\twriter.createElement( 'paragraph' );\n\t *\t\twriter.createElement( 'paragraph', { alignment: 'center' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/model/element~Element} Created element.\n\t */\n\tcreateElement( name, attributes ) {\n\t\treturn new Element( name, attributes );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/model/documentfragment~DocumentFragment document fragment}.\n\t *\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Created document fragment.\n\t */\n\tcreateDocumentFragment() {\n\t\treturn new DocumentFragment();\n\t}\n\n\t/**\n\t * Creates a copy of the element and returns it. Created element has the same name and attributes as the original element.\n\t * If clone is deep, the original element's children are also cloned. If not, then empty element is returned.\n\t *\n\t * @param {module:engine/model/element~Element} element The element to clone.\n\t * @param {Boolean} [deep=true] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any child.\n\t */\n\tcloneElement( element, deep = true ) {\n\t\treturn element._clone( deep );\n\t}\n\n\t/**\n\t * Inserts item on given position.\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.insert( paragraph, position );\n\t *\n\t * Instead of using position you can use parent and offset:\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\twriter.insert( text, paragraph, 5 );\n\t *\n\t * You can also use `end` instead of the offset to insert at the end:\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\twriter.insert( text, paragraph, 'end' );\n\t *\n\t * Or insert before or after another element:\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.insert( paragraph, anotherParagraph, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * Note that if the item already has parent it will be removed from the previous parent.\n\t *\n\t * Note that you cannot re-insert a node from a document to a different document or a document fragment. In this case,\n\t * `model-writer-insert-forbidden-move` is thrown.\n\t *\n\t * If you want to move {@link module:engine/model/range~Range range} instead of an\n\t * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.\n\t *\n\t * **Note:** For a paste-like content insertion mechanism see\n\t * {@link module:engine/model/model~Model#insertContent `model.insertContent()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment} item Item or document\n\t * fragment to insert.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * second parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsert( item, itemOrPosition, offset = 0 ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( item instanceof Text && item.data == '' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = Position._createAt( itemOrPosition, offset );\n\n\t\t// If item has a parent already.\n\t\tif ( item.parent ) {\n\t\t\t// We need to check if item is going to be inserted within the same document.\n\t\t\tif ( isSameTree( item.root, position.root ) ) {\n\t\t\t\t// If it's we just need to move it.\n\t\t\t\tthis.move( Range._createOn( item ), position );\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// If it isn't the same root.\n\t\t\telse {\n\t\t\t\tif ( item.root.document ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Cannot move a node from a document to a different tree.\n\t\t\t\t\t * It is forbidden to move a node that was already in a document outside of it.\n\t\t\t\t\t *\n\t\t\t\t\t * @error model-writer-insert-forbidden-move\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'model-writer-insert-forbidden-move',\n\t\t\t\t\t\tthis\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Move between two different document fragments or from document fragment to a document is possible.\n\t\t\t\t\t// In that case, remove the item from it's original parent.\n\t\t\t\t\tthis.remove( item );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst version = position.root.document ? position.root.document.version : null;\n\n\t\tconst insert = new InsertOperation( position, item, version );\n\n\t\tif ( item instanceof Text ) {\n\t\t\tinsert.shouldReceiveAttributes = true;\n\t\t}\n\n\t\tthis.batch.addOperation( insert );\n\t\tthis.model.applyOperation( insert );\n\n\t\t// When element is a DocumentFragment we need to move its markers to Document#markers.\n\t\tif ( item instanceof DocumentFragment ) {\n\t\t\tfor ( const [ markerName, markerRange ] of item.markers ) {\n\t\t\t\t// We need to migrate marker range from DocumentFragment to Document.\n\t\t\t\tconst rangeRootPosition = Position._createAt( markerRange.root, 0 );\n\t\t\t\tconst range = new Range(\n\t\t\t\t\tmarkerRange.start._getCombined( rangeRootPosition, position ),\n\t\t\t\t\tmarkerRange.end._getCombined( rangeRootPosition, position )\n\t\t\t\t);\n\n\t\t\t\tconst options = { range, usingOperation: true, affectsData: true };\n\n\t\t\t\tif ( this.model.markers.has( markerName ) ) {\n\t\t\t\t\tthis.updateMarker( markerName, options );\n\t\t\t\t} else {\n\t\t\t\t\tthis.addMarker( markerName, options );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates and inserts text on given position. You can optionally set text attributes:\n\t *\n\t *\t\twriter.insertText( 'foo', position );\n\t *\t\twriter.insertText( 'foo', { bold: true }, position );\n\t *\n\t * Instead of using position you can use parent and offset or define that text should be inserted at the end\n\t * or before or after other node:\n\t *\n\t *\t\t// Inserts 'foo' in paragraph, at offset 5:\n\t *\t\twriter.insertText( 'foo', paragraph, 5 );\n\t *\t\t// Inserts 'foo' at the end of a paragraph:\n\t *\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t// Inserts 'foo' after an image:\n\t *\t\twriter.insertText( 'foo', image, 'after' );\n\t *\n\t * These parameters work in the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * @param {String} data Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * third parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsertText( text, attributes, itemOrPosition, offset ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element || attributes instanceof Position ) {\n\t\t\tthis.insert( this.createText( text ), attributes, itemOrPosition );\n\t\t} else {\n\t\t\tthis.insert( this.createText( text, attributes ), itemOrPosition, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and inserts element on given position. You can optionally set attributes:\n\t *\n\t *\t\twriter.insertElement( 'paragraph', position );\n\t *\t\twriter.insertElement( 'paragraph', { alignment: 'center' }, position );\n\t *\n\t * Instead of using position you can use parent and offset or define that text should be inserted at the end\n\t * or before or after other node:\n\t *\n\t *\t\t// Inserts paragraph in the root at offset 5:\n\t *\t\twriter.insertElement( 'paragraph', root, 5 );\n\t *\t\t// Inserts paragraph at the end of a blockquote:\n\t *\t\twriter.insertElement( 'paragraph', blockquote, 'end' );\n\t *\t\t// Inserts after an image:\n\t *\t\twriter.insertElement( 'paragraph', image, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * third parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tinsertElement( name, attributes, itemOrPosition, offset ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element || attributes instanceof Position ) {\n\t\t\tthis.insert( this.createElement( name ), attributes, itemOrPosition );\n\t\t} else {\n\t\t\tthis.insert( this.createElement( name, attributes ), itemOrPosition, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Inserts item at the end of the given parent.\n\t *\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\twriter.append( paragraph, root );\n\t *\n\t * Note that if the item already has parent it will be removed from the previous parent.\n\t *\n\t * If you want to move {@link module:engine/model/range~Range range} instead of an\n\t * {@link module:engine/model/item~Item item} use {@link module:engine/model/writer~Writer#move `Writer#move()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/documentfragment~DocumentFragment}\n\t * item Item or document fragment to insert.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappend( item, parent ) {\n\t\tthis.insert( item, parent, 'end' );\n\t}\n\n\t/**\n\t * Creates text node and inserts it at the end of the parent. You can optionally set text attributes:\n\t *\n\t *\t\twriter.appendText( 'foo', paragraph );\n\t *\t\twriter.appendText( 'foo', { bold: true }, paragraph );\n\t *\n\t * @param {String} text Text data.\n\t * @param {Object} [attributes] Text attributes.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappendText( text, attributes, parent ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element ) {\n\t\t\tthis.insert( this.createText( text ), attributes, 'end' );\n\t\t} else {\n\t\t\tthis.insert( this.createText( text, attributes ), parent, 'end' );\n\t\t}\n\t}\n\n\t/**\n\t * Creates element and inserts it at the end of the parent. You can optionally set attributes:\n\t *\n\t *\t\twriter.appendElement( 'paragraph', root );\n\t *\t\twriter.appendElement( 'paragraph', { alignment: 'center' }, root );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} parent\n\t */\n\tappendElement( name, attributes, parent ) {\n\t\tif ( attributes instanceof DocumentFragment || attributes instanceof Element ) {\n\t\t\tthis.insert( this.createElement( name ), attributes, 'end' );\n\t\t} else {\n\t\t\tthis.insert( this.createElement( name, attributes ), parent, 'end' );\n\t\t}\n\t}\n\n\t/**\n\t * Sets value of the attribute with given key on a {@link module:engine/model/item~Item model item}\n\t * or on a {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {*} value Attribute new value.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range on which the attribute will be set.\n\t */\n\tsetAttribute( key, value, itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( itemOrRange instanceof Range ) {\n\t\t\tconst ranges = itemOrRange.getMinimalFlatRanges();\n\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tsetAttributeOnRange( this, key, value, range );\n\t\t\t}\n\t\t} else {\n\t\t\tsetAttributeOnItem( this, key, value, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Sets values of attributes on a {@link module:engine/model/item~Item model item}\n\t * or on a {@link module:engine/model/range~Range range}.\n\t *\n\t *\t\twriter.setAttributes( {\n\t *\t\t\tbold: true,\n\t *\t\t\titalic: true\n\t *\t\t}, range );\n\t *\n\t * @param {Object} attributes Attributes keys and values.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range on which the attributes will be set.\n\t */\n\tsetAttributes( attributes, itemOrRange ) {\n\t\tfor ( const [ key, val ] of toMap( attributes ) ) {\n\t\t\tthis.setAttribute( key, val, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Removes an attribute with given key from a {@link module:engine/model/item~Item model item}\n\t * or from a {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range from which the attribute will be removed.\n\t */\n\tremoveAttribute( key, itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( itemOrRange instanceof Range ) {\n\t\t\tconst ranges = itemOrRange.getMinimalFlatRanges();\n\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tsetAttributeOnRange( this, key, null, range );\n\t\t\t}\n\t\t} else {\n\t\t\tsetAttributeOnItem( this, key, null, itemOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Removes all attributes from all elements in the range or from the given item.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange\n\t * Model item or range from which all attributes will be removed.\n\t */\n\tclearAttributes( itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst removeAttributesFromItem = item => {\n\t\t\tfor ( const attribute of item.getAttributeKeys() ) {\n\t\t\t\tthis.removeAttribute( attribute, item );\n\t\t\t}\n\t\t};\n\n\t\tif ( !( itemOrRange instanceof Range ) ) {\n\t\t\tremoveAttributesFromItem( itemOrRange );\n\t\t} else {\n\t\t\tfor ( const item of itemOrRange.getItems() ) {\n\t\t\t\tremoveAttributesFromItem( item );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Moves all items in the source range to the target position.\n\t *\n\t *\t\twriter.move( sourceRange, targetPosition );\n\t *\n\t * Instead of the target position you can use parent and offset or define that range should be moved to the end\n\t * or before or after chosen item:\n\t *\n\t *\t\t// Moves all items in the range to the paragraph at offset 5:\n\t *\t\twriter.move( sourceRange, paragraph, 5 );\n\t *\t\t// Moves all items in the range to the end of a blockquote:\n\t *\t\twriter.move( sourceRange, blockquote, 'end' );\n\t *\t\t// Moves all items in the range to a position after an image:\n\t *\t\twriter.move( sourceRange, image, 'after' );\n\t *\n\t * These parameters works the same way as {@link #createPositionAt `writer.createPositionAt()`}.\n\t *\n\t * Note that items can be moved only within the same tree. It means that you can move items within the same root\n\t * (element or document fragment) or between {@link module:engine/model/document~Document#roots documents roots},\n\t * but you can not move items from document fragment to the document or from one detached element to another. Use\n\t * {@link module:engine/model/writer~Writer#insert} in such cases.\n\t *\n\t * @param {module:engine/model/range~Range} range Source range.\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * second parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tmove( range, itemOrPosition, offset ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !( range instanceof Range ) ) {\n\t\t\t/**\n\t\t\t * Invalid range to move.\n\t\t\t *\n\t\t\t * @error writer-move-invalid-range\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-invalid-range', this );\n\t\t}\n\n\t\tif ( !range.isFlat ) {\n\t\t\t/**\n\t\t\t * Range to move is not flat.\n\t\t\t *\n\t\t\t * @error writer-move-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-range-not-flat', this );\n\t\t}\n\n\t\tconst position = Position._createAt( itemOrPosition, offset );\n\n\t\t// Do not move anything if the move target is same as moved range start.\n\t\tif ( position.isEqual( range.start ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\tthis._addOperationForAffectedMarkers( 'move', range );\n\n\t\tif ( !isSameTree( range.root, position.root ) ) {\n\t\t\t/**\n\t\t\t * Range is going to be moved within not the same document. Please use\n\t\t\t * {@link module:engine/model/writer~Writer#insert insert} instead.\n\t\t\t *\n\t\t\t * @error writer-move-different-document\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-move-different-document', this );\n\t\t}\n\n\t\tconst version = range.root.document ? range.root.document.version : null;\n\t\tconst operation = new MoveOperation( range.start, range.end.offset - range.start.offset, position, version );\n\n\t\tthis.batch.addOperation( operation );\n\t\tthis.model.applyOperation( operation );\n\t}\n\n\t/**\n\t * Removes given model {@link module:engine/model/item~Item item} or {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/range~Range} itemOrRange Model item or range to remove.\n\t */\n\tremove( itemOrRange ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst rangeToRemove = itemOrRange instanceof Range ? itemOrRange : Range._createOn( itemOrRange );\n\t\tconst ranges = rangeToRemove.getMinimalFlatRanges().reverse();\n\n\t\tfor ( const flat of ranges ) {\n\t\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\t\tthis._addOperationForAffectedMarkers( 'move', flat );\n\n\t\t\tapplyRemoveOperation( flat.start, flat.end.offset - flat.start.offset, this.batch, this.model );\n\t\t}\n\t}\n\n\t/**\n\t * Merges two siblings at the given position.\n\t *\n\t * Node before and after the position have to be an element. Otherwise `writer-merge-no-element-before` or\n\t * `writer-merge-no-element-after` error will be thrown.\n\t *\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\tmerge( position ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst nodeBefore = position.nodeBefore;\n\t\tconst nodeAfter = position.nodeAfter;\n\n\t\t// If part of the marker is removed, create additional marker operation for undo purposes.\n\t\tthis._addOperationForAffectedMarkers( 'merge', position );\n\n\t\tif ( !( nodeBefore instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Node before merge position must be an element.\n\t\t\t *\n\t\t\t * @error writer-merge-no-element-before\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-merge-no-element-before', this );\n\t\t}\n\n\t\tif ( !( nodeAfter instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Node after merge position must be an element.\n\t\t\t *\n\t\t\t * @error writer-merge-no-element-after\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-merge-no-element-after', this );\n\t\t}\n\n\t\tif ( !position.root.document ) {\n\t\t\tthis._mergeDetached( position );\n\t\t} else {\n\t\t\tthis._merge( position );\n\t\t}\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionFromPath `Model#createPositionFromPath()`}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.} path Position path. See {@link module:engine/model/position~Position#path}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * See {@link module:engine/model/position~PositionStickiness}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionFromPath( root, path, stickiness ) {\n\t\treturn this.model.createPositionFromPath( root, path, stickiness );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn this.model.createPositionAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionAfter `Model#createPositionAfter()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn this.model.createPositionAfter( item );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createPositionBefore `Model#createPositionBefore()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn this.model.createPositionBefore( item );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRange `Model#createRange()`}.\n\t *\n\t * @param {module:engine/model/position~Position} start Start position.\n\t * @param {module:engine/model/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn this.model.createRange( start, end );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRangeIn `Model#createRangeIn()`}.\n\t *\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\tcreateRangeIn( element ) {\n\t\treturn this.model.createRangeIn( element );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createRangeOn `Model#createRangeOn()`}.\n\t *\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\tcreateRangeOn( element ) {\n\t\treturn this.model.createRangeOn( element );\n\t}\n\n\t/**\n\t * Shortcut for {@link module:engine/model/model~Model#createSelection `Model#createSelection()`}.\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @returns {module:engine/model/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn this.model.createSelection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Performs merge action in a detached tree.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\t_mergeDetached( position ) {\n\t\tconst nodeBefore = position.nodeBefore;\n\t\tconst nodeAfter = position.nodeAfter;\n\n\t\tthis.move( Range._createIn( nodeAfter ), Position._createAt( nodeBefore, 'end' ) );\n\t\tthis.remove( nodeAfter );\n\t}\n\n\t/**\n\t * Performs merge action in a non-detached tree.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position Position between merged elements.\n\t */\n\t_merge( position ) {\n\t\tconst targetPosition = Position._createAt( position.nodeBefore, 'end' );\n\t\tconst sourcePosition = Position._createAt( position.nodeAfter, 0 );\n\n\t\tconst graveyard = position.root.document.graveyard;\n\t\tconst graveyardPosition = new Position( graveyard, [ 0 ] );\n\n\t\tconst version = position.root.document.version;\n\n\t\tconst merge = new MergeOperation( sourcePosition, position.nodeAfter.maxOffset, targetPosition, graveyardPosition, version );\n\n\t\tthis.batch.addOperation( merge );\n\t\tthis.model.applyOperation( merge );\n\t}\n\n\t/**\n\t * Renames the given element.\n\t *\n\t * @param {module:engine/model/element~Element} element The element to rename.\n\t * @param {String} newName New element name.\n\t */\n\trename( element, newName ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !( element instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Trying to rename an object which is not an instance of Element.\n\t\t\t *\n\t\t\t * @error writer-rename-not-element-instance\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'writer-rename-not-element-instance',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tconst version = element.root.document ? element.root.document.version : null;\n\t\tconst renameOperation = new RenameOperation( Position._createBefore( element ), element.name, newName, version );\n\n\t\tthis.batch.addOperation( renameOperation );\n\t\tthis.model.applyOperation( renameOperation );\n\t}\n\n\t/**\n\t * Splits elements starting from the given position and going to the top of the model tree as long as given\n\t * `limitElement` is reached. When `limitElement` is not defined then only the parent of the given position will be split.\n\t *\n\t * The element needs to have a parent. It cannot be a root element nor a document fragment.\n\t * The `writer-split-element-no-parent` error will be thrown if you try to split an element with no parent.\n\t *\n\t * @param {module:engine/model/position~Position} position Position of split.\n\t * @param {module:engine/model/node~Node} [limitElement] Stop splitting when this element will be reached.\n\t * @returns {Object} result Split result.\n\t * @returns {module:engine/model/position~Position} result.position Position between split elements.\n\t * @returns {module:engine/model/range~Range} result.range Range that stars from the end of the first split element and ends\n\t * at the beginning of the first copy element.\n\t */\n\tsplit( position, limitElement ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tlet splitElement = position.parent;\n\n\t\tif ( !splitElement.parent ) {\n\t\t\t/**\n\t\t\t * Element with no parent can not be split.\n\t\t\t *\n\t\t\t * @error writer-split-element-no-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-split-element-no-parent', this );\n\t\t}\n\n\t\t// When limit element is not defined lets set splitElement parent as limit.\n\t\tif ( !limitElement ) {\n\t\t\tlimitElement = splitElement.parent;\n\t\t}\n\n\t\tif ( !position.parent.getAncestors( { includeSelf: true } ).includes( limitElement ) ) {\n\t\t\t/**\n\t\t\t * Limit element is not a position ancestor.\n\t\t\t *\n\t\t\t * @error writer-split-invalid-limit-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-split-invalid-limit-element', this );\n\t\t}\n\n\t\t// We need to cache elements that will be created as a result of the first split because\n\t\t// we need to create a range from the end of the first split element to the beginning of the\n\t\t// first copy element. This should be handled by LiveRange but it doesn't work on detached nodes.\n\t\tlet firstSplitElement, firstCopyElement;\n\n\t\tdo {\n\t\t\tconst version = splitElement.root.document ? splitElement.root.document.version : null;\n\t\t\tconst howMany = splitElement.maxOffset - position.offset;\n\n\t\t\tconst insertionPosition = SplitOperation.getInsertionPosition( position );\n\t\t\tconst split = new SplitOperation( position, howMany, insertionPosition, null, version );\n\n\t\t\tthis.batch.addOperation( split );\n\t\t\tthis.model.applyOperation( split );\n\n\t\t\t// Cache result of the first split.\n\t\t\tif ( !firstSplitElement && !firstCopyElement ) {\n\t\t\t\tfirstSplitElement = splitElement;\n\t\t\t\tfirstCopyElement = position.parent.nextSibling;\n\t\t\t}\n\n\t\t\tposition = this.createPositionAfter( position.parent );\n\t\t\tsplitElement = position.parent;\n\t\t} while ( splitElement !== limitElement );\n\n\t\treturn {\n\t\t\tposition,\n\t\t\trange: new Range( Position._createAt( firstSplitElement, 'end' ), Position._createAt( firstCopyElement, 0 ) )\n\t\t};\n\t}\n\n\t/**\n\t * Wraps the given range with the given element or with a new element (if a string was passed).\n\t *\n\t * **Note:** range to wrap should be a \"flat range\" (see {@link module:engine/model/range~Range#isFlat `Range#isFlat`}).\n\t * If not, an error will be thrown.\n\t *\n\t * @param {module:engine/model/range~Range} range Range to wrap.\n\t * @param {module:engine/model/element~Element|String} elementOrString Element or name of element to wrap the range with.\n\t */\n\twrap( range, elementOrString ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !range.isFlat ) {\n\t\t\t/**\n\t\t\t * Range to wrap is not flat.\n\t\t\t *\n\t\t\t * @error writer-wrap-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-range-not-flat', this );\n\t\t}\n\n\t\tconst element = elementOrString instanceof Element ? elementOrString : new Element( elementOrString );\n\n\t\tif ( element.childCount > 0 ) {\n\t\t\t/**\n\t\t\t * Element to wrap with is not empty.\n\t\t\t *\n\t\t\t * @error writer-wrap-element-not-empty\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-element-not-empty', this );\n\t\t}\n\n\t\tif ( element.parent !== null ) {\n\t\t\t/**\n\t\t\t * Element to wrap with is already attached to a tree model.\n\t\t\t *\n\t\t\t * @error writer-wrap-element-attached\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-wrap-element-attached', this );\n\t\t}\n\n\t\tthis.insert( element, range.start );\n\n\t\t// Shift the range-to-wrap because we just inserted an element before that range.\n\t\tconst shiftedRange = new Range( range.start.getShiftedBy( 1 ), range.end.getShiftedBy( 1 ) );\n\n\t\tthis.move( shiftedRange, Position._createAt( element, 0 ) );\n\t}\n\n\t/**\n\t * Unwraps children of the given element – all its children are moved before it and then the element is removed.\n\t * Throws error if you try to unwrap an element which does not have a parent.\n\t *\n\t * @param {module:engine/model/element~Element} element Element to unwrap.\n\t */\n\tunwrap( element ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( element.parent === null ) {\n\t\t\t/**\n\t\t\t * Trying to unwrap an element which has no parent.\n\t\t\t *\n\t\t\t * @error writer-unwrap-element-no-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-unwrap-element-no-parent', this );\n\t\t}\n\n\t\tthis.move( Range._createIn( element ), this.createPositionAfter( element ) );\n\t\tthis.remove( element );\n\t}\n\n\t/**\n\t * Adds a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks\n\t * changes in the document and updates its range automatically, when model tree changes.\n\t *\n\t * As the first parameter you can set marker name.\n\t *\n\t * The required `options.usingOperation` parameter lets you decide if the marker should be managed by operations or not. See\n\t * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between\n\t * markers managed by operations and not-managed by operations.\n\t *\n\t * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be\n\t * `true` when the marker change changes the data returned by the\n\t * {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.\n\t * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.\n\t * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.\n\t *\n\t * Create marker directly base on marker's name:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: false } );\n\t *\n\t * Create marker using operation:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: true } );\n\t *\n\t * Create marker that affects the editor data:\n\t *\n\t *\t\taddMarker( markerName, { range, usingOperation: false, affectsData: true } );\n\t *\n\t * Note: For efficiency reasons, it's best to create and keep as little markers as possible.\n\t *\n\t * @see module:engine/model/markercollection~Marker\n\t * @param {String} name Name of a marker to create - must be unique.\n\t * @param {Object} options\n\t * @param {Boolean} options.usingOperation Flag indicating that the marker should be added by MarkerOperation.\n\t * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.\n\t * @param {module:engine/model/range~Range} options.range Marker range.\n\t * @param {Boolean} [options.affectsData=false] Flag indicating that the marker changes the editor data.\n\t * @returns {module:engine/model/markercollection~Marker} Marker that was set.\n\t */\n\taddMarker( name, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( !options || typeof options.usingOperation != 'boolean' ) {\n\t\t\t/**\n\t\t\t * The `options.usingOperation` parameter is required when adding a new marker.\n\t\t\t *\n\t\t\t * @error writer-addmarker-no-usingoperation\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-addmarker-no-usingoperation', this );\n\t\t}\n\n\t\tconst usingOperation = options.usingOperation;\n\t\tconst range = options.range;\n\t\tconst affectsData = options.affectsData === undefined ? false : options.affectsData;\n\n\t\tif ( this.model.markers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Marker with provided name already exists.\n\t\t\t *\n\t\t\t * @error writer-addmarker-marker-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-addmarker-marker-exists', this );\n\t\t}\n\n\t\tif ( !range ) {\n\t\t\t/**\n\t\t\t * Range parameter is required when adding a new marker.\n\t\t\t *\n\t\t\t * @error writer-addmarker-no-range\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-addmarker-no-range', this );\n\t\t}\n\n\t\tif ( !usingOperation ) {\n\t\t\treturn this.model.markers._set( name, range, usingOperation, affectsData );\n\t\t}\n\n\t\tapplyMarkerOperation( this, name, null, range, affectsData );\n\n\t\treturn this.model.markers.get( name );\n\t}\n\n\t/**\n\t * Adds, updates or refreshes a {@link module:engine/model/markercollection~Marker marker}. Marker is a named range, which tracks\n\t * changes in the document and updates its range automatically, when model tree changes. Still, it is possible to change the\n\t * marker's range directly using this method.\n\t *\n\t * As the first parameter you can set marker name or instance. If none of them is provided, new marker, with a unique\n\t * name is created and returned.\n\t *\n\t * As the second parameter you can set the new marker data or leave this parameter as empty which will just refresh\n\t * the marker by triggering downcast conversion for it. Refreshing the marker is useful when you want to change\n\t * the marker {@link module:engine/view/element~Element view element} without changing any marker data.\n\t *\n\t * \t\tlet isCommentActive = false;\n\t *\n\t * \t\tmodel.conversion.markerToHighlight( {\n\t * \t\t\tmodel: 'comment',\n\t *\t\t\tview: data => {\n\t *\t\t\t\tconst classes = [ 'comment-marker' ];\n\t *\n\t *\t\t\t\tif ( isCommentActive ) {\n\t *\t\t\t\t\tclasses.push( 'comment-marker--active' );\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\treturn { classes };\n\t *\t\t\t}\n\t * \t\t} );\n\t *\n\t * \t\t// Change the property that indicates if marker is displayed as active or not.\n\t * \t\tisCommentActive = true;\n\t *\n\t * \t\t// And refresh the marker to convert it with additional class.\n\t * \t\tmodel.change( writer => writer.updateMarker( 'comment' ) );\n\t *\n\t * The `options.usingOperation` parameter lets you change if the marker should be managed by operations or not. See\n\t * {@link module:engine/model/markercollection~Marker marker class description} to learn about the difference between\n\t * markers managed by operations and not-managed by operations. It is possible to change this option for an existing marker.\n\t *\n\t * The `options.affectsData` parameter, which defaults to `false`, allows you to define if a marker affects the data. It should be\n\t * `true` when the marker change changes the data returned by\n\t * the {@link module:core/editor/utils/dataapimixin~DataApi#getData `editor.getData()`} method.\n\t * When set to `true` it fires the {@link module:engine/model/document~Document#event:change:data `change:data`} event.\n\t * When set to `false` it fires the {@link module:engine/model/document~Document#event:change `change`} event.\n\t *\n\t * Update marker directly base on marker's name:\n\t *\n\t *\t\tupdateMarker( markerName, { range } );\n\t *\n\t * Update marker using operation:\n\t *\n\t *\t\tupdateMarker( marker, { range, usingOperation: true } );\n\t *\t\tupdateMarker( markerName, { range, usingOperation: true } );\n\t *\n\t * Change marker's option (start using operations to manage it):\n\t *\n\t *\t\tupdateMarker( marker, { usingOperation: true } );\n\t *\n\t * Change marker's option (inform the engine, that the marker does not affect the data anymore):\n\t *\n\t *\t\tupdateMarker( markerName, { affectsData: false } );\n\t *\n\t * @see module:engine/model/markercollection~Marker\n\t * @param {String|module:engine/model/markercollection~Marker} markerOrName Name of a marker to update, or a marker instance.\n\t * @param {Object} [options] If options object is not defined then marker will be refreshed by triggering\n\t * downcast conversion for this marker with the same data.\n\t * @param {module:engine/model/range~Range} [options.range] Marker range to update.\n\t * @param {Boolean} [options.usingOperation] Flag indicated whether the marker should be added by MarkerOperation.\n\t * See {@link module:engine/model/markercollection~Marker#managedUsingOperations}.\n\t * @param {Boolean} [options.affectsData] Flag indicating that the marker changes the editor data.\n\t */\n\tupdateMarker( markerOrName, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst markerName = typeof markerOrName == 'string' ? markerOrName : markerOrName.name;\n\t\tconst currentMarker = this.model.markers.get( markerName );\n\n\t\tif ( !currentMarker ) {\n\t\t\t/**\n\t\t\t * Marker with provided name does not exists.\n\t\t\t *\n\t\t\t * @error writer-updatemarker-marker-not-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-updatemarker-marker-not-exists', this );\n\t\t}\n\n\t\tif ( !options ) {\n\t\t\tthis.model.markers._refresh( currentMarker );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst hasUsingOperationDefined = typeof options.usingOperation == 'boolean';\n\t\tconst affectsDataDefined = typeof options.affectsData == 'boolean';\n\n\t\t// Use previously defined marker's affectsData if the property is not provided.\n\t\tconst affectsData = affectsDataDefined ? options.affectsData : currentMarker.affectsData;\n\n\t\tif ( !hasUsingOperationDefined && !options.range && !affectsDataDefined ) {\n\t\t\t/**\n\t\t\t * One of the options is required - provide range, usingOperations or affectsData.\n\t\t\t *\n\t\t\t * @error writer-updatemarker-wrong-options\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-updatemarker-wrong-options', this );\n\t\t}\n\n\t\tconst currentRange = currentMarker.getRange();\n\t\tconst updatedRange = options.range ? options.range : currentRange;\n\n\t\tif ( hasUsingOperationDefined && options.usingOperation !== currentMarker.managedUsingOperations ) {\n\t\t\t// The marker type is changed so it's necessary to create proper operations.\n\t\t\tif ( options.usingOperation ) {\n\t\t\t\t// If marker changes to a managed one treat this as synchronizing existing marker.\n\t\t\t\t// Create `MarkerOperation` with `oldRange` set to `null`, so reverse operation will remove the marker.\n\t\t\t\tapplyMarkerOperation( this, markerName, null, updatedRange, affectsData );\n\t\t\t} else {\n\t\t\t\t// If marker changes to a marker that do not use operations then we need to create additional operation\n\t\t\t\t// that removes that marker first.\n\t\t\t\tapplyMarkerOperation( this, markerName, currentRange, null, affectsData );\n\n\t\t\t\t// Although not managed the marker itself should stay in model and its range should be preserver or changed to passed range.\n\t\t\t\tthis.model.markers._set( markerName, updatedRange, undefined, affectsData );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Marker's type doesn't change so update it accordingly.\n\t\tif ( currentMarker.managedUsingOperations ) {\n\t\t\tapplyMarkerOperation( this, markerName, currentRange, updatedRange, affectsData );\n\t\t} else {\n\t\t\tthis.model.markers._set( markerName, updatedRange, undefined, affectsData );\n\t\t}\n\t}\n\n\t/**\n\t * Removes given {@link module:engine/model/markercollection~Marker marker} or marker with given name.\n\t * The marker is removed accordingly to how it has been created, so if the marker was created using operation,\n\t * it will be destroyed using operation.\n\t *\n\t * @param {module:engine/model/markercollection~Marker|String} markerOrName Marker or marker name to remove.\n\t */\n\tremoveMarker( markerOrName ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tconst name = typeof markerOrName == 'string' ? markerOrName : markerOrName.name;\n\n\t\tif ( !this.model.markers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Trying to remove marker which does not exist.\n\t\t\t *\n\t\t\t * @error writer-removemarker-no-marker\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'writer-removemarker-no-marker', this );\n\t\t}\n\n\t\tconst marker = this.model.markers.get( name );\n\n\t\tif ( !marker.managedUsingOperations ) {\n\t\t\tthis.model.markers._remove( name );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldRange = marker.getRange();\n\n\t\tapplyMarkerOperation( this, name, oldRange, null, marker.affectsData );\n\t}\n\n\t/**\n\t * Sets the document's selection (ranges and direction) to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable} or creates an empty selection if no arguments were passed.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\twriter.setSelection( ranges );\n\t *\n\t *\t\t// Sets selection to other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\twriter.setSelection( otherSelection );\n\t *\n\t *\t\t// Sets selection to the given document selection.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\twriter.setSelection( documentSelection );\n\t *\n\t *\t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPosition( root, path );\n\t *\t\twriter.setSelection( position );\n\t *\n\t *\t\t// Sets collapsed selection at the position of the given node and an offset.\n\t *\t\twriter.setSelection( paragraph, offset );\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 *\t\twriter.setSelection( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\twriter.setSelection( paragraph, 'on' );\n\t *\n\t *\t\t// Removes all selection's ranges.\n\t *\t\twriter.setSelection( null );\n\t *\n\t * `Writer#setSelection()` allow passing additional options (`backward`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\twriter.setSelection( range, { backward: true } );\n\t *\n\t * Throws `writer-incorrect-use` error when the writer is used outside the `change()` block.\n\t *\n\t * @param {module:engine/model/selection~Selectable} selectable\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t */\n\tsetSelection( selectable, placeOrOffset, options ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tthis.model.document.selection._setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link #createPositionAt `writer.createPositionAt()`} parameters.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset=0] Offset or one of the flags. Used only when\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tsetSelectionFocus( itemOrPosition, offset ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tthis.model.document.selection._setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Sets attribute(s) on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * Using key and value pair:\n\t *\n\t * \twriter.setSelectionAttribute( 'italic', true );\n\t *\n\t * Using key-value object:\n\t *\n\t * \twriter.setSelectionAttribute( { italic: true, bold: false } );\n\t *\n\t * Using iterable object:\n\t *\n\t * \twriter.setSelectionAttribute( new Map( [ [ 'italic', true ] ] ) );\n\t *\n\t * @param {String|Object|Iterable.<*>} keyOrObjectOrIterable Key of the attribute to set\n\t * or object / iterable of key => value attribute pairs.\n\t * @param {*} [value] Attribute value.\n\t */\n\tsetSelectionAttribute( keyOrObjectOrIterable, value ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( typeof keyOrObjectOrIterable === 'string' ) {\n\t\t\tthis._setSelectionAttribute( keyOrObjectOrIterable, value );\n\t\t} else {\n\t\t\tfor ( const [ key, value ] of toMap( keyOrObjectOrIterable ) ) {\n\t\t\t\tthis._setSelectionAttribute( key, value );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Removes attribute(s) with given key(s) from the selection.\n\t *\n\t * Remove one attribute:\n\t *\n\t *\t\twriter.removeSelectionAttribute( 'italic' );\n\t *\n\t * Remove multiple attributes:\n\t *\n\t *\t\twriter.removeSelectionAttribute( [ 'italic', 'bold' ] );\n\t *\n\t * @param {String|Iterable.} keyOrIterableOfKeys Key of the attribute to remove or an iterable of attribute keys to remove.\n\t */\n\tremoveSelectionAttribute( keyOrIterableOfKeys ) {\n\t\tthis._assertWriterUsedCorrectly();\n\n\t\tif ( typeof keyOrIterableOfKeys === 'string' ) {\n\t\t\tthis._removeSelectionAttribute( keyOrIterableOfKeys );\n\t\t} else {\n\t\t\tfor ( const key of keyOrIterableOfKeys ) {\n\t\t\t\tthis._removeSelectionAttribute( key );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Temporarily changes the {@link module:engine/model/documentselection~DocumentSelection#isGravityOverridden gravity}\n\t * of the selection from left to right.\n\t *\n\t * The gravity defines from which direction the selection inherits its attributes. If it's the default left gravity,\n\t * then the selection (after being moved by the user) inherits attributes from its left-hand side.\n\t * This method allows to temporarily override this behavior by forcing the gravity to the right.\n\t *\n\t * For the following model fragment:\n\t *\n\t *\t\t<$text bold=\"true\" linkHref=\"url\">bar[]<$text bold=\"true\">biz\n\t *\n\t * * Default gravity: selection will have the `bold` and `linkHref` attributes.\n\t * * Overridden gravity: selection will have `bold` attribute.\n\t *\n\t * **Note**: It returns an unique identifier which is required to restore the gravity. It guarantees the symmetry\n\t * of the process.\n\t *\n\t * @returns {String} The unique id which allows restoring the gravity.\n\t */\n\toverrideSelectionGravity() {\n\t\treturn this.model.document.selection._overrideGravity();\n\t}\n\n\t/**\n\t * Restores {@link ~Writer#overrideSelectionGravity} gravity to default.\n\t *\n\t * Restoring the gravity is only possible using the unique identifier returned by\n\t * {@link ~Writer#overrideSelectionGravity}. Note that the gravity remains overridden as long as won't be restored\n\t * the same number of times it was overridden.\n\t *\n\t * @param {String} uid The unique id returned by {@link ~Writer#overrideSelectionGravity}.\n\t */\n\trestoreSelectionGravity( uid ) {\n\t\tthis.model.document.selection._restoreGravity( uid );\n\t}\n\n\t/**\n\t * @private\n\t * @param {String} key Key of the attribute to remove.\n\t * @param {*} value Attribute value.\n\t */\n\t_setSelectionAttribute( key, value ) {\n\t\tconst selection = this.model.document.selection;\n\n\t\t// Store attribute in parent element if the selection is collapsed in an empty node.\n\t\tif ( selection.isCollapsed && selection.anchor.parent.isEmpty ) {\n\t\t\tconst storeKey = DocumentSelection._getStoreAttributeKey( key );\n\n\t\t\tthis.setAttribute( storeKey, value, selection.anchor.parent );\n\t\t}\n\n\t\tselection._setAttribute( key, value );\n\t}\n\n\t/**\n\t * @private\n\t * @param {String} key Key of the attribute to remove.\n\t */\n\t_removeSelectionAttribute( key ) {\n\t\tconst selection = this.model.document.selection;\n\n\t\t// Remove stored attribute from parent element if the selection is collapsed in an empty node.\n\t\tif ( selection.isCollapsed && selection.anchor.parent.isEmpty ) {\n\t\t\tconst storeKey = DocumentSelection._getStoreAttributeKey( key );\n\n\t\t\tthis.removeAttribute( storeKey, selection.anchor.parent );\n\t\t}\n\n\t\tselection._removeAttribute( key );\n\t}\n\n\t/**\n\t * Throws `writer-detached-writer-tries-to-modify-model` error when the writer is used outside of the `change()` block.\n\t *\n\t * @private\n\t */\n\t_assertWriterUsedCorrectly() {\n\t\t/**\n\t\t * Trying to use a writer outside a {@link module:engine/model/model~Model#change `change()`} or\n\t\t * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()`} blocks.\n\t\t *\n\t\t * The writer can only be used inside these blocks which ensures that the model\n\t\t * can only be changed during such \"sessions\".\n\t\t *\n\t\t * @error writer-incorrect-use\n\t\t */\n\t\tif ( this.model._currentWriter !== this ) {\n\t\t\tthrow new CKEditorError( 'writer-incorrect-use', this );\n\t\t}\n\t}\n\n\t/**\n\t * For given action `type` and `positionOrRange` where the action happens, this function finds all affected markers\n\t * and applies a marker operation with the new marker range equal to the current range. Thanks to this, the marker range\n\t * can be later correctly processed during undo.\n\t *\n\t * @private\n\t * @param {'move'|'merge'} type Writer action type.\n\t * @param {module:engine/model/position~Position|module:engine/model/range~Range} positionOrRange Position or range\n\t * where the writer action happens.\n\t */\n\t_addOperationForAffectedMarkers( type, positionOrRange ) {\n\t\tfor ( const marker of this.model.markers ) {\n\t\t\tif ( !marker.managedUsingOperations ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst markerRange = marker.getRange();\n\t\t\tlet isAffected = false;\n\n\t\t\tif ( type === 'move' ) {\n\t\t\t\tisAffected =\n\t\t\t\t\tpositionOrRange.containsPosition( markerRange.start ) ||\n\t\t\t\t\tpositionOrRange.start.isEqual( markerRange.start ) ||\n\t\t\t\t\tpositionOrRange.containsPosition( markerRange.end ) ||\n\t\t\t\t\tpositionOrRange.end.isEqual( markerRange.end );\n\t\t\t} else {\n\t\t\t\t// if type === 'merge'.\n\t\t\t\tconst elementBefore = positionOrRange.nodeBefore;\n\t\t\t\tconst elementAfter = positionOrRange.nodeAfter;\n\n\t\t\t\t// Start:

Foo[

Bar]

\n\t\t\t\t// After merge:

Foo[Bar]

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

Foo

[Bar]

<-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedInLeftElement = markerRange.start.parent == elementBefore && markerRange.start.isAtEnd;\n\n\t\t\t\t// Start:

[Foo

]Bar

\n\t\t\t\t// After merge:

[Foo]Bar

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

[Foo]

Bar

<-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedInRightElement = markerRange.end.parent == elementAfter && markerRange.end.offset == 0;\n\n\t\t\t\t// Start:

[Foo

]

Bar

\n\t\t\t\t// After merge:

[Foo]Bar

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

[Foo]

Bar

<-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedAfterLeftElement = markerRange.end.nodeAfter == elementAfter;\n\n\t\t\t\t// Start:

Foo

[

Bar]

\n\t\t\t\t// After merge:

Foo[Bar]

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

Foo

[Bar]

<-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedBeforeRightElement = markerRange.start.nodeAfter == elementAfter;\n\n\t\t\t\tisAffected = affectedInLeftElement || affectedInRightElement || affectedAfterLeftElement || affectedBeforeRightElement;\n\t\t\t}\n\n\t\t\tif ( isAffected ) {\n\t\t\t\tthis.updateMarker( marker.name, { range: markerRange } );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Sets given attribute to each node in given range. When attribute value is null then attribute will be removed.\n//\n// Because attribute operation needs to have the same attribute value on the whole range, this function splits\n// the range into smaller parts.\n//\n// Given `range` must be flat.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/range~Range} range Model range on which the attribute will be set.\nfunction setAttributeOnRange( writer, key, value, range ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\t// Position of the last split, the beginning of the new range.\n\tlet lastSplitPosition = range.start;\n\n\t// Currently position in the scanning range. Because we need value after the position, it is not a current\n\t// position of the iterator but the previous one (we need to iterate one more time to get the value after).\n\tlet position;\n\n\t// Value before the currently position.\n\tlet valueBefore;\n\n\t// Value after the currently position.\n\tlet valueAfter;\n\n\tfor ( const val of range.getWalker( { shallow: true } ) ) {\n\t\tvalueAfter = val.item.getAttribute( key );\n\n\t\t// At the first run of the iterator the position in undefined. We also do not have a valueBefore, but\n\t\t// because valueAfter may be null, valueBefore may be equal valueAfter ( undefined == null ).\n\t\tif ( position && valueBefore != valueAfter ) {\n\t\t\t// if valueBefore == value there is nothing to change, so we add operation only if these values are different.\n\t\t\tif ( valueBefore != value ) {\n\t\t\t\taddOperation();\n\t\t\t}\n\n\t\t\tlastSplitPosition = position;\n\t\t}\n\n\t\tposition = val.nextPosition;\n\t\tvalueBefore = valueAfter;\n\t}\n\n\t// Because position in the loop is not the iterator position (see let position comment), the last position in\n\t// the while loop will be last but one position in the range. We need to check the last position manually.\n\tif ( position instanceof Position && position != lastSplitPosition && valueBefore != value ) {\n\t\taddOperation();\n\t}\n\n\tfunction addOperation() {\n\t\tconst range = new Range( lastSplitPosition, position );\n\t\tconst version = range.root.document ? doc.version : null;\n\t\tconst operation = new AttributeOperation( range, key, valueBefore, value, version );\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Sets given attribute to the given node. When attribute value is null then attribute will be removed.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/item~Item} item Model item on which the attribute will be set.\nfunction setAttributeOnItem( writer, key, value, item ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\tconst previousValue = item.getAttribute( key );\n\tlet range, operation;\n\n\tif ( previousValue != value ) {\n\t\tconst isRootChanged = item.root === item;\n\n\t\tif ( isRootChanged ) {\n\t\t\t// If we change attributes of root element, we have to use `RootAttributeOperation`.\n\t\t\tconst version = item.document ? doc.version : null;\n\n\t\t\toperation = new RootAttributeOperation( item, key, previousValue, value, version );\n\t\t} else {\n\t\t\trange = new Range( Position._createBefore( item ), writer.createPositionAfter( item ) );\n\n\t\t\tconst version = range.root.document ? doc.version : null;\n\n\t\t\toperation = new AttributeOperation( range, key, previousValue, value, version );\n\t\t}\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Creates and applies marker operation to {@link module:engine/model/operation/operation~Operation operation}.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} name Marker name.\n// @param {module:engine/model/range~Range} oldRange Marker range before the change.\n// @param {module:engine/model/range~Range} newRange Marker range after the change.\n// @param {Boolean} affectsData\nfunction applyMarkerOperation( writer, name, oldRange, newRange, affectsData ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\tconst operation = new MarkerOperation( name, oldRange, newRange, model.markers, affectsData, doc.version );\n\n\twriter.batch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Creates `MoveOperation` or `DetachOperation` that removes `howMany` nodes starting from `position`.\n// The operation will be applied on given model instance and added to given operation instance.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position from which nodes are removed.\n// @param {Number} howMany Number of nodes to remove.\n// @param {Batch} batch Batch to which the operation will be added.\n// @param {module:engine/model/model~Model} model Model instance on which operation will be applied.\nfunction applyRemoveOperation( position, howMany, batch, model ) {\n\tlet operation;\n\n\tif ( position.root.document ) {\n\t\tconst doc = model.document;\n\t\tconst graveyardPosition = new Position( doc.graveyard, [ 0 ] );\n\n\t\toperation = new MoveOperation( position, howMany, graveyardPosition, doc.version );\n\t} else {\n\t\toperation = new DetachOperation( position, howMany );\n\t}\n\n\tbatch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Returns `true` if both root elements are the same element or both are documents root elements.\n//\n// Elements in the same tree can be moved (for instance you can move element form one documents root to another, or\n// within the same document fragment), but when element supposed to be moved from document fragment to the document, or\n// to another document it should be removed and inserted to avoid problems with OT. This is because features like undo or\n// collaboration may track changes on the document but ignore changes on detached fragments and should not get\n// unexpected `move` operation.\nfunction isSameTree( rootA, rootB ) {\n\t// If it is the same root this is the same tree.\n\tif ( rootA === rootB ) {\n\t\treturn true;\n\t}\n\n\t// If both roots are documents root it is operation within the document what we still treat as the same tree.\n\tif ( rootA instanceof RootElement && rootB instanceof RootElement ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/textproxy\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * `TextProxy` represents a part of {@link module:engine/model/text~Text text node}.\n *\n * Since {@link module:engine/model/position~Position positions} can be placed between characters of a text node,\n * {@link module:engine/model/range~Range ranges} may contain only parts of text nodes. When {@link module:engine/model/range~Range#getItems\n * getting items}\n * contained in such range, we need to represent a part of that text node, since returning the whole text node would be incorrect.\n * `TextProxy` solves this issue.\n *\n * `TextProxy` has an API similar to {@link module:engine/model/text~Text Text} and allows to do most of the common tasks performed\n * on model nodes.\n *\n * **Note:** Some `TextProxy` instances may represent whole text node, not just a part of it.\n * See {@link module:engine/model/textproxy~TextProxy#isPartial}.\n *\n * **Note:** `TextProxy` is not an instance of {@link module:engine/model/node~Node node}. Keep this in mind when using it as a\n * parameter of methods.\n *\n * **Note:** `TextProxy` is a readonly interface. If you want to perform changes on model data represented by a `TextProxy`\n * use {@link module:engine/model/writer~Writer model writer API}.\n *\n * **Note:** `TextProxy` instances are created on the fly, basing on the current state of model. Because of this, it is\n * highly unrecommended to store references to `TextProxy` instances. `TextProxy` instances are not refreshed when\n * model changes, so they might get invalidated. Instead, consider creating {@link module:engine/model/liveposition~LivePosition live\n * position}.\n *\n * `TextProxy` instances are created by {@link module:engine/model/treewalker~TreeWalker model tree walker}. You should not need to create\n * an instance of this class by your own.\n */\nexport default class TextProxy {\n\t/**\n\t * Creates a text proxy.\n\t *\n\t * @protected\n\t * @param {module:engine/model/text~Text} textNode Text node which part is represented by this text proxy.\n\t * @param {Number} offsetInText Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy\n\t * starts.\n\t * @param {Number} length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.\n\t * @constructor\n\t */\n\tconstructor( textNode, offsetInText, length ) {\n\t\t/**\n\t\t * Text node which part is represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/text~Text}\n\t\t */\n\t\tthis.textNode = textNode;\n\n\t\tif ( offsetInText < 0 || offsetInText > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `offsetInText` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-offsetintext\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-offsetintext', this );\n\t\t}\n\n\t\tif ( length < 0 || offsetInText + length > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `length` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-length', this );\n\t\t}\n\n\t\t/**\n\t\t * Text data represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.data = textNode.data.substring( offsetInText, offsetInText + length );\n\n\t\t/**\n\t\t * Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy starts.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.offsetInText = offsetInText;\n\t}\n\n\t/**\n\t * Offset at which this text proxy starts in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#startOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget startOffset() {\n\t\treturn this.textNode.startOffset !== null ? this.textNode.startOffset + this.offsetInText : null;\n\t}\n\n\t/**\n\t * Offset size of this text proxy. Equal to the number of characters represented by the text proxy.\n\t *\n\t * @see module:engine/model/node~Node#offsetSize\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Offset at which this text proxy ends in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#endOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget endOffset() {\n\t\treturn this.startOffset !== null ? this.startOffset + this.offsetSize : null;\n\t}\n\n\t/**\n\t * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/model/text~Text text node}\n\t * (`true`) or the whole text node (`false`).\n\t *\n\t * This is `false` when text proxy starts at the very beginning of {@link module:engine/model/textproxy~TextProxy#textNode textNode}\n\t * ({@link module:engine/model/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to\n\t * text node size.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isPartial() {\n\t\treturn this.offsetSize !== this.textNode.offsetSize;\n\t}\n\n\t/**\n\t * Parent of this text proxy, which is same as parent of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tget parent() {\n\t\treturn this.textNode.parent;\n\t}\n\n\t/**\n\t * Root of this text proxy, which is same as root of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.textNode.root;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttextProxy.is( '$textProxy' ); // -> true\n\t *\t\ttextProxy.is( 'model:$textProxy' ); // -> true\n\t *\n\t *\t\ttextProxy.is( 'view:$textProxy' ); // -> false\n\t *\t\ttextProxy.is( 'range' ); // -> 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 * **Note:** Until version 20.0.0 this method wasn't accepting `'$textProxy'` type. The legacy `'textProxt'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$textProxy' || type === 'model:$textProxy' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'textProxy' || type === 'model:textProxy';\n\t}\n\n\t/**\n\t * Gets path to this text proxy.\n\t *\n\t * @see module:engine/model/node~Node#getPath\n\t * @returns {Array.}\n\t */\n\tgetPath() {\n\t\tconst path = this.textNode.getPath();\n\n\t\tif ( path.length > 0 ) {\n\t\t\tpath[ path.length - 1 ] += this.offsetInText;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this text proxy.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this text proxy will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from text proxy parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Checks if this text proxy has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on text proxy, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this.textNode.hasAttribute( key );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on text proxy.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this.textNode.getAttribute( key );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attributes. Attributes are returned as arrays containing two\n\t * items. First one is attribute key and second is attribute value.\n\t *\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this.textNode.getAttributes();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attribute keys.\n\t *\n\t * @returns {Iterable.}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this.textNode.getAttributeKeys();\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelTextProxy: ${ this }, ` +\n\t// @if CK_DEBUG_ENGINE // \t\t`attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/modifyselection\n */\n\nimport Position from '../position';\nimport TreeWalker from '../treewalker';\nimport Range from '../range';\nimport { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';\nimport DocumentSelection from '../documentselection';\n\nconst wordBoundaryCharacters = ' ,.?!:;\"-()';\n\n/**\n * Modifies the selection. Currently, the supported modifications are:\n *\n * * Extending. The selection focus is moved in the specified `options.direction` with a step specified in `options.unit`.\n * Possible values for `unit` are:\n * * `'character'` (default) - moves selection by one user-perceived character. In most cases this means moving by one\n * character in `String` sense. However, unicode also defines \"combing marks\". These are special symbols, that combines\n * with a symbol before it (\"base character\") to create one user-perceived character. For example, `q̣̇` is a normal\n * letter `q` with two \"combining marks\": upper dot (`Ux0307`) and lower dot (`Ux0323`). For most actions, i.e. extending\n * selection by one position, it is correct to include both \"base character\" and all of it's \"combining marks\". That is\n * why `'character'` value is most natural and common method of modifying selection.\n * * `'codePoint'` - moves selection by one unicode code point. In contrary to, `'character'` unit, this will insert\n * selection between \"base character\" and \"combining mark\", because \"combining marks\" have their own unicode code points.\n * However, for technical reasons, unicode code points with values above `UxFFFF` are represented in native `String` by\n * two characters, called \"surrogate pairs\". Halves of \"surrogate pairs\" have a meaning only when placed next to each other.\n * For example `𨭎` is represented in `String` by `\\uD862\\uDF4E`. Both `\\uD862` and `\\uDF4E` do not have any meaning\n * outside the pair (are rendered as ? when alone). Position between them would be incorrect. In this case, selection\n * extension will include whole \"surrogate pair\".\n * * `'word'` - moves selection by a whole word.\n *\n * **Note:** if you extend a forward selection in a backward direction you will in fact shrink it.\n *\n * **Note:** Use {@link module:engine/model/model~Model#modifySelection} instead of this function.\n * This function is only exposed to be reusable in algorithms\n * which change the {@link module:engine/model/model~Model#modifySelection}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which\n * the selection modification should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection to modify.\n * @param {Object} [options]\n * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.\n * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.\n */\nexport default function modifySelection( model, selection, options = {} ) {\n\tconst schema = model.schema;\n\tconst isForward = options.direction != 'backward';\n\tconst unit = options.unit ? options.unit : 'character';\n\n\tconst focus = selection.focus;\n\n\tconst walker = new TreeWalker( {\n\t\tboundaries: getSearchRange( focus, isForward ),\n\t\tsingleCharacters: true,\n\t\tdirection: isForward ? 'forward' : 'backward'\n\t} );\n\n\tconst data = { walker, schema, isForward, unit };\n\n\tlet next;\n\n\twhile ( ( next = walker.next() ) ) {\n\t\tif ( next.done ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = tryExtendingTo( data, next.value );\n\n\t\tif ( position ) {\n\t\t\tif ( selection instanceof DocumentSelection ) {\n\t\t\t\tmodel.change( writer => {\n\t\t\t\t\twriter.setSelectionFocus( position );\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tselection.setFocus( position );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n// Checks whether the selection can be extended to the the walker's next value (next position).\n// @param {{ walker, unit, isForward, schema }} data\n// @param {module:engine/view/treewalker~TreeWalkerValue} value\nfunction tryExtendingTo( data, value ) {\n\tconst { isForward, walker, unit, schema } = data;\n\tconst { type, item, nextPosition } = value;\n\n\t// If found text, we can certainly put the focus in it. Let's just find a correct position\n\t// based on the unit.\n\tif ( type == 'text' ) {\n\t\tif ( data.unit === 'word' ) {\n\t\t\treturn getCorrectWordBreakPosition( walker, isForward );\n\t\t}\n\n\t\treturn getCorrectPosition( walker, unit, isForward );\n\t}\n\n\t// Entering an element.\n\tif ( type == ( isForward ? 'elementStart' : 'elementEnd' ) ) {\n\t\t// If it's a selectable, we can select it now.\n\t\tif ( schema.isSelectable( item ) ) {\n\t\t\treturn Position._createAt( item, isForward ? 'after' : 'before' );\n\t\t}\n\n\t\t// If text allowed on this position, extend to this place.\n\t\tif ( schema.checkChild( nextPosition, '$text' ) ) {\n\t\t\treturn nextPosition;\n\t\t}\n\t}\n\t// Leaving an element.\n\telse {\n\t\t// If leaving a limit element, stop.\n\t\tif ( schema.isLimit( item ) ) {\n\t\t\t// NOTE: Fast-forward the walker until the end.\n\t\t\twalker.skip( () => true );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If text allowed on this position, extend to this place.\n\t\tif ( schema.checkChild( nextPosition, '$text' ) ) {\n\t\t\treturn nextPosition;\n\t\t}\n\t}\n}\n\n// Finds a correct position by walking in a text node and checking whether selection can be extended to given position\n// or should be extended further.\n//\n// @param {module:engine/model/treewalker~TreeWalker} walker\n// @param {String} unit The unit by which selection should be modified.\nfunction getCorrectPosition( walker, unit ) {\n\tconst textNode = walker.position.textNode;\n\n\tif ( textNode ) {\n\t\tconst data = textNode.data;\n\t\tlet offset = walker.position.offset - textNode.startOffset;\n\n\t\twhile ( isInsideSurrogatePair( data, offset ) || ( unit == 'character' && isInsideCombinedSymbol( data, offset ) ) ) {\n\t\t\twalker.next();\n\n\t\t\toffset = walker.position.offset - textNode.startOffset;\n\t\t}\n\t}\n\n\treturn walker.position;\n}\n\n// Finds a correct position of a word break by walking in a text node and checking whether selection can be extended to given position\n// or should be extended further.\n//\n// @param {module:engine/model/treewalker~TreeWalker} walker\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction getCorrectWordBreakPosition( walker, isForward ) {\n\tlet textNode = walker.position.textNode;\n\n\tif ( textNode ) {\n\t\tlet offset = walker.position.offset - textNode.startOffset;\n\n\t\twhile ( !isAtWordBoundary( textNode.data, offset, isForward ) && !isAtNodeBoundary( textNode, offset, isForward ) ) {\n\t\t\twalker.next();\n\n\t\t\t// Check of adjacent text nodes with different attributes (like BOLD).\n\t\t\t// Example : 'foofoo []bar<$text bold=\"true\">bar bazbaz'\n\t\t\t// should expand to : 'foofoo [bar<$text bold=\"true\">bar] bazbaz'.\n\t\t\tconst nextNode = isForward ? walker.position.nodeAfter : walker.position.nodeBefore;\n\n\t\t\t// Scan only text nodes. Ignore inline elements (like ``).\n\t\t\tif ( nextNode && nextNode.is( '$text' ) ) {\n\t\t\t\t// Check boundary char of an adjacent text node.\n\t\t\t\tconst boundaryChar = nextNode.data.charAt( isForward ? 0 : nextNode.data.length - 1 );\n\n\t\t\t\t// Go to the next node if the character at the boundary of that node belongs to the same word.\n\t\t\t\tif ( !wordBoundaryCharacters.includes( boundaryChar ) ) {\n\t\t\t\t\t// If adjacent text node belongs to the same word go to it & reset values.\n\t\t\t\t\twalker.next();\n\n\t\t\t\t\ttextNode = walker.position.textNode;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toffset = walker.position.offset - textNode.startOffset;\n\t\t}\n\t}\n\n\treturn walker.position;\n}\n\nfunction getSearchRange( start, isForward ) {\n\tconst root = start.root;\n\tconst searchEnd = Position._createAt( root, isForward ? 'end' : 0 );\n\n\tif ( isForward ) {\n\t\treturn new Range( start, searchEnd );\n\t} else {\n\t\treturn new Range( searchEnd, start );\n\t}\n}\n\n// Checks if selection is on word boundary.\n//\n// @param {String} data The text node value to investigate.\n// @param {Number} offset Position offset.\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction isAtWordBoundary( data, offset, isForward ) {\n\t// The offset to check depends on direction.\n\tconst offsetToCheck = offset + ( isForward ? 0 : -1 );\n\n\treturn wordBoundaryCharacters.includes( data.charAt( offsetToCheck ) );\n}\n\n// Checks if selection is on node boundary.\n//\n// @param {module:engine/model/text~Text} textNode The text node to investigate.\n// @param {Number} offset Position offset.\n// @param {Boolean} isForward Is the direction in which the selection should be modified is forward.\nfunction isAtNodeBoundary( textNode, offset, isForward ) {\n\treturn offset === ( isForward ? textNode.endOffset : 0 );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/text\n */\n\nimport Node from './node';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * Model text node. Type of {@link module:engine/model/node~Node node} that contains {@link module:engine/model/text~Text#data text data}.\n *\n * **Important:** see {@link module:engine/model/node~Node} to read about restrictions using `Text` and `Node` API.\n *\n * **Note:** keep in mind that `Text` instances might indirectly got removed from model tree when model is changed.\n * This happens when {@link module:engine/model/writer~Writer model writer} is used to change model and the text node is merged with\n * another text node. Then, both text nodes are removed and a new text node is inserted into the model. Because of\n * this behavior, keeping references to `Text` is not recommended. Instead, consider creating\n * {@link module:engine/model/liveposition~LivePosition live position} placed before the text node.\n *\n * @extends module:engine/model/node~Node\n */\nexport default class Text extends Node {\n\t/**\n\t * Creates a text node.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createText} method instead.\n\t *\n\t * @protected\n\t * @param {String} data Node's text.\n\t * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\tconstructor( data, attrs ) {\n\t\tsuper( attrs );\n\n\t\t/**\n\t\t * Text data contained in this text node.\n\t\t *\n\t\t * @protected\n\t\t * @type {String}\n\t\t */\n\t\tthis._data = data || '';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Returns a text data contained in the node.\n\t *\n\t * @readonly\n\t * @type {String}\n\t */\n\tget data() {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttext.is( '$text' ); // -> true\n\t *\t\ttext.is( 'node' ); // -> true\n\t *\t\ttext.is( 'model:$text' ); // -> true\n\t *\t\ttext.is( 'model:node' ); // -> true\n\t *\n\t *\t\ttext.is( 'view:$text' ); // -> false\n\t *\t\ttext.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 * **Note:** Until version 20.0.0 this method wasn't accepting `'$text'` type. The legacy `'text'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$text' || type === 'model:$text' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'text' || type === 'model:text' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'node' || type === 'model:node';\n\t}\n\n\t/**\n\t * Converts `Text` instance to plain object and returns it.\n\t *\n\t * @returns {Object} `Text` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.data = this.data;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\t_clone() {\n\t\treturn new Text( this.data, this.getAttributes() );\n\t}\n\n\t/**\n\t * Creates a `Text` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Text`.\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new Text( json.data, json.attributes );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelText: ${ this }, attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/deletecontent\n */\n\nimport LivePosition from '../liveposition';\nimport Range from '../range';\nimport DocumentSelection from '../documentselection';\n\n/**\n * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.\n *\n * **Note:** Use {@link module:engine/model/model~Model#deleteContent} instead of this function.\n * This function is only exposed to be reusable in algorithms\n * which change the {@link module:engine/model/model~Model#deleteContent}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which the insertion\n * should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * Selection of which the content should be deleted.\n * @param {Object} [options]\n * @param {Boolean} [options.leaveUnmerged=false] Whether to merge elements after removing the content of the selection.\n *\n * For example `x[xy]y` will become:\n *\n * * `x^y` with the option disabled (`leaveUnmerged == false`)\n * * `x^y` with enabled (`leaveUnmerged == true`).\n *\n * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}\n * elements will not be merged.\n *\n * @param {Boolean} [options.doNotResetEntireContent=false] Whether to skip replacing the entire content with a\n * paragraph when the entire content was selected.\n *\n * For example `[xy]` will become:\n *\n * * `^` with the option disabled (`doNotResetEntireContent == false`)\n * * `^` with enabled (`doNotResetEntireContent == true`).\n *\n * @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved\n * to a place where text cannot be inserted.\n *\n * For example `x[]` will become:\n *\n * * `x[]` with the option disabled (`doNotAutoparagraph == false`)\n * * `x[]` with the option enabled (`doNotAutoparagraph == true`).\n *\n * If you use this option you need to make sure to handle invalid selections yourself or leave\n * them to the selection post-fixer (may not always work).\n *\n * **Note:** if there is no valid position for the selection, the paragraph will always be created:\n *\n * `[]` -> `[]`.\n */\nexport default function deleteContent( model, selection, options = {} ) {\n\tif ( selection.isCollapsed ) {\n\t\treturn;\n\t}\n\n\tconst selRange = selection.getFirstRange();\n\n\t// If the selection is already removed, don't do anything.\n\tif ( selRange.root.rootName == '$graveyard' ) {\n\t\treturn;\n\t}\n\n\tconst schema = model.schema;\n\n\tmodel.change( writer => {\n\t\t// 1. Replace the entire content with paragraph.\n\t\t// See: https://github.com/ckeditor/ckeditor5-engine/issues/1012#issuecomment-315017594.\n\t\tif ( !options.doNotResetEntireContent && shouldEntireContentBeReplacedWithParagraph( schema, selection ) ) {\n\t\t\treplaceEntireContentWithParagraph( writer, selection, schema );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Get the live positions for the range adjusted to span only blocks selected from the user perspective.\n\t\tconst [ startPosition, endPosition ] = getLivePositionsForSelectedBlocks( selRange );\n\n\t\t// 2. Remove the content if there is any.\n\t\tif ( !startPosition.isTouching( endPosition ) ) {\n\t\t\twriter.remove( writer.createRange( startPosition, endPosition ) );\n\t\t}\n\n\t\t// 3. Merge elements in the right branch to the elements in the left branch.\n\t\t// The only reasonable (in terms of data and selection correctness) case in which we need to do that is:\n\t\t//\n\t\t// Fo[]ar => Fo^ar\n\t\t//\n\t\t// However, the algorithm supports also merging deeper structures (up to the depth of the shallower branch),\n\t\t// as it's hard to imagine what should actually be the default behavior. Usually, specific features will\n\t\t// want to override that behavior anyway.\n\t\tif ( !options.leaveUnmerged ) {\n\t\t\tmergeBranches( writer, startPosition, endPosition );\n\n\t\t\t// TMP this will be replaced with a postfixer.\n\t\t\t// We need to check and strip disallowed attributes in all nested nodes because after merge\n\t\t\t// some attributes could end up in a path where are disallowed.\n\t\t\t//\n\t\t\t// e.g. bold is disallowed for

\n\t\t\t//

Fo{o

b}ar

->

Fo{}ar

->

Fo{}ar

.\n\t\t\tschema.removeDisallowedAttributes( startPosition.parent.getChildren(), writer );\n\t\t}\n\n\t\tcollapseSelectionAt( writer, selection, startPosition );\n\n\t\t// 4. Add a paragraph to set selection in it.\n\t\t// Check if a text is allowed in the new container. If not, try to create a new paragraph (if it's allowed here).\n\t\t// If autoparagraphing is off, we assume that you know what you do so we leave the selection wherever it was.\n\t\tif ( !options.doNotAutoparagraph && shouldAutoparagraph( schema, startPosition ) ) {\n\t\t\tinsertParagraph( writer, startPosition, selection );\n\t\t}\n\n\t\tstartPosition.detach();\n\t\tendPosition.detach();\n\t} );\n}\n\n// Returns the live positions for the range adjusted to span only blocks selected from the user perspective. Example:\n//\n// [foo\n// bar\n// ]abc <-- this block is not considered as selected\n//\n// This is the same behavior as in Selection#getSelectedBlocks() \"special case\".\nfunction getLivePositionsForSelectedBlocks( range ) {\n\tconst model = range.root.document.model;\n\n\tconst startPosition = range.start;\n\tlet endPosition = range.end;\n\n\t// If the end of selection is at the start position of last block in the selection, then\n\t// shrink it to not include that trailing block. Note that this should happen only for not empty selection.\n\tif ( model.hasContent( range, { ignoreMarkers: true } ) ) {\n\t\tconst endBlock = getParentBlock( endPosition );\n\n\t\tif ( endBlock && endPosition.isTouching( model.createPositionAt( endBlock, 0 ) ) ) {\n\t\t\t// Create forward selection as a probe to find a valid position after excluding last block from the range.\n\t\t\tconst selection = model.createSelection( range );\n\n\t\t\t// Modify the forward selection in backward direction to shrink it and remove first position of following block from it.\n\t\t\t// This is how modifySelection works and here we are making use of it.\n\t\t\tmodel.modifySelection( selection, { direction: 'backward' } );\n\n\t\t\tendPosition = selection.getLastPosition();\n\t\t}\n\t}\n\n\treturn [\n\t\tLivePosition.fromPosition( startPosition, 'toPrevious' ),\n\t\tLivePosition.fromPosition( endPosition, 'toNext' )\n\t];\n}\n\n// Finds the lowest element in position's ancestors which is a block.\n// Returns null if a limit element is encountered before reaching a block element.\nfunction getParentBlock( position ) {\n\tconst element = position.parent;\n\tconst schema = element.root.document.model.schema;\n\tconst ancestors = element.getAncestors( { parentFirst: true, includeSelf: true } );\n\n\tfor ( const element of ancestors ) {\n\t\tif ( schema.isLimit( element ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( schema.isBlock( element ) ) {\n\t\t\treturn element;\n\t\t}\n\t}\n}\n\n// This function is a result of reaching the Ballmer's peak for just the right amount of time.\n// Even I had troubles documenting it after a while and after reading it again I couldn't believe that it really works.\nfunction mergeBranches( writer, startPosition, endPosition ) {\n\tconst model = writer.model;\n\n\t// Verify if there is a need and possibility to merge.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// If the start element on the common ancestor level is empty, and the end element on the same level is not empty\n\t// then merge those to the right element so that it's properties are preserved (name, attributes).\n\t// Because of OT merging is used instead of removing elements.\n\t//\n\t// Merge left:\n\t// foo[ -> foo[]bar\n\t// ]bar -> --^\n\t//\n\t// Merge right:\n\t// [ ->\n\t// ]bar -> []bar\n\t//\n\t// Merge left:\n\t//
->
\n\t// foo[ -> foo[]bar\n\t// ]bar -> --^\n\t//
->
\n\t//\n\t// Merge right:\n\t//
->
\n\t// [ ->\n\t// ]bar -> []bar\n\t//
->
\n\n\t// Merging should not go deeper than common ancestor.\n\tconst [ startAncestor, endAncestor ] = getAncestorsJustBelowCommonAncestor( startPosition, endPosition );\n\n\t// Branches can't be merged if one of the positions is directly inside a common ancestor.\n\t//\n\t// Example:\n\t//
\n\t// [foo]\n\t// ...
\n\t//
\n\t//\n\tif ( !startAncestor || !endAncestor ) {\n\t\treturn;\n\t}\n\n\tif ( !model.hasContent( startAncestor, { ignoreMarkers: true } ) && model.hasContent( endAncestor, { ignoreMarkers: true } ) ) {\n\t\tmergeBranchesRight( writer, startPosition, endPosition, startAncestor.parent );\n\t} else {\n\t\tmergeBranchesLeft( writer, startPosition, endPosition, startAncestor.parent );\n\t}\n}\n\n// Merging blocks to the left (properties of the left block are preserved).\n// Simple example:\n// foo[ -> foo[bar]\n// ]bar -> --^\n//\n// Nested example:\n//
->
\n// foo[ -> foo[bar\n//
->
] ^\n// -> |\n// ]bar -> ---\n// ->\n//\nfunction mergeBranchesLeft( writer, startPosition, endPosition, commonAncestor ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// Merging reached the common ancestor element, stop here.\n\tif ( startElement == commonAncestor || endElement == commonAncestor ) {\n\t\treturn;\n\t}\n\n\t// Remember next positions to merge in next recursive step (also used as modification points pointers).\n\tstartPosition = writer.createPositionAfter( startElement );\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Move endElement just after startElement if they aren't siblings.\n\tif ( !endPosition.isEqual( startPosition ) ) {\n\t\t//\n\t\t//
->
\n\t\t// foo[ -> foo[bar\n\t\t//
->
^\n\t\t// -> |\n\t\t// ]bar -> ] ---\n\t\t// -> \n\t\t//\n\t\twriter.insert( endElement, startPosition );\n\t}\n\n\t// Merge two siblings (nodes on sides of startPosition):\n\t//\n\t//
->
\n\t// foo[bar -> foo[bar\n\t//
->
\n\t// -> \n\t// ] -> ]\n\t// -> \n\t//\n\t// Or in simple case (without moving elements in above if):\n\t// foo[bar] -> foo[bar]\n\t//\n\twriter.merge( startPosition );\n\n\t// Remove empty end ancestors:\n\t//\n\t//
->
\n\t// foo[bar -> foo[bar\n\t//
->
\n\t// ->\n\t// ] -> ]\n\t// ->\n\t//\n\twhile ( endPosition.parent.isEmpty ) {\n\t\tconst parentToRemove = endPosition.parent;\n\n\t\tendPosition = writer.createPositionBefore( parentToRemove );\n\n\t\twriter.remove( parentToRemove );\n\t}\n\n\t// Verify if there is a need and possibility to merge next level.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// Continue merging next level (blockQuote with blockBlock in the examples above if it would not be empty and got removed).\n\tmergeBranchesLeft( writer, startPosition, endPosition, commonAncestor );\n}\n\n// Merging blocks to the right (properties of the right block are preserved).\n// Simple example:\n// foo[ -> --v\n// ]bar -> [foo]bar\n//\n// Nested example:\n//
->\n// foo[ -> ---\n//
-> |\n// -> [ v\n// ]bar -> foo]bar\n// -> \n//\nfunction mergeBranchesRight( writer, startPosition, endPosition, commonAncestor ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// Merging reached the common ancestor element, stop here.\n\tif ( startElement == commonAncestor || endElement == commonAncestor ) {\n\t\treturn;\n\t}\n\n\t// Remember next positions to merge in next recursive step (also used as modification points pointers).\n\tstartPosition = writer.createPositionAfter( startElement );\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Move startElement just before endElement if they aren't siblings.\n\tif ( !endPosition.isEqual( startPosition ) ) {\n\t\t//\n\t\t//
->
\n\t\t// foo[ -> [ ---\n\t\t//
->
|\n\t\t// -> v\n\t\t// ]bar -> foo]bar\n\t\t// -> \n\t\t//\n\t\twriter.insert( startElement, endPosition );\n\t}\n\n\t// Remove empty end ancestors:\n\t//\n\t//
->\n\t// [ -> [\n\t//
->\n\t// -> \n\t// foo]bar -> foo]bar\n\t// -> \n\t//\n\twhile ( startPosition.parent.isEmpty ) {\n\t\tconst parentToRemove = startPosition.parent;\n\n\t\tstartPosition = writer.createPositionBefore( parentToRemove );\n\n\t\twriter.remove( parentToRemove );\n\t}\n\n\t// Update endPosition after inserting and removing elements.\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Merge right two siblings (nodes on sides of endPosition):\n\t// ->\n\t// [ -> [\n\t// ->\n\t// -> \n\t// foo]bar -> foo]bar\n\t// -> \n\t//\n\t// Or in simple case (without moving elements in above if):\n\t// [foo]bar -> [foo]bar\n\t//\n\tmergeRight( writer, endPosition );\n\n\t// Verify if there is a need and possibility to merge next level.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// Continue merging next level (blockQuote with blockBlock in the examples above if it would not be empty and got removed).\n\tmergeBranchesRight( writer, startPosition, endPosition, commonAncestor );\n}\n\n// There is no right merge operation so we need to simulate it.\nfunction mergeRight( writer, position ) {\n\tconst startElement = position.nodeBefore;\n\tconst endElement = position.nodeAfter;\n\n\tif ( startElement.name != endElement.name ) {\n\t\twriter.rename( startElement, endElement.name );\n\t}\n\n\twriter.clearAttributes( startElement );\n\twriter.setAttributes( Object.fromEntries( endElement.getAttributes() ), startElement );\n\n\twriter.merge( position );\n}\n\n// Verifies if merging is needed and possible. It's not needed if both positions are in the same element\n// and it's not possible if some element is a limit or the range crosses a limit element.\nfunction checkShouldMerge( schema, startPosition, endPosition ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// If both positions ended up in the same parent, then there's nothing more to merge:\n\t// <$root>

x[

]y

=> <$root>

xy

[]\n\tif ( startElement == endElement ) {\n\t\treturn false;\n\t}\n\n\t// If one of the positions is a limit element, then there's nothing to merge because we don't want to cross the limit boundaries.\n\tif ( schema.isLimit( startElement ) || schema.isLimit( endElement ) ) {\n\t\treturn false;\n\t}\n\n\t// Check if operations we'll need to do won't need to cross object or limit boundaries.\n\t// E.g., we can't merge endElement into startElement in this case:\n\t// x[]\n\treturn isCrossingLimitElement( startPosition, endPosition, schema );\n}\n\n// Returns the elements that are the ancestors of the provided positions that are direct children of the common ancestor.\nfunction getAncestorsJustBelowCommonAncestor( positionA, positionB ) {\n\tconst ancestorsA = positionA.getAncestors();\n\tconst ancestorsB = positionB.getAncestors();\n\n\tlet i = 0;\n\n\twhile ( ancestorsA[ i ] && ancestorsA[ i ] == ancestorsB[ i ] ) {\n\t\ti++;\n\t}\n\n\treturn [ ancestorsA[ i ], ancestorsB[ i ] ];\n}\n\nfunction shouldAutoparagraph( schema, position ) {\n\tconst isTextAllowed = schema.checkChild( position, '$text' );\n\tconst isParagraphAllowed = schema.checkChild( position, 'paragraph' );\n\n\treturn !isTextAllowed && isParagraphAllowed;\n}\n\n// Check if parents of two positions can be merged by checking if there are no limit/object\n// boundaries between those two positions.\n//\n// E.g. in

x[]

{}\n// we'll check

, , and .\n// Usually, widget and caption are marked as objects/limits in the schema, so in this case merging will be blocked.\nfunction isCrossingLimitElement( leftPos, rightPos, schema ) {\n\tconst rangeToCheck = new Range( leftPos, rightPos );\n\n\tfor ( const value of rangeToCheck.getWalker() ) {\n\t\tif ( schema.isLimit( value.item ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction insertParagraph( writer, position, selection ) {\n\tconst paragraph = writer.createElement( 'paragraph' );\n\n\twriter.insert( paragraph, position );\n\n\tcollapseSelectionAt( writer, selection, writer.createPositionAt( paragraph, 0 ) );\n}\n\nfunction replaceEntireContentWithParagraph( writer, selection ) {\n\tconst limitElement = writer.model.schema.getLimitElement( selection );\n\n\twriter.remove( writer.createRangeIn( limitElement ) );\n\tinsertParagraph( writer, writer.createPositionAt( limitElement, 0 ), selection );\n}\n\n// We want to replace the entire content with a paragraph when:\n// * the entire content is selected,\n// * selection contains at least two elements,\n// * whether the paragraph is allowed in schema in the common ancestor.\nfunction shouldEntireContentBeReplacedWithParagraph( schema, selection ) {\n\tconst limitElement = schema.getLimitElement( selection );\n\n\tif ( !selection.containsEntireContent( limitElement ) ) {\n\t\treturn false;\n\t}\n\n\tconst range = selection.getFirstRange();\n\n\tif ( range.start.parent == range.end.parent ) {\n\t\treturn false;\n\t}\n\n\treturn schema.checkChild( limitElement, 'paragraph' );\n}\n\n// Helper function that sets the selection. Depending whether given `selection` is a document selection or not,\n// uses a different method to set it.\nfunction collapseSelectionAt( writer, selection, positionOrRange ) {\n\tif ( selection instanceof DocumentSelection ) {\n\t\twriter.setSelection( positionOrRange );\n\t} else {\n\t\tselection.setTo( positionOrRange );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/treewalker\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport Element from './element';\nimport {\n\tdefault as Position,\n\tgetTextNodeAtPosition,\n\tgetNodeAfterPosition,\n\tgetNodeBeforePosition\n} from './position';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Position iterator class. It allows to iterate forward and backward over the document.\n */\nexport default class TreeWalker {\n\t/**\n\t * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.\n\t *\n\t * @constructor\n\t * @param {Object} [options={}] Object with configuration.\n\t * @param {'forward'|'backward'} [options.direction='forward'] Walking direction.\n\t * @param {module:engine/model/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {module:engine/model/position~Position} [options.startPosition] Starting position.\n\t * @param {Boolean} [options.singleCharacters=false] Flag indicating whether all consecutive characters with the same attributes\n\t * should be returned one by one as multiple {@link module:engine/model/textproxy~TextProxy} (`true`) objects or as one\n\t * {@link module:engine/model/textproxy~TextProxy} (`false`).\n\t * @param {Boolean} [options.shallow=false] Flag indicating whether iterator should enter elements or not. If the\n\t * iterator is shallow child nodes of any iterated node will not be returned along with `elementEnd` tag.\n\t * @param {Boolean} [options.ignoreElementEnd=false] Flag indicating whether iterator should ignore `elementEnd`\n\t * tags. If the option is true walker will not return a parent node of start position. If this option is `true`\n\t * each {@link module:engine/model/element~Element} will be returned once, while if the option is `false` they might be returned\n\t * twice: for `'elementStart'` and `'elementEnd'`.\n\t */\n\tconstructor( options = {} ) {\n\t\tif ( !options.boundaries && !options.startPosition ) {\n\t\t\t/**\n\t\t\t * Neither boundaries nor starting position of a `TreeWalker` have been defined.\n\t\t\t *\n\t\t\t * @error model-tree-walker-no-start-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-tree-walker-no-start-position',\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\n\t\tconst direction = options.direction || 'forward';\n\n\t\tif ( direction != 'forward' && direction != 'backward' ) {\n\t\t\t/**\n\t\t\t * Only `backward` and `forward` direction allowed.\n\t\t\t *\n\t\t\t * @error model-tree-walker-unknown-direction\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-tree-walker-unknown-direction', options, { direction } );\n\t\t}\n\n\t\t/**\n\t\t * Walking direction. Defaults `'forward'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'backward'|'forward'} module:engine/model/treewalker~TreeWalker#direction\n\t\t */\n\t\tthis.direction = direction;\n\n\t\t/**\n\t\t * Iterator boundaries.\n\t\t *\n\t\t * When the iterator is walking `'forward'` on the end of boundary or is walking `'backward'`\n\t\t * on the start of boundary, then `{ done: true }` is returned.\n\t\t *\n\t\t * If boundaries are not defined they are set before first and after last child of the root node.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range} module:engine/model/treewalker~TreeWalker#boundaries\n\t\t */\n\t\tthis.boundaries = options.boundaries || null;\n\n\t\t/**\n\t\t * Iterator position. This is always static position, even if the initial position was a\n\t\t * {@link module:engine/model/liveposition~LivePosition live position}. If start position is not defined then position depends\n\t\t * on {@link #direction}. If direction is `'forward'` position starts form the beginning, when direction\n\t\t * is `'backward'` position starts from the end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/treewalker~TreeWalker#position\n\t\t */\n\t\tif ( options.startPosition ) {\n\t\t\tthis.position = options.startPosition.clone();\n\t\t} else {\n\t\t\tthis.position = Position._createAt( this.boundaries[ this.direction == 'backward' ? 'end' : 'start' ] );\n\t\t}\n\n\t\t// Reset position stickiness in case it was set to other value, as the stickiness is kept after cloning.\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * Flag indicating whether all consecutive characters with the same attributes should be\n\t\t * returned as one {@link module:engine/model/textproxy~TextProxy} (`true`) or one by one (`false`).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#singleCharacters\n\t\t */\n\t\tthis.singleCharacters = !!options.singleCharacters;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should enter elements or not. If the iterator is shallow child nodes of any\n\t\t * iterated node will not be returned along with `elementEnd` tag.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#shallow\n\t\t */\n\t\tthis.shallow = !!options.shallow;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should ignore `elementEnd` tags. If the option is true walker will not\n\t\t * return a parent node of the start position. If this option is `true` each {@link module:engine/model/element~Element} will\n\t\t * be returned once, while if the option is `false` they might be returned twice:\n\t\t * for `'elementStart'` and `'elementEnd'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#ignoreElementEnd\n\t\t */\n\t\tthis.ignoreElementEnd = !!options.ignoreElementEnd;\n\n\t\t/**\n\t\t * Start boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryStartParent\n\t\t */\n\t\tthis._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;\n\n\t\t/**\n\t\t * End boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryEndParent\n\t\t */\n\t\tthis._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;\n\n\t\t/**\n\t\t * Parent of the most recently visited node. Cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t\t * module:engine/model/treewalker~TreeWalker#_visitedParent\n\t\t */\n\t\tthis._visitedParent = this.position.parent;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.\n\t *\n\t * For example:\n\t *\n\t * \t\twalker.skip( value => value.type == 'text' ); // []foo -> foo[]\n\t * \t\twalker.skip( () => true ); // Move the position to the end: []foo -> foo[]\n\t * \t\twalker.skip( () => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t */\n\tskip( skip ) {\n\t\tlet done, value, prevPosition, prevVisitedParent;\n\n\t\tdo {\n\t\t\tprevPosition = this.position;\n\t\t\tprevVisitedParent = this._visitedParent;\n\n\t\t\t( { done, value } = this.next() );\n\t\t} while ( !done && skip( value ) );\n\n\t\tif ( !done ) {\n\t\t\tthis.position = prevPosition;\n\t\t\tthis._visitedParent = prevVisitedParent;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the next tree walker's value.\n\t *\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} Next tree walker's value.\n\t */\n\tnext() {\n\t\tif ( this.direction == 'forward' ) {\n\t\t\treturn this._next();\n\t\t} else {\n\t\t\treturn this._previous();\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step forward in model. Moves the {@link #position} to the next position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_next() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the end of the root.\n\t\tif ( parent.parent === null && position.offset === parent.maxOffset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent === this._boundaryEndParent && position.offset == this.boundaries.end.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just after the current position.\n\t\t// Use a highly optimized version instead of checking the text node first and then getting the node after. See #6582.\n\t\tconst positionParent = position.parent;\n\t\tconst textNodeAtPosition = getTextNodeAtPosition( position, positionParent );\n\t\tconst node = textNodeAtPosition ? textNodeAtPosition : getNodeAfterPosition( position, positionParent, textNodeAtPosition );\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\t// Manual operations on path internals for optimization purposes. Here and in the rest of the method.\n\t\t\t\tposition.path.push( 0 );\n\t\t\t\tthis._visitedParent = node;\n\t\t\t} else {\n\t\t\t\tposition.offset++;\n\t\t\t}\n\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.endOffset;\n\n\t\t\t\tif ( this._boundaryEndParent == parent && this.boundaries.end.offset < offset ) {\n\t\t\t\t\toffset = this.boundaries.end.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = offset - position.offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode, charactersCount );\n\n\t\t\tposition.offset += charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the end of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tposition.offset++;\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\treturn formatReturnValue( 'elementEnd', parent, previousPosition, position );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step backward in model. Moves the {@link #position} to the previous position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_previous() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the beginning of the root.\n\t\tif ( parent.parent === null && position.offset === 0 ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent == this._boundaryStartParent && position.offset == this.boundaries.start.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just before the current position.\n\t\t// Use a highly optimized version instead of checking the text node first and then getting the node before. See #6582.\n\t\tconst positionParent = position.parent;\n\t\tconst textNodeAtPosition = getTextNodeAtPosition( position, positionParent );\n\t\tconst node = textNodeAtPosition ? textNodeAtPosition : getNodeBeforePosition( position, positionParent, textNodeAtPosition );\n\n\t\tif ( node instanceof Element ) {\n\t\t\tposition.offset--;\n\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition.path.push( node.maxOffset );\n\t\t\t\tthis.position = position;\n\t\t\t\tthis._visitedParent = node;\n\n\t\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\t\treturn this._previous();\n\t\t\t\t} else {\n\t\t\t\t\treturn formatReturnValue( 'elementEnd', node, previousPosition, position );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t\t}\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.startOffset;\n\n\t\t\t\tif ( this._boundaryStartParent == parent && this.boundaries.start.offset > offset ) {\n\t\t\t\t\toffset = this.boundaries.start.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = position.offset - offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode - charactersCount, charactersCount );\n\n\t\t\tposition.offset -= charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the beginning of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\treturn formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );\n\t\t}\n\t}\n}\n\nfunction formatReturnValue( type, item, previousPosition, nextPosition, length ) {\n\treturn {\n\t\tdone: false,\n\t\tvalue: {\n\t\t\ttype,\n\t\t\titem,\n\t\t\tpreviousPosition,\n\t\t\tnextPosition,\n\t\t\tlength\n\t\t}\n\t};\n}\n\n/**\n * Type of the step made by {@link module:engine/model/treewalker~TreeWalker}.\n * Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end of node,\n * `'character'` if walker traversed over a character, or `'text'` if walker traversed over multiple characters (available in\n * character merging mode, see {@link module:engine/model/treewalker~TreeWalker#constructor}).\n *\n * @typedef {'elementStart'|'elementEnd'|'character'|'text'} module:engine/model/treewalker~TreeWalkerValueType\n */\n\n/**\n * Object returned by {@link module:engine/model/treewalker~TreeWalker} when traversing tree model.\n *\n * @typedef {Object} module:engine/model/treewalker~TreeWalkerValue\n * @property {module:engine/model/treewalker~TreeWalkerValueType} type\n * @property {module:engine/model/item~Item} item Item between old and new positions of {@link module:engine/model/treewalker~TreeWalker}.\n * @property {module:engine/model/position~Position} previousPosition Previous position of the iterator.\n * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the\n * position before the item.\n * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after item.\n * @property {module:engine/model/position~Position} nextPosition Next position of the iterator.\n * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after the item.\n * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position\n * before the item.\n * @property {Number} [length] Length of the item. For `'elementStart'` and `'character'` it is 1. For `'text'` it is\n * the length of the text. For `'elementEnd'` it is `undefined`.\n */\n\n/**\n * Tree walking directions.\n *\n * @typedef {'forward'|'backward'} module:engine/model/treewalker~TreeWalkerDirection\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/insertcontent\n */\n\nimport Position from '../position';\nimport LivePosition from '../liveposition';\nimport Element from '../element';\nimport Range from '../range';\nimport DocumentSelection from '../documentselection';\nimport Selection from '../selection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Inserts content into the editor (specified selection) as one would expect the paste functionality to work.\n *\n * It takes care of removing the selected content, splitting elements (if needed), inserting elements and merging elements appropriately.\n *\n * Some examples:\n *\n * \t\t

x^

+

y

=>

x

y

=>

xy[]

\n * \t\t

x^y

+

z

=>

x

^

y

+

z

=>

x

z

y

=>

xz[]y

\n * \t\t

x^y

+ =>

x

^

y

+ =>

x

y

\n * \t\t

x

^

z

+

y

=>

x

y[]

z

(no merging)\n * \t\t

x

[]

z

+

y

=>

x

^

z

+

y

=>

x

y[]

z

\n *\n * If an instance of {@link module:engine/model/selection~Selection} is passed as `selectable` it will be modified\n * to the insertion selection (equal to a range to be selected after insertion).\n *\n * If `selectable` is not passed, the content will be inserted using the current selection of the model document.\n *\n * **Note:** Use {@link module:engine/model/model~Model#insertContent} instead of this function.\n * This function is only exposed to be reusable in algorithms which change the {@link module:engine/model/model~Model#insertContent}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which the insertion\n * should be performed.\n * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n * Selection into which the content should be inserted.\n * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Sets place or offset of the selection.\n * @returns {module:engine/model/range~Range} Range which contains all the performed changes. This is a range that, if removed,\n * would return the model to the state before the insertion. If no changes were preformed by `insertContent`, returns a range collapsed\n * at the insertion position.\n */\nexport default function insertContent( model, content, selectable, placeOrOffset ) {\n\treturn model.change( writer => {\n\t\tlet selection;\n\n\t\tif ( !selectable ) {\n\t\t\tselection = model.document.selection;\n\t\t} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {\n\t\t\tselection = selectable;\n\t\t} else {\n\t\t\tselection = writer.createSelection( selectable, placeOrOffset );\n\t\t}\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\tmodel.deleteContent( selection, { doNotAutoparagraph: true } );\n\t\t}\n\n\t\tconst insertion = new Insertion( model, writer, selection.anchor );\n\n\t\tlet nodesToInsert;\n\n\t\tif ( content.is( 'documentFragment' ) ) {\n\t\t\tnodesToInsert = content.getChildren();\n\t\t} else {\n\t\t\tnodesToInsert = [ content ];\n\t\t}\n\n\t\tinsertion.handleNodes( nodesToInsert );\n\n\t\tconst newRange = insertion.getSelectionRange();\n\n\t\t/* istanbul ignore else */\n\t\tif ( newRange ) {\n\t\t\tif ( selection instanceof DocumentSelection ) {\n\t\t\t\twriter.setSelection( newRange );\n\t\t\t} else {\n\t\t\t\tselection.setTo( newRange );\n\t\t\t}\n\t\t} else {\n\t\t\t// We are not testing else because it's a safe check for unpredictable edge cases:\n\t\t\t// an insertion without proper range to select.\n\t\t\t//\n\t\t\t// @if CK_DEBUG // console.warn( 'Cannot determine a proper selection range after insertion.' );\n\t\t}\n\n\t\tconst affectedRange = insertion.getAffectedRange() || model.createRange( selection.anchor );\n\n\t\tinsertion.destroy();\n\n\t\treturn affectedRange;\n\t} );\n}\n\n/**\n * Utility class for performing content insertion.\n *\n * @private\n */\nclass Insertion {\n\tconstructor( model, writer, position ) {\n\t\t/**\n\t\t * The model in context of which the insertion should be performed.\n\t\t *\n\t\t * @member {module:engine/model~Model} #model\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Batch to which operations will be added.\n\t\t *\n\t\t * @member {module:engine/controller/writer~Batch} #writer\n\t\t */\n\t\tthis.writer = writer;\n\n\t\t/**\n\t\t * The position at which (or near which) the next node will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} #position\n\t\t */\n\t\tthis.position = position;\n\n\t\t/**\n\t\t * Elements with which the inserted elements can be merged.\n\t\t *\n\t\t *\t\t

x^

y

+

z

(can merge to

x

)\n\t\t *\t\t

x

^y

+

z

(can merge to

y

)\n\t\t *\t\t

x^y

+

z

(can merge to

xy

which will be split during the action,\n\t\t *\t\t\t\t\t\t\t\tso both its pieces will be added to this set)\n\t\t *\n\t\t *\n\t\t * @member {Set} #canMergeWith\n\t\t */\n\t\tthis.canMergeWith = new Set( [ this.position.parent ] );\n\n\t\t/**\n\t\t * Schema of the model.\n\t\t *\n\t\t * @member {module:engine/model/schema~Schema} #schema\n\t\t */\n\t\tthis.schema = model.schema;\n\n\t\t/**\n\t\t * The temporary DocumentFragment used for grouping multiple nodes for single insert operation.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t\t */\n\t\tthis._documentFragment = writer.createDocumentFragment();\n\n\t\t/**\n\t\t * The current position in the temporary DocumentFragment.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/position~Position}\n\t\t */\n\t\tthis._documentFragmentPosition = writer.createPositionAt( this._documentFragment, 0 );\n\n\t\t/**\n\t\t * The reference to the first inserted node.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/node~Node}\n\t\t */\n\t\tthis._firstNode = null;\n\n\t\t/**\n\t\t * The reference to the last inserted node.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/node~Node}\n\t\t */\n\t\tthis._lastNode = null;\n\n\t\t/**\n\t\t * The reference to the last auto paragraph node.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/node~Node}\n\t\t */\n\t\tthis._lastAutoParagraph = null;\n\n\t\t/**\n\t\t * The array of nodes that should be cleaned of not allowed attributes.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.}\n\t\t */\n\t\tthis._filterAttributesOf = [];\n\n\t\t/**\n\t\t * Beginning of the affected range. See {@link module:engine/model/utils/insertcontent~Insertion#getAffectedRange}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition|null} #_affectedStart\n\t\t */\n\t\tthis._affectedStart = null;\n\n\t\t/**\n\t\t * End of the affected range. See {@link module:engine/model/utils/insertcontent~Insertion#getAffectedRange}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/liveposition~LivePosition|null} #_affectedEnd\n\t\t */\n\t\tthis._affectedEnd = null;\n\t}\n\n\t/**\n\t * Handles insertion of a set of nodes.\n\t *\n\t * @param {Iterable.} nodes Nodes to insert.\n\t */\n\thandleNodes( nodes ) {\n\t\tfor ( const node of Array.from( nodes ) ) {\n\t\t\tthis._handleNode( node );\n\t\t}\n\n\t\t// Insert nodes collected in temporary DocumentFragment.\n\t\tthis._insertPartialFragment();\n\n\t\t// If there was an auto paragraph then we might need to adjust the end of insertion.\n\t\tif ( this._lastAutoParagraph ) {\n\t\t\tthis._updateLastNodeFromAutoParagraph( this._lastAutoParagraph );\n\t\t}\n\n\t\t// After the content was inserted we may try to merge it with its next sibling if the selection was in it initially.\n\t\t// Merging with the previous sibling was performed just after inserting the first node to the document.\n\t\tthis._mergeOnRight();\n\n\t\t// TMP this will become a post-fixer.\n\t\tthis.schema.removeDisallowedAttributes( this._filterAttributesOf, this.writer );\n\t\tthis._filterAttributesOf = [];\n\t}\n\n\t/**\n\t * Updates the last node after the auto paragraphing.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The last auto paragraphing node.\n\t */\n\t_updateLastNodeFromAutoParagraph( node ) {\n\t\tconst positionAfterLastNode = this.writer.createPositionAfter( this._lastNode );\n\t\tconst positionAfterNode = this.writer.createPositionAfter( node );\n\n\t\t// If the real end was after the last auto paragraph then update relevant properties.\n\t\tif ( positionAfterNode.isAfter( positionAfterLastNode ) ) {\n\t\t\tthis._lastNode = node;\n\n\t\t\t/* istanbul ignore if */\n\t\t\tif ( this.position.parent != node || !this.position.isAtEnd ) {\n\t\t\t\t// Algorithm's correctness check. We should never end up here but it's good to know that we did.\n\t\t\t\t// At this point the insertion position should be at the end of the last auto paragraph.\n\t\t\t\t// Note: This error is documented in other place in this file.\n\t\t\t\tthrow new CKEditorError( 'insertcontent-invalid-insertion-position', this );\n\t\t\t}\n\n\t\t\tthis.position = positionAfterNode;\n\t\t\tthis._setAffectedBoundaries( this.position );\n\t\t}\n\t}\n\n\t/**\n\t * Returns range to be selected after insertion.\n\t * Returns `null` if there is no valid range to select after insertion.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetSelectionRange() {\n\t\tif ( this.nodeToSelect ) {\n\t\t\treturn Range._createOn( this.nodeToSelect );\n\t\t}\n\n\t\treturn this.model.schema.getNearestSelectionRange( this.position );\n\t}\n\n\t/**\n\t * Returns a range which contains all the performed changes. This is a range that, if removed, would return the model to the state\n\t * before the insertion. Returns `null` if no changes were done.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetAffectedRange() {\n\t\tif ( !this._affectedStart ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new Range( this._affectedStart, this._affectedEnd );\n\t}\n\n\t/**\n\t * Destroys `Insertion` instance.\n\t */\n\tdestroy() {\n\t\tif ( this._affectedStart ) {\n\t\t\tthis._affectedStart.detach();\n\t\t}\n\n\t\tif ( this._affectedEnd ) {\n\t\t\tthis._affectedEnd.detach();\n\t\t}\n\t}\n\n\t/**\n\t * Handles insertion of a single node.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node\n\t */\n\t_handleNode( node ) {\n\t\t// Let's handle object in a special way.\n\t\t// * They should never be merged with other elements.\n\t\t// * If they are not allowed in any of the selection ancestors, they could be either autoparagraphed or totally removed.\n\t\tif ( this.schema.isObject( node ) ) {\n\t\t\tthis._handleObject( node );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Try to find a place for the given node.\n\n\t\t// Check if a node can be inserted in the given position or it would be accepted if a paragraph would be inserted.\n\t\t// Inserts the auto paragraph if it would allow for insertion.\n\t\tlet isAllowed = this._checkAndAutoParagraphToAllowedPosition( node );\n\n\t\tif ( !isAllowed ) {\n\t\t\t// Split the position.parent's branch up to a point where the node can be inserted.\n\t\t\t// If it isn't allowed in the whole branch, then of course don't split anything.\n\t\t\tisAllowed = this._checkAndSplitToAllowedPosition( node );\n\n\t\t\tif ( !isAllowed ) {\n\t\t\t\tthis._handleDisallowedNode( node );\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// Add node to the current temporary DocumentFragment.\n\t\tthis._appendToFragment( node );\n\n\t\t// Store the first and last nodes for easy access for merging with sibling nodes.\n\t\tif ( !this._firstNode ) {\n\t\t\tthis._firstNode = node;\n\t\t}\n\n\t\tthis._lastNode = node;\n\t}\n\n\t/**\n\t * Inserts the temporary DocumentFragment into the model.\n\t *\n\t * @private\n\t */\n\t_insertPartialFragment() {\n\t\tif ( this._documentFragment.isEmpty ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst livePosition = LivePosition.fromPosition( this.position, 'toNext' );\n\n\t\tthis._setAffectedBoundaries( this.position );\n\n\t\t// If the very first node of the whole insertion process is inserted, insert it separately for OT reasons (undo).\n\t\t// Note: there can be multiple calls to `_insertPartialFragment()` during one insertion process.\n\t\t// Note: only the very first node can be merged so we have to do separate operation only for it.\n\t\tif ( this._documentFragment.getChild( 0 ) == this._firstNode ) {\n\t\t\tthis.writer.insert( this._firstNode, this.position );\n\n\t\t\t// We must merge the first node just after inserting it to avoid problems with OT.\n\t\t\t// (See: https://github.com/ckeditor/ckeditor5/pull/8773#issuecomment-760945652).\n\t\t\tthis._mergeOnLeft();\n\n\t\t\tthis.position = livePosition.toPosition();\n\t\t}\n\n\t\t// Insert the remaining nodes from document fragment.\n\t\tif ( !this._documentFragment.isEmpty ) {\n\t\t\tthis.writer.insert( this._documentFragment, this.position );\n\t\t}\n\n\t\tthis._documentFragmentPosition = this.writer.createPositionAt( this._documentFragment, 0 );\n\n\t\tthis.position = livePosition.toPosition();\n\t\tlivePosition.detach();\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/element~Element} node The object element.\n\t */\n\t_handleObject( node ) {\n\t\t// Try finding it a place in the tree.\n\t\tif ( this._checkAndSplitToAllowedPosition( node ) ) {\n\t\t\tthis._appendToFragment( node );\n\t\t}\n\t\t// Try autoparagraphing.\n\t\telse {\n\t\t\tthis._tryAutoparagraphing( node );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node The disallowed node which needs to be handled.\n\t */\n\t_handleDisallowedNode( node ) {\n\t\t// If the node is an element, try inserting its children (strip the parent).\n\t\tif ( node.is( 'element' ) ) {\n\t\t\tthis.handleNodes( node.getChildren() );\n\t\t}\n\t\t// If text is not allowed, try autoparagraphing it.\n\t\telse {\n\t\t\tthis._tryAutoparagraphing( node );\n\t\t}\n\t}\n\n\t/**\n\t * Append a node to the temporary DocumentFragment.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node to insert.\n\t */\n\t_appendToFragment( node ) {\n\t\t/* istanbul ignore if */\n\t\tif ( !this.schema.checkChild( this.position, node ) ) {\n\t\t\t// Algorithm's correctness check. We should never end up here but it's good to know that we did.\n\t\t\t// Note that it would often be a silent issue if we insert node in a place where it's not allowed.\n\n\t\t\t/**\n\t\t\t * Given node cannot be inserted on the given position.\n\t\t\t *\n\t\t\t * @error insertcontent-wrong-position\n\t\t\t * @param {module:engine/model/node~Node} node Node to insert.\n\t\t\t * @param {module:engine/model/position~Position} position Position to insert the node at.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'insertcontent-wrong-position',\n\t\t\t\tthis,\n\t\t\t\t{ node, position: this.position }\n\t\t\t);\n\t\t}\n\n\t\tthis.writer.insert( node, this._documentFragmentPosition );\n\t\tthis._documentFragmentPosition = this._documentFragmentPosition.getShiftedBy( node.offsetSize );\n\n\t\t// The last inserted object should be selected because we can't put a collapsed selection after it.\n\t\tif ( this.schema.isObject( node ) && !this.schema.checkChild( this.position, '$text' ) ) {\n\t\t\tthis.nodeToSelect = node;\n\t\t} else {\n\t\t\tthis.nodeToSelect = null;\n\t\t}\n\n\t\tthis._filterAttributesOf.push( node );\n\t}\n\n\t/**\n\t * Sets `_affectedStart` and `_affectedEnd` to the given `position`. Should be used before a change is done during insertion process to\n\t * mark the affected range.\n\t *\n\t * This method is used before inserting a node or splitting a parent node. `_affectedStart` and `_affectedEnd` are also changed\n\t * during merging, but the logic there is more complicated so it is left out of this function.\n\t *\n\t * @private\n\t * @param {module:engine/model/position~Position} position\n\t */\n\t_setAffectedBoundaries( position ) {\n\t\t// Set affected boundaries stickiness so that those position will \"expand\" when something is inserted in between them:\n\t\t// Foo][bar -> Foo]xx[bar\n\t\t// This is why it cannot be a range but two separate positions.\n\t\tif ( !this._affectedStart ) {\n\t\t\tthis._affectedStart = LivePosition.fromPosition( position, 'toPrevious' );\n\t\t}\n\n\t\t// If `_affectedEnd` is before the new boundary position, expand `_affectedEnd`. This can happen if first inserted node was\n\t\t// inserted into the parent but the next node is moved-out of that parent:\n\t\t// (1) Foo][ -> Foo]xx[\n\t\t// (2) Foo]xx[ -> Foo]xx[\n\t\tif ( !this._affectedEnd || this._affectedEnd.isBefore( position ) ) {\n\t\t\tif ( this._affectedEnd ) {\n\t\t\t\tthis._affectedEnd.detach();\n\t\t\t}\n\n\t\t\tthis._affectedEnd = LivePosition.fromPosition( position, 'toNext' );\n\t\t}\n\t}\n\n\t/**\n\t * Merges the previous sibling of the first node if it should be merged.\n\t *\n\t * After the content was inserted we may try to merge it with its siblings.\n\t * This should happen only if the selection was in those elements initially.\n\t *\n\t * @private\n\t */\n\t_mergeOnLeft() {\n\t\tconst node = this._firstNode;\n\n\t\tif ( !( node instanceof Element ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !this._canMergeLeft( node ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst mergePosLeft = LivePosition._createBefore( node );\n\t\tmergePosLeft.stickiness = 'toNext';\n\n\t\tconst livePosition = LivePosition.fromPosition( this.position, 'toNext' );\n\n\t\t// If `_affectedStart` is sames as merge position, it means that the element \"marked\" by `_affectedStart` is going to be\n\t\t// removed and its contents will be moved. This won't transform `LivePosition` so `_affectedStart` needs to be moved\n\t\t// by hand to properly reflect affected range. (Due to `_affectedStart` and `_affectedEnd` stickiness, the \"range\" is\n\t\t// shown as `][`).\n\t\t//\n\t\t// Example - insert `AbcXyz` at the end of `Foo^`:\n\t\t//\n\t\t// FooBar -->\n\t\t// Foo]AbcXyz[Bar -->\n\t\t// Foo]AbcXyz[Bar\n\t\t//\n\t\t// Note, that if we are here then something must have been inserted, so `_affectedStart` and `_affectedEnd` have to be set.\n\t\tif ( this._affectedStart.isEqual( mergePosLeft ) ) {\n\t\t\tthis._affectedStart.detach();\n\t\t\tthis._affectedStart = LivePosition._createAt( mergePosLeft.nodeBefore, 'end', 'toPrevious' );\n\t\t}\n\n\t\t// We need to update the references to the first and last nodes if they will be merged into the previous sibling node\n\t\t// because the reference would point to the removed node.\n\t\t//\n\t\t//

A^A

+

X

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

A

^

A

\n\t\t//

A

X

A

\n\t\t//

AX

A

\n\t\t//

AXA

\n\t\tif ( this._firstNode === this._lastNode ) {\n\t\t\tthis._firstNode = mergePosLeft.nodeBefore;\n\t\t\tthis._lastNode = mergePosLeft.nodeBefore;\n\t\t}\n\n\t\tthis.writer.merge( mergePosLeft );\n\n\t\t// If only one element (the merged one) is in the \"affected range\", also move the affected range end appropriately.\n\t\t//\n\t\t// Example - insert `Abc` at the of `Foo^`:\n\t\t//\n\t\t// FooBar -->\n\t\t// Foo]Abc[Bar -->\n\t\t// Foo]Abc[Bar -->\n\t\t// Foo]Abc[Bar\n\t\tif ( mergePosLeft.isEqual( this._affectedEnd ) && this._firstNode === this._lastNode ) {\n\t\t\tthis._affectedEnd.detach();\n\t\t\tthis._affectedEnd = LivePosition._createAt( mergePosLeft.nodeBefore, 'end', 'toNext' );\n\t\t}\n\n\t\tthis.position = livePosition.toPosition();\n\t\tlivePosition.detach();\n\n\t\t// After merge elements that were marked by _insert() to be filtered might be gone so\n\t\t// we need to mark the new container.\n\t\tthis._filterAttributesOf.push( this.position.parent );\n\n\t\tmergePosLeft.detach();\n\t}\n\n\t/**\n\t * Merges the next sibling of the last node if it should be merged.\n\t *\n\t * After the content was inserted we may try to merge it with its siblings.\n\t * This should happen only if the selection was in those elements initially.\n\t *\n\t * @private\n\t */\n\t_mergeOnRight() {\n\t\tconst node = this._lastNode;\n\n\t\tif ( !( node instanceof Element ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !this._canMergeRight( node ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst mergePosRight = LivePosition._createAfter( node );\n\t\tmergePosRight.stickiness = 'toNext';\n\n\t\t/* istanbul ignore if */\n\t\tif ( !this.position.isEqual( mergePosRight ) ) {\n\t\t\t// Algorithm's correctness check. We should never end up here but it's good to know that we did.\n\t\t\t// At this point the insertion position should be after the node we'll merge. If it isn't,\n\t\t\t// it should need to be secured as in the left merge case.\n\t\t\t/**\n\t\t\t * An internal error occurred when merging inserted content with its siblings.\n\t\t\t * The insertion position should equal the merge position.\n\t\t\t *\n\t\t\t * If you encountered this error, report it back to the CKEditor 5 team\n\t\t\t * with as many details as possible regarding the content being inserted and the insertion position.\n\t\t\t *\n\t\t\t * @error insertcontent-invalid-insertion-position\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'insertcontent-invalid-insertion-position', this );\n\t\t}\n\n\t\t// Move the position to the previous node, so it isn't moved to the graveyard on merge.\n\t\t//

x

[]

y

=>

x[]

y

\n\t\tthis.position = Position._createAt( mergePosRight.nodeBefore, 'end' );\n\n\t\t// Explanation of setting position stickiness to `'toPrevious'`:\n\t\t// OK:

xx[]

+

yy

=>

xx[]yy

(when sticks to previous)\n\t\t// NOK:

xx[]

+

yy

=>

xxyy[]

(when sticks to next)\n\t\tconst livePosition = LivePosition.fromPosition( this.position, 'toPrevious' );\n\n\t\t// See comment in `_mergeOnLeft()` on moving `_affectedStart`.\n\t\tif ( this._affectedEnd.isEqual( mergePosRight ) ) {\n\t\t\tthis._affectedEnd.detach();\n\t\t\tthis._affectedEnd = LivePosition._createAt( mergePosRight.nodeBefore, 'end', 'toNext' );\n\t\t}\n\n\t\t// We need to update the references to the first and last nodes if they will be merged into the previous sibling node\n\t\t// because the reference would point to the removed node.\n\t\t//\n\t\t//

A^A

+

X

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

A

^

A

\n\t\t//

A

X

A

\n\t\t//

AX

A

\n\t\t//

AXA

\n\t\tif ( this._firstNode === this._lastNode ) {\n\t\t\tthis._firstNode = mergePosRight.nodeBefore;\n\t\t\tthis._lastNode = mergePosRight.nodeBefore;\n\t\t}\n\n\t\tthis.writer.merge( mergePosRight );\n\n\t\t// See comment in `_mergeOnLeft()` on moving `_affectedStart`.\n\t\tif ( mergePosRight.getShiftedBy( -1 ).isEqual( this._affectedStart ) && this._firstNode === this._lastNode ) {\n\t\t\tthis._affectedStart.detach();\n\t\t\tthis._affectedStart = LivePosition._createAt( mergePosRight.nodeBefore, 0, 'toPrevious' );\n\t\t}\n\n\t\tthis.position = livePosition.toPosition();\n\t\tlivePosition.detach();\n\n\t\t// After merge elements that were marked by _insert() to be filtered might be gone so\n\t\t// we need to mark the new container.\n\t\tthis._filterAttributesOf.push( this.position.parent );\n\n\t\tmergePosRight.detach();\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with previous sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @returns {Boolean}\n\t */\n\t_canMergeLeft( node ) {\n\t\tconst previousSibling = node.previousSibling;\n\n\t\treturn ( previousSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( previousSibling ) &&\n\t\t\tthis.model.schema.checkMerge( previousSibling, node );\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with next sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @returns {Boolean}\n\t */\n\t_canMergeRight( node ) {\n\t\tconst nextSibling = node.nextSibling;\n\n\t\treturn ( nextSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( nextSibling ) &&\n\t\t\tthis.model.schema.checkMerge( node, nextSibling );\n\t}\n\n\t/**\n\t * Tries wrapping the node in a new paragraph and inserting it this way.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which needs to be autoparagraphed.\n\t */\n\t_tryAutoparagraphing( node ) {\n\t\tconst paragraph = this.writer.createElement( 'paragraph' );\n\n\t\t// Do not autoparagraph if the paragraph won't be allowed there,\n\t\t// cause that would lead to an infinite loop. The paragraph would be rejected in\n\t\t// the next _handleNode() call and we'd be here again.\n\t\tif ( this._getAllowedIn( paragraph, this.position.parent ) && this.schema.checkChild( paragraph, node ) ) {\n\t\t\tparagraph._appendChild( node );\n\t\t\tthis._handleNode( paragraph );\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a node can be inserted in the given position or it would be accepted if a paragraph would be inserted.\n\t * It also handles inserting the paragraph.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node.\n\t * @returns {Boolean} Whether an allowed position was found.\n\t * `false` is returned if the node isn't allowed at the current position or in auto paragraph, `true` if was.\n\t */\n\t_checkAndAutoParagraphToAllowedPosition( node ) {\n\t\tif ( this.schema.checkChild( this.position.parent, node ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Do not auto paragraph if the paragraph won't be allowed there,\n\t\t// cause that would lead to an infinite loop. The paragraph would be rejected in\n\t\t// the next _handleNode() call and we'd be here again.\n\t\tif ( !this.schema.checkChild( this.position.parent, 'paragraph' ) || !this.schema.checkChild( 'paragraph', node ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Insert nodes collected in temporary DocumentFragment if the position parent needs change to process further nodes.\n\t\tthis._insertPartialFragment();\n\n\t\t// Insert a paragraph and move insertion position to it.\n\t\tconst paragraph = this.writer.createElement( 'paragraph' );\n\n\t\tthis.writer.insert( paragraph, this.position );\n\t\tthis._setAffectedBoundaries( this.position );\n\n\t\tthis._lastAutoParagraph = paragraph;\n\t\tthis.position = this.writer.createPositionAt( paragraph, 0 );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node\n\t * @returns {Boolean} Whether an allowed position was found.\n\t * `false` is returned if the node isn't allowed at any position up in the tree, `true` if was.\n\t */\n\t_checkAndSplitToAllowedPosition( node ) {\n\t\tconst allowedIn = this._getAllowedIn( node, this.position.parent );\n\n\t\tif ( !allowedIn ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Insert nodes collected in temporary DocumentFragment if the position parent needs change to process further nodes.\n\t\tif ( allowedIn != this.position.parent ) {\n\t\t\tthis._insertPartialFragment();\n\t\t}\n\n\t\twhile ( allowedIn != this.position.parent ) {\n\t\t\t// If a parent which we'd need to leave is a limit element, break.\n\t\t\tif ( this.schema.isLimit( this.position.parent ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ( this.position.isAtStart ) {\n\t\t\t\t// If insertion position is at the beginning of the parent, move it out instead of splitting.\n\t\t\t\t//

^Foo

-> ^

Foo

\n\t\t\t\tconst parent = this.position.parent;\n\n\t\t\t\tthis.position = this.writer.createPositionBefore( parent );\n\n\t\t\t\t// Special case – parent is empty (

^

).\n\t\t\t\t//\n\t\t\t\t// 1. parent.isEmpty\n\t\t\t\t// We can remove the element after moving insertion position out of it.\n\t\t\t\t//\n\t\t\t\t// 2. parent.parent === allowedIn\n\t\t\t\t// However parent should remain in place when allowed element is above limit element in document tree.\n\t\t\t\t// For example there shouldn't be allowed to remove empty paragraph from tableCell, when is pasted\n\t\t\t\t// content allowed in $root.\n\t\t\t\tif ( parent.isEmpty && parent.parent === allowedIn ) {\n\t\t\t\t\tthis.writer.remove( parent );\n\t\t\t\t}\n\t\t\t} else if ( this.position.isAtEnd ) {\n\t\t\t\t// If insertion position is at the end of the parent, move it out instead of splitting.\n\t\t\t\t//

Foo^

->

Foo

^\n\t\t\t\tthis.position = this.writer.createPositionAfter( this.position.parent );\n\t\t\t} else {\n\t\t\t\tconst tempPos = this.writer.createPositionAfter( this.position.parent );\n\n\t\t\t\tthis._setAffectedBoundaries( this.position );\n\t\t\t\tthis.writer.split( this.position );\n\n\t\t\t\tthis.position = tempPos;\n\n\t\t\t\tthis.canMergeWith.add( this.position.nodeAfter );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Gets the element in which the given node is allowed. It checks the passed element and all its ancestors.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node to check.\n\t * @param {module:engine/model/element~Element} element The element in which the node's correctness should be checked.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getAllowedIn( node, element ) {\n\t\tif ( this.schema.checkChild( element, node ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\tif ( element.parent ) {\n\t\t\treturn this._getAllowedIn( node, element.parent );\n\t\t}\n\n\t\treturn null;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/getselectedcontent\n */\n\n/**\n * Gets a clone of the selected content.\n *\n * For example, for the following selection:\n *\n * ```html\n *

x

y

fir[st

se]cond

z

\n * ```\n *\n * It will return a document fragment with such a content:\n *\n * ```html\n * st

se

\n * ```\n *\n * @param {module:engine/model/model~Model} model The model in context of which\n * the selection modification should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection of which content will be returned.\n * @returns {module:engine/model/documentfragment~DocumentFragment}\n */\nexport default function getSelectedContent( model, selection ) {\n\treturn model.change( writer => {\n\t\tconst frag = writer.createDocumentFragment();\n\t\tconst range = selection.getFirstRange();\n\n\t\tif ( !range || range.isCollapsed ) {\n\t\t\treturn frag;\n\t\t}\n\n\t\tconst root = range.start.root;\n\t\tconst commonPath = range.start.getCommonPath( range.end );\n\t\tconst commonParent = root.getNodeByPath( commonPath );\n\n\t\t// ## 1st step\n\t\t//\n\t\t// First, we'll clone a fragment represented by a minimal flat range\n\t\t// containing the original range to be cloned.\n\t\t// E.g. let's consider such a range:\n\t\t//\n\t\t//

x

y

fir[st

se]cond

z

\n\t\t//\n\t\t// A minimal flat range containing this one is:\n\t\t//\n\t\t//

x

[

y

first

second

]

z

\n\t\t//\n\t\t// We can easily clone this structure, preserving e.g. the element.\n\t\tlet flatSubtreeRange;\n\n\t\tif ( range.start.parent == range.end.parent ) {\n\t\t\t// The original range is flat, so take it.\n\t\t\tflatSubtreeRange = range;\n\t\t} else {\n\t\t\tflatSubtreeRange = writer.createRange(\n\t\t\t\twriter.createPositionAt( commonParent, range.start.path[ commonPath.length ] ),\n\t\t\t\twriter.createPositionAt( commonParent, range.end.path[ commonPath.length ] + 1 )\n\t\t\t);\n\t\t}\n\n\t\tconst howMany = flatSubtreeRange.end.offset - flatSubtreeRange.start.offset;\n\n\t\t// Clone the whole contents.\n\t\tfor ( const item of flatSubtreeRange.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\t\twriter.appendText( item.data, item.getAttributes(), frag );\n\t\t\t} else {\n\t\t\t\twriter.append( writer.cloneElement( item, true ), frag );\n\t\t\t}\n\t\t}\n\n\t\t// ## 2nd step\n\t\t//\n\t\t// If the original range wasn't flat, then we need to remove the excess nodes from the both ends of the cloned fragment.\n\t\t//\n\t\t// For example, for the range shown in the 1st step comment, we need to remove these pieces:\n\t\t//\n\t\t// [

y

][fir]st

se[cond]

\n\t\t//\n\t\t// So this will be the final copied content:\n\t\t//\n\t\t// st

se

\n\t\t//\n\t\t// In order to do that, we remove content from these two ranges:\n\t\t//\n\t\t// [

y

fir]st

se[cond

]\n\t\tif ( flatSubtreeRange != range ) {\n\t\t\t// Find the position of the original range in the cloned fragment.\n\t\t\tconst newRange = range._getTransformedByMove( flatSubtreeRange.start, writer.createPositionAt( frag, 0 ), howMany )[ 0 ];\n\n\t\t\tconst leftExcessRange = writer.createRange( writer.createPositionAt( frag, 0 ), newRange.start );\n\t\t\tconst rightExcessRange = writer.createRange( newRange.end, writer.createPositionAt( frag, 'end' ) );\n\n\t\t\tremoveRangeContent( rightExcessRange, writer );\n\t\t\tremoveRangeContent( leftExcessRange, writer );\n\t\t}\n\n\t\treturn frag;\n\t} );\n}\n\n// After https://github.com/ckeditor/ckeditor5-engine/issues/690 is fixed,\n// this function will, most likely, be able to rewritten using getMinimalFlatRanges().\nfunction removeRangeContent( range, writer ) {\n\tconst parentsToCheck = [];\n\n\tArray.from( range.getItems( { direction: 'backward' } ) )\n\t\t// We should better store ranges because text proxies will lose integrity\n\t\t// with the text nodes when we'll start removing content.\n\t\t.map( item => writer.createRangeOn( item ) )\n\t\t// Filter only these items which are fully contained in the passed range.\n\t\t//\n\t\t// E.g. for the following range: [

y

fir]st\n\t\t// the walker will return the entire element, when only the \"fir\" item inside it is fully contained.\n\t\t.filter( itemRange => {\n\t\t\t// We should be able to use Range.containsRange, but https://github.com/ckeditor/ckeditor5-engine/issues/691.\n\t\t\tconst contained =\n\t\t\t\t( itemRange.start.isAfter( range.start ) || itemRange.start.isEqual( range.start ) ) &&\n\t\t\t\t( itemRange.end.isBefore( range.end ) || itemRange.end.isEqual( range.end ) );\n\n\t\t\treturn contained;\n\t\t} )\n\t\t.forEach( itemRange => {\n\t\t\tparentsToCheck.push( itemRange.start.parent );\n\n\t\t\twriter.remove( itemRange );\n\t\t} );\n\n\t// Remove ancestors of the removed items if they turned to be empty now\n\t// (their whole content was contained in the range).\n\tparentsToCheck.forEach( parentToCheck => {\n\t\tlet parent = parentToCheck;\n\n\t\twhile ( parent.parent && parent.isEmpty ) {\n\t\t\tconst removeRange = writer.createRangeOn( parent );\n\n\t\t\tparent = parent.parent;\n\n\t\t\twriter.remove( removeRange );\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/autoparagraphing\n */\n\n/**\n * Fixes all empty roots.\n *\n * @protected\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @returns {Boolean} `true` if any change has been applied, `false` otherwise.\n */\nexport function autoParagraphEmptyRoots( writer ) {\n\tconst { schema, document } = writer.model;\n\n\tfor ( const rootName of document.getRootNames() ) {\n\t\tconst root = document.getRoot( rootName );\n\n\t\tif ( root.isEmpty && !schema.checkChild( root, '$text' ) ) {\n\t\t\t// If paragraph element is allowed in the root, create paragraph element.\n\t\t\tif ( schema.checkChild( root, 'paragraph' ) ) {\n\t\t\t\twriter.insertElement( 'paragraph', root );\n\n\t\t\t\t// Other roots will get fixed in the next post-fixer round. Those will be triggered\n\t\t\t\t// in the same batch no matter if this method was triggered by the post-fixing or not\n\t\t\t\t// (the above insertElement call will trigger the post-fixers).\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if the given node wrapped with a paragraph would be accepted by the schema in the given position.\n *\n * @protected\n * @param {module:engine/model/position~Position} position The position at which to check.\n * @param {module:engine/model/node~Node|String} nodeOrType The child node or child type to check.\n * @param {module:engine/model/schema~Schema} schema A schema instance used for element validation.\n */\nexport function isParagraphable( position, nodeOrType, schema ) {\n\tconst context = schema.createContext( position );\n\n\t// When paragraph is allowed in this context...\n\tif ( !schema.checkChild( context, 'paragraph' ) ) {\n\t\treturn false;\n\t}\n\n\t// And a node would be allowed in this paragraph...\n\tif ( !schema.checkChild( context.push( 'paragraph' ), nodeOrType ) ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Inserts a new paragraph at the given position and returns a position inside that paragraph.\n *\n * @protected\n * @param {module:engine/model/position~Position} position The position where a paragraph should be inserted.\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @returns {module:engine/model/position~Position} Position inside the created paragraph.\n */\nexport function wrapInParagraph( position, writer ) {\n\tconst paragraph = writer.createElement( 'paragraph' );\n\n\twriter.insert( paragraph, position );\n\n\treturn writer.createPositionAt( paragraph, 0 );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/selection-post-fixer\n */\n\nimport Range from '../range';\nimport Position from '../position';\n\n/**\n * Injects selection post-fixer to the model.\n *\n * The role of the selection post-fixer is to ensure that the selection is in a correct place\n * after a {@link module:engine/model/model~Model#change `change()`} block was executed.\n *\n * The correct position means that:\n *\n * * All collapsed selection ranges are in a place where the {@link module:engine/model/schema~Schema}\n * allows a `$text`.\n * * None of the selection's non-collapsed ranges crosses a {@link module:engine/model/schema~Schema#isLimit limit element}\n * boundary (a range must be rooted within one limit element).\n * * Only {@link module:engine/model/schema~Schema#isSelectable selectable elements} can be selected from the outside\n * (e.g. `[foo]` is invalid). This rule applies independently to both selection ends, so this\n * selection is correct: `f[oo]`.\n *\n * If the position is not correct, the post-fixer will automatically correct it.\n *\n * ## Fixing a non-collapsed selection\n *\n * See as an example a selection that starts in a P1 element and ends inside the text of a TD element\n * (`[` and `]` are range boundaries and `(l)` denotes an element defined as `isLimit=true`):\n *\n *\t\troot\n *\t\t |- element P1\n *\t\t | |- \"foo\" root\n *\t\t |- element TABLE (l) P1 TABLE P2\n *\t\t | |- element TR (l) f o[o TR TR b a r\n *\t\t | | |- element TD (l) TD TD\n *\t\t | | |- \"aaa\" a]a a b b b\n *\t\t | |- element TR (l)\n *\t\t | | |- element TD (l) ||\n *\t\t | | |- \"bbb\" ||\n *\t\t |- element P2 VV\n *\t\t | |- \"bar\"\n *\t\t root\n *\t\t P1 TABLE] P2\n *\t\t f o[o TR TR b a r\n *\t\t TD TD\n *\t\t a a a b b b\n *\n * In the example above, the TABLE, TR and TD are defined as `isLimit=true` in the schema. The range which is not contained within\n * a single limit element must be expanded to select the outermost limit element. The range end is inside the text node of the TD element.\n * As the TD element is a child of the TR and TABLE elements, where both are defined as `isLimit=true` in the schema, the range must be\n * expanded to select the whole TABLE element.\n *\n * **Note** If the selection contains multiple ranges, the method returns a minimal set of ranges that are not intersecting after expanding\n * them to select `isLimit=true` elements.\n *\n * @param {module:engine/model/model~Model} model\n */\nexport function injectSelectionPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => selectionPostFixer( writer, model ) );\n}\n\n// The selection post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction selectionPostFixer( writer, model ) {\n\tconst selection = model.document.selection;\n\tconst schema = model.schema;\n\n\tconst ranges = [];\n\n\tlet wasFixed = false;\n\n\tfor ( const modelRange of selection.getRanges() ) {\n\t\t// Go through all ranges in selection and try fixing each of them.\n\t\t// Those ranges might overlap but will be corrected later.\n\t\tconst correctedRange = tryFixingRange( modelRange, schema );\n\n\t\t// \"Selection fixing\" algorithms sometimes get lost. In consequence, it may happen\n\t\t// that a new range is returned but, in fact, it has the same positions as the original\n\t\t// range anyway. If this range is not discarded, a new selection will be set and that,\n\t\t// for instance, would destroy the selection attributes. Let's make sure that the post-fixer\n\t\t// actually worked first before setting a new selection.\n\t\t//\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6693\n\t\tif ( correctedRange && !correctedRange.isEqual( modelRange ) ) {\n\t\t\tranges.push( correctedRange );\n\t\t\twasFixed = true;\n\t\t} else {\n\t\t\tranges.push( modelRange );\n\t\t}\n\t}\n\n\t// If any of ranges were corrected update the selection.\n\tif ( wasFixed ) {\n\t\twriter.setSelection( mergeIntersectingRanges( ranges ), { backward: selection.isBackward } );\n\t}\n}\n\n// Tries fixing a range if it's incorrect.\n//\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingRange( range, schema ) {\n\tif ( range.isCollapsed ) {\n\t\treturn tryFixingCollapsedRange( range, schema );\n\t}\n\n\treturn tryFixingNonCollapsedRage( range, schema );\n}\n\n// Tries to fix collapsed ranges.\n//\n// * Fixes situation when a range is in a place where $text is not allowed\n//\n// @param {module:engine/model/range~Range} range Collapsed range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingCollapsedRange( range, schema ) {\n\tconst originalPosition = range.start;\n\n\tconst nearestSelectionRange = schema.getNearestSelectionRange( originalPosition );\n\n\t// This might be null ie when editor data is empty.\n\t// In such cases there is no need to fix the selection range.\n\tif ( !nearestSelectionRange ) {\n\t\treturn null;\n\t}\n\n\tif ( !nearestSelectionRange.isCollapsed ) {\n\t\treturn nearestSelectionRange;\n\t}\n\n\tconst fixedPosition = nearestSelectionRange.start;\n\n\t// Fixed position is the same as original - no need to return corrected range.\n\tif ( originalPosition.isEqual( fixedPosition ) ) {\n\t\treturn null;\n\t}\n\n\treturn new Range( fixedPosition );\n}\n\n// Tries to fix an expanded range.\n//\n// @param {module:engine/model/range~Range} range Expanded range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingNonCollapsedRage( range, schema ) {\n\tconst { start, end } = range;\n\n\tconst isTextAllowedOnStart = schema.checkChild( start, '$text' );\n\tconst isTextAllowedOnEnd = schema.checkChild( end, '$text' );\n\n\tconst startLimitElement = schema.getLimitElement( start );\n\tconst endLimitElement = schema.getLimitElement( end );\n\n\t// Ranges which both end are inside the same limit element (or root) might needs only minor fix.\n\tif ( startLimitElement === endLimitElement ) {\n\t\t// Range is valid when both position allows to place a text:\n\t\t// - f[oobarba]z\n\t\t// This would be \"fixed\" by a next check but as it will be the same it's better to return null so the selection stays the same.\n\t\tif ( isTextAllowedOnStart && isTextAllowedOnEnd ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Range that is on non-limit element (or is partially) must be fixed so it is placed inside the block around $text:\n\t\t// - [foo] -> [foo]\n\t\t// - [foo] -> [foo]\n\t\t// - f[oo] -> f[oo]\n\t\t// - [foo] -> [foo]\n\t\tif ( checkSelectionOnNonLimitElements( start, end, schema ) ) {\n\t\t\tconst isStartBeforeSelectable = start.nodeAfter && schema.isSelectable( start.nodeAfter );\n\t\t\tconst fixedStart = isStartBeforeSelectable ? null : schema.getNearestSelectionRange( start, 'forward' );\n\n\t\t\tconst isEndAfterSelectable = end.nodeBefore && schema.isSelectable( end.nodeBefore );\n\t\t\tconst fixedEnd = isEndAfterSelectable ? null : schema.getNearestSelectionRange( end, 'backward' );\n\n\t\t\t// The schema.getNearestSelectionRange might return null - if that happens use original position.\n\t\t\tconst rangeStart = fixedStart ? fixedStart.start : start;\n\t\t\tconst rangeEnd = fixedEnd ? fixedEnd.end : end;\n\n\t\t\treturn new Range( rangeStart, rangeEnd );\n\t\t}\n\t}\n\n\tconst isStartInLimit = startLimitElement && !startLimitElement.is( 'rootElement' );\n\tconst isEndInLimit = endLimitElement && !endLimitElement.is( 'rootElement' );\n\n\t// At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element\n\t// then the range crossed limit element boundaries and needs to be fixed.\n\tif ( isStartInLimit || isEndInLimit ) {\n\t\tconst bothInSameParent = ( start.nodeAfter && end.nodeBefore ) && start.nodeAfter.parent === end.nodeBefore.parent;\n\n\t\tconst expandStart = isStartInLimit && ( !bothInSameParent || !isSelectable( start.nodeAfter, schema ) );\n\t\tconst expandEnd = isEndInLimit && ( !bothInSameParent || !isSelectable( end.nodeBefore, schema ) );\n\n\t\t// Although we've already found limit element on start/end positions we must find the outer-most limit element.\n\t\t// as limit elements might be nested directly inside (ie table > tableRow > tableCell).\n\t\tlet fixedStart = start;\n\t\tlet fixedEnd = end;\n\n\t\tif ( expandStart ) {\n\t\t\tfixedStart = Position._createBefore( findOutermostLimitAncestor( startLimitElement, schema ) );\n\t\t}\n\n\t\tif ( expandEnd ) {\n\t\t\tfixedEnd = Position._createAfter( findOutermostLimitAncestor( endLimitElement, schema ) );\n\t\t}\n\n\t\treturn new Range( fixedStart, fixedEnd );\n\t}\n\n\t// Range was not fixed at this point so it is valid - ie it was placed around limit element already.\n\treturn null;\n}\n\n// Finds the outer-most ancestor.\n//\n// @param {module:engine/model/node~Node} startingNode\n// @param {module:engine/model/schema~Schema} schema\n// @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range.\n// @returns {module:engine/model/node~Node}\nfunction findOutermostLimitAncestor( startingNode, schema ) {\n\tlet isLimitNode = startingNode;\n\tlet parent = isLimitNode;\n\n\t// Find outer most isLimit block as such blocks might be nested (ie. in tables).\n\twhile ( schema.isLimit( parent ) && parent.parent ) {\n\t\tisLimitNode = parent;\n\t\tparent = parent.parent;\n\t}\n\n\treturn isLimitNode;\n}\n\n// Checks whether any of range boundaries is placed around non-limit elements.\n//\n// @param {module:engine/model/position~Position} start\n// @param {module:engine/model/position~Position} end\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction checkSelectionOnNonLimitElements( start, end, schema ) {\n\tconst startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' );\n\tconst endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' );\n\n\t// We should fix such selection when one of those nodes needs fixing.\n\treturn startIsOnBlock || endIsOnBlock;\n}\n\n// Returns a minimal non-intersecting array of ranges.\n//\n// @param {Array.} ranges\n// @returns {Array.}\nfunction mergeIntersectingRanges( ranges ) {\n\tconst nonIntersectingRanges = [];\n\n\t// First range will always be fine.\n\tnonIntersectingRanges.push( ranges.shift() );\n\n\tfor ( const range of ranges ) {\n\t\tconst previousRange = nonIntersectingRanges.pop();\n\n\t\tif ( range.isEqual( previousRange ) ) {\n\t\t\t// Use only one of two identical ranges.\n\t\t\tnonIntersectingRanges.push( previousRange );\n\t\t} else if ( range.isIntersecting( previousRange ) ) {\n\t\t\t// Get the sum of two ranges.\n\t\t\tconst start = previousRange.start.isAfter( range.start ) ? range.start : previousRange.start;\n\t\t\tconst end = previousRange.end.isAfter( range.end ) ? previousRange.end : range.end;\n\n\t\t\tconst merged = new Range( start, end );\n\t\t\tnonIntersectingRanges.push( merged );\n\t\t} else {\n\t\t\tnonIntersectingRanges.push( previousRange );\n\t\t\tnonIntersectingRanges.push( range );\n\t\t}\n\t}\n\n\treturn nonIntersectingRanges;\n}\n\n// Checks if node exists and if it's a selectable.\n//\n// @param {module:engine/model/node~Node} node\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isSelectable( node, schema ) {\n\treturn node && schema.isSelectable( node );\n}\n"],"sourceRoot":""}