{"version":3,"sources":["webpack:///./node_modules/@ckeditor/ckeditor5-engine/src/model/writer.js"],"names":["Writer","model","batch","Object","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_classCallCheck_js__WEBPACK_IMPORTED_MODULE_10__","this","data","attributes","Text","name","Element","DocumentFragment","element","deep","arguments","length","undefined","_clone","item","itemOrPosition","offset","_assertWriterUsedCorrectly","position","Position","_createAt","parent","isSameTree","root","move","Range","_createOn","document","CKEditorError","remove","version","insert","InsertOperation","shouldReceiveAttributes","addOperation","applyOperation","_step","_iterator","_createForOfIteratorHelper","markers","s","n","done","_step$value","D_Projects_UA_repo_Source_Client_UA_User_Web_node_modules_babel_runtime_helpers_esm_slicedToArray_js__WEBPACK_IMPORTED_MODULE_9__","value","markerName","markerRange","rangeRootPosition","range","start","_getCombined","end","options","usingOperation","affectsData","has","updateMarker","addMarker","err","e","f","text","createText","createElement","key","itemOrRange","_step2","ranges","getMinimalFlatRanges","_iterator2","setAttributeOnRange","setAttributeOnItem","_step3","_iterator3","toMap","_step3$value","val","setAttribute","_step4","_iterator4","_this","removeAttributesFromItem","_step5","_iterator5","getAttributeKeys","attribute","removeAttribute","_step6","_iterator6","getItems","isFlat","isEqual","_addOperationForAffectedMarkers","operation","MoveOperation","_step7","rangeToRemove","reverse","_iterator7","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","applyMarkerOperation","get","_set","markerOrName","currentMarker","hasUsingOperationDefined","affectsDataDefined","currentRange","getRange","updatedRange","managedUsingOperations","_refresh","marker","oldRange","_remove","selection","_setTo","_setFocus","keyOrObjectOrIterable","_setSelectionAttribute","_step8","_iterator8","_step8$value","keyOrIterableOfKeys","_removeSelectionAttribute","_step9","_iterator9","_overrideGravity","uid","_restoreGravity","isCollapsed","anchor","isEmpty","storeKey","DocumentSelection","_getStoreAttributeKey","_setAttribute","_removeAttribute","_currentWriter","type","positionOrRange","_step10","_iterator10","isAffected","containsPosition","elementBefore","elementAfter","affectedInLeftElement","isAtEnd","affectedInRightElement","affectedAfterLeftElement","affectedBeforeRightElement","writer","valueBefore","valueAfter","_step11","doc","lastSplitPosition","_iterator11","getWalker","shallow","getAttribute","nextPosition","AttributeOperation","previousValue","isRootChanged","RootAttributeOperation","newRange","MarkerOperation","DetachOperation","rootA","rootB","RootElement"],"mappings":";;;;OAoDqBA,aAWpB,SAAAA,EAAaC,EAAOC,GAAQC,OAAAC,EAAA,KAAAD,CAAAE,KAAAL,GAO3BK,KAAKJ,MAAQA,EAQbI,KAAKH,MAAQA,mDAad,SAAYI,EAAMC,GACjB,OAAO,IAAIC,OAAMF,EAAMC,gCAaxB,SAAeE,EAAMF,GACpB,OAAO,IAAIG,OAASD,EAAMF,yCAQ3B,WACC,OAAO,IAAII,mCAWZ,SAAcC,GAAuB,IAAdC,IAAcC,UAAAC,OAAA,QAAAC,IAAAF,UAAA,KAAAA,UAAA,GACpC,OAAOF,EAAQK,OAAQJ,yBA2CxB,SAAQK,EAAMC,GAA6B,IAAbC,EAAaN,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAAJ,EAGtC,GAFAT,KAAKgB,+BAEAH,aAAgBV,QAAqB,IAAbU,EAAKZ,MAAlC,CAIA,IAAMgB,EAAWC,OAASC,UAAWL,EAAgBC,GAGrD,GAAKF,EAAKO,OAAS,CAElB,GAAKC,EAAYR,EAAKS,KAAML,EAASK,MAIpC,YAFAtB,KAAKuB,KAAMC,OAAMC,UAAWZ,GAAQI,GAMpC,GAAKJ,EAAKS,KAAKI,SAOd,MAAM,IAAIC,OACT,qCACA3B,MAKDA,KAAK4B,OAAQf,GAKhB,IAAMgB,EAAUZ,EAASK,KAAKI,SAAWT,EAASK,KAAKI,SAASG,QAAU,KAEpEC,EAAS,IAAIC,OAAiBd,EAAUJ,EAAMgB,GAUpD,GARKhB,aAAgBV,SACpB2B,EAAOE,yBAA0B,GAGlChC,KAAKH,MAAMoC,aAAcH,GACzB9B,KAAKJ,MAAMsC,eAAgBJ,GAGtBjB,aAAgBP,OAAmB,KAAA6B,EAAAC,EAAAC,EACIxB,EAAKyB,SADT,IACvC,IAAAF,EAAAG,MAAAJ,EAAAC,EAAAI,KAAAC,MAA0D,KAAAC,EAAA5C,OAAA6C,EAAA,KAAA7C,CAAAqC,EAAAS,MAAA,GAA5CC,EAA4CH,EAAA,GAAhCI,EAAgCJ,EAAA,GAEnDK,EAAoB7B,OAASC,UAAW2B,EAAYxB,KAAM,GAC1D0B,EAAQ,IAAIxB,OACjBsB,EAAYG,MAAMC,aAAcH,EAAmB9B,GACnD6B,EAAYK,IAAID,aAAcH,EAAmB9B,IAG5CmC,GAAYJ,QAAOK,gBAAgB,EAAMC,aAAa,GAEvDtD,KAAKJ,MAAM0C,QAAQiB,IAAKV,GAC5B7C,KAAKwD,aAAcX,EAAYO,GAE/BpD,KAAKyD,UAAWZ,EAAYO,IAdS,MAAAM,GAAAtB,EAAAuB,EAAAD,GAAA,QAAAtB,EAAAwB,iCA4CzC,SAAYC,EAAM3D,EAAYY,EAAgBC,GACxCb,aAAsBI,QAAoBJ,aAAsBG,QAAWH,aAAsBgB,OACrGlB,KAAK8B,OAAQ9B,KAAK8D,WAAYD,GAAQ3D,EAAYY,GAElDd,KAAK8B,OAAQ9B,KAAK8D,WAAYD,EAAM3D,GAAcY,EAAgBC,gCA4BpE,SAAeX,EAAMF,EAAYY,EAAgBC,GAC3Cb,aAAsBI,QAAoBJ,aAAsBG,QAAWH,aAAsBgB,OACrGlB,KAAK8B,OAAQ9B,KAAK+D,cAAe3D,GAAQF,EAAYY,GAErDd,KAAK8B,OAAQ9B,KAAK+D,cAAe3D,EAAMF,GAAcY,EAAgBC,yBAmBvE,SAAQF,EAAMO,GACbpB,KAAK8B,OAAQjB,EAAMO,EAAQ,iCAa5B,SAAYyC,EAAM3D,EAAYkB,GACxBlB,aAAsBI,QAAoBJ,aAAsBG,OACpEL,KAAK8B,OAAQ9B,KAAK8D,WAAYD,GAAQ3D,EAAY,OAElDF,KAAK8B,OAAQ9B,KAAK8D,WAAYD,EAAM3D,GAAckB,EAAQ,oCAc5D,SAAehB,EAAMF,EAAYkB,GAC3BlB,aAAsBI,QAAoBJ,aAAsBG,OACpEL,KAAK8B,OAAQ9B,KAAK+D,cAAe3D,GAAQF,EAAY,OAErDF,KAAK8B,OAAQ9B,KAAK+D,cAAe3D,EAAMF,GAAckB,EAAQ,mCAa/D,SAAc4C,EAAKpB,EAAOqB,GAGzB,GAFAjE,KAAKgB,6BAEAiD,aAAuBzC,OAAQ,CACnC,IADmC0C,EAC7BC,EAASF,EAAYG,uBADQC,EAAAhC,EAGd8B,GAHc,IAGnC,IAAAE,EAAA9B,MAAA2B,EAAAG,EAAA7B,KAAAC,MAA8B,KAAlBO,EAAkBkB,EAAAtB,MAC7B0B,EAAqBtE,KAAMgE,EAAKpB,EAAOI,IAJL,MAAAU,GAAAW,EAAAV,EAAAD,GAAA,QAAAW,EAAAT,UAOnCW,EAAoBvE,KAAMgE,EAAKpB,EAAOqB,gCAiBxC,SAAe/D,EAAY+D,GAAc,IAAAO,EAAAC,EAAApC,EACZqC,eAAOxE,IADK,IACxC,IAAAuE,EAAAlC,MAAAiC,EAAAC,EAAAjC,KAAAC,MAAkD,KAAAkC,EAAA7E,OAAA6C,EAAA,KAAA7C,CAAA0E,EAAA5B,MAAA,GAApCoB,EAAoCW,EAAA,GAA/BC,EAA+BD,EAAA,GACjD3E,KAAK6E,aAAcb,EAAKY,EAAKX,IAFU,MAAAP,GAAAe,EAAAd,EAAAD,GAAA,QAAAe,EAAAb,oCAczC,SAAiBI,EAAKC,GAGrB,GAFAjE,KAAKgB,6BAEAiD,aAAuBzC,OAAQ,CACnC,IADmCsD,EAC7BX,EAASF,EAAYG,uBADQW,EAAA1C,EAGd8B,GAHc,IAGnC,IAAAY,EAAAxC,MAAAuC,EAAAC,EAAAvC,KAAAC,MAA8B,KAAlBO,EAAkB8B,EAAAlC,MAC7B0B,EAAqBtE,KAAMgE,EAAK,KAAMhB,IAJJ,MAAAU,GAAAqB,EAAApB,EAAAD,GAAA,QAAAqB,EAAAnB,UAOnCW,EAAoBvE,KAAMgE,EAAK,KAAMC,kCAUvC,SAAiBA,GAAc,IAAAe,EAAAhF,KAC9BA,KAAKgB,6BAEL,IAAMiE,EAA2B,SAAApE,GAAQ,IAAAqE,EAAAC,EAAA9C,EACfxB,EAAKuE,oBADU,IACxC,IAAAD,EAAA5C,MAAA2C,EAAAC,EAAA3C,KAAAC,MAAmD,KAAvC4C,EAAuCH,EAAAtC,MAClDoC,EAAKM,gBAAiBD,EAAWxE,IAFM,MAAA6C,GAAAyB,EAAAxB,EAAAD,GAAA,QAAAyB,EAAAvB,MAMzC,GAAQK,aAAuBzC,OAExB,KAAA+D,EAAAC,EAAAnD,EACc4B,EAAYwB,YAD1B,IACN,IAAAD,EAAAjD,MAAAgD,EAAAC,EAAAhD,KAAAC,MAA6C,KAAjC5B,EAAiC0E,EAAA3C,MAC5CqC,EAA0BpE,IAFrB,MAAA6C,GAAA8B,EAAA7B,EAAAD,GAAA,QAAA8B,EAAA5B,UADNqB,EAA0BhB,uBAmC5B,SAAMjB,EAAOlC,EAAgBC,GAG5B,GAFAf,KAAKgB,+BAEGgC,aAAiBxB,QAMxB,MAAM,IAAIG,OAAe,4BAA6B3B,MAGvD,IAAMgD,EAAM0C,OAMX,MAAM,IAAI/D,OAAe,6BAA8B3B,MAGxD,IAAMiB,EAAWC,OAASC,UAAWL,EAAgBC,GAGrD,IAAKE,EAAS0E,QAAS3C,EAAMC,OAA7B,CAOA,GAFAjD,KAAK4F,gCAAiC,OAAQ5C,IAExC3B,EAAY2B,EAAM1B,KAAML,EAASK,MAOtC,MAAM,IAAIK,OAAe,iCAAkC3B,MAG5D,IAAM6B,EAAUmB,EAAM1B,KAAKI,SAAWsB,EAAM1B,KAAKI,SAASG,QAAU,KAC9DgE,EAAY,IAAIC,OAAe9C,EAAMC,MAAOD,EAAMG,IAAIpC,OAASiC,EAAMC,MAAMlC,OAAQE,EAAUY,GAEnG7B,KAAKH,MAAMoC,aAAc4D,GACzB7F,KAAKJ,MAAMsC,eAAgB2D,0BAQ5B,SAAQ5B,GACPjE,KAAKgB,6BAEL,IAHqB+E,EAGfC,EAAgB/B,aAAuBzC,OAAQyC,EAAczC,OAAMC,UAAWwC,GAC9EE,EAAS6B,EAAc5B,uBAAuB6B,UAJ/BC,EAAA7D,EAMD8B,GANC,IAMrB,IAAA+B,EAAA3D,MAAAwD,EAAAG,EAAA1D,KAAAC,MAA6B,KAAjB0D,EAAiBJ,EAAAnD,MAE5B5C,KAAK4F,gCAAiC,OAAQO,GAE9CC,EAAsBD,EAAKlD,MAAOkD,EAAKhD,IAAIpC,OAASoF,EAAKlD,MAAMlC,OAAQf,KAAKH,MAAOG,KAAKJ,QAVpE,MAAA8D,GAAAwC,EAAAvC,EAAAD,GAAA,QAAAwC,EAAAtC,0BAsBtB,SAAO3C,GACNjB,KAAKgB,6BAEL,IAAMqF,EAAapF,EAASoF,WACtBC,EAAYrF,EAASqF,UAK3B,GAFAtG,KAAK4F,gCAAiC,QAAS3E,KAEvCoF,aAAsBhG,QAM7B,MAAM,IAAIsB,OAAe,iCAAkC3B,MAG5D,KAAQsG,aAAqBjG,QAM5B,MAAM,IAAIsB,OAAe,gCAAiC3B,MAGrDiB,EAASK,KAAKI,SAGnB1B,KAAKuG,OAAQtF,GAFbjB,KAAKwG,eAAgBvF,yCAevB,SAAwBK,EAAMmF,EAAMC,GACnC,OAAO1G,KAAKJ,MAAM+G,uBAAwBrF,EAAMmF,EAAMC,mCAWvD,SAAkB5F,EAAgBC,GACjC,OAAOf,KAAKJ,MAAMgH,iBAAkB9F,EAAgBC,sCASrD,SAAqBF,GACpB,OAAOb,KAAKJ,MAAMiH,oBAAqBhG,uCASxC,SAAsBA,GACrB,OAAOb,KAAKJ,MAAMkH,qBAAsBjG,8BAUzC,SAAaoC,EAAOE,GACnB,OAAOnD,KAAKJ,MAAMmH,YAAa9D,EAAOE,gCASvC,SAAe5C,GACd,OAAOP,KAAKJ,MAAMoH,cAAezG,gCASlC,SAAeA,GACd,OAAOP,KAAKJ,MAAMqH,cAAe1G,kCAYlC,SAAiB2G,EAAYC,EAAe/D,GAC3C,OAAOpD,KAAKJ,MAAMwH,gBAAiBF,EAAYC,EAAe/D,iCAS/D,SAAgBnC,GACf,IAAMoF,EAAapF,EAASoF,WACtBC,EAAYrF,EAASqF,UAE3BtG,KAAKuB,KAAMC,OAAM6F,UAAWf,GAAapF,OAASC,UAAWkF,EAAY,QACzErG,KAAK4B,OAAQ0E,yBASd,SAAQrF,GACP,IAAMqG,EAAiBpG,OAASC,UAAWF,EAASoF,WAAY,OAC1DkB,EAAiBrG,OAASC,UAAWF,EAASqF,UAAW,GAEzDkB,EAAYvG,EAASK,KAAKI,SAAS8F,UACnCC,EAAoB,IAAIvG,OAAUsG,GAAa,IAE/C3F,EAAUZ,EAASK,KAAKI,SAASG,QAEjC6F,EAAQ,IAAIC,OAAgBJ,EAAgBtG,EAASqF,UAAUsB,UAAWN,EAAgBG,EAAmB5F,GAEnH7B,KAAKH,MAAMoC,aAAcyF,GACzB1H,KAAKJ,MAAMsC,eAAgBwF,yBAS5B,SAAQnH,EAASsH,GAGhB,GAFA7H,KAAKgB,+BAEGT,aAAmBF,QAM1B,MAAM,IAAIsB,OACT,qCACA3B,MAIF,IAAM6B,EAAUtB,EAAQe,KAAKI,SAAWnB,EAAQe,KAAKI,SAASG,QAAU,KAClEiG,EAAkB,IAAIC,OAAiB7G,OAAS8G,cAAezH,GAAWA,EAAQH,KAAMyH,EAAShG,GAEvG7B,KAAKH,MAAMoC,aAAc6F,GACzB9H,KAAKJ,MAAMsC,eAAgB4F,wBAiB5B,SAAO7G,EAAUgH,GAChBjI,KAAKgB,6BAEL,IA4BIkH,EAAmBC,EA5BnBC,EAAenH,EAASG,OAE5B,IAAMgH,EAAahH,OAMlB,MAAM,IAAIO,OAAe,iCAAkC3B,MAQ5D,GAJMiI,IACLA,EAAeG,EAAahH,SAGvBH,EAASG,OAAOiH,cAAgBC,aAAa,IAASC,SAAUN,GAMrE,MAAM,IAAItG,OAAe,qCAAsC3B,MAQhE,EAAG,CACF,IAAM6B,EAAUuG,EAAa9G,KAAKI,SAAW0G,EAAa9G,KAAKI,SAASG,QAAU,KAC5E2G,EAAUJ,EAAaR,UAAY3G,EAASF,OAE5C0H,EAAoBC,OAAeC,qBAAsB1H,GACzD2H,EAAQ,IAAIF,OAAgBzH,EAAUuH,EAASC,EAAmB,KAAM5G,GAE9E7B,KAAKH,MAAMoC,aAAc2G,GACzB5I,KAAKJ,MAAMsC,eAAgB0G,GAGrBV,GAAsBC,IAC3BD,EAAoBE,EACpBD,EAAmBlH,EAASG,OAAOyH,aAGpC5H,EAAWjB,KAAK6G,oBAAqB5F,EAASG,QAC9CgH,EAAenH,EAASG,aACfgH,IAAiBH,GAE3B,OACChH,WACA+B,MAAO,IAAIxB,OAAON,OAASC,UAAW+G,EAAmB,OAAShH,OAASC,UAAWgH,EAAkB,yBAa1G,SAAMnF,EAAO8F,GAGZ,GAFA9I,KAAKgB,8BAECgC,EAAM0C,OAMX,MAAM,IAAI/D,OAAe,6BAA8B3B,MAGxD,IAAMO,EAAUuI,aAA2BzI,OAAUyI,EAAkB,IAAIzI,OAASyI,GAEpF,GAAKvI,EAAQwI,WAAa,EAMzB,MAAM,IAAIpH,OAAe,gCAAiC3B,MAG3D,GAAwB,OAAnBO,EAAQa,OAMZ,MAAM,IAAIO,OAAe,+BAAgC3B,MAG1DA,KAAK8B,OAAQvB,EAASyC,EAAMC,OAG5B,IAAM+F,EAAe,IAAIxH,OAAOwB,EAAMC,MAAMgG,aAAc,GAAKjG,EAAMG,IAAI8F,aAAc,IAEvFjJ,KAAKuB,KAAMyH,EAAc9H,OAASC,UAAWZ,EAAS,0BASvD,SAAQA,GAGP,GAFAP,KAAKgB,6BAEmB,OAAnBT,EAAQa,OAMZ,MAAM,IAAIO,OAAe,kCAAmC3B,MAG7DA,KAAKuB,KAAMC,OAAM6F,UAAW9G,GAAWP,KAAK6G,oBAAqBtG,IACjEP,KAAK4B,OAAQrB,4BA0Cd,SAAWH,EAAMgD,GAGhB,GAFApD,KAAKgB,8BAECoC,GAA4C,kBAA1BA,EAAQC,eAM/B,MAAM,IAAI1B,OAAe,qCAAsC3B,MAGhE,IAAMqD,EAAiBD,EAAQC,eACzBL,EAAQI,EAAQJ,MAChBM,OAAsC3C,IAAxByC,EAAQE,aAAoCF,EAAQE,YAExE,GAAKtD,KAAKJ,MAAM0C,QAAQiB,IAAKnD,GAM5B,MAAM,IAAIuB,OAAe,iCAAkC3B,MAG5D,IAAMgD,EAML,MAAM,IAAIrB,OAAe,4BAA6B3B,MAGvD,OAAMqD,GAIN6F,EAAsBlJ,KAAMI,EAAM,KAAM4C,EAAOM,GAExCtD,KAAKJ,MAAM0C,QAAQ6G,IAAK/I,IALvBJ,KAAKJ,MAAM0C,QAAQ8G,KAAMhJ,EAAM4C,EAAOK,EAAgBC,+BA6E/D,SAAc+F,EAAcjG,GAC3BpD,KAAKgB,6BAEL,IAAM6B,EAAoC,iBAAhBwG,EAA2BA,EAAeA,EAAajJ,KAC3EkJ,EAAgBtJ,KAAKJ,MAAM0C,QAAQ6G,IAAKtG,GAE9C,IAAMyG,EAML,MAAM,IAAI3H,OAAe,wCAAyC3B,MAGnE,GAAMoD,EAAN,CAMA,IAAMmG,EAA4D,kBAA1BnG,EAAQC,eAC1CmG,EAAmD,kBAAvBpG,EAAQE,YAGpCA,EAAckG,EAAqBpG,EAAQE,YAAcgG,EAAchG,YAE7E,IAAMiG,IAA6BnG,EAAQJ,QAAUwG,EAMpD,MAAM,IAAI7H,OAAe,oCAAqC3B,MAG/D,IAAMyJ,EAAeH,EAAcI,WAC7BC,EAAevG,EAAQJ,MAAQI,EAAQJ,MAAQyG,EAEhDF,GAA4BnG,EAAQC,iBAAmBiG,EAAcM,uBAEpExG,EAAQC,eAGZ6F,EAAsBlJ,KAAM6C,EAAY,KAAM8G,EAAcrG,IAI5D4F,EAAsBlJ,KAAM6C,EAAY4G,EAAc,KAAMnG,GAG5DtD,KAAKJ,MAAM0C,QAAQ8G,KAAMvG,EAAY8G,OAAchJ,EAAW2C,IAO3DgG,EAAcM,uBAClBV,EAAsBlJ,KAAM6C,EAAY4G,EAAcE,EAAcrG,GAEpEtD,KAAKJ,MAAM0C,QAAQ8G,KAAMvG,EAAY8G,OAAchJ,EAAW2C,QA7C9DtD,KAAKJ,MAAM0C,QAAQuH,SAAUP,+BAwD/B,SAAcD,GACbrJ,KAAKgB,6BAEL,IAAMZ,EAA8B,iBAAhBiJ,EAA2BA,EAAeA,EAAajJ,KAE3E,IAAMJ,KAAKJ,MAAM0C,QAAQiB,IAAKnD,GAM7B,MAAM,IAAIuB,OAAe,gCAAiC3B,MAG3D,IAAM8J,EAAS9J,KAAKJ,MAAM0C,QAAQ6G,IAAK/I,GAEvC,GAAM0J,EAAOF,uBAAb,CAMA,IAAMG,EAAWD,EAAOJ,WAExBR,EAAsBlJ,KAAMI,EAAM2J,EAAU,KAAMD,EAAOxG,kBAPxDtD,KAAKJ,MAAM0C,QAAQ0H,QAAS5J,+BA6D9B,SAAc8G,EAAYC,EAAe/D,GACxCpD,KAAKgB,6BAELhB,KAAKJ,MAAM8B,SAASuI,UAAUC,OAAQhD,EAAYC,EAAe/D,oCAalE,SAAmBtC,EAAgBC,GAClCf,KAAKgB,6BAELhB,KAAKJ,MAAM8B,SAASuI,UAAUE,UAAWrJ,EAAgBC,wCAsB1D,SAAuBqJ,EAAuBxH,GAG7C,GAFA5C,KAAKgB,6BAEiC,kBAA1BoJ,EACXpK,KAAKqK,uBAAwBD,EAAuBxH,OAC9C,KAAA0H,EAAAC,EAAAlI,EACwBqC,eAAO0F,IAD/B,IACN,IAAAG,EAAAhI,MAAA+H,EAAAC,EAAA/H,KAAAC,MAA+D,KAAA+H,EAAA1K,OAAA6C,EAAA,KAAA7C,CAAAwK,EAAA1H,MAAA,GAAjDoB,EAAiDwG,EAAA,GAA5C5H,EAA4C4H,EAAA,GAC9DxK,KAAKqK,uBAAwBrG,EAAKpB,IAF7B,MAAAc,GAAA6G,EAAA5G,EAAAD,GAAA,QAAA6G,EAAA3G,8CAoBR,SAA0B6G,GAGzB,GAFAzK,KAAKgB,6BAE+B,kBAAxByJ,EACXzK,KAAK0K,0BAA2BD,OAC1B,KAAAE,EAAAC,EAAAvI,EACaoI,GADb,IACN,IAAAG,EAAArI,MAAAoI,EAAAC,EAAApI,KAAAC,MAAyC,KAA7BuB,EAA6B2G,EAAA/H,MACxC5C,KAAK0K,0BAA2B1G,IAF3B,MAAAN,GAAAkH,EAAAjH,EAAAD,GAAA,QAAAkH,EAAAhH,8CA2BR,WACC,OAAO5D,KAAKJ,MAAM8B,SAASuI,UAAUY,0DAYtC,SAAyBC,GACxB9K,KAAKJ,MAAM8B,SAASuI,UAAUc,gBAAiBD,yCAQhD,SAAwB9G,EAAKpB,GAC5B,IAAMqH,EAAYjK,KAAKJ,MAAM8B,SAASuI,UAGtC,GAAKA,EAAUe,aAAef,EAAUgB,OAAO7J,OAAO8J,QAAU,CAC/D,IAAMC,EAAWC,OAAkBC,sBAAuBrH,GAE1DhE,KAAK6E,aAAcsG,EAAUvI,EAAOqH,EAAUgB,OAAO7J,QAGtD6I,EAAUqB,cAAetH,EAAKpB,4CAO/B,SAA2BoB,GAC1B,IAAMiG,EAAYjK,KAAKJ,MAAM8B,SAASuI,UAGtC,GAAKA,EAAUe,aAAef,EAAUgB,OAAO7J,OAAO8J,QAAU,CAC/D,IAAMC,EAAWC,OAAkBC,sBAAuBrH,GAE1DhE,KAAKsF,gBAAiB6F,EAAUlB,EAAUgB,OAAO7J,QAGlD6I,EAAUsB,iBAAkBvH,6CAQ7B,WAUC,GAAKhE,KAAKJ,MAAM4L,iBAAmBxL,KAClC,MAAM,IAAI2B,OAAe,uBAAwB3B,qDAcnD,SAAiCyL,EAAMC,GAAkB,IAAAC,EAAAC,EAAAvJ,EAClCrC,KAAKJ,MAAM0C,SADuB,IACxD,IAAAsJ,EAAArJ,MAAAoJ,EAAAC,EAAApJ,KAAAC,MAA2C,KAA/BqH,EAA+B6B,EAAA/I,MAC1C,GAAMkH,EAAOF,uBAAb,CAIA,IAAM9G,EAAcgH,EAAOJ,WACvBmC,GAAa,EAEjB,GAAc,SAATJ,EACJI,EACCH,EAAgBI,iBAAkBhJ,EAAYG,QAC9CyI,EAAgBzI,MAAM0C,QAAS7C,EAAYG,QAC3CyI,EAAgBI,iBAAkBhJ,EAAYK,MAC9CuI,EAAgBvI,IAAIwC,QAAS7C,EAAYK,SACpC,CAEN,IAAM4I,EAAgBL,EAAgBrF,WAChC2F,EAAeN,EAAgBpF,UAM/B2F,EAAwBnJ,EAAYG,MAAM7B,QAAU2K,GAAiBjJ,EAAYG,MAAMiJ,QAMvFC,EAAyBrJ,EAAYK,IAAI/B,QAAU4K,GAA0C,GAA1BlJ,EAAYK,IAAIpC,OAMnFqL,EAA2BtJ,EAAYK,IAAImD,WAAa0F,EAMxDK,EAA6BvJ,EAAYG,MAAMqD,WAAa0F,EAElEH,EAAaI,GAAyBE,GAA0BC,GAA4BC,EAGxFR,GACJ7L,KAAKwD,aAAcsG,EAAO1J,MAAQ4C,MAAOF,MAhDa,MAAAY,GAAAkI,EAAAjI,EAAAD,GAAA,QAAAkI,EAAAhI,cAkE1D,SAASU,EAAqBgI,EAAQtI,EAAKpB,EAAOI,GACjD,IAQI/B,EAGAsL,EAGAC,EAfqDC,EACnD7M,EAAQ0M,EAAO1M,MACf8M,EAAM9M,EAAM8B,SAGdiL,EAAoB3J,EAAMC,MAL2B2J,EAAAvK,EAiBtCW,EAAM6J,WAAaC,SAAS,KAjBU,IAiBzD,IAAAF,EAAArK,MAAAkK,EAAAG,EAAApK,KAAAC,MAA0D,KAA9CmC,EAA8C6H,EAAA7J,MACzD4J,EAAa5H,EAAI/D,KAAKkM,aAAc/I,GAI/B/C,GAAYsL,GAAeC,IAE1BD,GAAe3J,GACnBX,IAGD0K,EAAoB1L,GAGrBA,EAAW2D,EAAIoI,aACfT,EAAcC,GAhC0C,MAAA9I,GAAAkJ,EAAAjJ,EAAAD,GAAA,QAAAkJ,EAAAhJ,IAyCzD,SAAS3B,IACR,IAAMe,EAAQ,IAAIxB,OAAOmL,EAAmB1L,GACtCY,EAAUmB,EAAM1B,KAAKI,SAAWgL,EAAI7K,QAAU,KAC9CgE,EAAY,IAAIoH,OAAoBjK,EAAOgB,EAAKuI,EAAa3J,EAAOf,GAE1EyK,EAAOzM,MAAMoC,aAAc4D,GAC3BjG,EAAMsC,eAAgB2D,GAVlB5E,aAAoBC,QAAYD,GAAY0L,GAAqBJ,GAAe3J,GACpFX,IAoBF,SAASsC,EAAoB+H,EAAQtI,EAAKpB,EAAO/B,GAChD,IAGImC,EAAO6C,EAHLjG,EAAQ0M,EAAO1M,MACf8M,EAAM9M,EAAM8B,SACZwL,EAAgBrM,EAAKkM,aAAc/I,GAGzC,GAAKkJ,GAAiBtK,EAAQ,CAC7B,IAAMuK,EAAgBtM,EAAKS,OAAST,EAEpC,GAAKsM,EAAgB,CAEpB,IAAMtL,EAAUhB,EAAKa,SAAWgL,EAAI7K,QAAU,KAE9CgE,EAAY,IAAIuH,OAAwBvM,EAAMmD,EAAKkJ,EAAetK,EAAOf,OACnE,CACNmB,EAAQ,IAAIxB,OAAON,OAAS8G,cAAenH,GAAQyL,EAAOzF,oBAAqBhG,IAE/E,IAAMgB,EAAUmB,EAAM1B,KAAKI,SAAWgL,EAAI7K,QAAU,KAEpDgE,EAAY,IAAIoH,OAAoBjK,EAAOgB,EAAKkJ,EAAetK,EAAOf,GAGvEyK,EAAOzM,MAAMoC,aAAc4D,GAC3BjG,EAAMsC,eAAgB2D,IAYxB,SAASqD,EAAsBoD,EAAQlM,EAAM2J,EAAUsD,EAAU/J,GAChE,IAAM1D,EAAQ0M,EAAO1M,MACf8M,EAAM9M,EAAM8B,SAEZmE,EAAY,IAAIyH,OAAiBlN,EAAM2J,EAAUsD,EAAUzN,EAAM0C,QAASgB,EAAaoJ,EAAI7K,SAEjGyK,EAAOzM,MAAMoC,aAAc4D,GAC3BjG,EAAMsC,eAAgB2D,GAWvB,SAASO,EAAsBnF,EAAUuH,EAAS3I,EAAOD,GACxD,IAAIiG,EAEJ,GAAK5E,EAASK,KAAKI,SAAW,CAC7B,IAAMgL,EAAM9M,EAAM8B,SACZ+F,EAAoB,IAAIvG,OAAUwL,EAAIlF,WAAa,IAEzD3B,EAAY,IAAIC,OAAe7E,EAAUuH,EAASf,EAAmBiF,EAAI7K,cAEzEgE,EAAY,IAAI0H,OAAiBtM,EAAUuH,GAG5C3I,EAAMoC,aAAc4D,GACpBjG,EAAMsC,eAAgB2D,GAUvB,SAASxE,EAAYmM,EAAOC,GAE3B,OAAKD,IAAUC,GAKVD,aAAiBE,QAAeD,aAAiBC","file":"js/chunk-2d0a3479.fccdec80.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"],"sourceRoot":""}