{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/modifyselection.js","webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/utils/insertcontent.js"],"names":["wordBoundaryCharacters","modifySelection","model","selection","next","options","arguments","length","undefined","schema","isForward","direction","unit","focus","walker","TreeWalker","boundaries","getSearchRange","singleCharacters","data","_loop","done","v","position","tryExtendingTo","value","DocumentSelection","change","writer","setSelectionFocus","setFocus","_ret","Object","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_typeof_js__WEBPACK_IMPORTED_MODULE_1__","type","item","nextPosition","getCorrectWordBreakPosition","getCorrectPosition","isSelectable","Position","_createAt","checkChild","isLimit","skip","textNode","offset","startOffset","isInsideSurrogatePair","isInsideCombinedSymbol","isAtWordBoundary","isAtNodeBoundary","nextNode","nodeAfter","nodeBefore","is","boundaryChar","charAt","includes","start","root","searchEnd","Range","offsetToCheck","endOffset","insertContent","content","selectable","placeOrOffset","Selection","createSelection","document","isCollapsed","deleteContent","doNotAutoparagraph","nodesToInsert","insertion","Insertion","anchor","getChildren","handleNodes","newRange","getSelectionRange","setSelection","setTo","affectedRange","getAffectedRange","createRange","destroy","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_classCallCheck_js__WEBPACK_IMPORTED_MODULE_5__","this","canMergeWith","Set","parent","_documentFragment","createDocumentFragment","_documentFragmentPosition","createPositionAt","_firstNode","_lastNode","_lastAutoParagraph","_filterAttributesOf","_affectedStart","_affectedEnd","nodes","_i","_Array$from","Array","from","node","_handleNode","_insertPartialFragment","_updateLastNodeFromAutoParagraph","_mergeOnRight","removeDisallowedAttributes","positionAfterLastNode","createPositionAfter","positionAfterNode","isAfter","isAtEnd","CKEditorError","_setAffectedBoundaries","nodeToSelect","_createOn","getNearestSelectionRange","detach","isObject","_handleObject","isAllowed","_checkAndAutoParagraphToAllowedPosition","_checkAndSplitToAllowedPosition","_appendToFragment","_handleDisallowedNode","isEmpty","livePosition","LivePosition","fromPosition","getChild","insert","_mergeOnLeft","toPosition","_tryAutoparagraphing","getShiftedBy","offsetSize","push","isBefore","Element","_canMergeLeft","mergePosLeft","_createBefore","stickiness","isEqual","merge","_canMergeRight","mergePosRight","_createAfter","previousSibling","has","checkMerge","nextSibling","paragraph","createElement","_getAllowedIn","_appendChild","allowedIn","isAtStart","createPositionBefore","remove","tempPos","split","add","contextElement","childNode"],"mappings":"wOAeMA,EAAyB,cAqChB,SAASC,EAAiBC,EAAOC,GAA0B,IAerEC,EAfsDC,EAAeC,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,MACnEG,EAASP,EAAMO,OACfC,EAAiC,YAArBL,EAAQM,UACpBC,EAAOP,EAAQO,KAAOP,EAAQO,KAAO,YAErCC,EAAQV,EAAUU,MAElBC,EAAS,IAAIC,QAClBC,WAAYC,EAAgBJ,EAAOH,GACnCQ,kBAAkB,EAClBP,UAAWD,EAAY,UAAY,aAG9BS,GAASL,SAAQL,SAAQC,YAAWE,QAb+BQ,EAAA,WAkBxE,GAAKhB,EAAKiB,KACT,OAAAC,OAAA,GAGD,IAAMC,EAAWC,EAAgBL,EAAMf,EAAKqB,OAE5C,OAAKF,GACCpB,aAAqBuB,OACzBxB,EAAMyB,OAAQ,SAAAC,GACbA,EAAOC,kBAAmBN,KAG3BpB,EAAU2B,SAAUP,IAGrBD,OAAA,SATD,GAPD,MAAUlB,EAAOU,EAAOV,OAAW,KAAA2B,EAAAX,IAAA,cAAAY,OAAAC,EAAA,KAAAD,CAAAD,GAAA,OAAAA,EAAAT,GAwBpC,SAASE,EAAgBL,EAAMM,GAC9B,IAAQf,EAAoCS,EAApCT,UAAWI,EAAyBK,EAAzBL,OAAQF,EAAiBO,EAAjBP,KAAMH,EAAWU,EAAXV,OACzByB,EAA6BT,EAA7BS,KAAMC,EAAuBV,EAAvBU,KAAMC,EAAiBX,EAAjBW,aAIpB,GAAa,QAARF,EACJ,MAAmB,SAAdf,EAAKP,KACFyB,EAA6BvB,EAAQJ,GAGtC4B,EAAoBxB,EAAQF,EAAMF,GAI1C,GAAKwB,IAAUxB,EAAY,eAAiB,cAAiB,CAE5D,GAAKD,EAAO8B,aAAcJ,GACzB,OAAOK,OAASC,UAAWN,EAAMzB,EAAY,QAAU,UAIxD,GAAKD,EAAOiC,WAAYN,EAAc,SACrC,OAAOA,MAIJ,CAEJ,GAAK3B,EAAOkC,QAASR,GAIpB,YAFArB,EAAO8B,KAAM,kBAAM,IAMpB,GAAKnC,EAAOiC,WAAYN,EAAc,SACrC,OAAOA,GAUV,SAASE,EAAoBxB,EAAQF,GACpC,IAAMiC,EAAW/B,EAAOS,SAASsB,SAEjC,GAAKA,EAAW,CACf,IAAM1B,EAAO0B,EAAS1B,KAClB2B,EAAShC,EAAOS,SAASuB,OAASD,EAASE,YAE/C,MAAQC,eAAuB7B,EAAM2B,IAAsB,aAARlC,GAAuBqC,eAAwB9B,EAAM2B,GACvGhC,EAAOV,OAEP0C,EAAShC,EAAOS,SAASuB,OAASD,EAASE,YAI7C,OAAOjC,EAAOS,SAQf,SAASc,EAA6BvB,EAAQJ,GAC7C,IAAImC,EAAW/B,EAAOS,SAASsB,SAE/B,GAAKA,EAAW,CACf,IAAIC,EAAShC,EAAOS,SAASuB,OAASD,EAASE,YAE/C,OAASG,EAAkBL,EAAS1B,KAAM2B,EAAQpC,KAAgByC,EAAkBN,EAAUC,EAAQpC,GAAc,CACnHI,EAAOV,OAKP,IAAMgD,EAAW1C,EAAYI,EAAOS,SAAS8B,UAAYvC,EAAOS,SAAS+B,WAGzE,GAAKF,GAAYA,EAASG,GAAI,SAAY,CAEzC,IAAMC,EAAeJ,EAASjC,KAAKsC,OAAQ/C,EAAY,EAAI0C,EAASjC,KAAKZ,OAAS,GAG5EP,EAAuB0D,SAAUF,KAEtC1C,EAAOV,OAEPyC,EAAW/B,EAAOS,SAASsB,UAI7BC,EAAShC,EAAOS,SAASuB,OAASD,EAASE,aAI7C,OAAOjC,EAAOS,SAGf,SAASN,EAAgB0C,EAAOjD,GAC/B,IAAMkD,EAAOD,EAAMC,KACbC,EAAYrB,OAASC,UAAWmB,EAAMlD,EAAY,MAAQ,GAEhE,OAAKA,EACG,IAAIoD,OAAOH,EAAOE,GAElB,IAAIC,OAAOD,EAAWF,GAS/B,SAAST,EAAkB/B,EAAM2B,EAAQpC,GAExC,IAAMqD,EAAgBjB,GAAWpC,EAAY,GAAK,GAElD,OAAOV,EAAuB0D,SAAUvC,EAAKsC,OAAQM,IAQtD,SAASZ,EAAkBN,EAAUC,EAAQpC,GAC5C,OAAOoC,KAAapC,EAAYmC,EAASmB,UAAY;;;;;AClLvC,SAASC,EAAe/D,EAAOgE,EAASC,EAAYC,GAClE,OAAOlE,EAAMyB,OAAQ,SAAAC,GACpB,IAAIzB,EAKHA,EAHKgE,EAEMA,aAAsBE,QAAaF,aAAsBzC,OACxDyC,EAEAvC,EAAO0C,gBAAiBH,EAAYC,GAJpClE,EAAMqE,SAASpE,UAOtBA,EAAUqE,aACftE,EAAMuE,cAAetE,GAAauE,oBAAoB,IAGvD,IAEIC,EAFEC,EAAY,IAAIC,EAAW3E,EAAO0B,EAAQzB,EAAU2E,QAKzDH,EADIT,EAAQX,GAAI,oBACAW,EAAQa,eAENb,GAGnBU,EAAUI,YAAaL,GAEvB,IAAMM,EAAWL,EAAUM,oBAGtBD,IACC9E,aAAqBuB,OACzBE,EAAOuD,aAAcF,GAErB9E,EAAUiF,MAAOH,IASnB,IAAMI,EAAgBT,EAAUU,oBAAsBpF,EAAMqF,YAAapF,EAAU2E,QAInF,OAFAF,EAAUY,UAEHH,QASHR,aACL,SAAAA,EAAa3E,EAAO0B,EAAQL,GAAWS,OAAAyD,EAAA,KAAAzD,CAAA0D,KAAAb,GAMtCa,KAAKxF,MAAQA,EAObwF,KAAK9D,OAASA,EAOd8D,KAAKnE,SAAWA,EAahBmE,KAAKC,aAAe,IAAIC,KAAOF,KAAKnE,SAASsE,SAO7CH,KAAKjF,OAASP,EAAMO,OAQpBiF,KAAKI,kBAAoBlE,EAAOmE,yBAQhCL,KAAKM,0BAA4BpE,EAAOqE,iBAAkBP,KAAKI,kBAAmB,GAQlFJ,KAAKQ,WAAa,KAQlBR,KAAKS,UAAY,KAQjBT,KAAKU,mBAAqB,KAQ1BV,KAAKW,uBAQLX,KAAKY,eAAiB,KAQtBZ,KAAKa,aAAe,uDAQrB,SAAaC,GACZ,QAAAC,EAAA,EAAAC,EAAoBC,MAAMC,KAAMJ,GAAhCC,EAAAC,EAAAnG,OAAAkG,IAA0C,CAApC,IAAMI,EAAIH,EAAAD,GACff,KAAKoB,YAAaD,GAInBnB,KAAKqB,yBAGArB,KAAKU,oBACTV,KAAKsB,iCAAkCtB,KAAKU,oBAK7CV,KAAKuB,gBAGLvB,KAAKjF,OAAOyG,2BAA4BxB,KAAKW,oBAAqBX,KAAK9D,QACvE8D,KAAKW,uEASN,SAAkCQ,GACjC,IAAMM,EAAwBzB,KAAK9D,OAAOwF,oBAAqB1B,KAAKS,WAC9DkB,EAAoB3B,KAAK9D,OAAOwF,oBAAqBP,GAG3D,GAAKQ,EAAkBC,QAASH,GAA0B,CAIzD,GAHAzB,KAAKS,UAAYU,EAGZnB,KAAKnE,SAASsE,QAAUgB,IAASnB,KAAKnE,SAASgG,QAInD,MAAM,IAAIC,OAAe,2CAA4C9B,MAGtEA,KAAKnE,SAAW8F,EAChB3B,KAAK+B,uBAAwB/B,KAAKnE,4CAUpC,WACC,OAAKmE,KAAKgC,aACF5D,OAAM6D,UAAWjC,KAAKgC,cAGvBhC,KAAKxF,MAAMO,OAAOmH,yBAA0BlC,KAAKnE,0CASzD,WACC,OAAMmE,KAAKY,eAIJ,IAAIxC,OAAO4B,KAAKY,eAAgBZ,KAAKa,cAHpC,4BAST,WACMb,KAAKY,gBACTZ,KAAKY,eAAeuB,SAGhBnC,KAAKa,cACTb,KAAKa,aAAasB,oCAUpB,SAAahB,GAIZ,GAAKnB,KAAKjF,OAAOqH,SAAUjB,GAC1BnB,KAAKqC,cAAelB,OADrB,CAUA,IAAImB,EAAYtC,KAAKuC,wCAAyCpB,GAExDmB,IAGLA,EAAYtC,KAAKwC,gCAAiCrB,GAE5CmB,IAQPtC,KAAKyC,kBAAmBtB,GAGlBnB,KAAKQ,aACVR,KAAKQ,WAAaW,GAGnBnB,KAAKS,UAAYU,GAdfnB,KAAK0C,sBAAuBvB,0CAsB/B,WACC,IAAKnB,KAAKI,kBAAkBuC,QAA5B,CAIA,IAAMC,EAAeC,OAAaC,aAAc9C,KAAKnE,SAAU,UAE/DmE,KAAK+B,uBAAwB/B,KAAKnE,UAK7BmE,KAAKI,kBAAkB2C,SAAU,IAAO/C,KAAKQ,aACjDR,KAAK9D,OAAO8G,OAAQhD,KAAKQ,WAAYR,KAAKnE,UAI1CmE,KAAKiD,eAELjD,KAAKnE,SAAW+G,EAAaM,cAIxBlD,KAAKI,kBAAkBuC,SAC5B3C,KAAK9D,OAAO8G,OAAQhD,KAAKI,kBAAmBJ,KAAKnE,UAGlDmE,KAAKM,0BAA4BN,KAAK9D,OAAOqE,iBAAkBP,KAAKI,kBAAmB,GAEvFJ,KAAKnE,SAAW+G,EAAaM,aAC7BN,EAAaT,uCAOd,SAAehB,GAETnB,KAAKwC,gCAAiCrB,GAC1CnB,KAAKyC,kBAAmBtB,GAIxBnB,KAAKmD,qBAAsBhC,wCAQ7B,SAAuBA,GAEjBA,EAAKtD,GAAI,WACbmC,KAAKV,YAAa6B,EAAK9B,eAIvBW,KAAKmD,qBAAsBhC,oCAU7B,SAAmBA,GAElB,IAAMnB,KAAKjF,OAAOiC,WAAYgD,KAAKnE,SAAUsF,GAW5C,MAAM,IAAIW,OACT,+BACA9B,MACEmB,OAAMtF,SAAUmE,KAAKnE,WAIzBmE,KAAK9D,OAAO8G,OAAQ7B,EAAMnB,KAAKM,2BAC/BN,KAAKM,0BAA4BN,KAAKM,0BAA0B8C,aAAcjC,EAAKkC,YAG9ErD,KAAKjF,OAAOqH,SAAUjB,KAAWnB,KAAKjF,OAAOiC,WAAYgD,KAAKnE,SAAU,SAC5EmE,KAAKgC,aAAeb,EAEpBnB,KAAKgC,aAAe,KAGrBhC,KAAKW,oBAAoB2C,KAAMnC,yCAahC,SAAwBtF,GAIjBmE,KAAKY,iBACVZ,KAAKY,eAAiBiC,OAAaC,aAAcjH,EAAU,eAOtDmE,KAAKa,eAAgBb,KAAKa,aAAa0C,SAAU1H,KACjDmE,KAAKa,cACTb,KAAKa,aAAasB,SAGnBnC,KAAKa,aAAegC,OAAaC,aAAcjH,EAAU,uCAY3D,WACC,IAAMsF,EAAOnB,KAAKQ,WAElB,GAAQW,aAAgBqC,QAIlBxD,KAAKyD,cAAetC,GAA1B,CAIA,IAAMuC,EAAeb,OAAac,cAAexC,GACjDuC,EAAaE,WAAa,SAE1B,IAAMhB,EAAeC,OAAaC,aAAc9C,KAAKnE,SAAU,UAc1DmE,KAAKY,eAAeiD,QAASH,KACjC1D,KAAKY,eAAeuB,SACpBnC,KAAKY,eAAiBiC,OAAa9F,UAAW2G,EAAa9F,WAAY,MAAO,eAY1EoC,KAAKQ,aAAeR,KAAKS,YAC7BT,KAAKQ,WAAakD,EAAa9F,WAC/BoC,KAAKS,UAAYiD,EAAa9F,YAG/BoC,KAAK9D,OAAO4H,MAAOJ,GAUdA,EAAaG,QAAS7D,KAAKa,eAAkBb,KAAKQ,aAAeR,KAAKS,YAC1ET,KAAKa,aAAasB,SAClBnC,KAAKa,aAAegC,OAAa9F,UAAW2G,EAAa9F,WAAY,MAAO,WAG7EoC,KAAKnE,SAAW+G,EAAaM,aAC7BN,EAAaT,SAIbnC,KAAKW,oBAAoB2C,KAAMtD,KAAKnE,SAASsE,QAE7CuD,EAAavB,uCAWd,WACC,IAAMhB,EAAOnB,KAAKS,UAElB,GAAQU,aAAgBqC,QAIlBxD,KAAK+D,eAAgB5C,GAA3B,CAIA,IAAM6C,EAAgBnB,OAAaoB,aAAc9C,GAIjD,GAHA6C,EAAcJ,WAAa,UAGrB5D,KAAKnE,SAASgI,QAASG,GAa5B,MAAM,IAAIlC,OAAe,2CAA4C9B,MAKtEA,KAAKnE,SAAWiB,OAASC,UAAWiH,EAAcpG,WAAY,OAK9D,IAAMgF,EAAeC,OAAaC,aAAc9C,KAAKnE,SAAU,cAG1DmE,KAAKa,aAAagD,QAASG,KAC/BhE,KAAKa,aAAasB,SAClBnC,KAAKa,aAAegC,OAAa9F,UAAWiH,EAAcpG,WAAY,MAAO,WAYzEoC,KAAKQ,aAAeR,KAAKS,YAC7BT,KAAKQ,WAAawD,EAAcpG,WAChCoC,KAAKS,UAAYuD,EAAcpG,YAGhCoC,KAAK9D,OAAO4H,MAAOE,GAGdA,EAAcZ,cAAe,GAAIS,QAAS7D,KAAKY,iBAAoBZ,KAAKQ,aAAeR,KAAKS,YAChGT,KAAKY,eAAeuB,SACpBnC,KAAKY,eAAiBiC,OAAa9F,UAAWiH,EAAcpG,WAAY,EAAG,eAG5EoC,KAAKnE,SAAW+G,EAAaM,aAC7BN,EAAaT,SAIbnC,KAAKW,oBAAoB2C,KAAMtD,KAAKnE,SAASsE,QAE7C6D,EAAc7B,uCAUf,SAAehB,GACd,IAAM+C,EAAkB/C,EAAK+C,gBAE7B,OAASA,aAA2BV,QACnCxD,KAAKC,aAAakE,IAAKD,IACvBlE,KAAKxF,MAAMO,OAAOqJ,WAAYF,EAAiB/C,iCAUjD,SAAgBA,GACf,IAAMkD,EAAclD,EAAKkD,YAEzB,OAASA,aAAuBb,QAC/BxD,KAAKC,aAAakE,IAAKE,IACvBrE,KAAKxF,MAAMO,OAAOqJ,WAAYjD,EAAMkD,uCAStC,SAAsBlD,GACrB,IAAMmD,EAAYtE,KAAK9D,OAAOqI,cAAe,aAKxCvE,KAAKwE,cAAexE,KAAKnE,SAASsE,OAAQmE,IAAetE,KAAKjF,OAAOiC,WAAYsH,EAAWnD,KAChGmD,EAAUG,aAActD,GACxBnB,KAAKoB,YAAakD,2DAapB,SAAyCnD,GACxC,GAAKnB,KAAKjF,OAAOiC,WAAYgD,KAAKnE,SAASsE,OAAQgB,GAClD,OAAO,EAMR,IAAMnB,KAAKjF,OAAOiC,WAAYgD,KAAKnE,SAASsE,OAAQ,eAAkBH,KAAKjF,OAAOiC,WAAY,YAAamE,GAC1G,OAAO,EAIRnB,KAAKqB,yBAGL,IAAMiD,EAAYtE,KAAK9D,OAAOqI,cAAe,aAQ7C,OANAvE,KAAK9D,OAAO8G,OAAQsB,EAAWtE,KAAKnE,UACpCmE,KAAK+B,uBAAwB/B,KAAKnE,UAElCmE,KAAKU,mBAAqB4D,EAC1BtE,KAAKnE,SAAWmE,KAAK9D,OAAOqE,iBAAkB+D,EAAW,IAElD,iDASR,SAAiCnD,GAChC,IAAMuD,EAAY1E,KAAKwE,cAAexE,KAAKnE,SAASsE,OAAQgB,GAE5D,IAAMuD,EACL,OAAO,EAIHA,GAAa1E,KAAKnE,SAASsE,QAC/BH,KAAKqB,yBAGN,MAAQqD,GAAa1E,KAAKnE,SAASsE,OAClC,GAAKH,KAAKnE,SAAS8I,UAAY,CAG9B,IAAMxE,EAASH,KAAKnE,SAASsE,OAE7BH,KAAKnE,SAAWmE,KAAK9D,OAAO0I,qBAAsBzE,GAW7CA,EAAOwC,SAAWxC,EAAOA,SAAWuE,GACxC1E,KAAK9D,OAAO2I,OAAQ1E,QAEf,GAAKH,KAAKnE,SAASgG,QAGzB7B,KAAKnE,SAAWmE,KAAK9D,OAAOwF,oBAAqB1B,KAAKnE,SAASsE,YACzD,CACN,IAAM2E,EAAU9E,KAAK9D,OAAOwF,oBAAqB1B,KAAKnE,SAASsE,QAE/DH,KAAK+B,uBAAwB/B,KAAKnE,UAClCmE,KAAK9D,OAAO6I,MAAO/E,KAAKnE,UAExBmE,KAAKnE,SAAWiJ,EAEhB9E,KAAKC,aAAa+E,IAAKhF,KAAKnE,SAAS8B,WAIvC,OAAO,+BAWR,SAAesH,EAAgBC,GAC9B,OAAKlF,KAAKjF,OAAOiC,WAAYiI,EAAgBC,GACrCD,EAQHjF,KAAKjF,OAAOkC,QAASgI,GAClB,KAGDjF,KAAKwE,cAAeS,EAAe9E,OAAQ+E","file":"js/chunk-1a792e8d.8083ac99.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/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/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( this.position.parent, paragraph ) && 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( this.position.parent, node );\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\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/element~Element} contextElement The element in which context the node should be checked.\n\t * @param {module:engine/model/node~Node} childNode The node to check.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getAllowedIn( contextElement, childNode ) {\n\t\tif ( this.schema.checkChild( contextElement, childNode ) ) {\n\t\t\treturn contextElement;\n\t\t}\n\n\t\t// If the child wasn't allowed in the context element and the element is a limit there's no point in\n\t\t// checking any further towards the root. This is it: the limit is unsplittable and there's nothing\n\t\t// we can do about it. Without this check, the algorithm will analyze parent of the limit and may create\n\t\t// an illusion of the child being allowed. There's no way to insert it down there, though. It results in\n\t\t// infinite loops.\n\t\tif ( this.schema.isLimit( contextElement ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this._getAllowedIn( contextElement.parent, childNode );\n\t}\n}\n"],"sourceRoot":""}