trilium/libraries/ckeditor/ckeditor.js.map

1 line
5.2 MiB
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"version":3,"sources":["webpack://BalloonEditor/webpack/universalModuleDefinition","webpack://BalloonEditor/webpack/bootstrap","webpack://BalloonEditor/../ckeditor5-utils/src/ckeditorerror.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_root.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isBuffer.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_nodeUtil.js","webpack://BalloonEditor/../ckeditor5-utils/src/version.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_freeGlobal.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_cloneBuffer.js","webpack://BalloonEditor/(webpack)/buildin/harmony-module.js","webpack://BalloonEditor/../ckeditor5-ui/theme/components/responsive-form/responsiveform.css?95f8","webpack://BalloonEditor/(webpack)/buildin/global.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/code.css?dde1","webpack://BalloonEditor/../ckeditor5-heading/theme/heading.css?d85e","webpack://BalloonEditor/../ckeditor5-table/theme/form.css?01db","webpack://BalloonEditor/../ckeditor5-table/theme/tableform.css?2c36","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/stubFalse.js","webpack://BalloonEditor/../ckeditor5-ui/theme/globals/globals.css?a323","webpack://BalloonEditor/../ckeditor5-ui/theme/globals/globals.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/icon/icon.css?c2e8","webpack://BalloonEditor/../ckeditor5-ui/theme/components/icon/icon.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/tooltip/tooltip.css?a834","webpack://BalloonEditor/../ckeditor5-ui/theme/components/tooltip/tooltip.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/button/button.css?95d5","webpack://BalloonEditor/../ckeditor5-ui/theme/components/button/button.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/button/switchbutton.css?ddab","webpack://BalloonEditor/../ckeditor5-ui/theme/components/button/switchbutton.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/colorgrid/colorgrid.css?b7d1","webpack://BalloonEditor/../ckeditor5-ui/theme/components/colorgrid/colorgrid.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/splitbutton.css?1f42","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/splitbutton.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/dropdown.css?cb67","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/dropdown.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/toolbar/toolbar.css?49cc","webpack://BalloonEditor/../ckeditor5-ui/theme/components/toolbar/toolbar.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/list/list.css?bc1f","webpack://BalloonEditor/../ckeditor5-ui/theme/components/list/list.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/toolbardropdown.css?d629","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/toolbardropdown.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/listdropdown.css?96da","webpack://BalloonEditor/../ckeditor5-ui/theme/components/dropdown/listdropdown.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/editorui/editorui.css?4776","webpack://BalloonEditor/../ckeditor5-ui/theme/components/editorui/editorui.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/label/label.css?28ca","webpack://BalloonEditor/../ckeditor5-ui/theme/components/label/label.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/formheader/formheader.css?77e8","webpack://BalloonEditor/../ckeditor5-ui/theme/components/formheader/formheader.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/inputtext/inputtext.css?dc6a","webpack://BalloonEditor/../ckeditor5-ui/theme/components/inputtext/inputtext.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css?9964","webpack://BalloonEditor/../ckeditor5-ui/theme/components/labeledfield/labeledfieldview.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/balloonpanel.css?651c","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/balloonpanel.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/balloonrotator.css?0b47","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/balloonrotator.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/fakepanel.css?cb92","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/fakepanel.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/stickypanel.css?55b7","webpack://BalloonEditor/../ckeditor5-ui/theme/components/panel/stickypanel.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/toolbar/blocktoolbar.css?893a","webpack://BalloonEditor/../ckeditor5-ui/theme/components/toolbar/blocktoolbar.css","webpack://BalloonEditor/../ckeditor5-engine/theme/placeholder.css?ad7d","webpack://BalloonEditor/../ckeditor5-engine/theme/placeholder.css","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/code.css","webpack://BalloonEditor/../ckeditor5-block-quote/theme/blockquote.css?b502","webpack://BalloonEditor/../ckeditor5-block-quote/theme/blockquote.css","webpack://BalloonEditor/../ckeditor5-heading/theme/heading.css","webpack://BalloonEditor/../ckeditor5-widget/theme/widgettypearound.css?3e4b","webpack://BalloonEditor/../ckeditor5-widget/theme/widgettypearound.css","webpack://BalloonEditor/../ckeditor5-widget/theme/widget.css?e99c","webpack://BalloonEditor/../ckeditor5-widget/theme/widget.css","webpack://BalloonEditor/../ckeditor5-widget/theme/widgetresize.css?9146","webpack://BalloonEditor/../ckeditor5-widget/theme/widgetresize.css","webpack://BalloonEditor/../ckeditor5-image/theme/textalternativeform.css?7890","webpack://BalloonEditor/../ckeditor5-image/theme/textalternativeform.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/responsive-form/responsiveform.css","webpack://BalloonEditor/../ckeditor5-image/theme/image.css?7f7b","webpack://BalloonEditor/../ckeditor5-image/theme/image.css","webpack://BalloonEditor/../ckeditor5-image/theme/imagecaption.css?d07a","webpack://BalloonEditor/../ckeditor5-image/theme/imagecaption.css","webpack://BalloonEditor/../ckeditor5-image/theme/imagestyle.css?1b6c","webpack://BalloonEditor/../ckeditor5-image/theme/imagestyle.css","webpack://BalloonEditor/../ckeditor5-image/theme/imageuploadprogress.css?e142","webpack://BalloonEditor/../ckeditor5-image/theme/imageuploadprogress.css","webpack://BalloonEditor/../ckeditor5-image/theme/imageuploadicon.css?8af3","webpack://BalloonEditor/../ckeditor5-image/theme/imageuploadicon.css","webpack://BalloonEditor/../ckeditor5-image/theme/imageuploadloader.css?9880","webpack://BalloonEditor/../ckeditor5-image/theme/imageuploadloader.css","webpack://BalloonEditor/../ckeditor5-clipboard/theme/clipboard.css?32ba","webpack://BalloonEditor/../ckeditor5-clipboard/theme/clipboard.css","webpack://BalloonEditor/../ckeditor5-image/theme/imageresize.css?ce2c","webpack://BalloonEditor/../ckeditor5-image/theme/imageresize.css","webpack://BalloonEditor/../ckeditor5-link/theme/link.css?dd26","webpack://BalloonEditor/../ckeditor5-link/theme/link.css","webpack://BalloonEditor/../ckeditor5-link/theme/linkform.css?f8bb","webpack://BalloonEditor/../ckeditor5-link/theme/linkform.css","webpack://BalloonEditor/../ckeditor5-link/theme/linkactions.css?1991","webpack://BalloonEditor/../ckeditor5-link/theme/linkactions.css","webpack://BalloonEditor/../ckeditor5-list/theme/liststyles.css?6c5f","webpack://BalloonEditor/../ckeditor5-list/theme/liststyles.css","webpack://BalloonEditor/../ckeditor5-list/theme/todolist.css?5057","webpack://BalloonEditor/../ckeditor5-list/theme/todolist.css","webpack://BalloonEditor/../ckeditor5-table/theme/tableediting.css?abdc","webpack://BalloonEditor/../ckeditor5-table/theme/tableediting.css","webpack://BalloonEditor/../ckeditor5-table/theme/inserttable.css?fb9f","webpack://BalloonEditor/../ckeditor5-table/theme/inserttable.css","webpack://BalloonEditor/../ckeditor5-table/theme/tableselection.css?aa63","webpack://BalloonEditor/../ckeditor5-table/theme/tableselection.css","webpack://BalloonEditor/../ckeditor5-table/theme/table.css?7ae1","webpack://BalloonEditor/../ckeditor5-table/theme/table.css","webpack://BalloonEditor/../ckeditor5-table/theme/colorinput.css?8d34","webpack://BalloonEditor/../ckeditor5-table/theme/colorinput.css","webpack://BalloonEditor/../ckeditor5-table/theme/formrow.css?3153","webpack://BalloonEditor/../ckeditor5-table/theme/formrow.css","webpack://BalloonEditor/../ckeditor5-table/theme/form.css","webpack://BalloonEditor/../ckeditor5-table/theme/tableform.css","webpack://BalloonEditor/../ckeditor5-table/theme/tableproperties.css?3b98","webpack://BalloonEditor/../ckeditor5-table/theme/tableproperties.css","webpack://BalloonEditor/../ckeditor5-table/theme/tablecellproperties.css?6fff","webpack://BalloonEditor/../ckeditor5-table/theme/tablecellproperties.css","webpack://BalloonEditor/../ckeditor5-font/theme/fontcolor.css?a61f","webpack://BalloonEditor/../ckeditor5-font/theme/fontcolor.css","webpack://BalloonEditor/../ckeditor5-font/theme/fontsize.css?3c77","webpack://BalloonEditor/../ckeditor5-font/theme/fontsize.css","webpack://BalloonEditor/../ckeditor5-code-block/theme/codeblock.css?74a0","webpack://BalloonEditor/../ckeditor5-code-block/theme/codeblock.css","webpack://BalloonEditor/../ckeditor5-mention/theme/mentionui.css?d591","webpack://BalloonEditor/../ckeditor5-mention/theme/mentionui.css","webpack://BalloonEditor/../ckeditor5-mention/theme/mention.css?bd81","webpack://BalloonEditor/../ckeditor5-mention/theme/mention.css","webpack://BalloonEditor/../ckeditor5-horizontal-line/theme/horizontalline.css?623d","webpack://BalloonEditor/../ckeditor5-horizontal-line/theme/horizontalline.css","webpack://BalloonEditor/../ckeditor5-ui/theme/components/labeledinput/labeledinput.css?7026","webpack://BalloonEditor/../ckeditor5-ui/theme/components/labeledinput/labeledinput.css","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/theme/mathform.css?7f8c","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/theme/mathform.css","webpack://BalloonEditor/../ckeditor5-utils/src/spy.js","webpack://BalloonEditor/../ckeditor5-utils/src/eventinfo.js","webpack://BalloonEditor/../ckeditor5-utils/src/uid.js","webpack://BalloonEditor/../ckeditor5-utils/src/priorities.js","webpack://BalloonEditor/../ckeditor5-utils/src/emittermixin.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isObject.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_Symbol.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getRawTag.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_objectToString.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseGetTag.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isFunction.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_isMasked.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_coreJsData.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_toSource.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseIsNative.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getValue.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getNative.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_defineProperty.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseAssignValue.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/eq.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_assignValue.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_copyObject.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/identity.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_apply.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_overRest.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/constant.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseSetToString.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_shortOut.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_setToString.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseRest.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isLength.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isArrayLike.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_isIndex.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_isIterateeCall.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_createAssigner.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseTimes.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isObjectLike.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseIsArguments.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isArguments.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseIsTypedArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseUnary.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isTypedArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_arrayLikeKeys.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_isPrototype.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_nativeKeysIn.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseKeysIn.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/keysIn.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/assignIn.js","webpack://BalloonEditor/../ckeditor5-utils/src/observablemixin.js","webpack://BalloonEditor/../ckeditor5-utils/src/mix.js","webpack://BalloonEditor/../ckeditor5-core/src/plugin.js","webpack://BalloonEditor/../ckeditor5-core/src/command.js","webpack://BalloonEditor/../ckeditor5-core/src/multicommand.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_overArg.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getPrototype.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isPlainObject.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_listCacheClear.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_assocIndexOf.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_listCacheDelete.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_listCacheGet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_listCacheHas.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_listCacheSet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_ListCache.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_stackClear.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_stackDelete.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_stackGet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_stackHas.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_Map.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_nativeCreate.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_hashClear.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_hashDelete.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_hashGet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_hashHas.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_hashSet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_Hash.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_mapCacheClear.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_isKeyable.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getMapData.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_mapCacheDelete.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_mapCacheGet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_mapCacheHas.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_mapCacheSet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_MapCache.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_stackSet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_Stack.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_arrayEach.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_nativeKeys.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseKeys.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/keys.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseAssign.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseAssignIn.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_copyArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_arrayFilter.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/stubArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getSymbols.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_copySymbols.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_arrayPush.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getSymbolsIn.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_copySymbolsIn.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseGetAllKeys.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getAllKeys.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getAllKeysIn.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_DataView.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_Promise.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_Set.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_WeakMap.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_getTag.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_initCloneArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_Uint8Array.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_cloneArrayBuffer.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_cloneDataView.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_cloneRegExp.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_cloneSymbol.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_cloneTypedArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_initCloneByTag.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseCreate.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_initCloneObject.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseIsMap.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isMap.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseIsSet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isSet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseClone.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/cloneDeepWith.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isElement.js","webpack://BalloonEditor/../ckeditor5-utils/src/config.js","webpack://BalloonEditor/../ckeditor5-utils/src/isiterable.js","webpack://BalloonEditor/../ckeditor5-utils/src/collection.js","webpack://BalloonEditor/../ckeditor5-core/src/plugincollection.js","webpack://BalloonEditor/../ckeditor5-utils/src/toarray.js","webpack://BalloonEditor/../ckeditor5-utils/src/translation-service.js","webpack://BalloonEditor/../ckeditor5-utils/src/language.js","webpack://BalloonEditor/../ckeditor5-utils/src/locale.js","webpack://BalloonEditor/../ckeditor5-core/src/context.js","webpack://BalloonEditor/../ckeditor5-core/src/contextplugin.js","webpack://BalloonEditor/../ckeditor5-utils/src/comparearrays.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/clone.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/node.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/text.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/textproxy.js","webpack://BalloonEditor/../ckeditor5-utils/src/tomap.js","webpack://BalloonEditor/../ckeditor5-utils/src/objecttomap.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/matcher.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isSymbol.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_isKey.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/memoize.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_memoizeCapped.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_stringToPath.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_arrayMap.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseToString.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/toString.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_castPath.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/last.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_toKey.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseGet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseSlice.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_parent.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseUnset.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/unset.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/get.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_assignMergeValue.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_createBaseFor.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseFor.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isArrayLikeObject.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_safeGet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/toPlainObject.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseMergeDeep.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseMerge.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/merge.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseSet.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/set.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/stylesmap.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/element.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/containerelement.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/editableelement.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/rooteditableelement.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/treewalker.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/position.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/range.js","webpack://BalloonEditor/../ckeditor5-utils/src/count.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/selection.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/documentselection.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/bubblingeventinfo.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/bubblingemittermixin.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/document.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/attributeelement.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/emptyelement.js","webpack://BalloonEditor/../ckeditor5-utils/src/env.js","webpack://BalloonEditor/../ckeditor5-utils/src/keyboard.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/uielement.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/rawelement.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/documentfragment.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/downcastwriter.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/istext.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/filler.js","webpack://BalloonEditor/../ckeditor5-utils/src/fastdiff.js","webpack://BalloonEditor/../ckeditor5-utils/src/diff.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/insertat.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/remove.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/isnode.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/renderer.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/global.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/indexof.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/getancestors.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/domconverter.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/getcommonancestor.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/iswindow.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/emittermixin.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/observer.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_setCacheAdd.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_setCacheHas.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_SetCache.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_arraySome.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_cacheHas.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_equalArrays.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_mapToArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_setToArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_equalByTag.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_equalObjects.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseIsEqualDeep.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseIsEqual.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isEqualWith.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/mutationobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/domeventdata.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/domeventobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/keyobserver.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/now.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_trimmedEndIndex.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_baseTrim.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/toNumber.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/debounce.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/fakeselectionobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/selectionobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/focusobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/compositionobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/inputobserver.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isString.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/createelement.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/isrange.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/getborderwidths.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/rect.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/resizeobserver.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/setdatainelement.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/tounit.js","webpack://BalloonEditor/../ckeditor5-utils/src/first.js","webpack://BalloonEditor/../ckeditor5-utils/src/focustracker.js","webpack://BalloonEditor/../ckeditor5-utils/src/keystrokehandler.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/arrowkeysobserver.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/scroll.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/view.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/node.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/text.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/textproxy.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/nodelist.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/element.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/treewalker.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/position.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/range.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/mapper.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/modelconsumable.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/downcastdispatcher.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/selection.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/liverange.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/documentselection.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/conversionhelpers.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/cloneDeep.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/downcasthelpers.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/utils/autoparagraphing.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/upcasthelpers.js","webpack://BalloonEditor/../ckeditor5-engine/src/controller/editingcontroller.js","webpack://BalloonEditor/../ckeditor5-core/src/commandcollection.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/viewconsumable.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/schema.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/upcastdispatcher.js","webpack://BalloonEditor/../ckeditor5-engine/src/dataprocessor/basichtmlwriter.js","webpack://BalloonEditor/../ckeditor5-engine/src/dataprocessor/htmldataprocessor.js","webpack://BalloonEditor/../ckeditor5-engine/src/controller/datacontroller.js","webpack://BalloonEditor/../ckeditor5-engine/src/conversion/conversion.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/batch.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/operation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/documentfragment.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/utils.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/isEqual.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/attributeoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/detachoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/moveoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/insertoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/markeroperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/renameoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/rootattributeoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/mergeoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/splitoperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/rootelement.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/writer.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/differ.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/history.js","webpack://BalloonEditor/../ckeditor5-utils/src/unicode.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/document.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/markercollection.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/nooperation.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/operationfactory.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/liveposition.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/utils/insertcontent.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/utils/deletecontent.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/utils/modifyselection.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/utils/getselectedcontent.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/utils/selection-post-fixer.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/model.js","webpack://BalloonEditor/../ckeditor5-core/src/editingkeystrokehandler.js","webpack://BalloonEditor/../ckeditor5-core/src/editor/editor.js","webpack://BalloonEditor/../ckeditor5-ui/src/componentfactory.js","webpack://BalloonEditor/../ckeditor5-core/src/editor/editorui.js","webpack://BalloonEditor/../ckeditor5-core/src/editor/utils/dataapimixin.js","webpack://BalloonEditor/../ckeditor5-core/src/editor/utils/elementapimixin.js","webpack://BalloonEditor/../ckeditor5-core/src/pendingactions.js","webpack://BalloonEditor/../ckeditor5-core/theme/icons/cancel.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/check.svg","webpack://BalloonEditor/../ckeditor5-core/src/index.js","webpack://BalloonEditor/../ckeditor5-core/theme/icons/eraser.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/low-vision.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/image.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/align-bottom.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/align-middle.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/align-top.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/align-left.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/align-center.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/align-right.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/align-justify.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-left.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-center.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-right.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-full-width.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-size-full.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-size-large.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-size-small.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/object-size-medium.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/pencil.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/pilcrow.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/quote.svg","webpack://BalloonEditor/../ckeditor5-core/theme/icons/three-vertical-dots.svg","webpack://BalloonEditor/../ckeditor5-ui/src/bindings/clickoutsidehandler.js","webpack://BalloonEditor/../ckeditor5-ui/src/bindings/injectcsstransitiondisabler.js","webpack://BalloonEditor/../ckeditor5-ui/src/bindings/submithandler.js","webpack://BalloonEditor/../ckeditor5-ui/src/viewcollection.js","webpack://BalloonEditor/../ckeditor5-ui/src/view.js","webpack://BalloonEditor/../ckeditor5-ui/src/template.js","webpack://BalloonEditor/../ckeditor5-ui/src/editorui/bodycollection.js","webpack://BalloonEditor/../ckeditor5-ui/src/icon/iconview.js","webpack://BalloonEditor/../ckeditor5-ui/src/tooltip/tooltipview.js","webpack://BalloonEditor/../ckeditor5-ui/src/button/buttonview.js","webpack://BalloonEditor/../ckeditor5-ui/src/button/switchbuttonview.js","webpack://BalloonEditor/../ckeditor5-ui/src/colorgrid/utils.js","webpack://BalloonEditor/../ckeditor5-ui/src/colorgrid/colortileview.js","webpack://BalloonEditor/../ckeditor5-ui/theme/icons/color-tile-check.svg","webpack://BalloonEditor/../ckeditor5-ui/src/focuscycler.js","webpack://BalloonEditor/../ckeditor5-ui/src/colorgrid/colorgridview.js","webpack://BalloonEditor/../ckeditor5-ui/theme/icons/dropdown-arrow.svg","webpack://BalloonEditor/../ckeditor5-ui/src/dropdown/button/dropdownbuttonview.js","webpack://BalloonEditor/../ckeditor5-ui/src/dropdown/button/splitbuttonview.js","webpack://BalloonEditor/../ckeditor5-ui/src/dropdown/dropdownpanelview.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/position.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/getpositionedancestor.js","webpack://BalloonEditor/../ckeditor5-ui/src/dropdown/dropdownview.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/toolbarseparatorview.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/toolbarlinebreakview.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/normalizetoolbarconfig.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/toolbarview.js","webpack://BalloonEditor/../ckeditor5-ui/src/bindings/preventdefault.js","webpack://BalloonEditor/../ckeditor5-ui/src/list/listview.js","webpack://BalloonEditor/../ckeditor5-ui/src/list/listitemview.js","webpack://BalloonEditor/../ckeditor5-ui/src/list/listseparatorview.js","webpack://BalloonEditor/../ckeditor5-ui/src/dropdown/utils.js","webpack://BalloonEditor/../ckeditor5-ui/src/editorui/editoruiview.js","webpack://BalloonEditor/../ckeditor5-ui/src/label/labelview.js","webpack://BalloonEditor/../ckeditor5-ui/src/editableui/editableuiview.js","webpack://BalloonEditor/../ckeditor5-ui/src/editableui/inline/inlineeditableuiview.js","webpack://BalloonEditor/../ckeditor5-ui/src/formheader/formheaderview.js","webpack://BalloonEditor/../ckeditor5-ui/src/inputtext/inputtextview.js","webpack://BalloonEditor/../ckeditor5-ui/src/labeledfield/labeledfieldview.js","webpack://BalloonEditor/../ckeditor5-ui/src/labeledfield/utils.js","webpack://BalloonEditor/../ckeditor5-ui/src/notification/notification.js","webpack://BalloonEditor/../ckeditor5-ui/src/model.js","webpack://BalloonEditor/../ckeditor5-ui/src/panel/balloon/balloonpanelview.js","webpack://BalloonEditor/../ckeditor5-ui/src/panel/balloon/contextualballoon.js","webpack://BalloonEditor/../ckeditor5-ui/theme/icons/previous-arrow.svg","webpack://BalloonEditor/../ckeditor5-ui/theme/icons/next-arrow.svg","webpack://BalloonEditor/../ckeditor5-ui/src/panel/sticky/stickypanelview.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/balloon/balloontoolbar.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/block/blockbuttonview.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/block/blocktoolbar.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/placeholder.js","webpack://BalloonEditor/../ckeditor5-engine/src/model/operation/transform.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/clickobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/observer/mouseobserver.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/upcastwriter.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/styles/utils.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/styles/background.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/styles/border.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/styles/margin.js","webpack://BalloonEditor/../ckeditor5-engine/src/view/styles/padding.js","webpack://BalloonEditor/../ckeditor5-editor-balloon/src/ballooneditorui.js","webpack://BalloonEditor/../ckeditor5-ui/src/toolbar/enabletoolbarkeyboardfocus.js","webpack://BalloonEditor/../ckeditor5-editor-balloon/src/ballooneditoruiview.js","webpack://BalloonEditor/../ckeditor5-editor-balloon/src/ballooneditor.js","webpack://BalloonEditor/../ckeditor5-core/src/editor/utils/securesourceelement.js","webpack://BalloonEditor/../ckeditor5-core/src/editor/utils/attachtoform.js","webpack://BalloonEditor/../ckeditor5-utils/src/dom/getdatafromelement.js","webpack://BalloonEditor/../ckeditor5-upload/src/filereader.js","webpack://BalloonEditor/../ckeditor5-upload/src/filerepository.js","webpack://BalloonEditor/../ckeditor5-upload/src/ui/filedialogbuttonview.js","webpack://BalloonEditor/../ckeditor5-adapter-ckfinder/src/utils.js","webpack://BalloonEditor/../ckeditor5-adapter-ckfinder/src/uploadadapter.js","webpack://BalloonEditor/../ckeditor5-autoformat/src/blockautoformatediting.js","webpack://BalloonEditor/../ckeditor5-autoformat/src/inlineautoformatediting.js","webpack://BalloonEditor/../ckeditor5-autoformat/src/autoformat.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/attributecommand.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/bold/boldediting.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/bold/boldui.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/icons/bold.svg","webpack://BalloonEditor/../ckeditor5-basic-styles/src/italic/italicediting.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/italic/italicui.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/icons/italic.svg","webpack://BalloonEditor/../ckeditor5-basic-styles/src/superscript/superscriptediting.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/superscript/superscriptui.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/icons/superscript.svg","webpack://BalloonEditor/../ckeditor5-basic-styles/src/subscript/subscriptediting.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/subscript/subscriptui.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/icons/subscript.svg","webpack://BalloonEditor/../ckeditor5-basic-styles/src/underline/underlineediting.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/underline/underlineui.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/icons/underline.svg","webpack://BalloonEditor/../ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/strikethrough/strikethroughui.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/icons/strikethrough.svg","webpack://BalloonEditor/../ckeditor5-typing/src/utils/changebuffer.js","webpack://BalloonEditor/../ckeditor5-typing/src/inputcommand.js","webpack://BalloonEditor/../ckeditor5-typing/src/utils/injectunsafekeystrokeshandling.js","webpack://BalloonEditor/../ckeditor5-typing/src/utils/utils.js","webpack://BalloonEditor/../ckeditor5-utils/src/difftochanges.js","webpack://BalloonEditor/../ckeditor5-typing/src/utils/injecttypingmutationshandling.js","webpack://BalloonEditor/../ckeditor5-typing/src/input.js","webpack://BalloonEditor/../ckeditor5-typing/src/deletecommand.js","webpack://BalloonEditor/../ckeditor5-typing/src/deleteobserver.js","webpack://BalloonEditor/../ckeditor5-typing/src/delete.js","webpack://BalloonEditor/../ckeditor5-typing/src/utils/getlasttextline.js","webpack://BalloonEditor/../ckeditor5-typing/src/textwatcher.js","webpack://BalloonEditor/../ckeditor5-typing/src/twostepcaretmovement.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/escapeRegExp.js","webpack://BalloonEditor/../ckeditor5-typing/src/texttransformation.js","webpack://BalloonEditor/../ckeditor5-typing/src/utils/findattributerange.js","webpack://BalloonEditor/../ckeditor5-typing/src/utils/inlinehighlight.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/code/codeediting.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/code/codeui.js","webpack://BalloonEditor/../ckeditor5-basic-styles/theme/icons/code.svg","webpack://BalloonEditor/../ckeditor5-enter/src/utils.js","webpack://BalloonEditor/../ckeditor5-enter/src/entercommand.js","webpack://BalloonEditor/../ckeditor5-enter/src/enterobserver.js","webpack://BalloonEditor/../ckeditor5-enter/src/enter.js","webpack://BalloonEditor/../ckeditor5-enter/src/shiftentercommand.js","webpack://BalloonEditor/../ckeditor5-enter/src/shiftenter.js","webpack://BalloonEditor/../ckeditor5-block-quote/src/blockquotecommand.js","webpack://BalloonEditor/../ckeditor5-block-quote/src/blockquoteediting.js","webpack://BalloonEditor/../ckeditor5-block-quote/src/blockquoteui.js","webpack://BalloonEditor/../ckeditor5-paragraph/src/paragraphcommand.js","webpack://BalloonEditor/../ckeditor5-paragraph/src/insertparagraphcommand.js","webpack://BalloonEditor/../ckeditor5-paragraph/src/paragraph.js","webpack://BalloonEditor/../ckeditor5-heading/src/headingcommand.js","webpack://BalloonEditor/../ckeditor5-heading/src/headingediting.js","webpack://BalloonEditor/../ckeditor5-heading/src/utils.js","webpack://BalloonEditor/../ckeditor5-heading/src/headingui.js","webpack://BalloonEditor/../ckeditor5-widget/src/highlightstack.js","webpack://BalloonEditor/../ckeditor5-widget/src/utils.js","webpack://BalloonEditor/../ckeditor5-widget/theme/icons/drag-handle.svg","webpack://BalloonEditor/../ckeditor5-widget/src/widgettypearound/utils.js","webpack://BalloonEditor/../ckeditor5-widget/src/widgettypearound/widgettypearound.js","webpack://BalloonEditor/../ckeditor5-widget/theme/icons/return-arrow.svg","webpack://BalloonEditor/../ckeditor5-widget/src/verticalnavigation.js","webpack://BalloonEditor/../ckeditor5-widget/src/widget.js","webpack://BalloonEditor/../ckeditor5-widget/src/widgettoolbarrepository.js","webpack://BalloonEditor/../ckeditor5-widget/src/widgetresize/resizerstate.js","webpack://BalloonEditor/../ckeditor5-widget/src/widgetresize/resizer.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/throttle.js","webpack://BalloonEditor/../ckeditor5-widget/src/widgetresize.js","webpack://BalloonEditor/../ckeditor5-image/src/image/imageloadobserver.js","webpack://BalloonEditor/../ckeditor5-image/src/image/utils.js","webpack://BalloonEditor/../ckeditor5-image/src/image/converters.js","webpack://BalloonEditor/../ckeditor5-image/src/image/insertimagecommand.js","webpack://BalloonEditor/../ckeditor5-image/src/image/imageediting.js","webpack://BalloonEditor/../ckeditor5-image/src/imagetextalternative/imagetextalternativecommand.js","webpack://BalloonEditor/../ckeditor5-image/src/imagetextalternative/imagetextalternativeediting.js","webpack://BalloonEditor/../ckeditor5-image/src/imagetextalternative/ui/textalternativeformview.js","webpack://BalloonEditor/../ckeditor5-image/src/image/ui/utils.js","webpack://BalloonEditor/../ckeditor5-image/src/imagetextalternative/imagetextalternativeui.js","webpack://BalloonEditor/../ckeditor5-image/src/imagetextalternative.js","webpack://BalloonEditor/../ckeditor5-image/src/imagecaption/utils.js","webpack://BalloonEditor/../ckeditor5-image/src/imagecaption/imagecaptionediting.js","webpack://BalloonEditor/../ckeditor5-image/src/imagestyle/imagestylecommand.js","webpack://BalloonEditor/../ckeditor5-image/src/imagestyle/converters.js","webpack://BalloonEditor/../ckeditor5-image/src/imagestyle/utils.js","webpack://BalloonEditor/../ckeditor5-image/src/imagestyle/imagestyleediting.js","webpack://BalloonEditor/../ckeditor5-image/src/imagestyle/imagestyleui.js","webpack://BalloonEditor/../ckeditor5-image/src/imageupload/utils.js","webpack://BalloonEditor/../ckeditor5-image/src/imageupload/imageuploadui.js","webpack://BalloonEditor/../ckeditor5-image/src/imageupload/imageuploadprogress.js","webpack://BalloonEditor/../ckeditor5-image/theme/icons/image_placeholder.svg","webpack://BalloonEditor/../ckeditor5-clipboard/src/datatransfer.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/clipboardobserver.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/utils/viewtoplaintext.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/clipboardpipeline.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/utils/plaintexttohtml.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/utils/normalizeclipboarddata.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/dragdrop.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/pasteplaintext.js","webpack://BalloonEditor/../ckeditor5-clipboard/src/clipboard.js","webpack://BalloonEditor/../ckeditor5-image/src/imageupload/uploadimagecommand.js","webpack://BalloonEditor/../ckeditor5-image/src/imageupload/imageuploadediting.js","webpack://BalloonEditor/../ckeditor5-image/src/imageresize/resizeimagecommand.js","webpack://BalloonEditor/../ckeditor5-image/src/imageresize/imageresizeediting.js","webpack://BalloonEditor/../ckeditor5-image/src/imageresize/imageresizebuttons.js","webpack://BalloonEditor/../ckeditor5-image/src/imageresize/imageresizehandles.js","webpack://BalloonEditor/../ckeditor5-link/src/utils/automaticdecorators.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_castSlice.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_hasUnicode.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_asciiToArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_unicodeToArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_stringToArray.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/_createCaseFirst.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/lodash-es/upperFirst.js","webpack://BalloonEditor/../ckeditor5-link/src/utils.js","webpack://BalloonEditor/../ckeditor5-link/src/linkcommand.js","webpack://BalloonEditor/../ckeditor5-link/src/unlinkcommand.js","webpack://BalloonEditor/../ckeditor5-link/src/utils/manualdecorator.js","webpack://BalloonEditor/../ckeditor5-link/src/linkediting.js","webpack://BalloonEditor/../ckeditor5-link/src/ui/linkformview.js","webpack://BalloonEditor/../ckeditor5-link/src/ui/linkactionsview.js","webpack://BalloonEditor/../ckeditor5-link/theme/icons/unlink.svg","webpack://BalloonEditor/../ckeditor5-link/src/linkui.js","webpack://BalloonEditor/../ckeditor5-link/theme/icons/link.svg","webpack://BalloonEditor/../ckeditor5-link/src/autolink.js","webpack://BalloonEditor/../ckeditor5-list/src/listcommand.js","webpack://BalloonEditor/../ckeditor5-list/src/indentcommand.js","webpack://BalloonEditor/../ckeditor5-list/src/utils.js","webpack://BalloonEditor/../ckeditor5-list/src/converters.js","webpack://BalloonEditor/../ckeditor5-list/src/listediting.js","webpack://BalloonEditor/../ckeditor5-list/theme/icons/numberedlist.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/bulletedlist.svg","webpack://BalloonEditor/../ckeditor5-list/src/listui.js","webpack://BalloonEditor/../ckeditor5-list/src/liststylecommand.js","webpack://BalloonEditor/../ckeditor5-list/src/liststyleediting.js","webpack://BalloonEditor/../ckeditor5-list/src/liststyleui.js","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststyledisc.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststylecircle.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststylesquare.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststyledecimal.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststyledecimalleadingzero.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststylelowerroman.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststyleupperroman.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststylelowerlatin.svg","webpack://BalloonEditor/../ckeditor5-list/theme/icons/liststyleupperlatin.svg","webpack://BalloonEditor/../ckeditor5-list/src/checktodolistcommand.js","webpack://BalloonEditor/../ckeditor5-list/src/todolistconverters.js","webpack://BalloonEditor/../ckeditor5-list/src/todolistediting.js","webpack://BalloonEditor/../ckeditor5-list/src/todolistui.js","webpack://BalloonEditor/../ckeditor5-list/theme/icons/todolist.svg","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/filters/list.js","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/normalizers/googledocsnormalizer.js","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/filters/removeboldwrapper.js","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/filters/space.js","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/filters/parse.js","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/filters/image.js","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/normalizers/mswordnormalizer.js","webpack://BalloonEditor/../ckeditor5-table/src/utils/common.js","webpack://BalloonEditor/../ckeditor5-table/src/converters/upcasttable.js","webpack://BalloonEditor/../ckeditor5-table/src/tablewalker.js","webpack://BalloonEditor/../ckeditor5-table/src/converters/downcast.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/inserttablecommand.js","webpack://BalloonEditor/../ckeditor5-table/src/utils/selection.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/insertrowcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/insertcolumncommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/splitcellcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/utils/structure.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/mergecellcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/removerowcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/removecolumncommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/setheaderrowcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/setheadercolumncommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableutils.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/mergecellscommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/selectrowcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/commands/selectcolumncommand.js","webpack://BalloonEditor/../ckeditor5-table/src/converters/table-layout-post-fixer.js","webpack://BalloonEditor/../ckeditor5-table/src/converters/table-cell-paragraph-post-fixer.js","webpack://BalloonEditor/../ckeditor5-table/src/converters/table-cell-refresh-post-fixer.js","webpack://BalloonEditor/../ckeditor5-table/src/converters/table-heading-rows-refresh-post-fixer.js","webpack://BalloonEditor/../ckeditor5-table/src/tableediting.js","webpack://BalloonEditor/../ckeditor5-table/src/ui/inserttableview.js","webpack://BalloonEditor/../ckeditor5-table/src/tableui.js","webpack://BalloonEditor/../ckeditor5-table/theme/icons/table.svg","webpack://BalloonEditor/../ckeditor5-table/theme/icons/table-column.svg","webpack://BalloonEditor/../ckeditor5-table/theme/icons/table-row.svg","webpack://BalloonEditor/../ckeditor5-table/theme/icons/table-merge-cell.svg","webpack://BalloonEditor/../ckeditor5-table/src/tableselection.js","webpack://BalloonEditor/../ckeditor5-table/src/tableclipboard.js","webpack://BalloonEditor/../ckeditor5-table/src/tablekeyboard.js","webpack://BalloonEditor/../ckeditor5-table/src/tablemouse/mouseeventsobserver.js","webpack://BalloonEditor/../ckeditor5-table/src/tablemouse.js","webpack://BalloonEditor/../ckeditor5-table/src/utils/ui/widget.js","webpack://BalloonEditor/../ckeditor5-table/src/converters/tableproperties.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tablepropertycommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tablebackgroundcolorcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/utils/table-properties.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tablebordercolorcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tableborderstylecommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tableborderwidthcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tablewidthcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tableheightcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/commands/tablealignmentcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/tablepropertiesediting.js","webpack://BalloonEditor/../ckeditor5-table/src/ui/colorinputview.js","webpack://BalloonEditor/../ckeditor5-table/src/utils/ui/table-properties.js","webpack://BalloonEditor/../ckeditor5-table/src/ui/formrowview.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/ui/tablepropertiesview.js","webpack://BalloonEditor/../ckeditor5-table/src/utils/ui/contextualballoon.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties/tablepropertiesui.js","webpack://BalloonEditor/../ckeditor5-table/theme/icons/table-properties.svg","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/ui/tablecellpropertiesview.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/tablecellpropertiesui.js","webpack://BalloonEditor/../ckeditor5-table/theme/icons/table-cell-properties.svg","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellpropertycommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellpaddingcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellwidthcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellheightcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellbackgroundcolorcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellverticalalignmentcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellhorizontalalignmentcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellborderstylecommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellbordercolorcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/commands/tablecellborderwidthcommand.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties/tablecellpropertiesediting.js","webpack://BalloonEditor/../ckeditor5-heading/src/headingbuttonsui.js","webpack://BalloonEditor/../ckeditor5-heading/theme/icons/heading1.svg","webpack://BalloonEditor/../ckeditor5-heading/theme/icons/heading2.svg","webpack://BalloonEditor/../ckeditor5-heading/theme/icons/heading3.svg","webpack://BalloonEditor/../ckeditor5-heading/theme/icons/heading4.svg","webpack://BalloonEditor/../ckeditor5-heading/theme/icons/heading5.svg","webpack://BalloonEditor/../ckeditor5-heading/theme/icons/heading6.svg","webpack://BalloonEditor/../ckeditor5-font/src/fontcommand.js","webpack://BalloonEditor/../ckeditor5-font/src/documentcolorcollection.js","webpack://BalloonEditor/../ckeditor5-font/src/ui/colortableview.js","webpack://BalloonEditor/../ckeditor5-font/src/utils.js","webpack://BalloonEditor/../ckeditor5-font/src/fontfamily/fontfamilycommand.js","webpack://BalloonEditor/../ckeditor5-font/src/fontfamily/utils.js","webpack://BalloonEditor/../ckeditor5-font/src/fontfamily/fontfamilyediting.js","webpack://BalloonEditor/../ckeditor5-font/src/fontfamily/fontfamilyui.js","webpack://BalloonEditor/../ckeditor5-font/theme/icons/font-family.svg","webpack://BalloonEditor/../ckeditor5-font/src/fontfamily.js","webpack://BalloonEditor/../ckeditor5-font/src/fontsize/fontsizecommand.js","webpack://BalloonEditor/../ckeditor5-font/src/fontsize/utils.js","webpack://BalloonEditor/../ckeditor5-font/src/fontsize/fontsizeediting.js","webpack://BalloonEditor/../ckeditor5-font/src/fontsize/fontsizeui.js","webpack://BalloonEditor/../ckeditor5-font/theme/icons/font-size.svg","webpack://BalloonEditor/../ckeditor5-font/src/fontsize.js","webpack://BalloonEditor/../ckeditor5-font/src/fontcolor/fontcolorcommand.js","webpack://BalloonEditor/../ckeditor5-font/src/fontcolor/fontcolorediting.js","webpack://BalloonEditor/../ckeditor5-font/src/ui/colorui.js","webpack://BalloonEditor/../ckeditor5-font/src/fontcolor/fontcolorui.js","webpack://BalloonEditor/../ckeditor5-font/theme/icons/font-color.svg","webpack://BalloonEditor/../ckeditor5-font/src/fontcolor.js","webpack://BalloonEditor/../ckeditor5-font/src/fontbackgroundcolor/fontbackgroundcolorcommand.js","webpack://BalloonEditor/../ckeditor5-font/src/fontbackgroundcolor/fontbackgroundcolorediting.js","webpack://BalloonEditor/../ckeditor5-font/src/fontbackgroundcolor/fontbackgroundcolorui.js","webpack://BalloonEditor/../ckeditor5-font/theme/icons/font-background.svg","webpack://BalloonEditor/../ckeditor5-font/src/fontbackgroundcolor.js","webpack://BalloonEditor/../ckeditor5-code-block/src/utils.js","webpack://BalloonEditor/../ckeditor5-code-block/src/codeblockcommand.js","webpack://BalloonEditor/../ckeditor5-code-block/src/indentcodeblockcommand.js","webpack://BalloonEditor/../ckeditor5-code-block/src/outdentcodeblockcommand.js","webpack://BalloonEditor/../ckeditor5-code-block/src/converters.js","webpack://BalloonEditor/../ckeditor5-code-block/src/codeblockediting.js","webpack://BalloonEditor/../ckeditor5-code-block/src/codeblockui.js","webpack://BalloonEditor/../ckeditor5-code-block/theme/icons/codeblock.svg","webpack://BalloonEditor/../ckeditor5-mention/src/mentioncommand.js","webpack://BalloonEditor/../ckeditor5-mention/src/mentionediting.js","webpack://BalloonEditor/../ckeditor5-mention/src/ui/mentionsview.js","webpack://BalloonEditor/../ckeditor5-mention/src/ui/domwrapperview.js","webpack://BalloonEditor/../ckeditor5-mention/src/ui/mentionlistitemview.js","webpack://BalloonEditor/../ckeditor5-mention/src/mentionui.js","webpack://BalloonEditor/../ckeditor5-indent/src/indentediting.js","webpack://BalloonEditor/../ckeditor5-indent/theme/icons/indent.svg","webpack://BalloonEditor/../ckeditor5-indent/theme/icons/outdent.svg","webpack://BalloonEditor/../ckeditor5-indent/src/indentui.js","webpack://BalloonEditor/../ckeditor5-indent/src/indentblockcommand.js","webpack://BalloonEditor/../ckeditor5-indent/src/indentcommandbehavior/indentusingoffset.js","webpack://BalloonEditor/../ckeditor5-indent/src/indentcommandbehavior/indentusingclasses.js","webpack://BalloonEditor/../ckeditor5-indent/src/indentblock.js","webpack://BalloonEditor/../ckeditor5-select-all/src/selectallcommand.js","webpack://BalloonEditor/../ckeditor5-select-all/src/selectallediting.js","webpack://BalloonEditor/../ckeditor5-select-all/src/selectallui.js","webpack://BalloonEditor/../ckeditor5-select-all/theme/icons/select-all.svg","webpack://BalloonEditor/../ckeditor5-select-all/src/selectall.js","webpack://BalloonEditor/../ckeditor5-horizontal-line/src/horizontallinecommand.js","webpack://BalloonEditor/../ckeditor5-horizontal-line/src/horizontallineediting.js","webpack://BalloonEditor/../ckeditor5-horizontal-line/src/horizontallineui.js","webpack://BalloonEditor/../ckeditor5-horizontal-line/theme/icons/horizontalline.svg","webpack://BalloonEditor/../ckeditor5-undo/src/basecommand.js","webpack://BalloonEditor/../ckeditor5-undo/src/undocommand.js","webpack://BalloonEditor/../ckeditor5-undo/src/redocommand.js","webpack://BalloonEditor/../ckeditor5-undo/src/undoediting.js","webpack://BalloonEditor/../ckeditor5-undo/theme/icons/undo.svg","webpack://BalloonEditor/../ckeditor5-undo/theme/icons/redo.svg","webpack://BalloonEditor/../ckeditor5-undo/src/undoui.js","webpack://BalloonEditor/../ckeditor5-undo/src/undo.js","webpack://BalloonEditor/../ckeditor5-remove-format/src/removeformatui.js","webpack://BalloonEditor/../ckeditor5-remove-format/theme/icons/remove-format.svg","webpack://BalloonEditor/../ckeditor5-remove-format/src/removeformatcommand.js","webpack://BalloonEditor/../ckeditor5-remove-format/src/removeformatediting.js","webpack://BalloonEditor/./src/mention_customization.js","webpack://BalloonEditor/./src/uploadimage.js","webpack://BalloonEditor/./src/includenote.js","webpack://BalloonEditor/./src/icons/note.svg","webpack://BalloonEditor/./src/referencelink.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/utils.js","webpack://BalloonEditor/../ckeditor5-ui/src/labeledinput/labeledinputview.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/ui/mathview.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/ui/mainformview.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/mathcommand.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/mathediting.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/mathui.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/theme/icons/math.svg","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/automath.js","webpack://BalloonEditor/./src/ckeditor.js","webpack://BalloonEditor/../ckeditor5-typing/src/typing.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/bold.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/italic.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/underline.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/strikethrough.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/code.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/superscript.js","webpack://BalloonEditor/../ckeditor5-basic-styles/src/subscript.js","webpack://BalloonEditor/../ckeditor5-block-quote/src/blockquote.js","webpack://BalloonEditor/../ckeditor5-heading/src/heading.js","webpack://BalloonEditor/../ckeditor5-image/src/image.js","webpack://BalloonEditor/../ckeditor5-image/src/imagecaption.js","webpack://BalloonEditor/../ckeditor5-image/src/imagestyle.js","webpack://BalloonEditor/../ckeditor5-image/src/imagetoolbar.js","webpack://BalloonEditor/../ckeditor5-image/src/imageupload.js","webpack://BalloonEditor/../ckeditor5-image/src/imageresize.js","webpack://BalloonEditor/../ckeditor5-link/src/link.js","webpack://BalloonEditor/../ckeditor5-list/src/list.js","webpack://BalloonEditor/../ckeditor5-list/src/liststyle.js","webpack://BalloonEditor/../ckeditor5-list/src/todolist.js","webpack://BalloonEditor/../ckeditor5-paste-from-office/src/pastefromoffice.js","webpack://BalloonEditor/../ckeditor5-table/src/table.js","webpack://BalloonEditor/../ckeditor5-table/src/tabletoolbar.js","webpack://BalloonEditor/../ckeditor5-table/src/tableproperties.js","webpack://BalloonEditor/../ckeditor5-table/src/tablecellproperties.js","webpack://BalloonEditor/../ckeditor5-indent/src/indent.js","webpack://BalloonEditor/../ckeditor5-paragraph/src/paragraphbuttonui.js","webpack://BalloonEditor/../ckeditor5-paragraph/theme/icons/paragraph.svg","webpack://BalloonEditor/./src/internallink.js","webpack://BalloonEditor/./src/icons/trilium.svg","webpack://BalloonEditor/./src/markdownimport.js","webpack://BalloonEditor/./src/icons/markdown-mark.svg","webpack://BalloonEditor/./src/cuttonote.js","webpack://BalloonEditor/./src/icons/scissors.svg","webpack://BalloonEditor/../ckeditor5-font/src/font.js","webpack://BalloonEditor/../ckeditor5-code-block/src/codeblock.js","webpack://BalloonEditor/../ckeditor5-horizontal-line/src/horizontalline.js","webpack://BalloonEditor/../ckeditor5-remove-format/src/removeformat.js","webpack://BalloonEditor/../ckeditor5-mention/src/mention.js","webpack://BalloonEditor/./src/indent_block_shortcut.js","webpack://BalloonEditor/./src/remove_format_links.js","webpack://BalloonEditor//home/adam/trilium-ckeditor5/node_modules/ckeditor5-math/src/math.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","CKEditorError","Error","errorName","context","data","super","JSON","stringify","getLinkToDocumentationMessage","this","type","err","is","error","message","stack","logWarning","console","warn","formatConsoleArguments","documentationMessage","memo","isOldIE","Boolean","document","all","atob","getTarget","target","styleTarget","querySelector","HTMLIFrameElement","contentDocument","head","e","stylesInDom","getIndexByIdentifier","identifier","result","length","modulesToDom","list","options","idCountMap","identifiers","item","id","base","count","concat","index","obj","css","media","sourceMap","references","updater","push","addStyle","insertStyleElement","style","createElement","attributes","nonce","keys","forEach","setAttribute","insert","appendChild","textStore","replaceText","replacement","filter","join","applyToSingletonTag","remove","styleSheet","cssText","cssNode","createTextNode","childNodes","removeChild","insertBefore","applyToTag","removeAttribute","btoa","unescape","encodeURIComponent","firstChild","singleton","singletonCounter","update","styleIndex","parentNode","removeStyleElement","newObj","lastIdentifiers","newList","toString","newLastIdentifiers","_i","_index","splice","freeSelf","self","Function","freeExports","nodeType","freeModule","Buffer","undefined","isBuffer","freeProcess","process","nodeUtil","types","require","binding","windowOrGlobal","global","CKEDITOR_VERSION","freeGlobal","allocUnsafe","buffer","isDeep","slice","constructor","copy","originalModule","webpackPolyfill","children","api","content","default","locals","g","spy","called","source","path","stop","off","HEX_NUMBERS","Array","fill","map","val","r1","Math","random","r2","r3","r4","priority","normal","highest","high","low","lowest","_listeningTo","_emitterId","event","callback","listenTo","wasFired","args","stopListening","emitter","emitterInfo","eventCallbacks","emitters","_getEmitterId","_setEmitterId","emitterId","callbacks","listener","_addEventListener","addEventListener","removeEventListener","indexOf","pop","eventOrInfo","eventInfo","getCallbacksForEvent","eventName","_events","substr","lastIndexOf","callbackArgs","from","apply","_removeEventListener","_delegations","destinations","passAllDestinations","fireDelegatedEvents","return","rethrowUnexpectedError","events","to","nameOrFunction","Map","set","delete","clear","getEvents","childEventName","newEventNodes","childEvents","node","createEventNamespace","lists","getCallbacksListsForNamespace","callbackDefinition","added","eventNode","callbacksLists","childCallbacksLists","fireArgs","delegatedInfo","fire","objectProto","nativeObjectToString","symToStringTag","isOwn","tag","unmasked","uid","maskSrcKey","exec","IE_PROTO","func","funcToString","reIsHostCtor","reIsNative","RegExp","replace","test","other","objValue","props","customizer","isNew","newValue","thisArg","nativeMax","max","start","transform","arguments","array","otherArgs","string","nativeNow","Date","now","lastCalled","stamp","remaining","reIsUint","assigner","sources","guard","iteratee","propertyIsEnumerable","isArray","typedArrayTags","nodeIsTypedArray","isTypedArray","inherited","isArr","isArg","isBuff","isType","skipIndexes","String","Ctor","isProto","observablePropertiesSymbol","boundObservablesSymbol","boundPropertiesSymbol","_decoratedMethods","_decoratedOriginal","ObservableMixin","initObservable","properties","has","configurable","oldValue","bindProperties","isStringArray","Set","size","boundProperties","propertyName","bindings","a","bindTo","toMany","bindToMany","_observable","_bindProperties","_to","_bindings","unbindProperties","boundObservables","toObservable","toProperty","toProperties","toPropertyBindings","boundObservable","methodName","originalMethod","on","evt","observable","parsedArgs","parsed","lastObservable","parseBindToArgs","bindingsKeys","numberOfBindings","updateBoundObservableProperty","chain","toPropertyName","bindingsToObservable","add","updateBoundObservables","updateBindToBound","observables","attribute","observableAndAttributePairs","getBindingTargets","arr","every","propertyValue","mix","baseClass","mixins","mixin","getOwnPropertyNames","getOwnPropertySymbols","sourceDescriptor","getOwnPropertyDescriptor","editor","_disableStack","forceDisable","isEnabled","Command","decorate","model","refresh","forceDisabled","clearForceDisabled","_childCommands","command","_getFirstEnabledCommand","execute","_checkEnabled","find","arg","getPrototypeOf","objectCtorString","proto","__data__","ListCache","entries","entry","Hash","MapCache","pairs","LARGE_ARRAY_SIZE","Stack","predicate","resIndex","nativeGetSymbols","symbol","values","offset","keysFunc","symbolsFunc","dataViewCtorString","mapCtorString","promiseCtorString","setCtorString","weakMapCtorString","getTag","ArrayBuffer","resolve","ctorString","input","Uint8Array","arrayBuffer","byteLength","dataView","byteOffset","reFlags","regexp","lastIndex","symbolProto","symbolValueOf","valueOf","typedArray","objectCreate","nodeIsMap","isMap","nodeIsSet","isSet","cloneableTags","baseClone","bitmask","isFlat","isFull","isFunc","stacked","subValue","configurations","defaultConfigurations","_config","cloneConfig","_setObjectToTarget","_setToTarget","_getFromSource","isDefine","parts","split","part","configuration","leaveDOMReferences","isIterable","iterator","initialItemsOrOptions","hasInitialItems","_items","_itemMap","_idProperty","idProperty","_bindToExternalToInternalMap","WeakMap","_bindToInternalToExternalMap","_skippedIndexesFromExternal","_getItemIdBeforeAdding","addMany","items","itemId","currentItemIndex","removed","idOrIndex","itemOrId","subject","_remove","ctx","_bindToCollection","removedItems","externalCollection","as","Class","_setUpBindToBinding","using","callbackOrProperty","addItem","externalItem","isExternalBoundToThis","externalItemBound","finalIndex","skipped","getIndex","reduce","itemDoesNotExist","availablePlugins","contextPlugins","_context","_plugins","_availablePlugins","PluginConstructor","pluginName","_contextPlugins","pluginInstance","plugin","plugins","pluginsToRemove","pluginsSubstitutions","that","findAvailablePluginConstructors","processed","isPluginConstructor","requires","validatePlugins","pluginConstructors","getPluginConstructors","isPluginRemoved","pluginItem","pluginToReplace","indexInPluginConstructors","substitutePlugins","pluginInstances","_add","loadPlugins","initPlugins","then","isContextPlugin","some","removedPlugin","getPluginName","parentPluginConstructor","missingPlugin","requiredBy","checkMissingPlugin","checkContextPlugin","checkRemovedPlugin","method","promise","Promise","promises","destroy","plugin1","plugin2","toArray","_translate","language","quantity","numberOfLanguages","CKEDITOR_TRANSLATIONS","messageId","dictionary","hasTranslation","plural","getPluralForm","pluralFormIndex","Number","RTL_LANGUAGE_CODES","getLanguageDirection","languageCode","includes","uiLanguage","contentLanguage","uiLanguageDirection","contentLanguageDirection","_t","match","interpolateString","config","defaultConfig","builtinPlugins","languageConfig","locale","ui","editors","_contextOwner","Plugin","init","isContextOwner","names","ContextPlugin","compareArrays","b","minLen","min","parent","pos","getChildIndex","getChild","unshift","includeSelf","parentFirst","ancestors","ancestorsA","getAncestors","ancestorsB","thisPath","getPath","nodePath","isBefore","_removeChildren","_fireChange","json","_textData","otherNode","textNode","offsetInText","substring","toMap","objectToMap","Matcher","pattern","_patterns","classes","element","singleElement","isElementMatching","results","matchName","patterns","hasAttribute","getAttribute","matchAttributes","getClassNames","hasClass","matchClasses","styles","hasStyle","getStyle","matchStyles","reIsDeepProp","reIsPlainProp","memoize","resolver","TypeError","memoized","cache","Cache","rePropName","reEscapeChar","charCodeAt","number","quote","subString","symbolToString","baseToString","end","defaultValue","fromRight","iterable","srcIndex","mergeFunc","srcValue","isCommon","isTyped","baseMerge","nested","styleProcessor","_styles","_styleProcessor","isEmpty","getStyleNames","inlineStyle","parsedStyles","stylesString","quoteType","propertyNameStart","propertyValueStart","stylesMap","charAt","char","trim","parseInlineStyles","toNormalizedForm","propertyDescriptor","getReducedForm","nameOrObject","valueOrObject","toPath","_cleanEmptyObjectsOnPath","getNormalized","_getStylesEntries","sort","pathParts","parentPath","parentObject","_normalizers","_extractors","_reducers","_consumables","appendStyleValue","normalizer","extractor","normalizedValue","reducer","callbackOrPath","shorthandName","styleNames","_mapStyleNames","alsoName","stylesObject","nameOrPath","valueToSet","attrs","_attrs","parseAttributes","_children","_insertChild","_classes","classString","parseClasses","stylesProcessor","setTo","_customProperties","_isAllowedInsideAttributeElement","otherElement","isAllowedInsideAttributeElement","className","getAsString","matcher","deep","childrenClone","child","getChildren","_clone","cloned","getFillerOffset","childCount","nodes","normalize","howMany","classesSet","classesString","classArray","lastChild","isFocused","selection","editableElement","rootNameSymbol","rootName","getCustomProperty","_setCustomProperty","boundaries","startPosition","direction","position","_createAt","singleCharacters","shallow","ignoreElementEnd","_boundaryStartParent","_boundaryEndParent","skip","done","prevPosition","next","_next","_previous","clone","previousPosition","isAtEnd","_createAfter","_formatReturnValue","charactersCount","textLength","textProxy","isAtStart","_createBefore","startOffset","nextPosition","isEqual","endOffset","editable","shift","shifted","treeWalker","otherPosition","compareWith","otherPath","itemOrPosition","getLastMatchingPosition","enlargeTrimSkip","isAfter","nodeAfterStart","nodeAfter","nodeBeforeEnd","nodeBefore","otherRange","loose","isCollapsed","containsStart","containsPosition","containsEnd","ranges","isIntersecting","commonRangeStart","commonRangeEnd","getCommonAncestor","nextSibling","previousSibling","startElement","endElement","getShiftedBy","_createFromParentsAndOffsets","offsetSize","_createFromPositionAndShift","_","selectable","placeOrOffset","_ranges","_lastRangeBackward","_isFake","_fakeSelectionLabel","range","rangeCount","anchor","first","last","firstRange","getFirstRange","lastRange","getLastRange","otherSelection","isFake","fakeSelectionLabel","focus","thisRange","found","isBackward","numOfRangesA","getRanges","rangeA","getTrimmed","rangeB","getContainedElement","_setRanges","_setFakeOptions","fake","label","backward","_createIn","_createOn","newFocus","_addRange","newRanges","isLastBackward","_pushRange","storedRange","addedRange","intersectingRange","_selection","delegate","getFirstPosition","getLastPosition","getSelectedElement","isSimilar","setFocus","startRange","_eventPhase","_currentTarget","contextsSymbol","eventArgs","eventContexts","getBubblingContexts","updateEventInfo","fireListenerFor","selectedElement","isCustomContext","getCustomContext","startParent","endParent","startPath","endPath","getDeeperRangeParent","contexts","eventPhase","currentTarget","roots","_postFixers","postFixer","writer","wasFixed","_priority","_id","_clonesGroup","nonUiChildrenCount","DEFAULT_PRIORITY","userAgent","navigator","toLowerCase","isMac","isGecko","isSafari","isAndroid","isBlink","features","isRegExpUnicodePropertySupported","isSupported","search","modifiersToGlyphsMac","ctrl","cmd","alt","modifiersToGlyphsNonMac","keyCodes","arrowleft","arrowup","arrowright","arrowdown","backspace","enter","space","esc","tab","code","letter","fromCharCode","generateKnownKeyCodes","keyCodeNames","fromEntries","toUpperCase","getCode","keyCode","altKey","ctrlKey","shiftKey","metaKey","parseKeystroke","keystroke","splitKeystrokeText","endsWith","getEnvKeyCode","sum","getEnvKeystrokeText","keystrokeCode","modifiers","glyph","getLocalizedArrowKeyCodeDirection","isLtrContent","isForwardArrowKeyCode","localizedKeyCodeDirection","domDocument","toDomElement","domElement","getAttributeKeys","injectUiElementHandling","view","domConverter","domSelection","domTarget","ownerDocument","defaultView","getSelection","domSelectionCollapsed","getRangeAt","collapsed","domParent","focusNode","domOffset","focusOffset","viewPosition","domPositionToView","jumpedOverAnyUiElement","nextViewPosition","newDomPosition","viewPositionToDom","collapse","extend","jumpOverUiElement","_cloneGroups","_setTo","_setFocus","attributeElement","containerElement","_document","emptyElement","renderFunction","uiElement","render","rawElement","_setAttribute","_removeAttribute","_addClass","_removeClass","_setStyle","_removeStyle","_removeCustomProperty","positionOrRange","_breakAttributes","_breakAttributesRange","newElement","sourceRange","targetPosition","move","positionOffset","positionParent","_removeFromClonedElementsGroup","mergeAttributes","mergeTextNodes","_appendChild","prev","newPosition","validateNodesToInsert","errorContext","validNodesToInsert","validNode","nodeGroups","groups","lastGroup","breakAttributes","_insertNodes","rangeOrItem","validateRangeContainer","breakStart","breakEnd","parentContainer","mergePosition","walker","getWalker","current","rangeToRemove","parentElement","ancestor","countBefore","_wrapPosition","viewSelection","setSelection","_wrapRange","newRange","_unwrapChildren","newName","viewElement","getAttributes","groupName","insertionPosition","getParentContainer","breakTextNode","_addToClonedElementsGroup","endPosition","wrapElement","wrapPositions","isText","isAttribute","_wrapAttributeElement","shouldABeOutsideB","newAttribute","_wrapChildren","offsetChange","unwrapElement","unwrapPositions","unwrapped","_unwrapAttributeElement","movePositionToTextNode","fakePosition","createAttributeElement","POSITIVE_INFINITY","wrapRange","wrap","wrapper","toWrap","canBeJoined","setStyle","addClass","toUnwrap","removeClass","removeStyle","forceSplitText","rangeStart","rangeEnd","isContainerOrFragment","offsetAfter","clonedNode","nodesToMove","group","getIdentity","textToMove","_data","t1","t2","nodeBeforeLength","startContainer","endContainer","NBSP_FILLER","MARKED_NBSP_FILLER","span","dataset","ckeFiller","innerHTML","BR_FILLER","fillerBr","INLINE_FILLER","repeat","startsWithFiller","domNode","isInlineFiller","domText","getDataWithoutFiller","jumpOverInlineFiller","fastDiff","cmp","atomicChanges","changeIndexes","arr1","arr2","firstIndex","findFirstDifferenceIndex","lastIndexOld","lastIndexNew","oldArrayReversed","cutAndReverse","newArrayReversed","findChangeBoundaryIndexes","newLength","changeIndexesToAtomicChanges","newArray","changeIndexesToChanges","reverse","aLength","bLength","_insert","_delete","tmp","delta","es","fp","snake","k","y1","y2","dir","y","x","nodeToInsert","isNode","Document","Node","domDocuments","markedAttributes","markedChildren","markedTexts","_inlineFiller","_fakeSelectionContainer","mapViewToDom","inlineFillerPosition","_updateChildrenMappings","_isSelectionInInlineFiller","_removeInlineFiller","_getInlineFillerPosition","_needsInlineFillerAtSelection","_updateAttrs","_updateChildren","_updateText","fillerDomPosition","addInlineFiller","_updateFocus","_updateSelection","actualDomChildren","expectedDomChildren","viewChildrenToDom","withChildren","diff","_diffNodeLists","actions","_findReplaceActions","counter","equal","action","insertIndex","deleteIndex","viewChild","_updateElementMappings","unbindDomElement","bindElements","firstPos","selectionPosition","domFillerNode","selectionParent","selectionOffset","findAncestor","isEditable","viewText","findCorrespondingDomText","newDomText","viewToDom","actualText","expectedText","filler","insertData","deleteData","domAttrKeys","attr","viewAttrKeys","nodesToUnbind","_markDescendantTextToSync","domToView","domChildList","fakeSelectionContainer","childList","filterOutFakeSelectionContainer","actualDom","expectedDom","newActions","actualSlice","expectedSlice","areSimilar","viewNode","_removeDomSelection","_removeFakeSelection","domRoot","_updateFakeSelection","_updateDomSelection","container","assign","top","left","width","textContent","createFakeSelectionContainer","bindFakeSelection","_fakeSelectionNeedsUpdate","domRange","createRange","removeAllRanges","selectNodeContents","addRange","_domSelectionNeedsUpdate","ELEMENT_NODE","childAtOffset","tagName","fixGeckoSelectionAfterBr","isDomSelectionCorrect","oldViewSelection","domSelectionToView","anchorNode","contains","doc","activeDomElement","activeElement","mapDomToView","domParentOrArray","nodeAfterFiller","fillerNode","node1","node2","COMMENT_NODE","actualDomChild","expectedDomChild","isBlockFiller","DOCUMENT_NODE","BR_FILLER_REF","NBSP_FILLER_REF","MARKED_NBSP_FILLER_REF","blockFillerMode","preElements","blockElements","_domToViewMapping","_viewToDomMapping","_fakeSelectionMapping","_rawContentElementMatcher","_encounteredRawContentDomNodes","WeakSet","viewDocumentSelection","domFragment","viewFragment","textData","_processDataFromViewText","createDocumentFragment","bindDocumentFragments","createElementNS","fillerPositionOffset","childView","_getBlockFiller","viewRange","domStart","domEnd","setStart","setEnd","viewParent","domBefore","domAfter","hostElement","getHostViewElement","_processDataFromDomText","isComment","isDocumentFragment","viewName","keepOriginalCase","domChildrenToView","domChild","fakeSelectionToView","isDomSelectionBackward","viewRanges","domRangeToView","viewStart","viewEnd","findCorrespondingViewText","viewBefore","domElementOrDocumentFragment","isElement","documentFragmentOrElement","viewEditable","domEditable","scrollX","scrollY","scrollPositions","forEachDomNodeAncestor","scrollLeft","scrollTop","scrollTo","DOCUMENT_FRAGMENT_NODE","isEqualNode","hasBlockParent","isNbspBlockFiller","anchorOffset","detach","_isDomSelectionPositionCorrect","prevNode","_getTouchingViewTextNode","_nodeEndsWithSpace","nextNode","_hasDomParentOfType","_getTouchingInlineDomNode","shouldLeftTrim","_checkShouldLeftTrimDomText","shouldRightTrim","_checkShouldRightTrimDomText","Text","getNext","topmostParent","createTreeWalker","NodeFilter","SHOW_TEXT","SHOW_ELEMENT","acceptNode","FILTER_ACCEPT","FILTER_SKIP","currentNode","touchingNode","lca","nodeA","nodeB","boundaryParent","parents","isWindow","stringifiedObject","rest","proxy","_getProxyEmitter","attach","listeningEmitter","listenedToEmitterId","getNodeUID","_domNode","_domListeners","listenerOptions","capture","useCapture","passive","usePassive","domListener","_createDomListener","removeListener","domEvt","Observer","disable","matches","SetCache","equalFunc","isPartial","arrLength","othLength","arrStacked","othStacked","seen","arrValue","othValue","compared","othIndex","convert","objProps","objLength","objStacked","skipCtor","objCtor","othCtor","objIsArr","othIsArr","objTag","othTag","objIsObj","othIsObj","isSameTag","objIsWrapped","othIsWrapped","objUnwrapped","othUnwrapped","baseIsEqual","characterData","characterDataOldValue","subtree","renderer","_renderer","_domElements","_mutationObserver","MutationObserver","_onMutations","takeRecords","observe","enable","disconnect","domMutations","mutatedTexts","mutatedElements","mutation","_isBogusBrMutation","text","oldText","newText","viewMutations","mutatedText","markToSync","viewChildren","newViewChildren","sameNodes","oldChildren","newChildren","viewSelectionAnchor","viewSelectionFocus","child1","child2","forceRender","addedNode","removedNodes","addedNodes","domEvent","additionalData","preventDefault","stopPropagation","domEventType","checkShouldIgnoreEventFromTarget","onDomEvent","eventType","reWhitespace","reTrimStart","reIsBadHex","reIsBinary","reIsOctal","freeParseInt","parseInt","isBinary","nativeMin","wait","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","time","leadingEdge","setTimeout","timerExpired","shouldInvoke","timeSinceLastCall","trailingEdge","timeWaiting","remainingWait","debounced","isInvoking","clearTimeout","cancel","flush","_fireSelectionChangeDoneDebounced","_handleSelectionMove","newSelection","oldSelection","mutationObserver","getObserver","_documents","_clearInfiniteLoopInterval","setInterval","_clearInfiniteLoop","_loopbackCounter","_handleSelectionChange","clearInterval","newViewSelection","hasDomSelection","_renderTimeoutId","selectedEditable","isComposing","namespace","xmlns","isRange","getBorderWidths","getComputedStyle","borderTopWidth","right","borderRightWidth","bottom","borderBottomWidth","borderLeftWidth","rectProperties","isSourceRange","_source","writable","rangeRects","getDomRangeRects","copyRectProperties","getBoundingRect","getBoundingClientRect","innerWidth","innerHeight","height","anotherRect","rect","getIntersection","getArea","visibleRect","isBody","commonAncestorContainer","parentRect","intersectionRect","prop","intersectRect","scrollBarWidth","scrollBarHeight","documentElement","clientWidth","clientHeight","borderWidths","offsetWidth","offsetHeight","rects","clientRects","getClientRects","boundingRectData","NEGATIVE_INFINITY","rectangleCount","elementOrRange","body","_observerInstance","_createObserver","_element","_callback","_addElementCallback","_deleteElementCallback","_elementCallbacks","_getElementCallbacks","unobserve","ObserverConstructor","ResizeObserver","_elements","_previousRects","_periodicCheckTimeout","_checkElementRectsAndExecuteCallback","_startPeriodicCheck","_stopPeriodicCheck","periodicCheck","_hasRectChanged","contentRect","currentRect","previousRect","hasChanged","setDataInElement","el","HTMLTextAreaElement","toUnit","unit","iteratorItem","_nextEventLoopTimeout","_focus","_blur","focusedElement","_listener","keyEvtData","scrollViewportToShowTarget","viewportOffset","targetWindow","getWindow","currentWindow","currentFrame","firstAncestorToScroll","getParentElement","scrollAncestorsToShowRect","getRectRelativeToWindow","targetRect","scrollWindowToShowRect","frameElement","targetShiftedDownRect","moveBy","targetShiftedUpRect","viewportRect","excludeScrollbarsAndBorders","isAbove","isBelow","isLeftOf","isRightOf","getRect","parentWindow","firstRect","secondRect","relativeWindow","frame","frameRect","scrollAncestorsToShowTarget","domRoots","_initialDomRootAttributes","_observers","_ongoingChange","_postFixersInProgress","_renderingDisabled","_hasChangedSinceTheLastRendering","_writer","addObserver","_render","viewRoot","getRoot","_name","initialDomRootAttributes","updateContenteditableAttribute","isReadOnly","change","observer","viewRangeToDom","isRenderingInProgress","callbackResult","_callPostFixers","flag","disableObservers","enableObservers","getChildStartOffset","toJSON","_nodes","getNodeIndex","maxOffset","getNodeStartOffset","totalOffset","nodeList","indexStart","getNode","offsetToIndex","relativePath","parentName","_removeNodes","fromJSON","stickiness","_visitedParent","prevVisitedParent","textNodeAtPosition","getTextNodeAtPosition","getNodeAfterPosition","formatReturnValue","offsetInTextNode","getNodeBeforePosition","newOffset","diffAt","leftParent","getParentPath","operation","_getTransformedByInsertOperation","_getTransformedByMoveOperation","_getTransformedBySplitOperation","_getTransformedByMergeOperation","_getTransformedByInsertion","_getTransformedByMove","sourcePosition","movedRange","_getCombined","splitPosition","moveTargetPosition","graveyardPosition","_getTransformedByDeletion","deletionPosition","deletePosition","transformed","insertPosition","combined","graveyard","shouldJoin","isTouching","getCommonPath","posParent","operations","getTransformedByOperation","j","containsRange","spread","newPos","moveRange","differenceSet","getDifference","difference","common","transformedCommon","newStart","newEnd","ref","refIndex","_modelToViewMapping","_viewToModelMapping","_viewToModelLengthCallbacks","_markerNameToElements","_elementToMarkerNames","_unboundMarkerNames","viewContainer","modelPosition","findPositionIn","viewBlock","findMappedViewAncestor","modelParent","modelOffset","_toModelOffset","modelElement","toModelElement","markerName","toViewElement","elements","nameToElements","elementToNames","markerNames","toModelPosition","modelRange","toViewPosition","mapper","isPhantom","boundElements","getElementsWithSameId","viewElementName","lengthCallback","viewOffset","getModelLength","len","expectedOffset","lastLength","_moveViewPositionToTextNode","_consumable","_textProxyRegistry","_normalizeConsumableType","_getSymbolForTextProxy","itemConsumables","startMap","endMap","_addSymbolForTextProxy","conversionApi","dispatcher","_reconversionEventsMapping","differ","markers","getMarkersToRemove","convertMarkerRemove","changes","_mapChangesWithAutomaticReconversion","convertInsert","convertRemove","reconvertElement","convertAttribute","attributeKey","attributeOldValue","attributeNewValue","flushUnboundMarkerNames","markerRange","getRange","convertMarkerAdd","getMarkersToAdd","consumable","_createInsertConsumable","walkerValueToEventData","_convertInsertWithAttributes","_clearConversionApi","_createConsumableForRange","_testAndFire","elementRange","currentView","convertedViewElement","elementOrTextProxyToView","createRangeOn","unbindViewElement","markersAtSelection","getMarkersAtPosition","_createSelectionConsumable","marker","shouldMarkerChangeBeConverted","getItems","modelName","getEventName","itemsToReconvert","updated","getChanges","_isReconvertTriggerEvent","elementName","containsItem","anyNewRange","oldRange","_removeAllRanges","directChange","_popRange","attributeKeys","visited","startBlock","getParentBlock","isTopBlockInRange","block","isUnvisitedTopBlock","endBlock","limitStartPosition","limitEndPosition","_checkRange","isUnvisitedBlock","schema","isBlock","hasParentLimit","isLimit","parentBlock","findAncestorBlock","bindWithDocument","isDocumentOperation","_createFromRanges","boundariesChanged","contentChanged","doesOperationChangeRangeContent","toRange","hasOwnRange","isGravityOverridden","getSelectedBlocks","containsEntireContent","_updateMarkers","_updateAttributes","prefixOrName","observeMarkers","_getStoredAttributes","overrideGravity","restoreGravity","startsWith","_model","_attributePriority","_selectionRestorePosition","_hasChangedRange","_overriddenGravityRegister","_observedMarkers","_fixGraveyardSelection","_validateSelectionRange","_updateMarker","batch","changeParent","enqueueChange","storedAttributes","clearAttributesStoredInElement","_getDefaultRange","optionsOrPlaceOrOffset","overrideUid","liveRange","_prepareRange","fromRange","changed","markerGroup","selectionRange","oldMarkers","hasMarker","contained","clearAll","newAttributes","_getSurroundingAttributes","oldAttributes","_setAttributesTo","newKey","oldKey","realKey","getAttrsIfCharacter","isInline","isObject","getNearestSelectionRange","ConversionHelpers","dispatchers","_dispatchers","conversionHelper","normalizeToElementConfig","elementCreator","consume","converterPriority","triggerBy","_mapReconversionTriggerEvent","childName","downcastElementToElement","modelValue","getFromAttributeCreator","oldViewElement","newViewElement","viewWriter","toViewRange","unwrap","downcastAttributeToElement","normalizeToAttributeConfig","attributeCreator","oldAttribute","downcastAttributeToAttribute","isOpening","viewStartElement","viewEndElement","bindElementToMarker","markerNameToElements","unbindElementFromMarkerName","clearClonedElementsGroup","downcastMarkerToElement","highlightDescriptor","descriptor","prepareDescriptor","createViewElementFromHighlightDescriptor","rangeAfterWrap","highlightElement","viewHighlightElement","removeHighlight","downcastMarkerToHighlight","viewCreator","viewMarkerData","handleMarkerBoundary","viewData","removeMarkerFromAttribute","attributeName","removeMarkerData","downcastMarkerToData","isStart","checkChild","createUIElement","insertMarkerAsElement","insertMarkerAsAttribute","viewElementType","modelData","viewElementDefinition","createContainerElement","createViewElementFromDefinition","modelAttributeValue","autoParagraphEmptyRoots","getRootNames","insertElement","isParagraphable","nodeOrType","createContext","wrapInParagraph","paragraph","createPositionAt","upcastElementToElement","normalizeModelAttributeConfig","converter","prepareToAttributeConverter","getViewElementNameFromConfig","upcastElementToAttribute","viewKey","normalized","normalizeViewAttributeKeyValueConfig","upcastAttributeToAttribute","oldModel","normalizeElementToMarkerConfig","upcastElementToMarker","converterStart","prepareToElementConverter","normalizeDataToMarkerConfig","converterEnd","basePriority","maxPriority","priorityFactor","attrName","addMarkerElements","markerViewNames","markerViewName","modelCursor","convertChildren","viewItem","upcastAttributeToMarker","upcastDataToMarker","viewConfig","matcherResult","getModelElement","safeInsert","updateConversionResult","viewAttributeKeyToCopy","defaultModelValue","modelKey","configToTest","onlyViewNameIsDefined","modelAttribute","checkAttribute","setAttributeOn","configForElements","downcastDispatcher","_disableRendering","convertChanges","convertSelection","toModelRange","modelSelection","createSelection","convertSelectionChange","createText","modelEnd","createRangeIn","isAttached","brokenPosition","_commands","commandName","commands","ViewConsumable","consumables","elementConsumables","revert","instance","consumablesFromElement","createFrom","_canConsumeName","_test","_consume","_revert","getRelatedStyles","consumableName","toConsume","_sourceDefinitions","_attributeProperties","SchemaContext","getDefinition","itemName","definition","_clearCache","_compiledDefinitions","_compile","getDefinitions","def","isSelectable","isContent","_checkContextMatch","allowAttributes","positionOrBaseElement","elementToMerge","checkMerge","childDef","retValue","getAttributeProperties","selectionOrRangeOrPosition","rangeCommonAncestor","getMinimalFlatRanges","convertToMinimalFlatRanges","_getValidRangesForRange","backwardWalker","forwardWalker","limitElement","forward","step","combineWalkers","removeDisallowedAttributeFromNode","positionsInRange","getPositions","compiledDefinitions","sourceRules","itemNames","compileBaseItemRule","compileAllowContentOf","compileAllowWhere","compileAllowAttributesOf","compileInheritPropertiesFrom","cleanUpAllowIn","cleanUpAllowAttributes","contextItemIndex","contextItem","getItem","allowIn","parentRule","mapContextItem","query","getNames","sourceItemRules","itemRule","allowContentOf","allowWhere","allowAttributesOf","inheritTypesFrom","sourceItemRule","typeNames","copyTypes","copyProperty","inheritFrom","inheritAllFrom","makeInheritAllWork","allowContentOfItemName","getAllowedChildren","allowedItem","allowWhereItemName","allowedIn","allowAttributeOfItem","inheritAttributes","inheritPropertiesOfItem","existingItems","itemToCheck","ctxItem","_splitParts","_cursorParents","_modelCursor","convertItem","_convertItem","_convertChildren","_safeInsert","_updateConversionResult","splitToAllowedParent","_splitToAllowedParent","getSplitParts","_getSplitParts","contextDefinition","append","createContextTree","store","documentFragment","_removeEmptyElements","modelItem","markerElements","markerElement","currentPosition","createPositionBefore","extractMarkersFromModelFragment","elementOrModelCursor","nextModelCursor","splitResult","createPositionAfter","savedCursorParent","allowedParent","findAllowedParent","treeWalkerValue","originalPart","splitPart","_registerSplitPair","cursorParent","anyRemoved","BasicHtmlWriter","fragment","implementation","createHTMLDocument","_domParser","DOMParser","_domConverter","_htmlWriter","getHtml","_toDom","registerRawContentMatcher","parseFromString","upcastDispatcher","viewDocument","htmlProcessor","processor","_viewWriter","_checkIfRootsExists","hasContent","ignoreWhitespaces","modelElementOrFragment","viewDocumentFragment","toView","toData","clearBindings","intersection","_getMarkersRelativeToElement","version","initialData","main","modelRoot","parse","newData","removeSelectionAttribute","toModel","viewElementOrFragment","rootNames","downcastDispatchers","upcastDispatchers","_helpers","_downcast","_createConversionHelpers","isDowncast","_upcast","alias","for","elementToElement","_getAllUpcastDefinitions","attributeToElement","elementToAttribute","attributeToAttribute","helpers","upcastAlso","_getUpcastDefinition","upcastAlsoItem","Batch","op","baseVersion","Operation","__className","_normalizeNodes","_splitNodeAtPosition","_mergeNodesAtIndex","_move","_haveSameAttributes","mergedNode","offsetDiff","firstPart","secondPart","iteratorA","iteratorB","newTargetPosition","getMovedRangeStart","sourceElement","targetElement","sourceOffset","targetOffset","shouldReceiveAttributes","gyPosition","originalNodes","affectsData","_markers","oldName","mergedElement","splitElement","_assertWriterUsedCorrectly","isSameTree","addOperation","applyOperation","rangeRootPosition","usingOperation","updateMarker","addMarker","itemOrRange","setAttributeOnRange","setAttributeOnItem","removeAttributesFromItem","_addOperationForAffectedMarkers","flat","applyRemoveOperation","_merge","_mergeDetached","createPositionFromPath","merge","renameOperation","firstSplitElement","firstCopyElement","getInsertionPosition","elementOrString","shiftedRange","applyMarkerOperation","_set","markerOrName","currentMarker","_refresh","hasUsingOperationDefined","affectsDataDefined","currentRange","updatedRange","managedUsingOperations","keyOrObjectOrIterable","_setSelectionAttribute","keyOrIterableOfKeys","_removeSelectionAttribute","_overrideGravity","_restoreGravity","storeKey","_getStoreAttributeKey","_currentWriter","isAffected","elementBefore","elementAfter","affectedInLeftElement","affectedInRightElement","affectedAfterLeftElement","affectedBeforeRightElement","valueBefore","valueAfter","lastSplitPosition","previousValue","rootA","rootB","markerCollection","_markerCollection","_changesInElement","_elementSnapshots","_changedMarkers","_changeCount","_cachedChanges","_cachedChangesWithGraveyard","_isInInsertedElement","_markRemove","_markInsert","getMarkersIntersectingRange","bufferMarkerChange","_markAttribute","sourceParentInserted","targetParentInserted","graveyardParent","mergedIntoElement","buffered","includeChangesInGraveyard","diffSet","snapshotChildren","elementChildren","_getChildrenSnapshot","_generateActionsFromChanges","_getInsertDiff","_getRemoveDiff","elementAttributes","snapshotAttributes","_getAttributesDiff","changeCount","prevIndex","prevDiff","thisDiff","isConsecutiveTextRemove","isConsecutiveTextAdd","isConsecutiveAttributeChange","v","_changesInGraveyardFilter","changeItem","_markChange","_removeAllNestedChanges","_makeSnapshot","_getChangesForElement","_handleChange","inc","nodesToHandle","old","incEnd","oldEnd","intersectionLength","howManyAfter","attributePart","diffs","snapshot","oldChildrenLength","oldChildrenHandled","posInGy","rangeInGy","History","_operations","_undoPairs","_undoneOperations","undoneOperation","undoingOperation","isInsideSurrogatePair","character","isLowSurrogateHalf","isInsideCombinedSymbol","history","_hasSelectionChangedFromTheLastChangeBlock","createRoot","bufferOperation","_hasDocumentChangedFromTheLastChangeBlock","hasDataChanges","reset","defaultRoot","_getDefaultRoot","validateTextNodePosition","rangeBoundary","oldMarker","_attachLiveRange","_managedUsingOperations","_affectsData","_destroyMarker","prefix","_detachLiveRange","_liveRange","stopDelegating","oldPosition","toPosition","canMergeWith","_documentFragment","_documentFragmentPosition","_firstNode","_lastNode","_lastAutoParagraph","_filterAttributesOf","_affectedStart","_affectedEnd","_handleNode","_insertPartialFragment","_updateLastNodeFromAutoParagraph","_mergeOnRight","removeDisallowedAttributes","positionAfterLastNode","positionAfterNode","_setAffectedBoundaries","nodeToSelect","_handleObject","isAllowed","_checkAndAutoParagraphToAllowedPosition","_checkAndSplitToAllowedPosition","_appendToFragment","_handleDisallowedNode","livePosition","fromPosition","_mergeOnLeft","_tryAutoparagraphing","handleNodes","_canMergeLeft","mergePosLeft","_canMergeRight","mergePosRight","_getAllowedIn","tempPos","deleteContent","selRange","doNotResetEntireContent","getLimitElement","shouldEntireContentBeReplacedWithParagraph","insertParagraph","replaceEntireContentWithParagraph","ignoreMarkers","modifySelection","getLivePositionsForSelectedBlocks","leaveUnmerged","checkShouldMerge","startAncestor","endAncestor","positionA","positionB","getAncestorsJustBelowCommonAncestor","mergeBranchesRight","commonAncestor","parentToRemove","rename","clearAttributes","setAttributes","mergeRight","mergeBranchesLeft","mergeBranches","collapseSelectionAt","doNotAutoparagraph","isTextAllowed","isParagraphAllowed","shouldAutoparagraph","leftPos","rightPos","rangeToCheck","isCrossingLimitElement","tryExtendingTo","isForward","isAtWordBoundary","isAtNodeBoundary","boundaryChar","getCorrectWordBreakPosition","getCorrectPosition","getSearchRange","searchEnd","offsetToCheck","removeRangeContent","parentsToCheck","itemRange","parentToCheck","removeRange","injectSelectionPostFixer","registerPostFixer","correctedRange","tryFixingRange","nonIntersectingRanges","previousRange","merged","mergeIntersectingRanges","selectionPostFixer","originalPosition","nearestSelectionRange","fixedPosition","tryFixingCollapsedRange","isTextAllowedOnStart","isTextAllowedOnEnd","startLimitElement","endLimitElement","startIsOnBlock","endIsOnBlock","checkSelectionOnNonLimitElements","fixedStart","fixedEnd","isStartInLimit","isEndInLimit","bothInSameParent","expandStart","expandEnd","findOutermostLimitAncestor","tryFixingNonCollapsedRage","startingNode","isLimitNode","_pendingChanges","_validate","register","addChildCheck","childDefinition","_runPendingChanges","batchOrType","_execute","insertion","nodesToInsert","getSelectionRange","affectedRange","getAffectedRange","insertContent","setSelectionFocus","frag","commonPath","commonParent","getNodeByPath","flatSubtreeRange","appendText","cloneElement","leftExcessRange","getSelectedContent","rangeOrElement","intersectingMarker","ret","currentBatch","callbackReturnValue","_handleChangeBlock","evtData","_addEditor","_getEditorConfig","once","state","editing","conversion","addAlias","keystrokes","removePlugins","extraPlugins","readyPromise","_removeEditor","_components","originalName","componentFactory","focusTracker","_editableElementsMap","ckeditorInstance","editorUI","_actions","hasAny","check","clickOutsideHandler","activator","contextElements","composedPath","contextElement","injectCssTransitionDisabler","disableCssTransitions","_isCssTransitionsDisabled","enableCssTransitions","extendTemplate","class","bindTemplate","if","submitHandler","initialItems","_renderViewIntoCollectionParent","_parentElement","elementOrDocFragment","dest","evtName","isRendered","_viewCollections","_unboundChildren","createCollection","collection","_bindTemplate","views","template","registerChild","getViews","_revertData","_isRendered","_renderNode","intoFragment","isApplying","revertData","_revertTemplateFromNode","isView","isTemplate","eventNameOrFunctionOrAttribute","TemplateToBinding","eventNameOrFunction","valueIfTrue","TemplateIfBinding","extendObjectValueArray","eventListeners","childIndex","isInvalid","_renderText","_renderElement","_renderAttributes","_renderElementChildren","_setUpListeners","hasTemplateBinding","_bindToObservable","getTextUpdater","attrValue","domAttrValue","attrNs","valueToBind","shouldExtend","getAttributeUpdater","_renderStyleAttribute","arrayValueReducer","isFalsy","setAttributeNS","styleName","styleValue","getStyleUpdater","isViewCollection","setParent","childRevertData","revertBindings","schemaItem","domEvtName","domSelector","activateDomEventListener","syncValueSchemaValue","templateBinding","activateAttributeListener","revertBinding","TemplateBinding","getValue","getValueSchemaValue","removeAttributeNS","normalizePlainTextDefinition","normalizeTextDefinition","listeners","arrayify","normalizeListeners","normalizeAttributes","cur","ext","_bodyCollectionContainer","childElementCount","setTemplate","viewBox","_updateXMLContent","_colorFillPaths","svg","fillColor","querySelectorAll","ariaLabelUid","tooltipView","_createTooltipView","labelView","_createLabelView","iconView","keystrokeView","_createKeystrokeView","_getTooltipString","tabindex","isToggleable","mousedown","click","icon","withKeystroke","tooltip","toggleSwitchView","_createToggleView","getLocalizedColorOptions","localizedColorNames","Black","Grey","White","Red","Orange","Yellow","Green","Aquamarine","Turquoise","Blue","Purple","colorOption","normalizeColorOptions","normalizeSingleColorDefinition","option","color","hasBorder","backgroundColor","FocusCycler","keystrokeHandler","focusables","isFocusable","_getFocusableItem","viewIndex","focused","previous","collectionLength","display","colorDefinitions","viewStyleAttribute","columns","gridTemplateColumns","_focusCycler","focusPrevious","focusNext","colorTile","isOn","selectedColor","arrowView","_createArrowView","actionView","_createActionView","selectstart","focusLast","getOptimalPosition","positions","limiter","fitInViewport","positionedElementAncestor","offsetParent","getPositionedAncestor","elementRect","bestPositionRect","bestPositionName","bestPosition","elementRectArea","processedPositions","limiterRect","positionData","getPositionNameAndRect","positionName","positionRect","limiterIntersectArea","viewportIntersectArea","limiterViewportIntersectRect","getIntersectionArea","processedPosition","processPositionsToAreas","bestPositionData","getBestOfProcessedPositions","getBestPositionNameAndRect","getVisible","absoluteRectCoordinates","getAbsoluteRectCoordinates","ancestorPosition","ancestorBorderWidths","shiftRectCoordinatesDueToPositionedAncestor","moveTo","maxFitFactor","fitFactor","buttonView","panelView","isOpen","panelPosition","_getOptimalPosition","_panelPositions","closeDropdown","south","north","southEast","southWest","northEast","northWest","southMiddleEast","southMiddleWest","northMiddleEast","northMiddleWest","defaultPanelPositions","buttonRect","panelRect","normalizeToolbarConfig","removeItems","itemsView","shouldGroupWhenFull","isFloating","role","maxWidth","_behavior","StaticLayout","focusFirst","itemsOrConfig","itemsToClean","idx","itemsToAdd","_cleanSeparators","nonSeparatorPredicate","firstCommandItem","findIndex","lastCommandItem","viewFocusables","viewItemsView","viewFocusTracker","viewLocale","ungroupedItems","groupedItems","groupedItemsDropdown","_createGroupedItemsDropdown","resizeObserver","cachedPadding","shouldUpdateGroupingOnNextResize","_updateFocusCycleableItems","changeData","removedItem","currentIndex","addedItem","_updateGrouping","_enableGroupingOnResize","_enableGroupingOnMaxWidthChange","initialGroupedItemsCount","wereItemsGrouped","_areItemsOverflowing","_groupLastItem","_ungroupFirstItem","lastChildRect","toolbarRect","computedStyle","paddingProperty","previousWidth","dropdown","createDropdown","addToolbarToDropdown","tooltipPosition","toolbarView","ButtonClass","dropdownView","closeDropdownOnBlur","closeDropdownOnExecute","focusDropdownContentsOnArrows","addDefaultBehavior","buttons","addListToDropdown","listView","listItemView","attachToDom","detachFromDom","editingView","lang","_editableElement","_hasExternalElement","_editingView","_updateIsFocusedClasses","updateAfterRender","placeholder","readonly","_updateIsEmpty","_setDomElementValue","select","viewUid","statusUid","fieldView","statusView","_createStatusView","errorText","infoText","createLabeledInputText","labeledFieldView","inputView","ariaDescribedById","createLabeledDropdown","alert","_showNotification","title","toPx","defaultLimiterElement","isVisible","show","defaultPositions","positionOptions","southArrowNorth","southArrowNorthMiddleWest","southArrowNorthMiddleEast","southArrowNorthWest","southArrowNorthEast","northArrowSouth","northArrowSouthMiddleWest","northArrowSouthMiddleEast","northArrowSouthWest","northArrowSouthEast","optimalPosition","unpin","_pinWhenIsVisibleCallback","_startPinning","_stopPinning","hide","attachTo","getDomElement","limiterElement","scrollTarget","isWithinScrollTarget","isLimiterWithinScrollTarget","getNorthTop","balloonRect","arrowVerticalOffset","getSouthTop","arrowHorizontalOffset","northWestArrowSouthWest","northWestArrowSouthMiddleWest","northWestArrowSouth","northWestArrowSouthMiddleEast","northWestArrowSouthEast","northEastArrowSouthWest","northEastArrowSouthMiddleWest","northEastArrowSouth","northEastArrowSouthMiddleEast","northEastArrowSouthEast","southWestArrowNorthWest","southWestArrowNorthMiddleWest","southWestArrowNorth","southWestArrowNorthMiddleEast","southWestArrowNorthEast","southEastArrowNorthWest","southEastArrowNorthMiddleWest","southEastArrowNorth","southEastArrowNorthMiddleEast","southEastArrowNorthEast","positionLimiter","_viewToStack","_idToStack","_rotatorView","_createRotatorView","_fakePanelsView","_createFakePanelsView","hasView","stackId","_numberOfStacks","_visibleStack","singleViewMode","showStack","_showView","_singleViewMode","visibleView","_showNextStack","hideView","_getStackId","pin","_getBalloonPosition","updatePosition","visibleStack","stacks","nextIndex","isSingleViewMode","numberOfStacks","buttonNextView","buttonPrevView","_showPrevStack","balloonClassName","withArrow","showView","_createButtonView","balloonPanelView","_balloonPanelView","_addPanels","_removePanels","deregisterChild","numberOfPanels","_balloonConfig","_createToolbarView","getEditableElement","_resizeObserver","_balloon","_fireSelectionChangeDebounced","isToolbarVisible","shouldNotGroupWhenFull","_updatePosition","fillFromConfig","selectionContainsOnlyMultipleSelectables","_getBalloonPositionData","getBalloonPositions","documentPlaceholders","enablePlaceholder","isDirectHost","keepOnFocus","updateDocumentPlaceholders","hidePlaceholder","placeholders","directHostElements","wasViewModified","updatePlaceholder","getChildPlaceholderHostSubstitute","selectionAnchor","needsPlaceholder","showPlaceholder","transformations","setTransformation","OperationA","OperationB","transformationFunction","aGroup","noUpdateTransformation","getTransformation","transformSets","operationsA","operationsB","contextFactory","useRelations","forceWeakRemove","setOriginalOperations","originalOperations","nextTransformIndex","nextBaseVersionA","nextBaseVersionB","originalOperationsACount","originalOperationsBCount","opA","indexB","opB","newOpsA","getContext","newOpsB","updateRelation","newOpA","padWithNoOps","brokenOperationsACount","brokenOperationsBCount","updateBaseVersions","_history","_useRelations","_forceWeakRemove","_relations","takeFrom","originalOperation","_setRelation","hasSameParentAs","affectedLeft","affectedRight","side","wasInLeftElement","wasStartBeforeMergedElement","wasEndBeforeMergedElement","wasInRightElement","aIsStrong","aWasUndone","_wasUndone","bWasUndone","abRelation","_getRelation","baRelation","originalOp","wasUndone","isUndoneOperation","origB","undoneB","getUndoneOperation","origA","relationsA","relation","_getComplementaryAttributeOperations","insertOperation","insertValue","_moveTargetIntoMovedRange","_makeMoveOperationsFromRanges","moveOp","_breakRangeByMoveOperation","aNewRange","aToGraveyard","bToGraveyard","aIsWeak","removedRange","mergeInside","mergeSplittingElement","getReversed","aCompB","shouldSpread","rightRange","movesGraveyardElement","gyMoveSource","splitNodesMoveSource","gyMoveTarget","gyMove","splitNodesMoveTargetPath","splitNodesMoveTarget","splitNodesMove","extraRename","splitPath","additionalSplit","rangeToMove","gyElementMoved","newParentPosition","newTargetPath","splitAtTarget","howManyRemoved","aInGraveyard","bInGraveyard","newPositionPath","removeChildren","oldElement","insertChild","HEX_COLOR_REGEXP","RGB_COLOR_REGEXP","RGBA_COLOR_REGEXP","HSL_COLOR_REGEXP","HSLA_COLOR_REGEXP","COLOR_NAMES","isColor","lineStyleValues","isLineStyle","lengthRegExp","PERCENTAGE_VALUE_REGEXP","isPercentage","repeatValues","positionValues","isPosition","attachmentValues","isAttachment","urlRegExp","isURL","getBoxSidesValues","getShorthandValues","getBoxSidesValueReducer","styleShorthand","reduced","getBoxSidesShorthandValue","out","getPositionShorthandNormalizer","shorthand","addBackgroundRules","setNormalizer","normalizeBackground","setReducer","background","attachment","image","addBorderRules","borderNormalizer","getBorderPositionNormalizer","getBorderPropertyNormalizer","getBorderPropertyPositionNormalizer","setExtractor","getBorderPositionExtractor","getBorderPositionReducer","borderReducer","setStyleRelation","normalizeBorderShorthand","border","toBorderPropertyShorthand","which","extractBorderPosition","reduceBorderPosition","addMarginRules","addPaddingRules","balloonToolbar","editingRoot","setEditableElement","attachDomRoot","origin","originKeystrokeHandler","originFocusTracker","toolbar","beforeFocus","afterBlur","enableToolbarKeyboardFocus","_initPlaceholder","detachDomRoot","placeholderText","sourceElementOrData","secureSourceElement","updateSourceElement","form","originalSubmit","onSubmit","submit","attachToForm","getData","isHTMLElement","getInitialData","FileReader","reader","_reader","onprogress","loaded","file","total","reject","onload","onerror","onabort","readAsDataURL","abort","loaders","_updatePendingAction","_loadersMap","_pendingAction","uploaded","fileOrPromise","createUploadAdapter","loader","catch","aggregatedUploaded","aggregatedTotal","uploadTotal","fileOrPromiseOrLoader","getLoader","_destroy","pendingActions","getMessage","uploadedPercent","filePromise","uploadAdapterCreator","_filePromiseWrapper","_createFilePromiseWrapper","_adapter","status","read","upload","uploadResponse","isFulfilled","rejecter","_fileInputView","open","accept","multiple","files","getCsrfToken","token","cookie","pair","decodeURIComponent","getCookie","randValues","crypto","getRandomValues","generateToken","url","_initRequest","_initListeners","_sendRequest","xhr","XMLHttpRequest","responseType","genericError","response","lengthComputable","FormData","send","blockAutoformatEditing","callbackOrCommand","blockToFormat","firstNode","firstNodeRange","blockRange","inlineAutoformatEditing","testRegexpOrCallback","formatCallback","regExp","testCallback","format","leftDel","rightDel","delStart","delEnd","rangeText","getTextAfterCode","testOutput","rangesToFormat","testOutputToRanges","rangesToRemove","arrays","getCallbackFunctionForInlineAutoformat","validRanges","getValidRanges","_getValueFromFirstAllowedNode","checkAttributeInSelection","forceValue","setSelectionAttribute","setAttributeProperties","isFormatting","copyOnEnter","fontWeight","ChangeBuffer","limit","isLocked","_changeCallback","_batch","_reset","_selectionChangeCallback","createBatch","ignoreLock","undoStepSize","_buffer","_batches","textInsertions","resultRange","lock","unlock","safeKeycodes","isNonTypingKeystroke","keyData","getSingleTextNodeChange","output","lastOperation","pushLast","isContinuationOf","expected","diffToChanges","compareChildNodes","oldChild","newChild","mutations","containerChildrenMutated","_handleContainerChildrenMutations","_handleTextMutation","_handleTextNodeInsertion","mutationsCommonAncestor","getMutationsContainer","domMutationCommonAncestor","freshDomConverter","modelFromCurrentDom","currentModel","modelFromDomChildren","currentModelChildren","lastDomChild","lastCurrentChild","isLastDomChildSoftBreak","isLastCurrentChildSoftBreak","isSafeForTextMutation","diffResult","firstChangeAt","insertions","deletions","calculateChanges","modelSelectionRange","insertText","viewPos","modelPos","insertedText","lastChangeAt","inputCommand","latestCompositionSelection","handleUnsafeKeystroke","isSelectionUnchanged","deleteSelectionContent","isFlatSelection","injectUnsafeKeystrokesHandling","handle","injectTypingMutationsHandling","sequence","_shouldEntireContentBeReplacedWithParagraph","_replaceEntireContentWithParagraph","_shouldReplaceFirstBlockWithParagraph","limitElementFirstChild","fireViewDeleteEvent","originalEvent","hasWordModifier","inputType","selectionToRemove","deleteForwardCommand","deleteCommandParams","scrollToTheSelection","domSelectionAfterDeletion","getLastTextLine","hasMatch","_startListening","_evaluateTextBeforeSelection","suffix","rangeBeforeSelection","testResult","eventData","_overrideUid","arrowRightPressed","arrowLeftPressed","contentDirection","isMovementHandled","_handleForwardMovement","_handleBackwardMovement","_isNextGravityRestorationSkipped","_isGravityOverridden","isBetweenDifferentAttributes","hasAnyAttribute","preventCaretMovement","setSelectionAttributesFromTheNodeBefore","isStepAfterAnyAttributeBoundary","overrideSelectionGravity","restoreSelectionGravity","observedAttribute","attrBefore","reHasRegExpChar","TRANSFORMATIONS","copyright","registeredTrademark","trademark","oneHalf","oneThird","twoThirds","oneForth","threeQuarters","lessThanOrEqual","greaterThanOrEqual","notEqual","arrowLeft","arrowRight","horizontalEllipsis","enDash","emDash","quotesPrimary","buildQuotesRegExp","quotesSecondary","quotesPrimaryEnGb","quotesSecondaryEnGb","quotesPrimaryPl","quotesSecondaryPl","TRANSFORMATION_GROUPS","symbols","mathematical","typography","quotes","DEFAULT_TRANSFORMATIONS","normalizeFrom","normalizeTo","getTextAttributesAfterPosition","quoteCharacter","findAttributeRange","_findBound","lookBack","lastNode","inlineHighlight","highlightedElements","CODE","registerAttribute","getCopyOnEnterAttributes","allAttributes","isSelectionEmpty","attributesToCopy","splitBlock","isContainedWithinOneElement","enterBlock","splitPos","isSoft","insertBreak","softBreakAction","anchorPos","isInsideLimitElement","breakLineElement","createEmptyElement","_getValue","blocks","blocksToQuote","findQuote","checkCanBeQuoted","_applyQuote","_removeQuote","firstBlock","getRangesOfBlockGroups","groupRange","positionBefore","positionAfter","quotesToMerge","currentQuote","nextQuote","elementOrPosition","nextBlock","isBQAllowed","isBlockAllowedInBQ","blockQuoteCommand","checkCanBecomeParagraph","paragraphLikeElements","modelElements","heading","checkCanBecomeHeading","_addDefaultH1Conversion","enterCommand","getLocalizedOptions","localizedTitles","Paragraph","defaultTitle","dropdownTooltip","titles","itemDefinitions","headingCommand","paragraphCommand","withText","commandValue","areEnabled","para","whichModel","HighlightStack","_stack","oldTop","_insertDescriptor","newTop","compareDescriptors","oldDescriptor","newDescriptor","_removeDescriptor","shouldABeBeforeB","classesToString","isWidget","toWidget","setCustomProperty","labelOrCreator","setLabel","hasSelectionHandle","widgetElement","selectionHandle","addSelectionHandle","setHighlightHandling","addHighlight","getLabel","labelCreator","toWidgetEditable","findOptimalInsertionPosition","typeAroundFakeCaretPosition","getTypeAroundFakeCaretPosition","checkSelectionOnObject","viewToModelPositionOutsideModelElement","viewElementMatcher","centeredBalloonPositionForLongWidgets","widgetRect","viewportWidgetInsersectionRect","balloonTotalHeight","isTypeAroundWidget","POSSIBLE_INSERTION_POSITIONS","RETURN_ARROW_ICON_ELEMENT","_currentFakeCaretModelElement","_enableTypeAroundUIInjection","_enableInsertingParagraphsOnButtonClick","_enableInsertingParagraphsOnEnterKeypress","_enableInsertingParagraphsOnTypingKeystroke","_enableTypeAroundFakeCaretActivationUsingKeyboardArrows","_enableDeleteIntegration","_enableInsertContentIntegration","widgetModelElement","selectedModelElement","_insertParagraph","buttonTitles","before","after","widgetViewElement","typeAroundWrapper","wrapperDomElement","buttonTemplate","importNode","injectButtons","caretTemplate","injectFakeCaret","injectUIIntoWidget","positionToWidgetCssClass","_listenToIfEnabled","domEventData","_handleArrowKeyPress","selectedViewElement","shouldStopAndPreventDefault","_handleArrowKeyPressOnSelectedWidget","_handleArrowKeyPressWhenSelectionNextToAWidget","widgetPlugin","modelElementNextToSelection","_getObjectElementNextToSelection","_setSelectionOverElement","button","closest","buttonPosition","classList","getTypeAroundButtonPosition","widgetDomElement","getClosestWidgetViewElement","wasHandled","_insertParagraphAccordingToFakeCaretPosition","keyCodesHandledSomewhereElse","selectedModelWidget","isDeleteForward","probe","deepestEmptyRangeAncestor","deepestEmptyAncestor","getDeepestEmptyElementAncestor","documentSelection","verticalNavigationHandler","arrowUpPressed","arrowDownPressed","expandSelection","selectionWillShrink","getNearestNonInlineLimit","lastRangePosition","getNearestTextPosition","firstRangePosition","findTextRangeFromSelection","boundaryVerticalPosition","round","isSingleLineRange","walkerValueType","_previouslySelected","_clearPreviouslySelectedWidgets","lastMarked","isChild","_onMousedown","_handleSelectionChangeOnArrowKeyPress","_preventDefaultOnArrowKeyPress","_handleDelete","isInsideNestedEditable","detail","objectElement","objectElementNextToSelection","previousNode","nodeToRemove","widget","isWidgetSelected","_toolbarDefinitions","_updateToolbarsVisibility","toolbarConfig","toolbarId","ariaLabel","getRelatedElement","maxRelatedElementDepth","deepestRelatedElement","deepestToolbarDefinition","relatedElement","relatedElementDepth","_isToolbarVisible","_hideToolbar","_isToolbarInBalloon","_showToolbar","toolbarDefinition","repositionContextualBalloon","getBalloonPositionData","balloon","_options","_referenceCoordinates","domResizeHandle","domHandleHost","domResizeHost","clientRect","activeHandlePosition","domHandle","resizerPositions","getHandlePosition","resizerPosition","positionParts","getAbsoluteBoundaryPoint","replacements","getOppositePosition","originalWidth","originalHeight","aspectRatio","widthStyle","originalWidthPercents","parseFloat","resizeHostRect","domResizeHostParent","parentWidth","calculateHostPercentageWidth","newSize","proposedWidth","proposedHeight","proposedWidthPercents","widthPercents","proposedHandleHostWidth","handleHostWidth","proposedHandleHostHeight","handleHostHeight","_domResizerWrapper","_viewResizerWrapper","_cleanup","redraw","viewResizerWrapper","_appendHandles","_appendSizeUI","propName","_sizeUI","bindToState","_initialViewWidth","begin","_getHandleHost","_getResizeHost","_proposeNewSize","newWidth","domHandleHostRect","domResizeHostRect","onCommit","handleHostRect","domWrapper","widgetWrapper","handleHost","resizerWrapper","currentDimensions","newDimensions","isSameNode","offsetLeft","offsetTop","dismiss","currentCoordinates","pageX","pageY","isCentered","enlargement","proposedSize","abs","dominant","targetSize","getResizeHost","getHandleHost","sizeUI","visible","resizerState","unbind","_resizers","_observer","_mouseDownListener","_mouseMoveListener","_mouseUpListener","redrawFocusedResizer","visibleResizer","redrawFocusedResizerThrottled","getResizerByViewElement","resizer","widgetToolbarRepository","containsHandle","resizeHandle","isResizeHandle","_activeResizer","_getResizerByHandle","updateSize","commit","_fireEvents","isImageWidget","getSelectedImageWidget","insertImage","imageElement","insertAtSelection","isImageAllowed","getInsertImageParent","isImageAllowedInParent","isInOtherImage","getViewImgFromWidget","figureView","figureChildren","figureChild","modelToViewAttributeConverter","img","src","createImageViewElement","altText","toImageWidget","srcset","srcsetAttributeConverter","viewImage","modelImage","viewFigureToModel","insertImageCommand","figure","labeledInput","_createLabeledInputView","saveButtonView","_createButton","cancelButtonView","_focusables","_createForm","_form","_showForm","_hideForm","_isVisible","_isInBalloon","focusEditable","getCaptionFromImage","imageModelElement","matchImageCaption","_insertMissingModelCaptionElement","captionModelToView","createCaptionForEditing","createEditableElement","captionElementCreator","_fixCaptionVisibility","_updateCaptionVisibility","lastCaption","_lastSelectedCaption","viewCaption","modelCaption","getParentCaption","hideCaptionIfEmpty","showCaption","viewModified","nodeFinder","imagesWithoutCaption","nestedItem","appendElement","captionElement","insertViewCaptionAndBind","caption","defaultStyle","isDefault","attributeValue","getStyleByName","defaultStyles","full","alignLeft","alignCenter","alignRight","defaultIcons","center","normalizeImageStyles","configuredStyles","_normalizeStyle","extendedStyle","modelToViewConverter","newStyle","oldStyle","modelToViewStyleAttribute","filteredStyles","viewFigureElement","modelImageElement","viewToModelStyleAttribute","translatedStyles","translateStyles","localizedDefaultStylesTitles","componentName","createImageTypeRegExp","regExpSafeNames","fetchLocalImage","imageSrc","fetch","resource","blob","mimeType","getImageMimeType","File","canvas","drawImage","toBlob","getBlobFromCanvas","convertLocalImageOnCanvas","componentCreator","imageTypes","imageTypesRegExp","acceptedType","allowMultipleFiles","imagesToUpload","uploadStatusChange","uploadId","fileRepository","viewFigure","_startAppearEffect","_showPlaceholder","_hidePlaceholder","progressBar","_createProgressBar","_showProgressBar","viewImg","_displayLocalImage","completeIcon","_showCompleteIcon","_removeUIElement","_hideProgressBar","_stopAppearEffect","_getUIElement","_createPlaceholder","imageFigure","uniqueProperty","DataTransfer","nativeDataTransfer","kind","getAsFile","getFiles","_native","setData","effectAllowed","dropEffect","mozUserCancelled","handleInput","targetRanges","dropRange","dataTransfer","clipboardData","domDoc","clientX","clientY","caretRangeFromPoint","rangeParent","rangeOffset","getDropViewRange","smallPaddingElements","_setupPasteDrop","_setupCopyCut","fullMatch","spaces","modelFragment","modelDocument","onCopyCut","viewToPlainText","childText","_draggedRange","_draggingUid","_draggableElement","_updateDropMarkerThrottled","targetRange","_updateDropMarker","_removeDropMarkerDelayed","delay","_removeDropMarker","_clearDraggableAttributesDelayed","_clearDraggableAttributes","_setupDragging","_setupContentInsertionIntegration","_setupClipboardInputIntegration","_setupDropMarker","_setupDraggableAttributeHandling","_finalizeDragging","draggableWidget","findDraggableWidget","draggedSelection","isCanceled","findDropTargetRange","getFinalDropEffect","clipboardPipeline","isMove","isSuccess","draggableElement","markerToHighlight","markerToElement","removeMarker","moved","targetViewRanges","targetViewElement","targetViewPosition","findDropTargetRangeOnWidget","targetModelElement","getClosestMappedModelElement","targetModelPosition","positionAtElementStart","findDropTargetRangeBetweenBlocks","findDropTargetRangeOnAncestorObject","findDropTargetRangeInElement","timer","delayed","shiftPressed","isPlainTextFragment","textAttributes","isImage","uploadImage","createLoader","uploadImageCommand","images","fetchableImages","isLocalImage","fetchableImage","isInGraveyard","getImagesFromChangeItem","_readAndUpload","urls","_parseAndSetSrcsetAttributeOnImage","notification","domFigure","originalDisplay","_ckHack","clean","showWarning","destroyLoader","srcsetAttribute","isNaN","resizeUnit","resizeOptions","resizeImageCommand","_registerSchema","_registerConverters","RESIZE_ICONS","small","medium","large","original","_resizeUnit","_registerImageResizeButton","_registerImageResizeDropdown","optionValueWithUnit","labelText","_getOptionLabelValue","getIsOnButtonCallback","originalSizeOption","dropdownButton","_getResizeDropdownListItemDefinitions","forTooltip","_setupResizerCreator","widgetView","imageModel","domWidgetElement","imageStyle","_definitions","linkInImage","reHasUnicode","rsAstral","rsCombo","rsFitz","rsNonAstral","rsRegional","rsSurrPair","reOptMod","rsSeq","rsSymbol","reUnicode","strSymbols","chr","ATTRIBUTE_WHITESPACES","SAFE_URL","EMAIL_REG_EXP","PROTOCOL_REG_EXP","createLinkElement","href","linkElement","ensureSafeUrl","isSafeUrl","addLinkProtocolIfApplicable","link","defaultProtocol","protocol","isProtocolNeeded","manualDecorators","automaticDecorators","manualDecorator","_getDecoratorStateFromModel","manualDecoratorIds","truthyManualDecorators","falsyManualDecorators","linkRange","allowedRanges","rangesToUpdate","_isRangeToUpdate","decoratorName","allowedRange","linkCommand","rangesToUnlink","ManualDecorator","EXTERNAL_LINKS_REGEXP","addTargetToExternalLinks","linkDecorators","decorators","localizedDecoratorsLabels","decorator","getLocalizedDecorators","retArray","normalizeDecorators","_enableAutomaticDecorators","_enableManualDecorators","_enableInsertContentSelectionAttributesFixer","_enableClickingAfterLink","_enableTypingOverLink","_handleDeleteContentAfterLink","automaticDecoratorDefinitions","rel","getDispatcher","manualDecoratorDefinitions","manualDecoratorName","removeLinkAttributesFromSelection","clicked","selectionAttributes","deletedContent","isTyping","firstPosition","lastPosition","nodeAtFirstPosition","nodeAtLastPosition","shouldCopyAttributes","shouldPreserveAttributes","hasBackspacePressed","linkHref","isInput","urlInputView","_createUrlInput","_manualDecoratorSwitches","_createManualDecoratorSwitches","_createFormChildren","accumulator","switchButton","switches","decoratorValue","additionalButtonsView","previewButtonView","_createPreviewButton","unlinkButtonView","editButtonView","actionsView","_createActionsView","formView","_createFormView","_createToolbarLinkButton","_enableUserBalloonInteractions","unlinkCommand","_addFormView","_hideUI","parsedUrl","getDecoratorSwitchesState","_closeFormView","_showUI","_getSelectedLinkElement","_areActionsVisible","_isUIVisible","_isUIInPanel","_areActionsInPanel","_isFormInPanel","restoreManualDecoratorStates","_removeFormView","_hideFakeVisualSelection","forceVisible","_addActionsView","_showFakeVisualSelection","_startUpdatingUI","prevSelectedLink","prevSelectionParent","getSelectionParent","selectedLink","markerViewElements","targetLink","findLinkElementAncestor","startLink","endLink","isLinkElement","URL_REG_EXP","_enableTypingHandling","_enableEnterHandling","_enableShiftEnterHandling","watcher","isSingleSpaceAtTheEnd","getUrlAtTextEnd","linkEnd","linkStart","_applyAutoLink","_checkAndApplyAutoLinkOnRange","shiftEnterCommand","isLinkAllowedOnRange","checkCanBecomeListItem","turnOff","currentIndent","indent","newIndent","listIndent","lowestIndent","_fixType","listType","listItem","startingItem","indentDirection","_indentBy","itemsToChange","lastItem","generateLiInUl","getListItemFillerOffset","createViewListItemElement","viewList","injectViewList","injectedItem","injectedList","refItem","getSiblingListItem","sameIndent","smallerIndent","prevItem","breakContainer","mappedViewAncestor","nestedList","findNestedList","positionAfterUiElements","prevView","breakPosition","mergeViewLists","nextViewList","lastSubChild","modelChild","firstList","secondList","mergeContainers","itemIndent","createUIComponent","getSiblingNodes","walkerOptions","limitIndent","hasOnlyLists","modelViewInsertion","modelViewChangeType","listName","modelViewMergeAfterChangeType","modelViewSplitOnInsert","removeStart","removeEnd","previousList","mergePos","modelViewMergeAfter","viewItemPrev","viewItemNext","viewModelConverter","getIndent","listItemModel","convertedChild","findNextListItem","viewToModelListItemChildrenConverter","cleanList","isList","cleanListItem","foundList","trimStart","trimEnd","modelToViewPosition","topmostViewList","modelIndentPasteFixer","indentChange","hoistNestedLists","nextIndent","modelRemoveStartPosition","viewRemoveStartPosition","viewRemovedItem","prevModelItem","foo","prevIndent","prevViewList","itemToListHead","applied","_addListToFix","innerItem","listHead","_fixListIndents","_fixListTypes","maxIndent","fixBy","typesStack","modelChangePostFixer","registerViewToModelLength","getViewListItemLength","modelNode","modelLength","viewListPrev","modelViewChangeIndent","modelViewRemove","getCommandExecuter","outdent","registerChildCommand","defaultType","_defaultType","listItems","numberedList","bulletedList","changedItems","rootIndent","itemsToUpdate","fixListAfterIndentListCommand","fixListAfterOutdentListCommand","restoreDefaultListStyle","insertedListItems","getChangedListItems","existingListItem","shouldInheritListTypeFromPreviousItem","shouldInheritListType","fixListStyleAttributeOnListItemElements","listStyle","currentElement","previousElement","listItem1","listItem2","_mergeListStyleAttributeWhileMergingLists","todoListItems","removeListStyleAttributeFromTodoList","firstMostOuterItem","mostOuterItemList","secondListMostOuterItem","baseItem","itemToChange","baseListStyle","previousItem","previousItemIndent","previousItemListStyle","getItemFromChange","getSplitButtonCreator","parentCommandName","buttonLabel","buttonIcon","toolbarAriaLabel","styleDefinitions","parentCommand","listStyleCommand","splitButtonView","styleButtonCreator","getStyleButtonCreator","_selectedElements","_getSelectedItems","dataViewModelCheckmarkInsertion","mapModelToViewPosition","descSpan","findDescription","createCheckmarkElement","isChecked","onChange","contenteditable","checkbox","ITEM_TOGGLE_KEYSTROKE","addAttributeCheck","checkTodoListCommand","onCheckedChange","disabled","dataModelViewInsertion","onCheckboxChecked","checkmarkElement","_handleCheckmarkChange","labelElement","findLabel","descriptionStart","descriptionEnd","descriptionRange","descriptionSpan","oldCheckmarkElement","newCheckmarkElement","modelViewChangeChecked","jumpOverCheckmarkOnSideArrowKeyPress","listItemsToFix","previousSelectionRanges","transformListItemLikeElementsIntoLists","itemLikeElements","itemLikeElementsMatcher","itemData","getListItemData","order","findAllItemLikeElements","currentList","currentIndentation","itemLikeElement","isDifferentList","currentItem","isNewListNeeded","previousItemLikeElement","indentationDifference","listLikeItem","listStyleRegexp","listStyleTypeRegex","listStyleMatch","listStyleType","listStyleTypeMatch","bulletedStyle","listMarkerElement","textNodeOrElement","findListMarkerNode","listMarker","findBulletedListStyle","mapListStyleDefinition","detectListStyle","lastListItem","lastListItemChild","insertNewEmptyList","differentIndentation","listElement","parentList","levelChange","findParentListAtLevel","bulletMatcher","removeBulletElement","transformElementIntoListItem","idMatch","orderMatch","indentMatch","googleDocsMatch","htmlString","removeBoldWrapper","unwrapParagraphInListItem","normalizeSafariSpaceSpans","parseHtml","domParser","normalizedHtml","normalizeSpacing","bodyCloseIndex","htmlCloseIndex","cleanContentAfterBody","htmlDocument","innerTextLength","innerText","normalizeSpacerunSpans","bodyString","bodyView","documentToView","styleTags","getElementsByTagName","sheet","cssRules","extractStyles","replaceImagesSourceWithBase64","rtfData","upcastWriter","shapesIds","imageElementsMatcher","imgs","shapes","shape","removeAllImgElementsRepresentingShapes","shapeElementsMatcher","prevSiblingName","findAllShapesIds","removeAllShapeElements","findAllImageElementsWithLocalSource","imageElements","imagesHexSources","newSrc","hexString","hex","replaceImagesFileSourceWithInlineRepresentation","regexPictureHeader","regexPicture","imageType","extractImageDataFromRtf","msWordMatch1","msWordMatch2","updateNumericAttribute","createEmptyTableCell","tableCell","isHeadingColumnCell","tableUtils","table","headingColumns","column","getCellLocation","upcastTable","viewTable","rows","headingRows","tableMeta","headRows","bodyRows","firstTheadElement","tableChild","trs","tr","headingCols","scanRowForHeadingColumns","scanTable","row","ensureParagraphInTableCell","th","TableWalker","_table","_startRow","startRow","_endRow","endRow","_startColumn","startColumn","_endColumn","endColumn","_includeAllSlots","includeAllSlots","_skipRows","_row","_column","_cellIndex","_spannedCells","_nextCellAtColumn","_isOverEndRow","_isOverEndColumn","_advanceToNextRow","outValue","spanData","_getSpanned","_shouldSkipSlot","_formatOutValue","cell","colspan","rowspan","_recordSpans","anchorRow","anchorColumn","TableSlot","rowIsMarkedAsSkipped","rowIsBeforeStartRow","columnIsBeforeStartColumn","columnIsAfterEndColumn","rowMap","rowToUpdate","columnToUpdate","_markSpannedCell","tableWalker","cellAnchorRow","cellAnchorColumn","downcastInsertTable","asWidget","figureElement","tableElement","tableWidget","tableAttributes","viewRows","tableSlot","tableRow","trElement","createTr","createViewTableCellElement","rowIndex","convertParagraphInTableCell","isSingleParagraphWithoutAttributes","renameViewTableCellIfRequired","desiredCellElementName","getCellElementName","viewCell","renamedCell","renameViewTableCell","cellElementName","cellElement","isSingleParagraph","innerParagraph","tableSection","sectionName","viewTableSection","getExistingTableSectionElement","tableChildElement","createTableSection","getOrCreateTableSection","getSectionName","removeTableSectionIfEmpty","validParent","isAllowedInParent","createTable","getSelectedTableCells","cells","sortRanges","getTableCellsContainingSelection","cellWithSelection","getSelectionAffectedTableCells","selectedCells","getRowIndexes","tableCells","getFirstLastIndexesObject","getColumnIndexes","isSelectionRectangular","selectedTableCells","rowIndexes","areIndexesInSameSection","areCellInTheSameTableSection","areaOfSelectedCells","rowsIndexes","columnIndexes","lastRow","firstRow","lastColumn","firstColumn","getBiggestRectangleArea","compareRangeOrder","indexes","allIndexesSorted","indexA","posA","posB","headingSectionSize","tableParent","insertAbove","affectedTableCells","insertRows","at","copyStructureFromAbove","insertColumns","isHorizontal","splitCellHorizontally","splitCellVertically","cropTableToDimensions","sourceTable","cropDimensions","croppedTable","cropHeight","tableMap","sourceRow","sourceColumn","isAnchor","rowInCroppedTable","tableCellCopy","trimTableCellIfNeeded","addHeadingsToCroppedTable","getVerticallyOverlappingCells","overlapRow","slotInfo","cellHeight","cellEndRow","splitHorizontally","splitRow","newRowspan","newCellAttributes","newCellRowSpan","columnIndex","newCell","getPositionBefore","getHorizontallyOverlappingCells","overlapColumn","cellsToSplit","cellWidth","cellEndColumn","splitVertically","splitColumn","newColspan","newCellColSpan","cellRow","cellColumn","limitRow","limitColumn","removeEmptyColumns","getColumns","columnsMap","emptyColumns","cellsCount","emptyColumn","removeColumns","removeEmptyRows","emptyRows","emptyRow","removeRows","removeEmptyRowsColumns","adjustLastRowIndex","dimensions","lastRowMap","rowspanAdjustment","adjustLastColumnIndex","lastColumnMap","colspanAdjustment","cellToMerge","_getMergeableCell","isMergeNext","cellToExpand","cellToRemove","removedTableCellRow","mergeTableCells","spanAttribute","cellSpan","cellToMergeSpan","horizontalCell","hasHeadingColumns","cellOnLeft","cellOnRight","leftCellColumn","rightCellColumn","leftCellSpan","isCellOnLeftInHeadingColumn","isCellOnRightInHeadingColumn","getHorizontalCell","isMergeWithBodyCell","isMergeWithHeadCell","currentCellRowSpan","rowOfCellToMerge","mergeColumn","cellToMergeData","getVerticalCell","firstCell","lastRowIndex","getRows","selectedRowIndexes","areAllRowsSelected","referenceCells","removedRowIndexes","columnIndexToFocus","rowsToRemove","cellToFocus","removedRowIndex","columnToFocus","getCellToFocus","tableColumnCount","lastCell","returnValue","getBoundaryCells","removedColumnIndexes","columnsToRemove","isInTable","_isInHeading","headingRowsToSet","currentHeadingRows","overlappingCells","headingColumnsToSet","createEmptyRows","insertAt","rowsToInsert","isCopyStructure","copyStructureFrom","walkerEndRow","tableIterator","rowColSpansMap","lastCellRow","isReferenceRow","cellIndex","columnsToInsert","tableColumns","createCells","skipRow","cellsToMove","cellsToTrim","lastRowOfCell","rowSpanToSet","getCellsToMoveAndTrimOnRemoveRow","targetRowIndex","tableRowMap","previousCell","cellToMove","moveCellsToRow","updateHeadingRows","headingsRemoved","adjustHeadingColumns","removedColumnIndex","numberOfCells","newCellsSpan","updatedSpan","breakSpanEvenly","newCellsAttributes","cellsToInsert","splitCellColumn","cellsToUpdate","splitCellRow","isOnSameColumn","isInEvenlySplitRow","rowspanToSet","tableCellToInsert","floor","firstTableCell","mergeWidth","mergeHeight","maxWidthOffset","maxHeightOffset","getMaxOffset","firstCellRow","firstCellColumn","getMergeDimensions","cellBeingMerged","targetCell","currentMaxOffset","dimensionValue","rangesToSelect","startLocation","endLocation","cellInfo","injectTableLayoutPostFixer","analyzedTables","isTableAttributeEntry","fixTableCellsRowspan","fixTableRowsSizes","tableLayoutPostFixer","maxRows","rowLimit","findCellsToTrim","rowsLengths","lengths","getRowsLengths","tableSize","maxColumns","isAttributeType","injectTableCellParagraphPostFixer","fixTable","fixTableRow","fixTableCellContent","checkTableCellChange","tableCellContentsPostFixer","textNodes","injectTableCellRefreshPostFixer","cellsToCheck","shouldRefresh","refreshItem","tableCellRefreshPostFixer","injectTableHeadingRowsRefreshPostFixer","tablesToRefresh","tableHeadingRowsRefreshPostFixer","getViewTable","oldColumns","newColumns","lastColumnToCheck","_createGridCollection","_highlightGridBoxes","boxView","boxes","isContentLtr","insertTableView","bindIsOn","_prepareDropdown","_prepareMergeSplitButtonDropdown","_fillDropdownWithListOptions","addListOption","_handleDeleteContent","_defineSelectionConverter","_enablePluginDisabling","adjustedLastRow","adjustedLastColumn","anchorCell","cellsToSelect","_getCellsToSelect","highlighted","previouslyHighlighted","clearHighlightedTableCells","lastViewCell","tableCellToSelect","rangeToSelect","selectionMap","flipVertically","flipHorizontally","_onCopyCut","_onInsertContent","tableSelection","dataController","getSelectionAsFragment","pastedTable","contentRange","rangeBefore","rangeAfter","getTableIfOnlyTableInContent","pastedDimensions","selectedTable","shouldExpandSelection","expectedHeight","expectedWidth","tableWidth","tableHeight","expandTableSize","doVerticalSplit","doHorizontalSplit","splitCellsToRectangularSelection","prepareTableForPasting","selectionHeight","selectionWidth","_replaceSelectedCellsWithPasted","selectionRanges","pastedWidth","pastedHeight","pastedTableLocationMap","createLocationMap","selectedTableMap","pastedRow","pastedColumn","pastedCell","cellToInsert","newTableCell","_replaceTableSlotCell","areHeadingRowsIntersectingSelection","areHeadingColumnsIntersectingSelection","newCells","limitColumns","isAffectedBySelection","limitRows","endIndex","_handleTabOnSelectedTable","_getTabHandler","_onArrowKey","getFocusCell","currentRowIndex","currentCellIndex","isFirstCellInRow","isLastCellInRow","isLastRow","nextRow","previousRow","_handleArrowKeys","focusCell","_navigateFromCellInDirection","_isSelectionAtCellEdge","currentCellInfo","cellToSelect","getAnchorCell","setCellSelection","positionToSelect","_enableShiftClickSelection","_enableMouseDragSelection","blockSelectionChange","_getModelTableCellFromDomEvent","haveSameTableParent","beganCellSelection","newTargetCell","viewTargetElement","cellA","cellB","getSelectedTableWidget","isTableWidget","getTableWidgetAncestor","parentTable","positionOrElement","upcastStyleToAttribute","getNormalizedStyle","upcastBorderStyles","stylesToConsume","matcherPattern","downcastAttributeToStyle","downcastTableAttribute","_getValueToSet","getSingleValue","objectOrString","addDefaultUnitToNumericValue","defaultUnit","numericValue","ALIGN_VALUES_REG_EXP","addStyleProcessorRules","enableBorderProperties","float","align","enableAlignmentProperty","enableTableToFigureProperty","enableProperty","_dropdownView","_createDropdownView","_inputView","_createInputTextView","_stillTyping","inputValue","_setInputValue","colorGrid","_createColorGrid","colorPreview","removeColorButton","_createRemoveColorButton","blur","mappedColor","normalizedInputValue","normalizeColor","colorString","getBorderStyleLabels","none","solid","dotted","dashed","double","groove","ridge","inset","outset","getLocalizedColorErrorText","getLocalizedLengthErrorText","colorFieldValidator","lengthFieldValidator","isNumberString","lineWidthFieldValidator","getBorderStyleDefinitions","styleLabels","_borderStyleValue","fillToolbar","icons","labels","nameToValue","defaultColors","getLabeledColorInputCreator","colorConfig","parsedValue","_role","_ariaLabelledBy","ALIGNMENT_ICONS","borderStyle","borderWidth","borderColor","alignment","borderStyleDropdown","borderWidthInput","borderColorInput","borderRowLabel","_createBorderFields","backgroundRowLabel","backgroundInput","_createBackgroundFields","widthInput","operatorLabel","heightInput","dimensionsLabel","_createDimensionFields","alignmentToolbar","alignmentLabel","_createAlignmentFields","_createActionButtons","colorInputCreator","borderColors","isBorderStyleSet","backgroundInputCreator","backgroundColors","isCompact","_alignmentLabels","fieldsThatShouldValidateToSave","errorTexts","DEFAULT_BALLOON_POSITIONS","BALLOON_POSITIONS","TABLE_PROPERTIES_BALLOON_POSITIONS","getBalloonCellPositionData","getBalloonTablePositionData","modelTable","modelTableCell","getTableCellAtPosition","viewTableCell","createBoundingRect","propertyToCommandMap","_createPropertiesView","_undoStepBatch","isCommandEnabled","borderColorsConfig","localizedBorderColors","backgroundColorsConfig","localizedBackgroundColors","_hideView","_isViewInBalloon","colorErrorText","lengthErrorText","_getPropertyChangeCallback","_getValidatedPropertyChangeCallback","viewField","validator","_updateView","_fillViewFormFromCommandValues","_isViewVisible","setErrorTextDebounced","justify","middle","padding","horizontalAlignment","verticalAlignment","horizontalAlignmentToolbar","verticalAlignmentToolbar","paddingInput","_createPaddingField","isContentRTL","_horizontalAlignmentLabels","_verticalAlignmentLabels","_getSingleValue","firstCellValue","_getAttribute","VALIGN_VALUES_REG_EXP","enableHorizontalAlignmentProperty","valign","enableVerticalAlignmentProperty","heading1","heading2","heading3","heading4","heading5","heading6","colors","removeButtonLabel","documentColorsLabel","documentColorsCount","documentColors","_documentColorsLabel","_removeColorButton","maxCount","_addColorToDocumentColors","documentColorsGrid","staticColorsGrid","_createStaticColorsGrid","_createDocumentColorsGrid","colorObj","predefinedColor","buildDefinition","modelAttributeKey","renderUpcastAttribute","styleAttr","renderDowncastElement","normalizeOptions","configuredOptions","getOptionDefinition","fontDefinition","fontNames","firstFontName","cssFontNames","normalizeFontNameForCSS","generateFontPreset","fontName","supportAllValues","_prepareAnyValueConverters","_prepareCompatibilityConverter","_getLocalizedOptions","commandParam","_prepareListOptions","attachPriority","preset","namedPresets","findPreset","numberValue","isNumericalDefinition","generatePixelPreset","styleFontSize","presets","isRelative","maxSize","clampedSize","Default","Tiny","Small","Big","Huge","dropdownLabel","colorTableView","localizedColors","addColorTableToDropdown","appendGrids","updateDocumentColors","updateSelectedColors","getNormalizedAndLocalizedLanguageDefinitions","languageDefs","getPropertyAssociation","association","getLeadingWhiteSpaces","getIndentOutdentPositions","leadingWhiteSpaces","isModelSelectionInCodeBlock","firstLanguageInConfig","_applyCodeBlock","_removeCodeBlock","canBeCodeBlock","allowedBlocks","currentBlock","codeBlocks","_indentSequence","getLastOutdentableSequenceRange","nodeAtPosition","getCodeLineTextNodeAtPosition","lastIndexOfSequence","modelToViewCodeBlockInsertion","useLabels","languagesToClasses","languagesToLabels","codeBlockLanguage","preAttributes","spellcheck","pre","languages","indentSequence","normalizedLanguagesDefs","modelToDataViewSoftBreakInsertion","classesToLanguages","defaultLanguageName","viewCodeElement","viewPreElement","codeBlock","viewChildClasses","dataViewToModelCodeBlockInsertion","textLines","lastLine","softBreak","insertionRange","line","lineIndex","rawSnippetTextToViewDocumentFragment","docFragment","newDocumentFragment","isSoftEnter","modelDoc","lastSelectionPosition","newBlock","leaveBlockStartOnEnter","emptyLineRangeToRemoveOnEnter","leaveBlockEndOnEnter","breakLineOnEnter","normalizedLanguageDefs","defaultLanguageDefinition","_codeBlockLanguage","_getLanguageListItemDefinitions","languageDef","mentionData","mention","mentionID","mentionText","_addMentionAttributes","_text","currentAttributes","attributesWithMention","_toMentionAttribute","createViewMentionElement","preventPartialMentionDowncast","wasChanged","nodeAfterInsertedTextNode","checkAndFix","insertedNode","nodeAfterInserted","removePartialMentionPostFixer","isBrokenMentionNode","extendAttributeOnMentionPostFixer","shouldNotTypeWithMentionAt","selectionMentionAttributePostFixer","baseMentionData","viewElementOrMention","dataMention","selected","indexToGet","highlight","_isItemVisibleInScrolledArea","handledKeyCodes","_mentionsView","_createMentionView","_mentionsConfigurations","_requestFeedDebounced","_requestFeed","feeds","_hideUIAndRemoveMarker","selectNext","selectPrevious","executeSelected","mentionDescription","feed","isValidMentionMarker","minimumCharacters","feedCallback","createFeedCallback","_setupTextWatcherForFeed","itemRenderer","_handleFeedResponse","mentionsView","_renderItem","mentionMarker","getStart","feedText","_lastRequested","feedResponse","createRegExp","createTestCallback","hasMention","hasExistingMention","requestFeedText","matchedTextLength","checkIfStillInCompletionMode","mentionCommand","feedItem","_showOrUpdateUI","markerMarker","_getBalloonPanelPositionData","selectFirst","_getItemRenderer","renderResult","preferredPosition","getBalloonPanelPositions","caret_se","caret_sw","caret_ne","caret_nw","numberOfCharacters","openAfterCharacters","feedItems","localizedIndentIcon","localizedOutdentIcon","_defineButton","indentBehavior","_indentBehavior","checkEnabled","blocksToChange","getBlocksToChange","getNextIndent","IndentUsingOffset","indentAttributeValue","currentOffset","offsetToSet","IndentUsingClasses","indexStep","DEFAULT_ELEMENTS","scopeElement","isSelectAllScope","SELECT_ALL_KEYSTROKE","getInsertHorizontalLineParent","isHorizontalLineAllowedInParent","isHorizontalLineAllowed","horizontalElement","nextElement","viewWrapper","viewHrElement","toHorizontalLineWidget","_createdBatches","clearStack","docSelection","transformedRangeGroups","getTransformedByOperations","allRanges","rangeGroup","isRangeContainedByAnyOtherRange","normalizeRanges","batchToUndo","undoingBatch","operationsToUndo","operationToUndo","nextBaseVersion","historyOperations","getOperations","reversedOperations","setOperationAsUndone","joinedRange","getJoined","batchIndex","_undo","_restoreSelection","redoingBatch","_batchRegistry","_undoCommand","_redoCommand","isRedoBatch","isUndoBatch","addBatch","undoneBatch","localizedUndoIcon","undo","redo","localizedRedoIcon","_addButton","Icon","_getFormattingItems","_getFormattingAttributes","itemHasRemovableFormatting","curRange","attributeProperties","editorEl","getDomRoot","glob","getComponentByEl","createNoteForReferenceLink","noteTitle","notePath","insertReference","getHeaders","headers","noteId","getActiveTabNote","headerName","setRequestHeader","_defineSchema","_defineConverters","modelWriter","boxSize","section","includedNoteWrapper","loadIncludedNote","$","stopEventPropagationAndHackRendererFocus","preventCKEditorHandling","triggerCommand","treeCache","getNote","referenceLinkView","noteTitleView","loadReferenceLinkTitle","note","getNoteFromCache","hasDelimiters","extractDelimiters","equation","hasInlineDelimiters","hasDisplayDelimiters","async","renderEquation","engine","lazyLoad","preview","previewUid","previewClassName","MathJax","selectRenderMode","cb","promiseFunction","tex2chtmlPromise","tex2svgPromise","renderMathJax3","moveAndScaleElement","visibility","Hub","Queue","renderMathJax2","katex","throwOnError","displayMode","CKEDITOR_MATH_LAZY_LOAD","previewEl","getElementById","ticking","renderTransformation","requestAnimationFrame","moveElement","getPreviewElement","createPreviewElement","domRect","zIndex","pointerEvents","InputView","inputUid","_createInputView","updateMath","previewEnabled","popupClassName","_createKeyAndFocusTrackers","mathInputView","_createMathInput","displayButtonView","_createDisplayButton","previewLabel","mathView","mathInput","equationInput","params","outputType","forceOutputType","mathtex","typeAttr","selectedEquation","getSelectedMathModelWidget","enablePreview","mathConfig","createMathtexEditingView","mathtexView","createMathtexView","_previewUid","_createToolbarMathButton","mathCommand","_timeoutId","_positionToInsert","leftLivePosition","rightLivePosition","_mathBetweenPositions","leftPosition","rightPosition","equationRange","delimitersCounts","innerWriter","mathElement","_addListAutoformats","_addBasicStylesAutoformats","_addHeadingAutoformats","_addBlockQuoteAutoformats","_addCodeBlockAutoformats","_addHorizontalLineAutoformats","boldCallback","italicCallback","codeCallback","strikethroughCallback","level","normalizers","isTransformedWithPasteFromOffice","activeNormalizer","isActive","tableContentToolbarItems","tableToolbarItems","useOffsetConfig","indentConfig","outdentConfig","_setupConversionUsingOffset","_setupConversionUsingClasses","indentCommand","outdentCommand","isRegistered","marginProperty","_blockToolbarConfig","_createPanelView","_hidePanel","_updateButton","_getToolbarMaxWidth","_showPanel","_hideButton","modelTarget","_attachButtonToElement","wasVisible","contentStyles","editableRect","contentPaddingTop","paddingTop","contentLineHeight","lineHeight","fontSize","importMarkdownInline","htmlDataProcessor","cutToNote","getSelectedHtml","removeSelection","component","include","_enableTransformationWatchers","normalizedTransformations","extra","isNotRemoved","transformation","definitions","definedTransformations","transformationOrGroup","expandGroupsAndRemoveDuplicates","normalizeTransformations","normalizedTransformation","replaces","matchedRange","changeIndex","replaceWith","replacePosition","replaceRange","blockToolbar","contentToolbar"],"mappings":"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","file":"ckeditor.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"BalloonEditor\"] = factory();\n\telse\n\t\troot[\"BalloonEditor\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 136);\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 utils/ckeditorerror\n */\n\n/* globals console */\n\n/**\n * URL to the documentation with error codes.\n */\nexport const DOCUMENTATION_URL =\n\t'https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html';\n\n/**\n * The CKEditor error class.\n *\n * You should throw `CKEditorError` when:\n *\n * * An unexpected situation occurred and the editor (most probably) will not work properly. Such exception will be handled\n * by the {@link module:watchdog/watchdog~Watchdog watchdog} (if it is integrated),\n * * If the editor is incorrectly integrated or the editor API is used in the wrong way. This way you will give\n * feedback to the developer as soon as possible. Keep in mind that for common integration issues which should not\n * stop editor initialization (like missing upload adapter, wrong name of a toolbar component) we use\n * {@link module:utils/ckeditorerror~logWarning `logWarning()`} and\n * {@link module:utils/ckeditorerror~logError `logError()`}\n * to improve developers experience and let them see the a working editor as soon as possible.\n *\n *\t\t/**\n *\t\t * Error thrown when a plugin cannot be loaded due to JavaScript errors, lack of plugins with a given name, etc.\n *\t\t *\n *\t\t * @error plugin-load\n *\t\t * @param pluginName The name of the plugin that could not be loaded.\n *\t\t * @param moduleName The name of the module which tried to load this plugin.\n *\t\t * /\n *\t\tthrow new CKEditorError( 'plugin-load', {\n *\t\t\tpluginName: 'foo',\n *\t\t\tmoduleName: 'bar'\n *\t\t} );\n *\n * @extends Error\n */\nexport default class CKEditorError extends Error {\n\t/**\n\t * Creates an instance of the CKEditorError class.\n\t *\n\t * @param {String} errorName The error id in an `error-name` format. A link to this error documentation page will be added\n\t * to the thrown error's `message`.\n\t * @param {Object|null} context A context of the error by which the {@link module:watchdog/watchdog~Watchdog watchdog}\n\t * is able to determine which editor crashed. It should be an editor instance or a property connected to it. It can be also\n\t * a `null` value if the editor should not be restarted in case of the error (e.g. during the editor initialization).\n\t * The error context should be checked using the `areConnectedThroughProperties( editor, context )` utility\n\t * to check if the object works as the context.\n\t * @param {Object} [data] Additional data describing the error. A stringified version of this object\n\t * will be appended to the error message, so the data are quickly visible in the console. The original\n\t * data object will also be later available under the {@link #data} property.\n\t */\n\tconstructor( errorName, context, data ) {\n\t\tconst message = `${ errorName }${ ( data ? ` ${ JSON.stringify( data ) }` : '' ) }${ getLinkToDocumentationMessage( errorName ) }`;\n\n\t\tsuper( message );\n\n\t\t/**\n\t\t * @type {String}\n\t\t */\n\t\tthis.name = 'CKEditorError';\n\n\t\t/**\n\t\t * A context of the error by which the Watchdog is able to determine which editor crashed.\n\t\t *\n\t\t * @type {Object|null}\n\t\t */\n\t\tthis.context = context;\n\n\t\t/**\n\t\t * The additional error data passed to the constructor. Undefined if none was passed.\n\t\t *\n\t\t * @type {Object|undefined}\n\t\t */\n\t\tthis.data = data;\n\t}\n\n\t/**\n\t * Checks if the error is of the `CKEditorError` type.\n\t */\n\tis( type ) {\n\t\treturn type === 'CKEditorError';\n\t}\n\n\t/**\n\t * A utility that ensures that the thrown error is a {@link module:utils/ckeditorerror~CKEditorError} one.\n\t * It is useful when combined with the {@link module:watchdog/watchdog~Watchdog} feature, which can restart the editor in case\n\t * of a {@link module:utils/ckeditorerror~CKEditorError} error.\n\t *\n\t * @static\n\t * @param {Error} err The error to rethrow.\n\t * @param {Object} context An object connected through properties with the editor instance. This context will be used\n\t * by the watchdog to verify which editor should be restarted.\n\t */\n\tstatic rethrowUnexpectedError( err, context ) {\n\t\tif ( err.is && err.is( 'CKEditorError' ) ) {\n\t\t\tthrow err;\n\t\t}\n\n\t\t/**\n\t\t * An unexpected error occurred inside the CKEditor 5 codebase. This error will look like the original one\n\t\t * to make the debugging easier.\n\t\t *\n\t\t * This error is only useful when the editor is initialized using the {@link module:watchdog/watchdog~Watchdog} feature.\n\t\t * In case of such error (or any {@link module:utils/ckeditorerror~CKEditorError} error) the watchdog should restart the editor.\n\t\t *\n\t\t * @error unexpected-error\n\t\t */\n\t\tconst error = new CKEditorError( err.message, context );\n\n\t\t// Restore the original stack trace to make the error look like the original one.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/5595 for more details.\n\t\terror.stack = err.stack;\n\n\t\tthrow error;\n\t}\n}\n\n/**\n * Logs a warning to the console with a properly formatted message and adds a link to the documentation.\n * Use whenever you want to log a warning to the console.\n *\n *\t\t/**\n *\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n *\t\t * name does not exist, so it was omitted when rendering the toolbar.\n *\t\t *\n *\t\t * @error toolbarview-item-unavailable\n *\t\t * @param {String} name The name of the component.\n *\t\t * /\n *\t\tlogWarning( 'toolbarview-item-unavailable', { name } );\n *\n * See also {@link module:utils/ckeditorerror~CKEditorError} for an explanation when to throw an error and when to log\n * a warning or an error to the console.\n *\n * @param {String} errorName The error name to be logged.\n * @param {Object} [data] Additional data to be logged.\n * @returns {String}\n */\nexport function logWarning( errorName, data ) {\n\tconsole.warn( ...formatConsoleArguments( errorName, data ) );\n}\n\n/**\n * Logs an error to the console with a properly formatted message and adds a link to the documentation.\n * Use whenever you want to log an error to the console.\n *\n *\t\t/**\n *\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n *\t\t * name does not exist, so it was omitted when rendering the toolbar.\n *\t\t *\n *\t\t * @error toolbarview-item-unavailable\n *\t\t * @param {String} name The name of the component.\n *\t\t * /\n *\t\t logError( 'toolbarview-item-unavailable', { name } );\n *\n * **Note**: In most cases logging a warning using {@link module:utils/ckeditorerror~logWarning} is enough.\n *\n * See also {@link module:utils/ckeditorerror~CKEditorError} for an explanation when to use each method.\n *\n * @param {String} errorName The error name to be logged.\n * @param {Object} [data] Additional data to be logged.\n * @returns {String}\n */\nexport function logError( errorName, data ) {\n\tconsole.error( ...formatConsoleArguments( errorName, data ) );\n}\n\nfunction getLinkToDocumentationMessage( errorName ) {\n\treturn `\\nRead more: ${ DOCUMENTATION_URL }#error-${ errorName }`;\n}\n\nfunction formatConsoleArguments( errorName, data ) {\n\tconst documentationMessage = getLinkToDocumentationMessage( errorName );\n\n\treturn data ? [ errorName, data, documentationMessage ] : [ errorName, documentationMessage ];\n}\n","\"use strict\";\n\nvar isOldIE = function isOldIE() {\n var memo;\n return function memorize() {\n if (typeof memo === 'undefined') {\n // Test for IE <= 9 as proposed by Browserhacks\n // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805\n // Tests for existence of standard globals is to allow style-loader\n // to operate correctly into non-standard environments\n // @see https://github.com/webpack-contrib/style-loader/issues/177\n memo = Boolean(window && document && document.all && !window.atob);\n }\n\n return memo;\n };\n}();\n\nvar getTarget = function getTarget() {\n var memo = {};\n return function memorize(target) {\n if (typeof memo[target] === 'undefined') {\n var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n\n memo[target] = styleTarget;\n }\n\n return memo[target];\n };\n}();\n\nvar stylesInDom = [];\n\nfunction getIndexByIdentifier(identifier) {\n var result = -1;\n\n for (var i = 0; i < stylesInDom.length; i++) {\n if (stylesInDom[i].identifier === identifier) {\n result = i;\n break;\n }\n }\n\n return result;\n}\n\nfunction modulesToDom(list, options) {\n var idCountMap = {};\n var identifiers = [];\n\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var count = idCountMap[id] || 0;\n var identifier = \"\".concat(id, \" \").concat(count);\n idCountMap[id] = count + 1;\n var index = getIndexByIdentifier(identifier);\n var obj = {\n css: item[1],\n media: item[2],\n sourceMap: item[3]\n };\n\n if (index !== -1) {\n stylesInDom[index].references++;\n stylesInDom[index].updater(obj);\n } else {\n stylesInDom.push({\n identifier: identifier,\n updater: addStyle(obj, options),\n references: 1\n });\n }\n\n identifiers.push(identifier);\n }\n\n return identifiers;\n}\n\nfunction insertStyleElement(options) {\n var style = document.createElement('style');\n var attributes = options.attributes || {};\n\n if (typeof attributes.nonce === 'undefined') {\n var nonce = typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;\n\n if (nonce) {\n attributes.nonce = nonce;\n }\n }\n\n Object.keys(attributes).forEach(function (key) {\n style.setAttribute(key, attributes[key]);\n });\n\n if (typeof options.insert === 'function') {\n options.insert(style);\n } else {\n var target = getTarget(options.insert || 'head');\n\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n\n target.appendChild(style);\n }\n\n return style;\n}\n\nfunction removeStyleElement(style) {\n // istanbul ignore if\n if (style.parentNode === null) {\n return false;\n }\n\n style.parentNode.removeChild(style);\n}\n/* istanbul ignore next */\n\n\nvar replaceText = function replaceText() {\n var textStore = [];\n return function replace(index, replacement) {\n textStore[index] = replacement;\n return textStore.filter(Boolean).join('\\n');\n };\n}();\n\nfunction applyToSingletonTag(style, index, remove, obj) {\n var css = remove ? '' : obj.media ? \"@media \".concat(obj.media, \" {\").concat(obj.css, \"}\") : obj.css; // For old IE\n\n /* istanbul ignore if */\n\n if (style.styleSheet) {\n style.styleSheet.cssText = replaceText(index, css);\n } else {\n var cssNode = document.createTextNode(css);\n var childNodes = style.childNodes;\n\n if (childNodes[index]) {\n style.removeChild(childNodes[index]);\n }\n\n if (childNodes.length) {\n style.insertBefore(cssNode, childNodes[index]);\n } else {\n style.appendChild(cssNode);\n }\n }\n}\n\nfunction applyToTag(style, options, obj) {\n var css = obj.css;\n var media = obj.media;\n var sourceMap = obj.sourceMap;\n\n if (media) {\n style.setAttribute('media', media);\n } else {\n style.removeAttribute('media');\n }\n\n if (sourceMap && typeof btoa !== 'undefined') {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n } // For old IE\n\n /* istanbul ignore if */\n\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n while (style.firstChild) {\n style.removeChild(style.firstChild);\n }\n\n style.appendChild(document.createTextNode(css));\n }\n}\n\nvar singleton = null;\nvar singletonCounter = 0;\n\nfunction addStyle(obj, options) {\n var style;\n var update;\n var remove;\n\n if (options.singleton) {\n var styleIndex = singletonCounter++;\n style = singleton || (singleton = insertStyleElement(options));\n update = applyToSingletonTag.bind(null, style, styleIndex, false);\n remove = applyToSingletonTag.bind(null, style, styleIndex, true);\n } else {\n style = insertStyleElement(options);\n update = applyToTag.bind(null, style, options);\n\n remove = function remove() {\n removeStyleElement(style);\n };\n }\n\n update(obj);\n return function updateStyle(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {\n return;\n }\n\n update(obj = newObj);\n } else {\n remove();\n }\n };\n}\n\nmodule.exports = function (list, options) {\n options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style>\n // tags it will allow on a page\n\n if (!options.singleton && typeof options.singleton !== 'boolean') {\n options.singleton = isOldIE();\n }\n\n list = list || [];\n var lastIdentifiers = modulesToDom(list, options);\n return function update(newList) {\n newList = newList || [];\n\n if (Object.prototype.toString.call(newList) !== '[object Array]') {\n return;\n }\n\n for (var i = 0; i < lastIdentifiers.length; i++) {\n var identifier = lastIdentifiers[i];\n var index = getIndexByIdentifier(identifier);\n stylesInDom[index].references--;\n }\n\n var newLastIdentifiers = modulesToDom(newList, options);\n\n for (var _i = 0; _i < lastIdentifiers.length; _i++) {\n var _identifier = lastIdentifiers[_i];\n\n var _index = getIndexByIdentifier(_identifier);\n\n if (stylesInDom[_index].references === 0) {\n stylesInDom[_index].updater();\n\n stylesInDom.splice(_index, 1);\n }\n }\n\n lastIdentifiers = newLastIdentifiers;\n };\n};","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `self`. */\nvar freeSelf = typeof self == 'object' && self && self.Object === Object && self;\n\n/** Used as a reference to the global object. */\nvar root = freeGlobal || freeSelf || Function('return this')();\n\nexport default root;\n","import root from './_root.js';\nimport stubFalse from './stubFalse.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined;\n\n/**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\nvar isBuffer = nativeIsBuffer || stubFalse;\n\nexport default isBuffer;\n","import freeGlobal from './_freeGlobal.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Detect free variable `process` from Node.js. */\nvar freeProcess = moduleExports && freeGlobal.process;\n\n/** Used to access faster Node.js helpers. */\nvar nodeUtil = (function() {\n try {\n // Use `util.types` for Node.js 10+.\n var types = freeModule && freeModule.require && freeModule.require('util').types;\n\n if (types) {\n return types;\n }\n\n // Legacy `process.binding('util')` for Node.js < 10.\n return freeProcess && freeProcess.binding && freeProcess.binding('util');\n } catch (e) {}\n}());\n\nexport default nodeUtil;\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 utils/version\n */\n\n/* globals window, global */\n\nimport CKEditorError from './ckeditorerror';\n\nconst version = '27.1.0';\n\nexport default version;\n\n/* istanbul ignore next */\nconst windowOrGlobal = typeof window === 'object' ? window : global;\n\n/* istanbul ignore next */\nif ( windowOrGlobal.CKEDITOR_VERSION ) {\n\t/**\n\t * This error is thrown when due to a mistake in how CKEditor 5 was installed or initialized, some\n\t * of its modules were duplicated (evaluated and executed twice). Module duplication leads to inevitable runtime\n\t * errors.\n\t *\n\t * There are many situations in which some modules can be loaded twice. In the worst case scenario,\n\t * you may need to check your project for each of these issues and fix them all.\n\t *\n\t * # Trying to add a plugin to an existing build\n\t *\n\t * If you import an existing CKEditor 5 build and a plugin like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-build-classic';\n\t *\t\timport Highlight from '@ckeditor/ckeditor5-highlight/src/highlight';\n\t *\n\t * Then your project loads some CKEditor 5 packages twice. How does it happen?\n\t *\n\t * The build package contains a file which is already compiled with webpack. This means\n\t * that it contains all the necessary code from e.g. `@ckeditor/ckeditor5-engine` and `@ckeditor/ckeditor5-utils`.\n\t *\n\t * However, the `Highlight` plugin imports some of the modules from these packages, too. If you ask webpack to\n\t * build such a project, you will end up with the modules being included (and run) twice &mdash; first, because they are\n\t * included inside the build package, and second, because they are required by the `Highlight` plugin.\n\t *\n\t * Therefore, **you must never add plugins to an existing build** unless your plugin has no dependencies.\n\t *\n\t * Adding plugins to a build is done by taking the source version of this build (so, before it was built with webpack)\n\t * and adding plugins there. In this situation, webpack will know that it only needs to load each plugin once.\n\t *\n\t * Read more in the {@glink builds/guides/integration/installing-plugins \"Installing plugins\"} guide.\n\t *\n\t * # Confused an editor build with an editor implementation\n\t *\n\t * This scenario is very similar to the previous one, but has a different origin.\n\t *\n\t * Let's assume that you wanted to use CKEditor 5 from source, as explained in the\n\t * {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source \"Building from source\"} section\n\t * or in the {@glink framework/guides/quick-start \"Quick start\"} guide of CKEditor 5 Framework.\n\t *\n\t * The correct way to do so is to import an editor and plugins and run them together like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\n\t *\t\tClassicEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ), {\n\t *\t\t\t\tplugins: [ Essentials, Paragraph, Bold, Italic ],\n\t *\t\t\t\ttoolbar: [ 'bold', 'italic' ]\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( error => {\n\t *\t\t\t\tconsole.error( error.stack );\n\t *\t\t\t} );\n\t *\n\t * However, you might have mistakenly imported a build instead of the source `ClassicEditor`. In this case\n\t * your imports will look like this:\n\t *\n\t *\t\timport ClassicEditor from '@ckeditor/ckeditor5-build-classic';\n\t *\t\timport Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';\n\t *\t\timport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\n\t *\t\timport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\n\t *\t\timport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\n\t *\n\t * This creates the same situation as in the previous section because you use a build together with source plugins.\n\t *\n\t * Remember: `@ckeditor/ckeditor5-build-*` packages contain editor builds and `@ckeditor/ckeditor5-editor-*` contain source editors.\n\t *\n\t * # Loading two or more builds on one page\n\t *\n\t * If you use CKEditor 5 builds, you might have loaded two (or more) `ckeditor.js` files on one web page.\n\t * Check your web page for duplicated `<script>` elements or make sure your page builder/bundler includes CKEditor only once.\n\t *\n\t * If you want to use two different types of editors at once, see the\n\t * {@glink builds/guides/integration/advanced-setup#scenario-3-using-two-different-editors \"Using two different editors\"}\n\t * section.\n\t *\n\t * # Using outdated packages\n\t *\n\t * Building CKEditor 5 from source requires using multiple npm packages. These packages have their dependencies\n\t * to other packages. If you use the latest version of, for example, `@ckeditor/ckeditor5-editor-classic` with\n\t * an outdated version of `@ckeditor/ckeditor5-image`, npm or yarn will need to install two different versions of\n\t * `@ckeditor/ckeditor5-core` because `@ckeditor/ckeditor5-editor-classic` and `@ckeditor/ckeditor5-image` may require\n\t * different versions of the core package.\n\t *\n\t * The solution to this issue is to update all packages to their latest version. We recommend\n\t * using tools like [`npm-check-updates`](https://www.npmjs.com/package/npm-check-updates) which simplify this process.\n\t *\n\t * # Conflicting version of dependencies\n\t *\n\t * This is a special case of the previous scenario. If you use CKEditor 5 with some third-party plugins,\n\t * it may happen that even if you use the latest versions of the official packages and the latest version of\n\t * these third-party packages, there will be a conflict between some of their dependencies.\n\t *\n\t * Such a problem can be resolved by either downgrading CKEditor 5 packages (which we do not recommend) or\n\t * asking the author of the third-party package to upgrade its depdendencies (or forking their project and doing this yourself).\n\t *\n\t * **Note:** All official CKEditor 5 packages (excluding integrations and `ckeditor5-dev-*` packages) are released in the\n\t * same major version. This is &mdash; in the `x.y.z`, the `x` is the same for all packages. This is the simplest way to check\n\t * whether you use packages coming from the same CKEditor 5 version. You can read more about versioning in the\n\t * {@glink framework/guides/support/versioning-policy Versioning policy} guide.\n\t *\n\t * # Packages were duplicated in `node_modules`\n\t *\n\t * In some situations, especially when calling `npm install` multiple times, it may happen\n\t * that npm will not correctly \"deduplicate\" packages.\n\t *\n\t * Normally, npm deduplicates all packages so, for example, `@ckeditor/ckeditor5-core` is installed only once in `node_modules/`.\n\t * However, it is known to fail to do so from time to time.\n\t *\n\t * We recommend checking if any of the steps listed below help:\n\t *\n\t * * `rm -rf node_modules && npm install` to make sure you have a clean `node_modules/` directory. This step\n\t * is known to help in most cases.\n\t * * If you use `yarn.lock` or `package-lock.json`, remove it before `npm install`.\n\t * * Check whether all CKEditor 5 packages are up to date and reinstall them\n\t * if you changed anything (`rm -rf node_modules && npm install`).\n\t *\n\t * If all packages are correct and compatible with each other, the steps above are known to help. If not, you may\n\t * try to check with `npm ls` how many times packages like `@ckeditor/ckeditor5-core`, `@ckeditor/ckeditor5-engine` and\n\t *`@ckeditor/ckeditor5-utils` are installed. If more than once, verify which package causes that.\n\t *\n\t * @error ckeditor-duplicated-modules\n\t */\n\tthrow new CKEditorError(\n\t\t'ckeditor-duplicated-modules',\n\t\tnull\n\t);\n} else {\n\twindowOrGlobal.CKEDITOR_VERSION = version;\n}\n","/** Detect free variable `global` from Node.js. */\nvar freeGlobal = typeof global == 'object' && global && global.Object === Object && global;\n\nexport default freeGlobal;\n","import root from './_root.js';\n\n/** Detect free variable `exports`. */\nvar freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;\n\n/** Detect free variable `module`. */\nvar freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;\n\n/** Detect the popular CommonJS extension `module.exports`. */\nvar moduleExports = freeModule && freeModule.exports === freeExports;\n\n/** Built-in value references. */\nvar Buffer = moduleExports ? root.Buffer : undefined,\n allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined;\n\n/**\n * Creates a clone of `buffer`.\n *\n * @private\n * @param {Buffer} buffer The buffer to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Buffer} Returns the cloned buffer.\n */\nfunction cloneBuffer(buffer, isDeep) {\n if (isDeep) {\n return buffer.slice();\n }\n var length = buffer.length,\n result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);\n\n buffer.copy(result);\n return result;\n}\n\nexport default cloneBuffer;\n","module.exports = function(originalModule) {\n\tif (!originalModule.webpackPolyfill) {\n\t\tvar module = Object.create(originalModule);\n\t\t// module.parent = undefined by default\n\t\tif (!module.children) module.children = [];\n\t\tObject.defineProperty(module, \"loaded\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.l;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"id\", {\n\t\t\tenumerable: true,\n\t\t\tget: function() {\n\t\t\t\treturn module.i;\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(module, \"exports\", {\n\t\t\tenumerable: true\n\t\t});\n\t\tmodule.webpackPolyfill = 1;\n\t}\n\treturn module;\n};\n","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./responsiveform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./code.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./heading.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./form.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tableform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","/**\n * This method returns `false`.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {boolean} Returns `false`.\n * @example\n *\n * _.times(2, _.stubFalse);\n * // => [false, false]\n */\nfunction stubFalse() {\n return false;\n}\n\nexport default stubFalse;\n","var api = require(\"!../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./globals.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-hidden{display:none!important}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{box-sizing:border-box;width:auto;height:auto;position:static}:root{--ck-z-default:1;--ck-z-modal:calc(var(--ck-z-default) + 999)}.ck-transitions-disabled,.ck-transitions-disabled *{transition:none!important}:root{--ck-color-base-foreground:#fafafa;--ck-color-base-background:#fff;--ck-color-base-border:#c4c4c4;--ck-color-base-action:#61b045;--ck-color-base-focus:#6cb5f9;--ck-color-base-text:#333;--ck-color-base-active:#198cf0;--ck-color-base-active-focus:#0e7fe1;--ck-color-base-error:#db3700;--ck-color-focus-border-coordinates:208,79%,51%;--ck-color-focus-border:hsl(var(--ck-color-focus-border-coordinates));--ck-color-focus-outer-shadow:#bcdefb;--ck-color-focus-disabled-shadow:rgba(119,186,248,0.3);--ck-color-focus-error-shadow:rgba(255,64,31,0.3);--ck-color-text:var(--ck-color-base-text);--ck-color-shadow-drop:rgba(0,0,0,0.15);--ck-color-shadow-drop-active:rgba(0,0,0,0.2);--ck-color-shadow-inner:rgba(0,0,0,0.1);--ck-color-button-default-background:transparent;--ck-color-button-default-hover-background:#e6e6e6;--ck-color-button-default-active-background:#d9d9d9;--ck-color-button-default-active-shadow:#bfbfbf;--ck-color-button-default-disabled-background:transparent;--ck-color-button-on-background:#dedede;--ck-color-button-on-hover-background:#c4c4c4;--ck-color-button-on-active-background:#bababa;--ck-color-button-on-active-shadow:#a1a1a1;--ck-color-button-on-disabled-background:#dedede;--ck-color-button-action-background:var(--ck-color-base-action);--ck-color-button-action-hover-background:#579e3d;--ck-color-button-action-active-background:#53973b;--ck-color-button-action-active-shadow:#498433;--ck-color-button-action-disabled-background:#7ec365;--ck-color-button-action-text:var(--ck-color-base-background);--ck-color-button-save:#008a00;--ck-color-button-cancel:#db3700;--ck-color-switch-button-off-background:#b0b0b0;--ck-color-switch-button-off-hover-background:#a3a3a3;--ck-color-switch-button-on-background:var(--ck-color-button-action-background);--ck-color-switch-button-on-hover-background:#579e3d;--ck-color-switch-button-inner-background:var(--ck-color-base-background);--ck-color-switch-button-inner-shadow:rgba(0,0,0,0.1);--ck-color-dropdown-panel-background:var(--ck-color-base-background);--ck-color-dropdown-panel-border:var(--ck-color-base-border);--ck-color-input-background:var(--ck-color-base-background);--ck-color-input-border:#c7c7c7;--ck-color-input-error-border:var(--ck-color-base-error);--ck-color-input-text:var(--ck-color-base-text);--ck-color-input-disabled-background:#f2f2f2;--ck-color-input-disabled-border:#c7c7c7;--ck-color-input-disabled-text:#757575;--ck-color-list-background:var(--ck-color-base-background);--ck-color-list-button-hover-background:var(--ck-color-button-default-hover-background);--ck-color-list-button-on-background:var(--ck-color-base-active);--ck-color-list-button-on-background-focus:var(--ck-color-base-active-focus);--ck-color-list-button-on-text:var(--ck-color-base-background);--ck-color-panel-background:var(--ck-color-base-background);--ck-color-panel-border:var(--ck-color-base-border);--ck-color-toolbar-background:var(--ck-color-base-foreground);--ck-color-toolbar-border:var(--ck-color-base-border);--ck-color-tooltip-background:var(--ck-color-base-text);--ck-color-tooltip-text:var(--ck-color-base-background);--ck-color-engine-placeholder-text:#707070;--ck-color-upload-bar-background:#6cb5f9;--ck-color-link-default:#0000f0;--ck-color-link-selected-background:rgba(31,177,255,0.1);--ck-color-link-fake-selection:rgba(31,177,255,0.3);--ck-disabled-opacity:.5;--ck-focus-outer-shadow-geometry:0 0 0 3px;--ck-focus-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-outer-shadow);--ck-focus-disabled-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-disabled-shadow);--ck-focus-error-outer-shadow:var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-error-shadow);--ck-focus-ring:1px solid var(--ck-color-focus-border);--ck-font-size-base:13px;--ck-line-height-base:1.84615;--ck-font-face:Helvetica,Arial,Tahoma,Verdana,Sans-Serif;--ck-font-size-tiny:0.7em;--ck-font-size-small:0.75em;--ck-font-size-normal:1em;--ck-font-size-big:1.4em;--ck-font-size-large:1.8em;--ck-ui-component-min-height:2.3em}.ck.ck-reset,.ck.ck-reset_all,.ck.ck-reset_all *{margin:0;padding:0;border:0;background:transparent;text-decoration:none;vertical-align:middle;transition:none;word-wrap:break-word}.ck.ck-reset_all,.ck.ck-reset_all *{border-collapse:collapse;font:normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face);color:var(--ck-color-text);text-align:left;white-space:nowrap;cursor:auto;float:none}.ck.ck-reset_all .ck-rtl *{text-align:right}.ck.ck-reset_all iframe{vertical-align:inherit}.ck.ck-reset_all textarea{white-space:pre-wrap}.ck.ck-reset_all input[type=password],.ck.ck-reset_all input[type=text],.ck.ck-reset_all textarea{cursor:text}.ck.ck-reset_all input[type=password][disabled],.ck.ck-reset_all input[type=text][disabled],.ck.ck-reset_all textarea[disabled]{cursor:default}.ck.ck-reset_all fieldset{padding:10px;border:2px groove #dfdee3}.ck.ck-reset_all button::-moz-focus-inner{padding:0;border:0}.ck[dir=rtl],.ck[dir=rtl] .ck{text-align:right}:root{--ck-border-radius:2px;--ck-inner-shadow:2px 2px 3px var(--ck-color-shadow-inner) inset;--ck-drop-shadow:0 1px 2px 1px var(--ck-color-shadow-drop);--ck-drop-shadow-active:0 3px 6px 1px var(--ck-color-shadow-drop-active);--ck-spacing-unit:0.6em;--ck-spacing-large:calc(var(--ck-spacing-unit)*1.5);--ck-spacing-standard:var(--ck-spacing-unit);--ck-spacing-medium:calc(var(--ck-spacing-unit)*0.8);--ck-spacing-small:calc(var(--ck-spacing-unit)*0.5);--ck-spacing-tiny:calc(var(--ck-spacing-unit)*0.3);--ck-spacing-extra-tiny:calc(var(--ck-spacing-unit)*0.16)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./icon.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-icon{vertical-align:middle}:root{--ck-icon-size:calc(var(--ck-line-height-base)*var(--ck-font-size-normal))}.ck.ck-icon{width:var(--ck-icon-size);height:var(--ck-icon-size);font-size:.8333350694em;will-change:transform}.ck.ck-icon,.ck.ck-icon *{color:inherit;cursor:inherit}.ck.ck-icon :not([fill]){fill:currentColor}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tooltip.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-tooltip,.ck.ck-tooltip .ck-tooltip__text:after{position:absolute;pointer-events:none;-webkit-backface-visibility:hidden}.ck.ck-tooltip{visibility:hidden;opacity:0;display:none;z-index:var(--ck-z-modal)}.ck.ck-tooltip .ck-tooltip__text{display:inline-block}.ck.ck-tooltip .ck-tooltip__text:after{content:\\\"\\\";width:0;height:0}:root{--ck-tooltip-arrow-size:5px}.ck.ck-tooltip{left:50%;top:0;transition:opacity .2s ease-in-out .2s}.ck.ck-tooltip .ck-tooltip__text{border-radius:0}.ck-rounded-corners .ck.ck-tooltip .ck-tooltip__text,.ck.ck-tooltip .ck-tooltip__text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-tooltip .ck-tooltip__text{font-size:.9em;line-height:1.5;color:var(--ck-color-tooltip-text);padding:var(--ck-spacing-small) var(--ck-spacing-medium);background:var(--ck-color-tooltip-background);position:relative;left:-50%}.ck.ck-tooltip .ck-tooltip__text:after{transition:opacity .2s ease-in-out .2s;border-style:solid;left:50%}.ck.ck-tooltip.ck-tooltip_s,.ck.ck-tooltip.ck-tooltip_se,.ck.ck-tooltip.ck-tooltip_sw{bottom:calc(var(--ck-tooltip-arrow-size)*-1);transform:translateY(100%)}.ck.ck-tooltip.ck-tooltip_s .ck-tooltip__text:after,.ck.ck-tooltip.ck-tooltip_se .ck-tooltip__text:after,.ck.ck-tooltip.ck-tooltip_sw .ck-tooltip__text:after{top:calc(var(--ck-tooltip-arrow-size)*-1 + 1px);transform:translateX(-50%);border-left-color:transparent;border-bottom-color:var(--ck-color-tooltip-background);border-right-color:transparent;border-top-color:transparent;border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:var(--ck-tooltip-arrow-size);border-top-width:0}.ck.ck-tooltip.ck-tooltip_sw{right:50%;left:auto}.ck.ck-tooltip.ck-tooltip_sw .ck-tooltip__text{left:auto;right:calc(var(--ck-tooltip-arrow-size)*-2)}.ck.ck-tooltip.ck-tooltip_sw .ck-tooltip__text:after{left:auto;right:0}.ck.ck-tooltip.ck-tooltip_se{left:50%;right:auto}.ck.ck-tooltip.ck-tooltip_se .ck-tooltip__text{right:auto;left:calc(var(--ck-tooltip-arrow-size)*-2)}.ck.ck-tooltip.ck-tooltip_se .ck-tooltip__text:after{right:auto;left:0;transform:translateX(50%)}.ck.ck-tooltip.ck-tooltip_n{top:calc(var(--ck-tooltip-arrow-size)*-1);transform:translateY(-100%)}.ck.ck-tooltip.ck-tooltip_n .ck-tooltip__text:after{bottom:calc(var(--ck-tooltip-arrow-size)*-1);transform:translateX(-50%);border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent;border-top-color:var(--ck-color-tooltip-background);border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:0;border-right-width:var(--ck-tooltip-arrow-size);border-top-width:var(--ck-tooltip-arrow-size)}.ck.ck-tooltip.ck-tooltip_e{left:calc(100% + var(--ck-tooltip-arrow-size));top:50%}.ck.ck-tooltip.ck-tooltip_e .ck-tooltip__text{left:0;transform:translateY(-50%)}.ck.ck-tooltip.ck-tooltip_e .ck-tooltip__text:after{left:calc(var(--ck-tooltip-arrow-size)*-1);top:calc(50% - var(--ck-tooltip-arrow-size)*1);border-left-color:transparent;border-bottom-color:transparent;border-right-color:var(--ck-color-tooltip-background);border-top-color:transparent;border-left-width:0;border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:var(--ck-tooltip-arrow-size);border-top-width:var(--ck-tooltip-arrow-size)}.ck.ck-tooltip.ck-tooltip_w{right:calc(100% + var(--ck-tooltip-arrow-size));left:auto;top:50%}.ck.ck-tooltip.ck-tooltip_w .ck-tooltip__text{left:0;transform:translateY(-50%)}.ck.ck-tooltip.ck-tooltip_w .ck-tooltip__text:after{left:100%;top:calc(50% - var(--ck-tooltip-arrow-size)*1);border-left-color:var(--ck-color-tooltip-background);border-bottom-color:transparent;border-right-color:transparent;border-top-color:transparent;border-left-width:var(--ck-tooltip-arrow-size);border-bottom-width:var(--ck-tooltip-arrow-size);border-right-width:0;border-top-width:var(--ck-tooltip-arrow-size)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./button.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-button,a.ck.ck-button{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:block}@media (hover:none){.ck.ck-button .ck-tooltip,a.ck.ck-button .ck-tooltip{display:none}}.ck.ck-button,a.ck.ck-button{position:relative;display:inline-flex;align-items:center;justify-content:left}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{display:none}.ck.ck-button.ck-button_with-text .ck-button__label,a.ck.ck-button.ck-button_with-text .ck-button__label{display:inline-block}.ck.ck-button:not(.ck-button_with-text),a.ck.ck-button:not(.ck-button_with-text){justify-content:center}.ck.ck-button:hover .ck-tooltip,a.ck.ck-button:hover .ck-tooltip{visibility:visible;opacity:1}.ck.ck-button:focus:not(:hover) .ck-tooltip,a.ck.ck-button:focus:not(:hover) .ck-tooltip{display:none}.ck.ck-button,a.ck.ck-button{background:var(--ck-color-button-default-background)}.ck.ck-button:not(.ck-disabled):hover,a.ck.ck-button:not(.ck-disabled):hover{background:var(--ck-color-button-default-hover-background)}.ck.ck-button:not(.ck-disabled):active,a.ck.ck-button:not(.ck-disabled):active{background:var(--ck-color-button-default-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-default-active-shadow)}.ck.ck-button.ck-disabled,a.ck.ck-button.ck-disabled{background:var(--ck-color-button-default-disabled-background)}.ck.ck-button,a.ck.ck-button{border-radius:0}.ck-rounded-corners .ck.ck-button,.ck-rounded-corners a.ck.ck-button,.ck.ck-button.ck-rounded-corners,a.ck.ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-button,a.ck.ck-button{white-space:nowrap;cursor:default;vertical-align:middle;padding:var(--ck-spacing-tiny);text-align:center;min-width:var(--ck-ui-component-min-height);min-height:var(--ck-ui-component-min-height);line-height:1;font-size:inherit;border:1px solid transparent;transition:box-shadow .2s ease-in-out,border .2s ease-in-out;-webkit-appearance:none}.ck.ck-button:active,.ck.ck-button:focus,a.ck.ck-button:active,a.ck.ck-button:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),0 0}.ck.ck-button .ck-button__icon use,.ck.ck-button .ck-button__icon use *,a.ck.ck-button .ck-button__icon use,a.ck.ck-button .ck-button__icon use *{color:inherit}.ck.ck-button .ck-button__label,a.ck.ck-button .ck-button__label{font-size:inherit;font-weight:inherit;color:inherit;cursor:inherit;vertical-align:middle}[dir=ltr] .ck.ck-button .ck-button__label,[dir=ltr] a.ck.ck-button .ck-button__label{text-align:left}[dir=rtl] .ck.ck-button .ck-button__label,[dir=rtl] a.ck.ck-button .ck-button__label{text-align:right}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{color:inherit}[dir=ltr] .ck.ck-button .ck-button__keystroke,[dir=ltr] a.ck.ck-button .ck-button__keystroke{margin-left:var(--ck-spacing-large)}[dir=rtl] .ck.ck-button .ck-button__keystroke,[dir=rtl] a.ck.ck-button .ck-button__keystroke{margin-right:var(--ck-spacing-large)}.ck.ck-button .ck-button__keystroke,a.ck.ck-button .ck-button__keystroke{font-weight:700;opacity:.7}.ck.ck-button.ck-disabled:active,.ck.ck-button.ck-disabled:focus,a.ck.ck-button.ck-disabled:active,a.ck.ck-button.ck-disabled:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),0 0}.ck.ck-button.ck-disabled .ck-button__icon,a.ck.ck-button.ck-disabled .ck-button__icon{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__label,a.ck.ck-button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-disabled .ck-button__keystroke,a.ck.ck-button.ck-disabled .ck-button__keystroke{opacity:.3}.ck.ck-button.ck-button_with-text,a.ck.ck-button.ck-button_with-text{padding:var(--ck-spacing-tiny) var(--ck-spacing-standard)}[dir=ltr] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=ltr] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-left:calc(var(--ck-spacing-small)*-1);margin-right:var(--ck-spacing-small)}[dir=rtl] .ck.ck-button.ck-button_with-text .ck-button__icon,[dir=rtl] a.ck.ck-button.ck-button_with-text .ck-button__icon{margin-right:calc(var(--ck-spacing-small)*-1);margin-left:var(--ck-spacing-small)}.ck.ck-button.ck-button_with-keystroke .ck-button__label,a.ck.ck-button.ck-button_with-keystroke .ck-button__label{flex-grow:1}.ck.ck-button.ck-on,a.ck.ck-button.ck-on{background:var(--ck-color-button-on-background)}.ck.ck-button.ck-on:not(.ck-disabled):hover,a.ck.ck-button.ck-on:not(.ck-disabled):hover{background:var(--ck-color-button-on-hover-background)}.ck.ck-button.ck-on:not(.ck-disabled):active,a.ck.ck-button.ck-on:not(.ck-disabled):active{background:var(--ck-color-button-on-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-on-active-shadow)}.ck.ck-button.ck-on.ck-disabled,a.ck.ck-button.ck-on.ck-disabled{background:var(--ck-color-button-on-disabled-background)}.ck.ck-button.ck-button-save,a.ck.ck-button.ck-button-save{color:var(--ck-color-button-save)}.ck.ck-button.ck-button-cancel,a.ck.ck-button.ck-button-cancel{color:var(--ck-color-button-cancel)}.ck.ck-button-action,a.ck.ck-button-action{background:var(--ck-color-button-action-background)}.ck.ck-button-action:not(.ck-disabled):hover,a.ck.ck-button-action:not(.ck-disabled):hover{background:var(--ck-color-button-action-hover-background)}.ck.ck-button-action:not(.ck-disabled):active,a.ck.ck-button-action:not(.ck-disabled):active{background:var(--ck-color-button-action-active-background);box-shadow:inset 0 2px 2px var(--ck-color-button-action-active-shadow)}.ck.ck-button-action.ck-disabled,a.ck.ck-button-action.ck-disabled{background:var(--ck-color-button-action-disabled-background)}.ck.ck-button-action,a.ck.ck-button-action{color:var(--ck-color-button-action-text)}.ck.ck-button-bold,a.ck.ck-button-bold{font-weight:700}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./switchbutton.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{display:block}:root{--ck-switch-button-toggle-width:2.6153846154em;--ck-switch-button-toggle-inner-size:1.0769230769em;--ck-switch-button-toggle-spacing:1px;--ck-switch-button-translation:calc(var(--ck-switch-button-toggle-width) - var(--ck-switch-button-toggle-inner-size) - var(--ck-switch-button-toggle-spacing)*2)}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__label{margin-right:calc(var(--ck-spacing-large)*2)}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__label{margin-left:calc(var(--ck-spacing-large)*2)}.ck.ck-button.ck-switchbutton .ck-button__toggle{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle,.ck.ck-button.ck-switchbutton .ck-button__toggle.ck-rounded-corners{border-radius:var(--ck-border-radius)}[dir=ltr] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-left:auto}[dir=rtl] .ck.ck-button.ck-switchbutton .ck-button__toggle{margin-right:auto}.ck.ck-button.ck-switchbutton .ck-button__toggle{transition:background .4s ease;width:var(--ck-switch-button-toggle-width);background:var(--ck-color-switch-button-off-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{border-radius:0}.ck-rounded-corners .ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner,.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner.ck-rounded-corners{border-radius:var(--ck-border-radius);border-radius:calc(var(--ck-border-radius)*0.5)}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{margin:var(--ck-switch-button-toggle-spacing);width:var(--ck-switch-button-toggle-inner-size);height:var(--ck-switch-button-toggle-inner-size);background:var(--ck-color-switch-button-inner-background);transition:all .3s ease}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover{background:var(--ck-color-switch-button-off-hover-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover .ck-button__toggle__inner{box-shadow:0 0 0 5px var(--ck-color-switch-button-inner-shadow)}.ck.ck-button.ck-switchbutton.ck-disabled .ck-button__toggle{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle{background:var(--ck-color-switch-button-on-background)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle:hover{background:var(--ck-color-switch-button-on-hover-background)}[dir=ltr] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(var(--ck-switch-button-translation))}[dir=rtl] .ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner{transform:translateX(calc(var(--ck-switch-button-translation)*-1))}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./colorgrid.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-color-grid{display:grid}:root{--ck-color-grid-tile-size:24px;--ck-color-color-grid-check-icon:#000}.ck.ck-color-grid{grid-gap:5px;padding:8px}.ck.ck-color-grid__tile{width:var(--ck-color-grid-tile-size);height:var(--ck-color-grid-tile-size);min-width:var(--ck-color-grid-tile-size);min-height:var(--ck-color-grid-tile-size);padding:0;transition:box-shadow .2s ease;border:0}.ck.ck-color-grid__tile.ck-disabled{cursor:unset;transition:unset}.ck.ck-color-grid__tile.ck-color-table__color-tile_bordered{box-shadow:0 0 0 1px var(--ck-color-base-border)}.ck.ck-color-grid__tile .ck.ck-icon{display:none;color:var(--ck-color-color-grid-check-icon)}.ck.ck-color-grid__tile.ck-on{box-shadow:inset 0 0 0 1px var(--ck-color-base-background),0 0 0 2px var(--ck-color-base-text)}.ck.ck-color-grid__tile.ck-on .ck.ck-icon{display:block}.ck.ck-color-grid__tile.ck-on,.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){border:0}.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){box-shadow:inset 0 0 0 1px var(--ck-color-base-background),0 0 0 2px var(--ck-color-focus-border)}.ck.ck-color-grid__label{padding:0 var(--ck-spacing-standard)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./splitbutton.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-splitbutton{font-size:inherit}.ck.ck-splitbutton .ck-splitbutton__action:focus{z-index:calc(var(--ck-z-default) + 1)}.ck.ck-splitbutton.ck-splitbutton_open>.ck-button .ck-tooltip{display:none}:root{--ck-color-split-button-hover-background:#ebebeb;--ck-color-split-button-hover-border:#b3b3b3}[dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__action{border-top-right-radius:unset;border-bottom-right-radius:unset}[dir=rtl] .ck.ck-splitbutton>.ck-splitbutton__action{border-top-left-radius:unset;border-bottom-left-radius:unset}.ck.ck-splitbutton>.ck-splitbutton__arrow{min-width:unset}[dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__arrow{border-radius:0}.ck-rounded-corners [dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__arrow,[dir=ltr] .ck.ck-splitbutton>.ck-splitbutton__arrow.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:unset;border-bottom-left-radius:unset}[dir=rtl] .ck.ck-splitbutton>.ck-splitbutton__arrow{border-top-right-radius:unset;border-bottom-right-radius:unset}.ck.ck-splitbutton>.ck-splitbutton__arrow svg{width:var(--ck-dropdown-arrow-size)}.ck.ck-splitbutton.ck-splitbutton_open>.ck-button:not(.ck-on):not(.ck-disabled):not(:hover),.ck.ck-splitbutton:hover>.ck-button:not(.ck-on):not(.ck-disabled):not(:hover){background:var(--ck-color-split-button-hover-background)}[dir=ltr] .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__arrow:not(.ck-disabled),[dir=ltr] .ck.ck-splitbutton:hover>.ck-splitbutton__arrow:not(.ck-disabled){border-left-color:var(--ck-color-split-button-hover-border)}[dir=rtl] .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__arrow:not(.ck-disabled),[dir=rtl] .ck.ck-splitbutton:hover>.ck-splitbutton__arrow:not(.ck-disabled){border-right-color:var(--ck-color-split-button-hover-border)}.ck.ck-splitbutton.ck-splitbutton_open{border-radius:0}.ck-rounded-corners .ck.ck-splitbutton.ck-splitbutton_open,.ck.ck-splitbutton.ck-splitbutton_open.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck-rounded-corners .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__action,.ck.ck-splitbutton.ck-splitbutton_open.ck-rounded-corners>.ck-splitbutton__action{border-bottom-left-radius:0}.ck-rounded-corners .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__arrow,.ck.ck-splitbutton.ck-splitbutton_open.ck-rounded-corners>.ck-splitbutton__arrow{border-bottom-right-radius:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./dropdown.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-dropdown-max-width:75vw}.ck.ck-dropdown{display:inline-block;position:relative}.ck.ck-dropdown .ck-dropdown__arrow{pointer-events:none;z-index:var(--ck-z-default)}.ck.ck-dropdown .ck-button.ck-dropdown__button{width:100%}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on .ck-tooltip{display:none}.ck.ck-dropdown .ck-dropdown__panel{-webkit-backface-visibility:hidden;display:none;z-index:var(--ck-z-modal);max-width:var(--ck-dropdown-max-width);position:absolute}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel-visible{display:inline-block}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_n,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nme,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nmw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw{bottom:100%}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{top:100%;bottom:auto}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se{left:0}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{right:0}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_n,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s{left:50%;transform:translateX(-50%)}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nmw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw{left:75%;transform:translateX(-75%)}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nme,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme{left:25%;transform:translateX(-25%)}.ck.ck-toolbar .ck-dropdown__panel{z-index:calc(var(--ck-z-modal) + 1)}:root{--ck-dropdown-arrow-size:calc(var(--ck-icon-size)*0.5)}.ck.ck-dropdown{font-size:inherit}.ck.ck-dropdown .ck-dropdown__arrow{width:var(--ck-dropdown-arrow-size)}[dir=ltr] .ck.ck-dropdown .ck-dropdown__arrow{right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-standard)}[dir=rtl] .ck.ck-dropdown .ck-dropdown__arrow{left:var(--ck-spacing-standard);margin-right:var(--ck-spacing-small)}.ck.ck-dropdown.ck-disabled .ck-dropdown__arrow{opacity:var(--ck-disabled-opacity)}[dir=ltr] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-left:var(--ck-spacing-small)}[dir=rtl] .ck.ck-dropdown .ck-button.ck-dropdown__button:not(.ck-button_with-text){padding-right:var(--ck-spacing-small)}.ck.ck-dropdown .ck-button.ck-dropdown__button .ck-button__label{width:7em;overflow:hidden;text-overflow:ellipsis}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on{border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-dropdown__button_label-width_auto .ck-button__label{width:auto}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-off:active,.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on:active{box-shadow:none}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-off:active:focus,.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on:active:focus{box-shadow:var(--ck-focus-outer-shadow),0 0}.ck.ck-dropdown__panel{border-radius:0}.ck-rounded-corners .ck.ck-dropdown__panel,.ck.ck-dropdown__panel.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-dropdown__panel{box-shadow:var(--ck-drop-shadow),0 0;background:var(--ck-color-dropdown-panel-background);border:1px solid var(--ck-color-dropdown-panel-border);bottom:0;min-width:100%}.ck.ck-dropdown__panel.ck-dropdown__panel_se{border-top-left-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_sw{border-top-right-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_ne{border-bottom-left-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_nw{border-bottom-right-radius:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./toolbar.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-toolbar{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-flow:row nowrap;align-items:center}.ck.ck-toolbar>.ck-toolbar__items{display:flex;flex-flow:row wrap;align-items:center;flex-grow:1}.ck.ck-toolbar .ck.ck-toolbar__separator{display:inline-block}.ck.ck-toolbar .ck.ck-toolbar__separator:first-child,.ck.ck-toolbar .ck.ck-toolbar__separator:last-child{display:none}.ck.ck-toolbar .ck-toolbar__line-break{flex-basis:100%}.ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items{flex-direction:column}.ck.ck-toolbar.ck-toolbar_floating>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck-dropdown__button .ck-dropdown__arrow{display:none}.ck.ck-toolbar{border-radius:0}.ck-rounded-corners .ck.ck-toolbar,.ck.ck-toolbar.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-toolbar{background:var(--ck-color-toolbar-background);padding:0 var(--ck-spacing-small);border:1px solid var(--ck-color-toolbar-border)}.ck.ck-toolbar .ck.ck-toolbar__separator{align-self:stretch;width:1px;min-width:1px;background:var(--ck-color-toolbar-border);margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck.ck-toolbar .ck-toolbar__line-break{height:0}.ck.ck-toolbar>.ck-toolbar__items>:not(.ck-toolbar__line-break){margin-right:var(--ck-spacing-small)}.ck.ck-toolbar>.ck-toolbar__items:empty+.ck.ck-toolbar__separator{display:none}.ck.ck-toolbar>.ck-toolbar__items>:not(.ck-toolbar__line-break),.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck.ck-toolbar.ck-toolbar_vertical{padding:0}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items>.ck{width:100%;margin:0;border-radius:0;border:0}.ck.ck-toolbar.ck-toolbar_compact{padding:0}.ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>*{margin:0}.ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>:not(:first-child):not(:last-child){border-radius:0}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck.ck-button.ck-dropdown__button{padding-left:var(--ck-spacing-tiny)}.ck-toolbar-container .ck.ck-toolbar{border:0}.ck.ck-toolbar[dir=rtl]>.ck-toolbar__items>.ck,[dir=rtl] .ck.ck-toolbar>.ck-toolbar__items>.ck{margin-right:0}.ck.ck-toolbar[dir=rtl]:not(.ck-toolbar_compact)>.ck-toolbar__items>.ck,[dir=rtl] .ck.ck-toolbar:not(.ck-toolbar_compact)>.ck-toolbar__items>.ck{margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=rtl]>.ck-toolbar__items>.ck:last-child,[dir=rtl] .ck.ck-toolbar>.ck-toolbar__items>.ck:last-child{margin-left:0}.ck.ck-toolbar[dir=rtl].ck-toolbar_compact>.ck-toolbar__items>.ck:first-child,[dir=rtl] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-toolbar[dir=rtl].ck-toolbar_compact>.ck-toolbar__items>.ck:last-child,[dir=rtl] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:last-child{border-top-right-radius:0;border-bottom-right-radius:0}.ck.ck-toolbar[dir=rtl]>.ck.ck-toolbar__separator,[dir=rtl] .ck.ck-toolbar>.ck.ck-toolbar__separator{margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=rtl].ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child),[dir=rtl] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child){margin-left:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr]>.ck-toolbar__items>.ck:last-child,[dir=ltr] .ck.ck-toolbar>.ck-toolbar__items>.ck:last-child{margin-right:0}.ck.ck-toolbar[dir=ltr].ck-toolbar_compact>.ck-toolbar__items>.ck:first-child,[dir=ltr] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.ck.ck-toolbar[dir=ltr].ck-toolbar_compact>.ck-toolbar__items>.ck:last-child,[dir=ltr] .ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>.ck:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-toolbar[dir=ltr]>.ck.ck-toolbar__separator,[dir=ltr] .ck.ck-toolbar>.ck.ck-toolbar__separator{margin-right:var(--ck-spacing-small)}.ck.ck-toolbar[dir=ltr].ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child),[dir=ltr] .ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child){margin-right:var(--ck-spacing-small)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./list.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-list{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;display:flex;flex-direction:column}.ck.ck-list .ck-list__item,.ck.ck-list .ck-list__separator{display:block}.ck.ck-list .ck-list__item>:focus{position:relative;z-index:var(--ck-z-default)}.ck.ck-list{border-radius:0}.ck-rounded-corners .ck.ck-list,.ck.ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-list{list-style-type:none;background:var(--ck-color-list-background)}.ck.ck-list__item{cursor:default;min-width:12em}.ck.ck-list__item .ck-button{min-height:unset;width:100%;text-align:left;border-radius:0;padding:calc(var(--ck-line-height-base)*0.2*var(--ck-font-size-base)) calc(var(--ck-line-height-base)*0.4*var(--ck-font-size-base))}.ck.ck-list__item .ck-button .ck-button__label{line-height:calc(var(--ck-line-height-base)*1.2*var(--ck-font-size-base))}.ck.ck-list__item .ck-button:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on{background:var(--ck-color-list-button-on-background);color:var(--ck-color-list-button-on-text)}.ck.ck-list__item .ck-button.ck-on:active{box-shadow:none}.ck.ck-list__item .ck-button.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-on-background-focus)}.ck.ck-list__item .ck-button.ck-on:focus:not(.ck-disabled){border-color:var(--ck-color-base-background)}.ck.ck-list__item .ck-button:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background)}.ck.ck-list__item .ck-switchbutton.ck-on{background:var(--ck-color-list-background);color:inherit}.ck.ck-list__item .ck-switchbutton.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background);color:inherit}.ck.ck-list__separator{height:1px;width:100%;background:var(--ck-color-base-border)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./toolbardropdown.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-toolbar-dropdown-max-width:60vw}.ck.ck-toolbar-dropdown>.ck-dropdown__panel{width:max-content;max-width:var(--ck-toolbar-dropdown-max-width)}.ck.ck-toolbar-dropdown>.ck-dropdown__panel .ck-button:focus{z-index:calc(var(--ck-z-default) + 1)}.ck.ck-toolbar-dropdown .ck-toolbar{border:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./listdropdown.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-dropdown .ck-dropdown__panel .ck-list{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list,.ck.ck-dropdown .ck-dropdown__panel .ck-list.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:first-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button{border-radius:0}.ck-rounded-corners .ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button,.ck.ck-dropdown .ck-dropdown__panel .ck-list .ck-list__item:last-child .ck-button.ck-rounded-corners{border-radius:var(--ck-border-radius);border-top-left-radius:0;border-top-right-radius:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./editorui.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-color-editable-blur-selection:#d9d9d9}.ck.ck-editor__editable:not(.ck-editor__nested-editable){border-radius:0}.ck-rounded-corners .ck.ck-editor__editable:not(.ck-editor__nested-editable),.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-focused{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0}.ck.ck-editor__editable_inline{overflow:auto;padding:0 var(--ck-spacing-standard);border:1px solid transparent}.ck.ck-editor__editable_inline[dir=ltr]{text-align:left}.ck.ck-editor__editable_inline[dir=rtl]{text-align:right}.ck.ck-editor__editable_inline>:first-child{margin-top:var(--ck-spacing-large)}.ck.ck-editor__editable_inline>:last-child{margin-bottom:var(--ck-spacing-large)}.ck.ck-editor__editable_inline.ck-blurred ::selection{background:var(--ck-color-editable-blur-selection)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_n]:after{border-bottom-color:var(--ck-color-base-foreground)}.ck.ck-balloon-panel.ck-toolbar-container[class*=arrow_s]:after{border-top-color:var(--ck-color-base-foreground)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./label.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-label{display:block}.ck.ck-voice-label{display:none}.ck.ck-label{font-weight:700}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./formheader.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-form__header{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;justify-content:space-between}:root{--ck-form-header-height:38px}.ck.ck-form__header{padding:var(--ck-spacing-small) var(--ck-spacing-large);height:var(--ck-form-header-height);line-height:var(--ck-form-header-height);border-bottom:1px solid var(--ck-color-base-border)}.ck.ck-form__header .ck-form__header__label{font-weight:700}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./inputtext.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-input-text-width:18em}.ck.ck-input-text{border-radius:0}.ck-rounded-corners .ck.ck-input-text,.ck.ck-input-text.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-input-text{background:var(--ck-color-input-background);border:1px solid var(--ck-color-input-border);padding:var(--ck-spacing-extra-tiny) var(--ck-spacing-medium);min-width:var(--ck-input-text-width);min-height:var(--ck-ui-component-min-height);transition:box-shadow .1s ease-in-out,border .1s ease-in-out}.ck.ck-input-text:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow),0 0}.ck.ck-input-text[readonly]{border:1px solid var(--ck-color-input-disabled-border);background:var(--ck-color-input-disabled-background);color:var(--ck-color-input-disabled-text)}.ck.ck-input-text[readonly]:focus{box-shadow:var(--ck-focus-disabled-outer-shadow),0 0}.ck.ck-input-text.ck-error{border-color:var(--ck-color-input-error-border);animation:ck-text-input-shake .3s ease both}.ck.ck-input-text.ck-error:focus{box-shadow:var(--ck-focus-error-outer-shadow),0 0}@keyframes ck-text-input-shake{20%{transform:translateX(-2px)}40%{transform:translateX(2px)}60%{transform:translateX(-1px)}80%{transform:translateX(1px)}}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./labeledfieldview.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper{display:flex;position:relative}.ck.ck-labeled-field-view .ck.ck-label{display:block;position:absolute}:root{--ck-labeled-field-view-transition:.1s cubic-bezier(0,0,0.24,0.95);--ck-labeled-field-empty-unfocused-max-width:100% - 2 * var(--ck-spacing-medium);--ck-color-labeled-field-label-background:var(--ck-color-base-background)}.ck.ck-labeled-field-view{border-radius:0}.ck-rounded-corners .ck.ck-labeled-field-view,.ck.ck-labeled-field-view.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper{width:100%}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{top:0}[dir=ltr] .ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{left:0}[dir=rtl] .ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{right:0}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{pointer-events:none;transform-origin:0 0;transform:translate(var(--ck-spacing-medium),-6px) scale(.75);background:var(--ck-color-labeled-field-label-background);padding:0 calc(var(--ck-font-size-tiny)*0.5);line-height:normal;font-weight:400;text-overflow:ellipsis;overflow:hidden;max-width:100%;transition:transform var(--ck-labeled-field-view-transition),padding var(--ck-labeled-field-view-transition),background var(--ck-labeled-field-view-transition)}.ck.ck-labeled-field-view.ck-error .ck-input:not([readonly])+.ck.ck-label,.ck.ck-labeled-field-view.ck-error>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{color:var(--ck-color-base-error)}.ck.ck-labeled-field-view .ck-labeled-field-view__status{font-size:var(--ck-font-size-small);margin-top:var(--ck-spacing-small);white-space:normal}.ck.ck-labeled-field-view .ck-labeled-field-view__status.ck-labeled-field-view__status_error{color:var(--ck-color-base-error)}.ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{color:var(--ck-color-input-disabled-text)}[dir=ltr] .ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,[dir=ltr] .ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{transform:translate(var(--ck-spacing-medium),calc(var(--ck-font-size-base)*0.6)) scale(1)}[dir=rtl] .ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,[dir=rtl] .ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{transform:translate(calc(var(--ck-spacing-medium)*-1),calc(var(--ck-font-size-base)*0.6)) scale(1)}.ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{max-width:calc(var(--ck-labeled-field-empty-unfocused-max-width));background:transparent;padding:0}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown>.ck.ck-button{background:transparent}.ck.ck-labeled-field-view.ck-labeled-field-view_empty>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown>.ck-button>.ck-button__label{opacity:0}.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown+.ck-label{max-width:calc(var(--ck-labeled-field-empty-unfocused-max-width) - var(--ck-dropdown-arrow-size) - var(--ck-spacing-standard))}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./balloonpanel.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-balloon-panel-arrow-z-index:calc(var(--ck-z-default) - 3)}.ck.ck-balloon-panel{display:none;position:absolute;z-index:var(--ck-z-modal)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{content:\\\"\\\";position:absolute}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_n]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_n]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*=arrow_s]:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*=arrow_s]:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel.ck-balloon-panel_visible{display:block}:root{--ck-balloon-arrow-offset:2px;--ck-balloon-arrow-height:10px;--ck-balloon-arrow-half-width:8px;--ck-balloon-arrow-drop-shadow:0 2px 2px var(--ck-color-shadow-drop)}.ck.ck-balloon-panel{border-radius:0}.ck-rounded-corners .ck.ck-balloon-panel,.ck.ck-balloon-panel.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-balloon-panel{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{width:0;height:0;border-style:solid}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:var(--ck-balloon-arrow-height);border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:0}.ck.ck-balloon-panel[class*=arrow_n]:before{border-bottom-color:var(--ck-color-panel-border)}.ck.ck-balloon-panel[class*=arrow_n]:after,.ck.ck-balloon-panel[class*=arrow_n]:before{border-left-color:transparent;border-right-color:transparent;border-top-color:transparent}.ck.ck-balloon-panel[class*=arrow_n]:after{border-bottom-color:var(--ck-color-panel-background);margin-top:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-width:var(--ck-balloon-arrow-half-width);border-bottom-width:0;border-right-width:var(--ck-balloon-arrow-half-width);border-top-width:var(--ck-balloon-arrow-height)}.ck.ck-balloon-panel[class*=arrow_s]:before{border-top-color:var(--ck-color-panel-border);filter:drop-shadow(var(--ck-balloon-arrow-drop-shadow))}.ck.ck-balloon-panel[class*=arrow_s]:after,.ck.ck-balloon-panel[class*=arrow_s]:before{border-left-color:transparent;border-bottom-color:transparent;border-right-color:transparent}.ck.ck-balloon-panel[class*=arrow_s]:after{border-top-color:var(--ck-color-panel-background);margin-bottom:var(--ck-balloon-arrow-offset)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:before{left:50%;margin-left:calc(var(--ck-balloon-arrow-half-width)*-1);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:before{left:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:before{right:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:before{left:50%;margin-left:calc(var(--ck-balloon-arrow-half-width)*-1);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:before{left:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:before{right:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sme:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sme:before{right:25%;margin-right:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_smw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_smw:before{left:25%;margin-left:calc(var(--ck-balloon-arrow-half-width)*2);bottom:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nme:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nme:before{right:25%;margin-right:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nmw:after,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nmw:before{left:25%;margin-left:calc(var(--ck-balloon-arrow-half-width)*2);top:calc(var(--ck-balloon-arrow-height)*-1)}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./balloonrotator.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-balloon-rotator__navigation{display:flex;align-items:center;justify-content:center}.ck .ck-balloon-rotator__content .ck-toolbar{justify-content:center}.ck .ck-balloon-rotator__navigation{background:var(--ck-color-toolbar-background);border-bottom:1px solid var(--ck-color-toolbar-border);padding:0 var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation>*{margin-right:var(--ck-spacing-small);margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation .ck-balloon-rotator__counter{margin-right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-small)}.ck .ck-balloon-rotator__content .ck.ck-annotation-wrapper{box-shadow:none}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./fakepanel.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-fake-panel{position:absolute;z-index:calc(var(--ck-z-modal) - 1)}.ck .ck-fake-panel div{position:absolute}.ck .ck-fake-panel div:first-child{z-index:2}.ck .ck-fake-panel div:nth-child(2){z-index:1}:root{--ck-balloon-fake-panel-offset-horizontal:6px;--ck-balloon-fake-panel-offset-vertical:6px}.ck .ck-fake-panel div{box-shadow:var(--ck-drop-shadow),0 0;min-height:15px;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border);border-radius:var(--ck-border-radius);width:100%;height:100%}.ck .ck-fake-panel div:first-child{margin-left:var(--ck-balloon-fake-panel-offset-horizontal);margin-top:var(--ck-balloon-fake-panel-offset-vertical)}.ck .ck-fake-panel div:nth-child(2){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*2);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*2)}.ck .ck-fake-panel div:nth-child(3){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal)*3);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical)*3)}.ck .ck-balloon-panel_arrow_s+.ck-fake-panel,.ck .ck-balloon-panel_arrow_se+.ck-fake-panel,.ck .ck-balloon-panel_arrow_sw+.ck-fake-panel{--ck-balloon-fake-panel-offset-vertical:-6px}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./stickypanel.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-sticky-panel .ck-sticky-panel__content_sticky{z-index:var(--ck-z-modal);position:fixed;top:0}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky_bottom-limit{top:auto;position:absolute}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky{box-shadow:var(--ck-drop-shadow),0 0;border-width:0 1px 1px;border-top-left-radius:0;border-top-right-radius:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./blocktoolbar.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-block-toolbar-button{position:absolute;z-index:var(--ck-z-default)}:root{--ck-color-block-toolbar-button:var(--ck-color-text);--ck-block-toolbar-button-size:var(--ck-font-size-normal)}.ck.ck-block-toolbar-button{color:var(--ck-color-block-toolbar-button);font-size:var(--ck-block-toolbar-size)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./placeholder.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-placeholder,.ck .ck-placeholder{position:relative}.ck.ck-placeholder:before,.ck .ck-placeholder:before{position:absolute;left:0;right:0;content:attr(data-placeholder);pointer-events:none}.ck.ck-read-only .ck-placeholder:before{display:none}.ck.ck-placeholder:before,.ck .ck-placeholder:before{cursor:text;color:var(--ck-color-engine-placeholder-text)}\"","module.exports = \".ck-content code{background-color:hsla(0,0%,78%,.3);padding:.15em;border-radius:2px}.ck.ck-editor__editable .ck-code_selected{background-color:hsla(0,0%,78%,.5)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./blockquote.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content blockquote{overflow:hidden;padding-right:1.5em;padding-left:1.5em;margin-left:0;margin-right:0;font-style:italic;border-left:5px solid #ccc}.ck-content[dir=rtl] blockquote{border-left:0;border-right:5px solid #ccc}\"","module.exports = \".ck.ck-heading_heading1{font-size:20px}.ck.ck-heading_heading2{font-size:17px}.ck.ck-heading_heading3{font-size:14px}.ck[class*=ck-heading_heading]{font-weight:700}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__button .ck-button__label{width:8em}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item{min-width:18em}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./widgettypearound.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-widget .ck-widget__type-around__button{display:block;position:absolute;overflow:hidden;z-index:var(--ck-z-default)}.ck .ck-widget .ck-widget__type-around__button svg{position:absolute;top:50%;left:50%;z-index:calc(var(--ck-z-default) + 2)}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_before{top:calc(var(--ck-widget-outline-thickness)*-0.5);left:min(10%,30px);transform:translateY(-50%)}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_after{bottom:calc(var(--ck-widget-outline-thickness)*-0.5);right:min(10%,30px);transform:translateY(50%)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:after,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover:after{content:\\\"\\\";display:block;position:absolute;top:1px;left:1px;z-index:calc(var(--ck-z-default) + 1)}.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__fake-caret{display:none;position:absolute;left:0;right:0}.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__fake-caret{left:calc(var(--ck-widget-outline-thickness)*-1);right:calc(var(--ck-widget-outline-thickness)*-1)}.ck .ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__fake-caret{top:calc(var(--ck-widget-outline-thickness)*-1 - 1px);display:block}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__fake-caret{bottom:calc(var(--ck-widget-outline-thickness)*-1 - 1px);display:block}.ck.ck-editor__editable.ck-read-only .ck-widget__type-around,.ck.ck-editor__editable.ck-restricted-editing_mode_restricted .ck-widget__type-around,.ck.ck-editor__editable.ck-widget__type-around_disabled .ck-widget__type-around{display:none}:root{--ck-widget-type-around-button-size:20px;--ck-color-widget-type-around-button-active:var(--ck-color-focus-border);--ck-color-widget-type-around-button-hover:var(--ck-color-widget-hover-border);--ck-color-widget-type-around-button-blurred-editable:var(--ck-color-widget-blurred-border);--ck-color-widget-type-around-button-radar-start-alpha:0;--ck-color-widget-type-around-button-radar-end-alpha:.3;--ck-color-widget-type-around-button-icon:var(--ck-color-base-background)}.ck .ck-widget .ck-widget__type-around__button{width:var(--ck-widget-type-around-button-size);height:var(--ck-widget-type-around-button-size);background:var(--ck-color-widget-type-around-button);border-radius:100px;transition:opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);opacity:0;pointer-events:none}.ck .ck-widget .ck-widget__type-around__button svg{width:10px;height:8px;transform:translate(-50%,-50%);transition:transform .5s ease;margin-top:1px}.ck .ck-widget .ck-widget__type-around__button svg *{stroke-dasharray:10;stroke-dashoffset:0;fill:none;stroke:var(--ck-color-widget-type-around-button-icon);stroke-width:1.5px;stroke-linecap:round;stroke-linejoin:round}.ck .ck-widget .ck-widget__type-around__button svg line{stroke-dasharray:7}.ck .ck-widget .ck-widget__type-around__button:hover{animation:ck-widget-type-around-button-sonar 1s ease infinite}.ck .ck-widget .ck-widget__type-around__button:hover svg polyline{animation:ck-widget-type-around-arrow-dash 2s linear}.ck .ck-widget .ck-widget__type-around__button:hover svg line{animation:ck-widget-type-around-arrow-tip-dash 2s linear}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__button{opacity:1;pointer-events:auto}.ck .ck-widget:not(.ck-widget_selected)>.ck-widget__type-around>.ck-widget__type-around__button{background:var(--ck-color-widget-type-around-button-hover)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover{background:var(--ck-color-widget-type-around-button-active)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:after,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover:after{width:calc(var(--ck-widget-type-around-button-size) - 2px);height:calc(var(--ck-widget-type-around-button-size) - 2px);border-radius:100px;background:linear-gradient(135deg,hsla(0,0%,100%,0),hsla(0,0%,100%,.3))}.ck .ck-widget.ck-widget_with-selection-handle>.ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:20px}.ck .ck-widget .ck-widget__type-around__fake-caret{pointer-events:none;height:1px;animation:ck-widget-type-around-fake-caret-pulse 1s linear infinite normal forwards;outline:1px solid hsla(0,0%,100%,.5);background:var(--ck-color-base-text)}.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_after,.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_before{outline-color:transparent}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_selected:hover,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_selected:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_with-selection-handle.ck-widget_selected:hover>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_with-selection-handle.ck-widget_selected>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_with-selection-handle.ck-widget_selected:hover>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_with-selection-handle.ck-widget_selected>.ck-widget__selection-handle{opacity:0}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after.ck-widget_selected.ck-widget_with-resizer>.ck-widget__resizer,.ck .ck-widget.ck-widget_type-around_show-fake-caret_before.ck-widget_selected.ck-widget_with-resizer>.ck-widget__resizer{opacity:0}.ck[dir=rtl] .ck-widget.ck-widget_with-selection-handle .ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:0;margin-right:20px}.ck-editor__nested-editable.ck-editor__editable_selected .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck-editor__nested-editable.ck-editor__editable_selected .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover){background:var(--ck-color-widget-type-around-button-blurred-editable)}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover) svg *{stroke:#999}@keyframes ck-widget-type-around-arrow-dash{0%{stroke-dashoffset:10}20%,to{stroke-dashoffset:0}}@keyframes ck-widget-type-around-arrow-tip-dash{0%,20%{stroke-dashoffset:7}40%,to{stroke-dashoffset:0}}@keyframes ck-widget-type-around-button-sonar{0%{box-shadow:0 0 0 0 hsla(var(--ck-color-focus-border-coordinates),var(--ck-color-widget-type-around-button-radar-start-alpha))}50%{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates),var(--ck-color-widget-type-around-button-radar-end-alpha))}to{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates),var(--ck-color-widget-type-around-button-radar-start-alpha))}}@keyframes ck-widget-type-around-fake-caret-pulse{0%{opacity:1}49%{opacity:1}50%{opacity:0}99%{opacity:0}to{opacity:1}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./widget.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-color-resizer:var(--ck-color-focus-border);--ck-color-resizer-tooltip-background:#262626;--ck-color-resizer-tooltip-text:#f2f2f2;--ck-resizer-border-radius:var(--ck-border-radius);--ck-resizer-tooltip-offset:10px}.ck .ck-widget,.ck .ck-widget.ck-widget_with-selection-handle{position:relative}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{position:absolute}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{display:block}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle:hover>.ck-widget__selection-handle{visibility:visible}.ck .ck-size-view{background:var(--ck-color-resizer-tooltip-background);color:var(--ck-color-resizer-tooltip-text);border:1px solid var(--ck-color-resizer-tooltip-text);border-radius:var(--ck-resizer-border-radius);font-size:var(--ck-font-size-tiny);display:block;padding:var(--ck-spacing-small)}.ck .ck-size-view.ck-orientation-bottom-left,.ck .ck-size-view.ck-orientation-bottom-right,.ck .ck-size-view.ck-orientation-top-left,.ck .ck-size-view.ck-orientation-top-right{position:absolute}.ck .ck-size-view.ck-orientation-top-left{top:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-top-right{top:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-right{bottom:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-left{bottom:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}:root{--ck-widget-outline-thickness:3px;--ck-widget-handler-icon-size:16px;--ck-widget-handler-animation-duration:200ms;--ck-widget-handler-animation-curve:ease;--ck-color-widget-blurred-border:#dedede;--ck-color-widget-hover-border:#ffc83d;--ck-color-widget-editable-focus-background:var(--ck-color-base-background);--ck-color-widget-drag-handler-icon-color:var(--ck-color-base-background)}.ck .ck-widget{outline-width:var(--ck-widget-outline-thickness);outline-style:solid;outline-color:transparent;transition:outline-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_selected,.ck .ck-widget.ck-widget_selected:hover{outline:var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border)}.ck .ck-widget:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-editor__nested-editable{border:1px solid transparent}.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{outline:none;border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow),0 0;background-color:var(--ck-color-widget-editable-focus-background)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{padding:4px;box-sizing:border-box;background-color:transparent;opacity:0;transition:background-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),visibility var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve),opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);border-radius:var(--ck-border-radius) var(--ck-border-radius) 0 0;transform:translateY(-100%);left:calc(0px - var(--ck-widget-outline-thickness))}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{width:var(--ck-widget-handler-icon-size);height:var(--ck-widget-handler-icon-size);color:var(--ck-color-widget-drag-handler-icon-color)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:0;transition:opacity .3s var(--ck-widget-handler-animation-curve)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle:hover>.ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-widget-hover-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover>.ck-widget__selection-handle,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected>.ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-focus-border)}.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover>.ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator,.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected>.ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:1}.ck[dir=rtl] .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{left:auto;right:calc(0px - var(--ck-widget-outline-thickness))}.ck.ck-editor__editable.ck-read-only .ck-widget{transition:none}.ck.ck-editor__editable.ck-read-only .ck-widget:not(.ck-widget_selected){--ck-widget-outline-thickness:0px}.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover{outline-color:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle>.ck-widget__selection-handle,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected.ck-widget_with-selection-handle>.ck-widget__selection-handle:hover,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle>.ck-widget__selection-handle,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover.ck-widget_with-selection-handle>.ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable>.ck-widget.ck-widget_with-selection-handle:first-child,.ck.ck-editor__editable blockquote>.ck-widget.ck-widget_with-selection-handle:first-child{margin-top:calc(1em + var(--ck-widget-handler-icon-size))}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./widgetresize.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-widget_with-resizer{position:relative}.ck .ck-widget__resizer{display:none;position:absolute;pointer-events:none;left:0;top:0}.ck-focused .ck-widget_with-resizer.ck-widget_selected>.ck-widget__resizer{display:block}.ck .ck-widget__resizer__handle{position:absolute;pointer-events:all}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right,.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left{cursor:nwse-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left,.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right{cursor:nesw-resize}:root{--ck-resizer-size:10px;--ck-resizer-offset:calc(var(--ck-resizer-size)/-2 - 2px);--ck-resizer-border-width:1px}.ck .ck-widget__resizer{outline:1px solid var(--ck-color-resizer)}.ck .ck-widget__resizer__handle{width:var(--ck-resizer-size);height:var(--ck-resizer-size);background:var(--ck-color-focus-border);border:var(--ck-resizer-border-width) solid #fff;border-radius:var(--ck-resizer-border-radius)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left{top:var(--ck-resizer-offset);left:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right{top:var(--ck-resizer-offset);right:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right{bottom:var(--ck-resizer-offset);right:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left{bottom:var(--ck-resizer-offset);left:var(--ck-resizer-offset)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./textalternativeform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-text-alternative-form{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-text-alternative-form .ck-labeled-field-view{display:inline-block}.ck.ck-text-alternative-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-text-alternative-form{flex-wrap:wrap}.ck.ck-text-alternative-form .ck-labeled-field-view{flex-basis:100%}.ck.ck-text-alternative-form .ck-button{flex-basis:50%}}\"","module.exports = \".ck-vertical-form .ck-button:after{content:\\\"\\\";width:0;position:absolute;right:-1px;top:var(--ck-spacing-small);bottom:var(--ck-spacing-small);z-index:1}@media screen and (max-width:600px){.ck.ck-responsive-form .ck-button:after{content:\\\"\\\";width:0;position:absolute;right:-1px;top:var(--ck-spacing-small);bottom:var(--ck-spacing-small);z-index:1}}.ck-vertical-form>.ck-button:nth-last-child(2):after{border-right:1px solid var(--ck-color-base-border)}.ck.ck-responsive-form{padding:var(--ck-spacing-large)}.ck.ck-responsive-form:focus{outline:none}[dir=ltr] .ck.ck-responsive-form>:not(:first-child),[dir=rtl] .ck.ck-responsive-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-responsive-form{padding:0;width:calc(var(--ck-input-text-width)*0.8)}.ck.ck-responsive-form .ck-labeled-field-view{margin:var(--ck-spacing-large) var(--ck-spacing-large) 0}.ck.ck-responsive-form .ck-labeled-field-view .ck-input-text{min-width:0;width:100%}.ck.ck-responsive-form .ck-labeled-field-view .ck-labeled-field-view__error{white-space:normal}.ck.ck-responsive-form>.ck-button:last-child,.ck.ck-responsive-form>.ck-button:nth-last-child(2){padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-large);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-responsive-form>.ck-button:last-child,[dir=ltr] .ck.ck-responsive-form>.ck-button:nth-last-child(2),[dir=rtl] .ck.ck-responsive-form>.ck-button:last-child,[dir=rtl] .ck.ck-responsive-form>.ck-button:nth-last-child(2){margin-left:0}.ck.ck-responsive-form>.ck-button:nth-last-child(2):after,[dir=rtl] .ck.ck-responsive-form>.ck-button:last-child:last-of-type,[dir=rtl] .ck.ck-responsive-form>.ck-button:nth-last-child(2):last-of-type{border-right:1px solid var(--ck-color-base-border)}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./image.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .image{display:table;clear:both;text-align:center;margin:1em auto}.ck-content .image img{display:block;margin:0 auto;max-width:100%;min-width:50px}.ck.ck-editor__editable .image>figcaption.ck-placeholder:before{position:static}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imagecaption.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .image>figcaption{display:table-caption;caption-side:bottom;word-break:break-word;color:#333;background-color:#f7f7f7;padding:.6em;font-size:.75em;outline-offset:-1px}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imagestyle.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-image-style-spacing:1.5em}.ck-content .image-style-side{float:right;margin-left:var(--ck-image-style-spacing);max-width:50%}.ck-content .image-style-align-left{float:left;margin-right:var(--ck-image-style-spacing)}.ck-content .image-style-align-center{margin-left:auto;margin-right:auto}.ck-content .image-style-align-right{float:right;margin-left:var(--ck-image-style-spacing)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imageuploadprogress.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-editor__editable .image{position:relative}.ck.ck-editor__editable .image .ck-progress-bar{position:absolute;top:0;left:0}.ck.ck-editor__editable .image.ck-appear{animation:fadeIn .7s}.ck.ck-editor__editable .image .ck-progress-bar{height:2px;width:0;background:var(--ck-color-upload-bar-background);transition:width .1s}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imageuploadicon.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-image-upload-complete-icon{display:block;position:absolute;top:10px;right:10px;border-radius:50%}.ck-image-upload-complete-icon:after{content:\\\"\\\";position:absolute}:root{--ck-color-image-upload-icon:#fff;--ck-color-image-upload-icon-background:#008a00;--ck-image-upload-icon-size:20px;--ck-image-upload-icon-width:2px}.ck-image-upload-complete-icon{width:var(--ck-image-upload-icon-size);height:var(--ck-image-upload-icon-size);opacity:0;background:var(--ck-color-image-upload-icon-background);animation-name:ck-upload-complete-icon-show,ck-upload-complete-icon-hide;animation-fill-mode:forwards,forwards;animation-duration:.5s,.5s;font-size:var(--ck-image-upload-icon-size);animation-delay:0ms,3s}.ck-image-upload-complete-icon:after{left:25%;top:50%;opacity:0;height:0;width:0;transform:scaleX(-1) rotate(135deg);transform-origin:left top;border-top:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);border-right:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);animation-name:ck-upload-complete-icon-check;animation-duration:.5s;animation-delay:.5s;animation-fill-mode:forwards;box-sizing:border-box}@keyframes ck-upload-complete-icon-show{0%{opacity:0}to{opacity:1}}@keyframes ck-upload-complete-icon-hide{0%{opacity:1}to{opacity:0}}@keyframes ck-upload-complete-icon-check{0%{opacity:1;width:0;height:0}33%{width:.3em;height:0}to{opacity:1;width:.3em;height:.45em}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imageuploadloader.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-upload-placeholder-loader{position:absolute;display:flex;align-items:center;justify-content:center;top:0;left:0}.ck .ck-upload-placeholder-loader:before{content:\\\"\\\";position:relative}:root{--ck-color-upload-placeholder-loader:#b3b3b3;--ck-upload-placeholder-loader-size:32px}.ck .ck-image-upload-placeholder{width:100%;margin:0}.ck .ck-upload-placeholder-loader{width:100%;height:100%}.ck .ck-upload-placeholder-loader:before{width:var(--ck-upload-placeholder-loader-size);height:var(--ck-upload-placeholder-loader-size);border-radius:50%;border-top:3px solid var(--ck-color-upload-placeholder-loader);border-right:2px solid transparent;animation:ck-upload-placeholder-loader 1s linear infinite}@keyframes ck-upload-placeholder-loader{to{transform:rotate(1turn)}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./clipboard.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-editor__editable .ck.ck-clipboard-drop-target-position{display:inline;position:relative;pointer-events:none}.ck.ck-editor__editable .ck.ck-clipboard-drop-target-position span{position:absolute;width:0}.ck.ck-editor__editable .ck-widget:-webkit-drag>.ck-widget__selection-handle,.ck.ck-editor__editable .ck-widget:-webkit-drag>.ck-widget__type-around{display:none}:root{--ck-clipboard-drop-target-dot-width:12px;--ck-clipboard-drop-target-dot-height:8px;--ck-clipboard-drop-target-color:var(--ck-color-focus-border)}.ck.ck-editor__editable .ck.ck-clipboard-drop-target-position span{bottom:calc(var(--ck-clipboard-drop-target-dot-height)*-0.5);top:calc(var(--ck-clipboard-drop-target-dot-height)*-0.5);border:1px solid var(--ck-clipboard-drop-target-color);background:var(--ck-clipboard-drop-target-color);margin-left:-1px}.ck.ck-editor__editable .ck.ck-clipboard-drop-target-position span:after{content:\\\"\\\";width:0;height:0;display:block;position:absolute;left:50%;top:calc(var(--ck-clipboard-drop-target-dot-height)*-0.5);transform:translateX(-50%);border-left:calc(var(--ck-clipboard-drop-target-dot-width)*0.5) solid transparent;border-bottom:0 solid transparent;border-right:calc(var(--ck-clipboard-drop-target-dot-width)*0.5) solid transparent;border-top:calc(var(--ck-clipboard-drop-target-dot-height)) solid var(--ck-clipboard-drop-target-color)}.ck.ck-editor__editable .ck-widget.ck-clipboard-drop-target-range{outline:var(--ck-widget-outline-thickness) solid var(--ck-clipboard-drop-target-color)!important}.ck.ck-editor__editable .ck-widget:-webkit-drag{zoom:.6;outline:none!important}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./imageresize.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .image.image_resized{max-width:100%;display:block;box-sizing:border-box}.ck-content .image.image_resized img{width:100%}.ck-content .image.image_resized>figcaption{display:block}[dir=ltr] .ck.ck-button.ck-button_with-text.ck-resize-image-button .ck-button__icon{margin-right:var(--ck-spacing-standard)}[dir=rtl] .ck.ck-button.ck-button_with-text.ck-resize-image-button .ck-button__icon{margin-left:var(--ck-spacing-standard)}.ck.ck-dropdown .ck-button.ck-resize-image-button .ck-button__label{width:4em}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./link.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-link_selected{background:var(--ck-color-link-selected-background)}.ck .ck-fake-link-selection{background:var(--ck-color-link-fake-selection)}.ck .ck-fake-link-selection_collapsed{height:100%;border-right:1px solid var(--ck-color-base-text);margin-right:-1px;outline:1px solid hsla(0,0%,100%,.5)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./linkform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-link-form{display:flex}.ck.ck-link-form .ck-label{display:none}@media screen and (max-width:600px){.ck.ck-link-form{flex-wrap:wrap}.ck.ck-link-form .ck-labeled-field-view{flex-basis:100%}.ck.ck-link-form .ck-button{flex-basis:50%}}.ck.ck-link-form_layout-vertical{display:block}.ck.ck-link-form_layout-vertical .ck-button.ck-button-cancel,.ck.ck-link-form_layout-vertical .ck-button.ck-button-save{margin-top:var(--ck-spacing-medium)}.ck.ck-link-form_layout-vertical{padding:0;min-width:var(--ck-input-text-width)}.ck.ck-link-form_layout-vertical .ck-labeled-field-view{margin:var(--ck-spacing-large) var(--ck-spacing-large) var(--ck-spacing-small)}.ck.ck-link-form_layout-vertical .ck-labeled-field-view .ck-input-text{min-width:0;width:100%}.ck.ck-link-form_layout-vertical .ck-button{padding:var(--ck-spacing-standard);margin:0;border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border);width:50%}[dir=ltr] .ck.ck-link-form_layout-vertical .ck-button,[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button{margin-left:0}[dir=rtl] .ck.ck-link-form_layout-vertical .ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}.ck.ck-link-form_layout-vertical .ck.ck-list{margin:var(--ck-spacing-standard) var(--ck-spacing-large)}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton{border:0;padding:0;width:100%}.ck.ck-link-form_layout-vertical .ck.ck-list .ck-button.ck-switchbutton:hover{background:none}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./linkactions.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-link-actions{display:flex;flex-direction:row;flex-wrap:nowrap}.ck.ck-link-actions .ck-link-actions__preview{display:inline-block}.ck.ck-link-actions .ck-link-actions__preview .ck-button__label{overflow:hidden}@media screen and (max-width:600px){.ck.ck-link-actions{flex-wrap:wrap}.ck.ck-link-actions .ck-link-actions__preview{flex-basis:100%}.ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){flex-basis:50%}}.ck.ck-link-actions .ck-button.ck-link-actions__preview{padding-left:0;padding-right:0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{padding:0 var(--ck-spacing-medium);color:var(--ck-color-link-default);text-overflow:ellipsis;cursor:pointer;max-width:var(--ck-input-text-width);min-width:3em;text-align:center}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label:hover{text-decoration:underline}.ck.ck-link-actions .ck-button.ck-link-actions__preview,.ck.ck-link-actions .ck-button.ck-link-actions__preview:active,.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus,.ck.ck-link-actions .ck-button.ck-link-actions__preview:hover{background:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:active{box-shadow:none}.ck.ck-link-actions .ck-button.ck-link-actions__preview:focus .ck-button__label{text-decoration:underline}[dir=ltr] .ck.ck-link-actions .ck-button:not(:first-child),[dir=rtl] .ck.ck-link-actions .ck-button:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-link-actions .ck-button.ck-link-actions__preview{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-link-actions .ck-button.ck-link-actions__preview .ck-button__label{min-width:0;max-width:100%}[dir=ltr] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview),[dir=rtl] .ck.ck-link-actions .ck-button:not(.ck-link-actions__preview){margin-left:0}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./liststyles.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-list-styles-dropdown>.ck-dropdown__panel>.ck-toolbar>.ck-toolbar__items{display:grid}:root{--ck-list-style-button-size:44px}.ck.ck-list-styles-dropdown>.ck-dropdown__panel>.ck-toolbar{background:none;padding:0}.ck.ck-list-styles-dropdown>.ck-dropdown__panel>.ck-toolbar>.ck-toolbar__items{grid-template-columns:repeat(3,auto);row-gap:var(--ck-spacing-medium);column-gap:var(--ck-spacing-medium);padding:var(--ck-spacing-medium)}.ck.ck-list-styles-dropdown>.ck-dropdown__panel>.ck-toolbar>.ck-toolbar__items .ck-button{width:var(--ck-list-style-button-size);height:var(--ck-list-style-button-size);padding:0;margin:0;box-sizing:content-box}.ck.ck-list-styles-dropdown>.ck-dropdown__panel>.ck-toolbar>.ck-toolbar__items .ck-button .ck-icon{width:var(--ck-list-style-button-size);height:var(--ck-list-style-button-size)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./todolist.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-todo-list-checkmark-size:16px}.ck-content .todo-list{list-style:none}.ck-content .todo-list li{margin-bottom:5px}.ck-content .todo-list li .todo-list{margin-top:5px}.ck-content .todo-list .todo-list__label>input{-webkit-appearance:none;display:inline-block;position:relative;width:var(--ck-todo-list-checkmark-size);height:var(--ck-todo-list-checkmark-size);vertical-align:middle;border:0;left:-25px;margin-right:-15px;right:0;margin-left:0}.ck-content .todo-list .todo-list__label>input:before{display:block;position:absolute;box-sizing:border-box;content:\\\"\\\";width:100%;height:100%;border:1px solid #333;border-radius:2px;transition:box-shadow .25s ease-in-out,background .25s ease-in-out,border .25s ease-in-out}.ck-content .todo-list .todo-list__label>input:after{display:block;position:absolute;box-sizing:content-box;pointer-events:none;content:\\\"\\\";left:calc(var(--ck-todo-list-checkmark-size)/3);top:calc(var(--ck-todo-list-checkmark-size)/5.3);width:calc(var(--ck-todo-list-checkmark-size)/5.3);height:calc(var(--ck-todo-list-checkmark-size)/2.6);border-left:0 solid transparent;border-bottom:calc(var(--ck-todo-list-checkmark-size)/8) solid transparent;border-right:calc(var(--ck-todo-list-checkmark-size)/8) solid transparent;border-top:0 solid transparent;transform:rotate(45deg)}.ck-content .todo-list .todo-list__label>input[checked]:before{background:#26ab33;border-color:#26ab33}.ck-content .todo-list .todo-list__label>input[checked]:after{border-color:#fff}.ck-content .todo-list .todo-list__label .todo-list__label__description{vertical-align:middle}[dir=rtl] .todo-list .todo-list__label>input{left:0;margin-right:0;right:-25px;margin-left:-15px}.ck-editor__editable .todo-list .todo-list__label>input{cursor:pointer}.ck-editor__editable .todo-list .todo-list__label>input:hover:before{box-shadow:0 0 0 5px rgba(0,0,0,.1)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tableediting.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-color-table-focused-cell-background:rgba(158,207,250,0.3)}.ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck-widget.table td.ck-editor__nested-editable:focus,.ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck-widget.table th.ck-editor__nested-editable:focus{background:var(--ck-color-table-focused-cell-background);border-style:none;outline:1px solid var(--ck-color-focus-border);outline-offset:-1px}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./inserttable.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-insert-table-dropdown__grid{display:flex;flex-direction:row;flex-wrap:wrap}:root{--ck-insert-table-dropdown-padding:10px;--ck-insert-table-dropdown-box-height:11px;--ck-insert-table-dropdown-box-width:12px;--ck-insert-table-dropdown-box-margin:1px}.ck .ck-insert-table-dropdown__grid{width:calc(var(--ck-insert-table-dropdown-box-width)*10 + var(--ck-insert-table-dropdown-box-margin)*20 + var(--ck-insert-table-dropdown-padding)*2);padding:var(--ck-insert-table-dropdown-padding) var(--ck-insert-table-dropdown-padding) 0}.ck .ck-insert-table-dropdown__label{text-align:center}.ck .ck-insert-table-dropdown-grid-box{width:var(--ck-insert-table-dropdown-box-width);height:var(--ck-insert-table-dropdown-box-height);margin:var(--ck-insert-table-dropdown-box-margin);border:1px solid var(--ck-color-base-border);border-radius:1px}.ck .ck-insert-table-dropdown-grid-box.ck-on{border-color:var(--ck-color-focus-border);background:var(--ck-color-focus-outer-shadow)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tableselection.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-table-selected-cell-background:rgba(158,207,250,0.3)}.ck.ck-editor__editable .table table td.ck-editor__editable_selected,.ck.ck-editor__editable .table table th.ck-editor__editable_selected{position:relative;caret-color:transparent;outline:unset;box-shadow:unset}.ck.ck-editor__editable .table table td.ck-editor__editable_selected:after,.ck.ck-editor__editable .table table th.ck-editor__editable_selected:after{content:\\\"\\\";pointer-events:none;background-color:var(--ck-table-selected-cell-background);position:absolute;top:0;left:0;right:0;bottom:0}.ck.ck-editor__editable .table table td.ck-editor__editable_selected ::selection,.ck.ck-editor__editable .table table td.ck-editor__editable_selected:focus,.ck.ck-editor__editable .table table th.ck-editor__editable_selected ::selection,.ck.ck-editor__editable .table table th.ck-editor__editable_selected:focus{background-color:transparent}.ck.ck-editor__editable .table table td.ck-editor__editable_selected .ck-widget_selected,.ck.ck-editor__editable .table table th.ck-editor__editable_selected .ck-widget_selected{outline:unset}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./table.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .table{margin:1em auto;display:table}.ck-content .table table{border-collapse:collapse;border-spacing:0;width:100%;height:100%;border:1px double #b3b3b3}.ck-content .table table td,.ck-content .table table th{min-width:2em;padding:.4em;border:1px solid #bfbfbf}.ck-content .table table th{font-weight:700;background:hsla(0,0%,0%,5%)}.ck-content[dir=rtl] .table th{text-align:right}.ck-content[dir=ltr] .table th{text-align:left}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./colorinput.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-input-color{width:100%;display:flex;flex-direction:row-reverse}.ck.ck-input-color>input.ck.ck-input-text{min-width:auto;flex-grow:1}.ck.ck-input-color>div.ck.ck-dropdown{min-width:auto}.ck.ck-input-color>div.ck.ck-dropdown>.ck-input-color__button .ck-dropdown__arrow{display:none}.ck.ck-input-color .ck.ck-input-color__button .ck.ck-input-color__button__preview{position:relative;overflow:hidden}.ck.ck-input-color .ck.ck-input-color__button .ck.ck-input-color__button__preview>.ck.ck-input-color__button__preview__no-color-indicator{position:absolute;display:block}[dir=ltr] .ck.ck-input-color>.ck.ck-input-text{border-top-right-radius:0;border-bottom-right-radius:0}[dir=rtl] .ck.ck-input-color>.ck.ck-input-text{border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button{padding:0}[dir=ltr] .ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button{border-left-width:0;border-top-left-radius:0;border-bottom-left-radius:0}[dir=rtl] .ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button{border-right-width:0;border-top-right-radius:0;border-bottom-right-radius:0}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button.ck-disabled{background:var(--ck-color-input-disabled-background)}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview{border-radius:0}.ck-rounded-corners .ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview,.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview{width:20px;height:20px;border:1px solid var(--ck-color-input-border)}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview>.ck.ck-input-color__button__preview__no-color-indicator{top:-30%;left:50%;height:150%;width:8%;background:red;border-radius:2px;transform:rotate(45deg);transform-origin:50%}.ck.ck-input-color .ck.ck-input-color__remove-color{width:100%;border-bottom:1px solid var(--ck-color-input-border);padding:calc(var(--ck-spacing-standard)/2) var(--ck-spacing-standard);border-bottom-left-radius:0;border-bottom-right-radius:0}[dir=ltr] .ck.ck-input-color .ck.ck-input-color__remove-color{border-top-right-radius:0}[dir=rtl] .ck.ck-input-color .ck.ck-input-color__remove-color{border-top-left-radius:0}.ck.ck-input-color .ck.ck-input-color__remove-color .ck.ck-icon{margin-right:var(--ck-spacing-standard)}[dir=rtl] .ck.ck-input-color .ck.ck-input-color__remove-color .ck.ck-icon{margin-right:0;margin-left:var(--ck-spacing-standard)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./formrow.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-form__row{display:flex;flex-direction:row;flex-wrap:nowrap;justify-content:space-between}.ck.ck-form__row>:not(.ck-label){flex-grow:1}.ck.ck-form__row.ck-table-form__action-row .ck-button-cancel,.ck.ck-form__row.ck-table-form__action-row .ck-button-save{justify-content:center}.ck.ck-form__row{padding:var(--ck-spacing-standard) var(--ck-spacing-large) 0}[dir=ltr] .ck.ck-form__row>:not(.ck-label)+*{margin-left:var(--ck-spacing-large)}[dir=rtl] .ck.ck-form__row>:not(.ck-label)+*{margin-right:var(--ck-spacing-large)}.ck.ck-form__row>.ck-label{width:100%;min-width:100%}.ck.ck-form__row.ck-table-form__action-row{margin-top:var(--ck-spacing-large)}.ck.ck-form__row.ck-table-form__action-row .ck-button .ck-button__label{color:var(--ck-color-text)}\"","module.exports = \".ck.ck-form{padding:0 0 var(--ck-spacing-large)}.ck.ck-form:focus{outline:none}.ck.ck-form .ck.ck-input-text{min-width:100%;width:0}.ck.ck-form .ck.ck-dropdown{min-width:100%}.ck.ck-form .ck.ck-dropdown .ck-dropdown__button:not(:focus){border:1px solid var(--ck-color-base-border)}.ck.ck-form .ck.ck-dropdown .ck-dropdown__button .ck-button__label{width:100%}\"","module.exports = \".ck.ck-table-form .ck-form__row.ck-table-form__background-row,.ck.ck-table-form .ck-form__row.ck-table-form__border-row{flex-wrap:wrap}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row{flex-wrap:wrap;align-items:center}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-labeled-field-view{display:flex;flex-direction:column-reverse;align-items:center}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-labeled-field-view .ck.ck-dropdown,.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimension-operator{flex-grow:0}.ck.ck-table-form .ck.ck-labeled-field-view{position:relative}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{position:absolute;left:50%;bottom:calc(var(--ck-table-properties-error-arrow-size)*-1);transform:translate(-50%,100%);z-index:1}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status:after{content:\\\"\\\";position:absolute;top:calc(var(--ck-table-properties-error-arrow-size)*-1);left:50%;transform:translateX(-50%)}:root{--ck-table-properties-error-arrow-size:6px;--ck-table-properties-min-error-width:150px}.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-labeled-field-view>.ck-label{font-size:var(--ck-font-size-tiny);text-align:center}.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-style,.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-width{width:80px;min-width:80px;max-width:80px}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row{padding:0}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__height,.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__width{margin:0}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimension-operator{align-self:flex-end;display:inline-block;height:var(--ck-ui-component-min-height);line-height:var(--ck-ui-component-min-height);margin:0 var(--ck-spacing-small)}.ck.ck-table-form .ck.ck-labeled-field-view{padding-top:var(--ck-spacing-standard)}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{border-radius:0}.ck-rounded-corners .ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status,.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status.ck-rounded-corners{border-radius:var(--ck-border-radius)}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{background:var(--ck-color-base-error);color:var(--ck-color-base-background);padding:var(--ck-spacing-small) var(--ck-spacing-medium);min-width:var(--ck-table-properties-min-error-width);text-align:center}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status:after{border-left:var(--ck-table-properties-error-arrow-size) solid transparent;border-bottom:var(--ck-table-properties-error-arrow-size) solid var(--ck-color-base-error);border-right:var(--ck-table-properties-error-arrow-size) solid transparent;border-top:0 solid transparent}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{animation:ck-table-form-labeled-view-status-appear .15s ease both}.ck.ck-table-form .ck.ck-labeled-field-view .ck-input.ck-error:not(:focus)+.ck.ck-labeled-field-view__status{display:none}@keyframes ck-table-form-labeled-view-status-appear{0%{opacity:0}to{opacity:1}}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tableproperties.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row{flex-wrap:wrap;flex-basis:0;align-content:baseline}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar .ck-toolbar__items{flex-wrap:nowrap}.ck.ck-table-properties-form{width:320px}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row{align-self:flex-end;padding:0}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar{background:none;margin-top:var(--ck-spacing-standard)}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar .ck-toolbar__items>*{width:40px}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./tablecellproperties.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row{flex-wrap:wrap}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar:first-of-type{flex-grow:0.57}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar:last-of-type{flex-grow:0.43}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar .ck-button{flex-grow:1}.ck.ck-table-cell-properties-form{width:320px}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__padding-row{align-self:flex-end;padding:0;width:25%}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar{background:none;margin-top:var(--ck-spacing-standard)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./fontcolor.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck .ck-button.ck-color-table__remove-color{display:flex;align-items:center;width:100%}label.ck.ck-color-grid__label{font-weight:unset}.ck .ck-button.ck-color-table__remove-color{padding:calc(var(--ck-spacing-standard)/2) var(--ck-spacing-standard);border-bottom-left-radius:0;border-bottom-right-radius:0}.ck .ck-button.ck-color-table__remove-color:not(:focus){border-bottom:1px solid var(--ck-color-base-border)}[dir=ltr] .ck .ck-button.ck-color-table__remove-color .ck.ck-icon{margin-right:var(--ck-spacing-standard)}[dir=rtl] .ck .ck-button.ck-color-table__remove-color .ck.ck-icon{margin-left:var(--ck-spacing-standard)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./fontsize.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content .text-tiny{font-size:.7em}.ck-content .text-small{font-size:.85em}.ck-content .text-big{font-size:1.4em}.ck-content .text-huge{font-size:1.8em}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./codeblock.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-content pre{padding:1em;color:#353535;background:hsla(0,0%,78%,.3);border:1px solid #c4c4c4;border-radius:2px;text-align:left;direction:ltr;tab-size:4;white-space:pre-wrap;font-style:normal;min-width:200px}.ck-content pre code{background:unset;padding:0;border-radius:0}.ck.ck-editor__editable pre{position:relative}.ck.ck-editor__editable pre[data-language]:after{content:attr(data-language);position:absolute}:root{--ck-color-code-block-label-background:#757575}.ck.ck-editor__editable pre[data-language]:after{top:-1px;right:10px;background:var(--ck-color-code-block-label-background);font-size:10px;font-family:var(--ck-font-face);line-height:16px;padding:var(--ck-spacing-tiny) var(--ck-spacing-medium);color:#fff;white-space:nowrap}.ck.ck-code-block-dropdown .ck-dropdown__panel{max-height:250px;overflow-y:auto;overflow-x:hidden}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./mentionui.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-mention-list-max-height:300px}.ck.ck-mentions{max-height:var(--ck-mention-list-max-height);overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}.ck.ck-mentions>.ck-list__item{overflow:hidden;flex-shrink:0}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./mention.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \":root{--ck-color-mention-background:rgba(153,0,48,0.1);--ck-color-mention-text:#990030}.ck-content .mention{background:var(--ck-color-mention-background);color:var(--ck-color-mention-text)}\"","var api = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../node_modules/postcss-loader/src/index.js??ref--5-1!./horizontalline.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck-editor__editable .ck-horizontal-line{display:flow-root}.ck-content hr{margin:15px 0;height:4px;background:#dedede;border:0}\"","var api = require(\"!../../../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../../../../node_modules/postcss-loader/src/index.js??ref--5-1!./labeledinput.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-labeled-input .ck-labeled-input__status{font-size:var(--ck-font-size-small);margin-top:var(--ck-spacing-small);white-space:normal}.ck.ck-labeled-input .ck-labeled-input__status_error{color:var(--ck-color-base-error)}\"","var api = require(\"!../../style-loader/dist/runtime/injectStylesIntoStyleTag.js\");\n var content = require(\"!!../../postcss-loader/src/index.js??ref--5-1!./mathform.css\");\n\n content = content.__esModule ? content.default : content;\n\n if (typeof content === 'string') {\n content = [[module.id, content, '']];\n }\n\nvar options = {\"injectType\":\"singletonStyleTag\",\"attributes\":{\"data-cke\":true}};\n\noptions.insert = \"head\";\noptions.singleton = true;\n\nvar update = api(content, options);\n\n\n\nmodule.exports = content.locals || {};","module.exports = \".ck.ck-math-form{display:flex;align-items:flex-start;flex-direction:row;flex-wrap:nowrap}@media screen and (max-width:600px){.ck.ck-math-form{flex-wrap:wrap}.ck.ck-math-form .ck-math-view,.ck.ck-math-form .ck-math-view .ck-label,.ck.ck-math-form .ck-math-view .ck-labeled-input{flex-basis:100%}.ck.ck-math-form .ck-button{flex-basis:50%}}.ck-math-tex.ck-placeholder:before{display:none!important}.ck.ck-toolbar-container{z-index:calc(var(--ck-z-modal) + 2)}.ck.ck-math-form{padding:var(--ck-spacing-standard)}.ck.ck-math-form:focus{outline:none}[dir=ltr] .ck.ck-math-form>:not(:first-child),[dir=rtl] .ck.ck-math-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (max-width:600px){.ck.ck-math-form{padding:0}.ck.ck-math-form .ck-labeled-input{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-math-form .ck-labeled-input .ck-input-text{min-width:0;width:100%}.ck.ck-math-form .ck-label,.ck.ck-math-form .ck-math-view .ck-button,.ck.ck-math-form .ck-math-view .ck.ck-math-preview{margin:var(--ck-spacing-standard) var(--ck-spacing-standard) 0}.ck.ck-math-form>.ck-button{padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-standard);border-radius:0;border:0;border-top:1px solid var(--ck-color-base-border)}[dir=ltr] .ck.ck-math-form>.ck-button{margin-left:0}[dir=ltr] .ck.ck-math-form>.ck-button:first-of-type{border-right:1px solid var(--ck-color-base-border)}[dir=rtl] .ck.ck-math-form>.ck-button{margin-left:0}[dir=rtl] .ck.ck-math-form>.ck-button:last-of-type{border-right:1px solid var(--ck-color-base-border)}}\"","/**\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 utils/spy\n */\n\n/**\n * Creates a spy function (ala Sinon.js) that can be used to inspect call to it.\n *\n * The following are the present features:\n *\n * * spy.called: property set to `true` if the function has been called at least once.\n *\n * @returns {Function} The spy function.\n */\nfunction spy() {\n\treturn function spy() {\n\t\tspy.called = true;\n\t};\n}\n\nexport default spy;\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 utils/eventinfo\n */\n\nimport spy from './spy';\n\n/**\n * The event object passed to event callbacks. It is used to provide information about the event as well as a tool to\n * manipulate it.\n */\nexport default class EventInfo {\n\t/**\n\t * @param {Object} source The emitter.\n\t * @param {String} name The event name.\n\t */\n\tconstructor( source, name ) {\n\t\t/**\n\t\t * The object that fired the event.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object}\n\t\t */\n\t\tthis.source = source;\n\n\t\t/**\n\t\t * The event name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Path this event has followed. See {@link module:utils/emittermixin~EmitterMixin#delegate}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<Object>}\n\t\t */\n\t\tthis.path = [];\n\n\t\t// The following methods are defined in the constructor because they must be re-created per instance.\n\n\t\t/**\n\t\t * Stops the event emitter to call further callbacks for this event interaction.\n\t\t *\n\t\t * @method #stop\n\t\t */\n\t\tthis.stop = spy();\n\n\t\t/**\n\t\t * Removes the current callback from future interactions of this event.\n\t\t *\n\t\t * @method #off\n\t\t */\n\t\tthis.off = spy();\n\n\t\t/**\n\t\t * The value which will be returned by {@link module:utils/emittermixin~EmitterMixin#fire}.\n\t\t *\n\t\t * It's `undefined` by default and can be changed by an event listener:\n\t\t *\n\t\t *\t\tdataController.fire( 'getSelectedContent', ( evt ) => {\n\t\t *\t\t\t// This listener will make `dataController.fire( 'getSelectedContent' )`\n\t\t *\t\t\t// always return an empty DocumentFragment.\n\t\t *\t\t\tevt.return = new DocumentFragment();\n\t\t *\n\t\t *\t\t\t// Make sure no other listeners are executed.\n\t\t *\t\t\tevt.stop();\n\t\t *\t\t} );\n\t\t *\n\t\t * @member #return\n\t\t */\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/uid\n */\n\n// A hash table of hex numbers to avoid using toString() in uid() which is costly.\n// [ '00', '01', '02', ..., 'fe', 'ff' ]\nconst HEX_NUMBERS = new Array( 256 ).fill()\n\t.map( ( val, index ) => ( '0' + ( index ).toString( 16 ) ).slice( -2 ) );\n\n/**\n * Returns a unique id. The id starts with an \"e\" character and a randomly generated string of\n * 32 alphanumeric characters.\n *\n * **Note**: The characters the unique id is built from correspond to the hex number notation\n * (from \"0\" to \"9\", from \"a\" to \"f\"). In other words, each id corresponds to an \"e\" followed\n * by 16 8-bit numbers next to each other.\n *\n * @returns {String} An unique id string.\n */\nexport default function uid() {\n\t// Let's create some positive random 32bit integers first.\n\t//\n\t// 1. Math.random() is a float between 0 and 1.\n\t// 2. 0x100000000 is 2^32 = 4294967296.\n\t// 3. >>> 0 enforces integer (in JS all numbers are floating point).\n\t//\n\t// For instance:\n\t//\t\tMath.random() * 0x100000000 = 3366450031.853859\n\t// but\n\t//\t\tMath.random() * 0x100000000 >>> 0 = 3366450031.\n\tconst r1 = Math.random() * 0x100000000 >>> 0;\n\tconst r2 = Math.random() * 0x100000000 >>> 0;\n\tconst r3 = Math.random() * 0x100000000 >>> 0;\n\tconst r4 = Math.random() * 0x100000000 >>> 0;\n\n\t// Make sure that id does not start with number.\n\treturn 'e' +\n\t\tHEX_NUMBERS[ r1 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r1 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r2 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r3 >> 24 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 0 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 8 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 16 & 0xFF ] +\n\t\tHEX_NUMBERS[ r4 >> 24 & 0xFF ];\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 utils/priorities\n */\n\n/**\n * String representing a priority value.\n *\n * @typedef {'highest'|'high'|'normal'|'low'|'lowest'} module:utils/priorities~PriorityString\n */\n\n/**\n * Provides group of constants to use instead of hardcoding numeric priority values.\n *\n * @namespace\n */\nconst priorities = {\n\t/**\n\t * Converts a string with priority name to it's numeric value. If `Number` is given, it just returns it.\n\t *\n\t * @static\n\t * @param {module:utils/priorities~PriorityString|Number} priority Priority to convert.\n\t * @returns {Number} Converted priority.\n\t */\n\tget( priority ) {\n\t\tif ( typeof priority != 'number' ) {\n\t\t\treturn this[ priority ] || this.normal;\n\t\t} else {\n\t\t\treturn priority;\n\t\t}\n\t},\n\n\thighest: 100000,\n\thigh: 1000,\n\tnormal: 0,\n\tlow: -1000,\n\tlowest: -100000\n};\n\nexport default priorities;\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 utils/emittermixin\n */\n\nimport EventInfo from './eventinfo';\nimport uid from './uid';\nimport priorities from './priorities';\n\n// To check if component is loaded more than once.\nimport './version';\nimport CKEditorError from './ckeditorerror';\n\nconst _listeningTo = Symbol( 'listeningTo' );\nconst _emitterId = Symbol( 'emitterId' );\n\n/**\n * Mixin that injects the {@link ~Emitter events API} into its host.\n *\n * Read more about the concept of emitters in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables Event system and observables}\n * section of the {@glink framework/guides/architecture/core-editor-architecture Core editor architecture} guide.\n * * {@glink framework/guides/deep-dive/event-system Event system} deep dive guide.\n *\n * @mixin EmitterMixin\n * @implements module:utils/emittermixin~Emitter\n */\nconst EmitterMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\ton( event, callback, options = {} ) {\n\t\tthis.listenTo( this, event, callback, options );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tonce( event, callback, options ) {\n\t\tlet wasFired = false;\n\n\t\tconst onceCallback = function( event, ...args ) {\n\t\t\t// Ensure the callback is called only once even if the callback itself leads to re-firing the event\n\t\t\t// (which would call the callback again).\n\t\t\tif ( !wasFired ) {\n\t\t\t\twasFired = true;\n\n\t\t\t\t// Go off() at the first call.\n\t\t\t\tevent.off();\n\n\t\t\t\t// Go with the original callback.\n\t\t\t\tcallback.call( this, event, ...args );\n\t\t\t}\n\t\t};\n\n\t\t// Make a similar on() call, simply replacing the callback.\n\t\tthis.listenTo( this, event, onceCallback, options );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\toff( event, callback ) {\n\t\tthis.stopListening( this, event, callback );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tlistenTo( emitter, event, callback, options = {} ) {\n\t\tlet emitterInfo, eventCallbacks;\n\n\t\t// _listeningTo contains a list of emitters that this object is listening to.\n\t\t// This list has the following format:\n\t\t//\n\t\t// _listeningTo: {\n\t\t// emitterId: {\n\t\t// emitter: emitter,\n\t\t// callbacks: {\n\t\t// event1: [ callback1, callback2, ... ]\n\t\t// ....\n\t\t// }\n\t\t// },\n\t\t// ...\n\t\t// }\n\n\t\tif ( !this[ _listeningTo ] ) {\n\t\t\tthis[ _listeningTo ] = {};\n\t\t}\n\n\t\tconst emitters = this[ _listeningTo ];\n\n\t\tif ( !_getEmitterId( emitter ) ) {\n\t\t\t_setEmitterId( emitter );\n\t\t}\n\n\t\tconst emitterId = _getEmitterId( emitter );\n\n\t\tif ( !( emitterInfo = emitters[ emitterId ] ) ) {\n\t\t\temitterInfo = emitters[ emitterId ] = {\n\t\t\t\temitter,\n\t\t\t\tcallbacks: {}\n\t\t\t};\n\t\t}\n\n\t\tif ( !( eventCallbacks = emitterInfo.callbacks[ event ] ) ) {\n\t\t\teventCallbacks = emitterInfo.callbacks[ event ] = [];\n\t\t}\n\n\t\teventCallbacks.push( callback );\n\n\t\t// Finally register the callback to the event.\n\t\taddEventListener( this, emitter, event, callback, options );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstopListening( emitter, event, callback ) {\n\t\tconst emitters = this[ _listeningTo ];\n\t\tlet emitterId = emitter && _getEmitterId( emitter );\n\t\tconst emitterInfo = emitters && emitterId && emitters[ emitterId ];\n\t\tconst eventCallbacks = emitterInfo && event && emitterInfo.callbacks[ event ];\n\n\t\t// Stop if nothing has been listened.\n\t\tif ( !emitters || ( emitter && !emitterInfo ) || ( event && !eventCallbacks ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// All params provided. off() that single callback.\n\t\tif ( callback ) {\n\t\t\tremoveEventListener( this, emitter, event, callback );\n\n\t\t\t// We must remove callbacks as well in order to prevent memory leaks.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/pull/8480\n\t\t\tconst index = eventCallbacks.indexOf( callback );\n\n\t\t\tif ( index !== -1 ) {\n\t\t\t\tif ( eventCallbacks.length === 1 ) {\n\t\t\t\t\tdelete emitterInfo.callbacks[ event ];\n\t\t\t\t} else {\n\t\t\t\t\tremoveEventListener( this, emitter, event, callback );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Only `emitter` and `event` provided. off() all callbacks for that event.\n\t\telse if ( eventCallbacks ) {\n\t\t\twhile ( ( callback = eventCallbacks.pop() ) ) {\n\t\t\t\tremoveEventListener( this, emitter, event, callback );\n\t\t\t}\n\n\t\t\tdelete emitterInfo.callbacks[ event ];\n\t\t}\n\t\t// Only `emitter` provided. off() all events for that emitter.\n\t\telse if ( emitterInfo ) {\n\t\t\tfor ( event in emitterInfo.callbacks ) {\n\t\t\t\tthis.stopListening( emitter, event );\n\t\t\t}\n\t\t\tdelete emitters[ emitterId ];\n\t\t}\n\t\t// No params provided. off() all emitters.\n\t\telse {\n\t\t\tfor ( emitterId in emitters ) {\n\t\t\t\tthis.stopListening( emitters[ emitterId ].emitter );\n\t\t\t}\n\t\t\tdelete this[ _listeningTo ];\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfire( eventOrInfo, ...args ) {\n\t\ttry {\n\t\t\tconst eventInfo = eventOrInfo instanceof EventInfo ? eventOrInfo : new EventInfo( this, eventOrInfo );\n\t\t\tconst event = eventInfo.name;\n\t\t\tlet callbacks = getCallbacksForEvent( this, event );\n\n\t\t\t// Record that the event passed this emitter on its path.\n\t\t\teventInfo.path.push( this );\n\n\t\t\t// Handle event listener callbacks first.\n\t\t\tif ( callbacks ) {\n\t\t\t\t// Arguments passed to each callback.\n\t\t\t\tconst callbackArgs = [ eventInfo, ...args ];\n\n\t\t\t\t// Copying callbacks array is the easiest and most secure way of preventing infinite loops, when event callbacks\n\t\t\t\t// are added while processing other callbacks. Previous solution involved adding counters (unique ids) but\n\t\t\t\t// failed if callbacks were added to the queue before currently processed callback.\n\t\t\t\t// If this proves to be too inefficient, another method is to change `.on()` so callbacks are stored if same\n\t\t\t\t// event is currently processed. Then, `.fire()` at the end, would have to add all stored events.\n\t\t\t\tcallbacks = Array.from( callbacks );\n\n\t\t\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\t\t\tcallbacks[ i ].callback.apply( this, callbackArgs );\n\n\t\t\t\t\t// Remove the callback from future requests if off() has been called.\n\t\t\t\t\tif ( eventInfo.off.called ) {\n\t\t\t\t\t\t// Remove the called mark for the next calls.\n\t\t\t\t\t\tdelete eventInfo.off.called;\n\n\t\t\t\t\t\tthis._removeEventListener( event, callbacks[ i ].callback );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Do not execute next callbacks if stop() was called.\n\t\t\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Delegate event to other emitters if needed.\n\t\t\tif ( this._delegations ) {\n\t\t\t\tconst destinations = this._delegations.get( event );\n\t\t\t\tconst passAllDestinations = this._delegations.get( '*' );\n\n\t\t\t\tif ( destinations ) {\n\t\t\t\t\tfireDelegatedEvents( destinations, eventInfo, args );\n\t\t\t\t}\n\n\t\t\t\tif ( passAllDestinations ) {\n\t\t\t\t\tfireDelegatedEvents( passAllDestinations, eventInfo, args );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn eventInfo.return;\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdelegate( ...events ) {\n\t\treturn {\n\t\t\tto: ( emitter, nameOrFunction ) => {\n\t\t\t\tif ( !this._delegations ) {\n\t\t\t\t\tthis._delegations = new Map();\n\t\t\t\t}\n\n\t\t\t\t// Originally there was a for..of loop which unfortunately caused an error in Babel that didn't allow\n\t\t\t\t// build an application. See: https://github.com/ckeditor/ckeditor5-react/issues/40.\n\t\t\t\tevents.forEach( eventName => {\n\t\t\t\t\tconst destinations = this._delegations.get( eventName );\n\n\t\t\t\t\tif ( !destinations ) {\n\t\t\t\t\t\tthis._delegations.set( eventName, new Map( [ [ emitter, nameOrFunction ] ] ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdestinations.set( emitter, nameOrFunction );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstopDelegating( event, emitter ) {\n\t\tif ( !this._delegations ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !event ) {\n\t\t\tthis._delegations.clear();\n\t\t} else if ( !emitter ) {\n\t\t\tthis._delegations.delete( event );\n\t\t} else {\n\t\t\tconst destinations = this._delegations.get( event );\n\n\t\t\tif ( destinations ) {\n\t\t\t\tdestinations.delete( emitter );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_addEventListener( event, callback, options ) {\n\t\tcreateEventNamespace( this, event );\n\n\t\tconst lists = getCallbacksListsForNamespace( this, event );\n\t\tconst priority = priorities.get( options.priority );\n\n\t\tconst callbackDefinition = {\n\t\t\tcallback,\n\t\t\tpriority\n\t\t};\n\n\t\t// Add the callback to all callbacks list.\n\t\tfor ( const callbacks of lists ) {\n\t\t\t// Add the callback to the list in the right priority position.\n\t\t\tlet added = false;\n\n\t\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\t\tif ( callbacks[ i ].priority < priority ) {\n\t\t\t\t\tcallbacks.splice( i, 0, callbackDefinition );\n\t\t\t\t\tadded = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add at the end, if right place was not found.\n\t\t\tif ( !added ) {\n\t\t\t\tcallbacks.push( callbackDefinition );\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_removeEventListener( event, callback ) {\n\t\tconst lists = getCallbacksListsForNamespace( this, event );\n\n\t\tfor ( const callbacks of lists ) {\n\t\t\tfor ( let i = 0; i < callbacks.length; i++ ) {\n\t\t\t\tif ( callbacks[ i ].callback == callback ) {\n\t\t\t\t\t// Remove the callback from the list (fixing the next index).\n\t\t\t\t\tcallbacks.splice( i, 1 );\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\nexport default EmitterMixin;\n\n/**\n * Emitter/listener interface.\n *\n * Can be easily implemented by a class by mixing the {@link module:utils/emittermixin~EmitterMixin} mixin.\n *\n * Read more about the usage of this interface in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables Event system and observables}\n * section of the {@glink framework/guides/architecture/core-editor-architecture Core editor architecture} guide.\n * * {@glink framework/guides/deep-dive/event-system Event system} deep dive guide.\n *\n * @interface Emitter\n */\n\n/**\n * Registers a callback function to be executed when an event is fired.\n *\n * Shorthand for {@link #listenTo `this.listenTo( this, event, callback, options )`} (it makes the emitter\n * listen on itself).\n *\n * @method #on\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Registers a callback function to be executed on the next time the event is fired only. This is similar to\n * calling {@link #on} followed by {@link #off} in the callback.\n *\n * @method #once\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Stops executing the callback on the given event.\n * Shorthand for {@link #stopListening `this.stopListening( this, event, callback )`}.\n *\n * @method #off\n * @param {String} event The name of the event.\n * @param {Function} callback The function to stop being called.\n */\n\n/**\n * Registers a callback function to be executed when an event is fired in a specific (emitter) object.\n *\n * Events can be grouped in namespaces using `:`.\n * When namespaced event is fired, it additionally fires all callbacks for that namespace.\n *\n *\t\t// myEmitter.on( ... ) is a shorthand for myEmitter.listenTo( myEmitter, ... ).\n *\t\tmyEmitter.on( 'myGroup', genericCallback );\n *\t\tmyEmitter.on( 'myGroup:myEvent', specificCallback );\n *\n *\t\t// genericCallback is fired.\n *\t\tmyEmitter.fire( 'myGroup' );\n *\t\t// both genericCallback and specificCallback are fired.\n *\t\tmyEmitter.fire( 'myGroup:myEvent' );\n *\t\t// genericCallback is fired even though there are no callbacks for \"foo\".\n *\t\tmyEmitter.fire( 'myGroup:foo' );\n *\n * An event callback can {@link module:utils/eventinfo~EventInfo#stop stop the event} and\n * set the {@link module:utils/eventinfo~EventInfo#return return value} of the {@link #fire} method.\n *\n * @method #listenTo\n * @param {module:utils/emittermixin~Emitter} emitter The object that fires the event.\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Stops listening for events. It can be used at different levels:\n *\n * * To stop listening to a specific callback.\n * * To stop listening to a specific event.\n * * To stop listening to all events fired by a specific object.\n * * To stop listening to all events fired by all objects.\n *\n * @method #stopListening\n * @param {module:utils/emittermixin~Emitter} [emitter] The object to stop listening to. If omitted, stops it for all objects.\n * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it\n * for all events from `emitter`.\n * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given\n * `event`.\n */\n\n/**\n * Fires an event, executing all callbacks registered for it.\n *\n * The first parameter passed to callbacks is an {@link module:utils/eventinfo~EventInfo} object,\n * followed by the optional `args` provided in the `fire()` method call.\n *\n * @method #fire\n * @param {String|module:utils/eventinfo~EventInfo} eventOrInfo The name of the event or `EventInfo` object if event is delegated.\n * @param {...*} [args] Additional arguments to be passed to the callbacks.\n * @returns {*} By default the method returns `undefined`. However, the return value can be changed by listeners\n * through modification of the {@link module:utils/eventinfo~EventInfo#return `evt.return`}'s property (the event info\n * is the first param of every callback).\n */\n\n/**\n * Delegates selected events to another {@link module:utils/emittermixin~Emitter}. For instance:\n *\n *\t\temitterA.delegate( 'eventX' ).to( emitterB );\n *\t\temitterA.delegate( 'eventX', 'eventY' ).to( emitterC );\n *\n * then `eventX` is delegated (fired by) `emitterB` and `emitterC` along with `data`:\n *\n *\t\temitterA.fire( 'eventX', data );\n *\n * and `eventY` is delegated (fired by) `emitterC` along with `data`:\n *\n *\t\temitterA.fire( 'eventY', data );\n *\n * @method #delegate\n * @param {...String} events Event names that will be delegated to another emitter.\n * @returns {module:utils/emittermixin~EmitterMixinDelegateChain}\n */\n\n/**\n * Stops delegating events. It can be used at different levels:\n *\n * * To stop delegating all events.\n * * To stop delegating a specific event to all emitters.\n * * To stop delegating a specific event to a specific emitter.\n *\n * @method #stopDelegating\n * @param {String} [event] The name of the event to stop delegating. If omitted, stops it all delegations.\n * @param {module:utils/emittermixin~Emitter} [emitter] (requires `event`) The object to stop delegating a particular event to.\n * If omitted, stops delegation of `event` to all emitters.\n */\n\n/**\n * Adds callback to emitter for given event.\n *\n * @protected\n * @method #_addEventListener\n * @param {String} event The name of the event.\n * @param {Function} callback The function to be called on event.\n * @param {Object} [options={}] Additional options.\n * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n * order they were added.\n */\n\n/**\n * Removes callback from emitter for given event.\n *\n * @protected\n * @method #_removeEventListener\n * @param {String} event The name of the event.\n * @param {Function} callback The function to stop being called.\n */\n\n/**\n * Checks if `listeningEmitter` listens to an emitter with given `listenedToEmitterId` and if so, returns that emitter.\n * If not, returns `null`.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} listeningEmitter An emitter that listens.\n * @param {String} listenedToEmitterId Unique emitter id of emitter listened to.\n * @returns {module:utils/emittermixin~Emitter|null}\n */\nexport function _getEmitterListenedTo( listeningEmitter, listenedToEmitterId ) {\n\tif ( listeningEmitter[ _listeningTo ] && listeningEmitter[ _listeningTo ][ listenedToEmitterId ] ) {\n\t\treturn listeningEmitter[ _listeningTo ][ listenedToEmitterId ].emitter;\n\t}\n\n\treturn null;\n}\n\n/**\n * Sets emitter's unique id.\n *\n * **Note:** `_emitterId` can be set only once.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} emitter An emitter for which id will be set.\n * @param {String} [id] Unique id to set. If not passed, random unique id will be set.\n */\nexport function _setEmitterId( emitter, id ) {\n\tif ( !emitter[ _emitterId ] ) {\n\t\temitter[ _emitterId ] = id || uid();\n\t}\n}\n\n/**\n * Returns emitter's unique id.\n *\n * @protected\n * @param {module:utils/emittermixin~Emitter} emitter An emitter which id will be returned.\n */\nexport function _getEmitterId( emitter ) {\n\treturn emitter[ _emitterId ];\n}\n\n// Gets the internal `_events` property of the given object.\n// `_events` property store all lists with callbacks for registered event names.\n// If there were no events registered on the object, empty `_events` object is created.\nfunction getEvents( source ) {\n\tif ( !source._events ) {\n\t\tObject.defineProperty( source, '_events', {\n\t\t\tvalue: {}\n\t\t} );\n\t}\n\n\treturn source._events;\n}\n\n// Creates event node for generic-specific events relation architecture.\nfunction makeEventNode() {\n\treturn {\n\t\tcallbacks: [],\n\t\tchildEvents: []\n\t};\n}\n\n// Creates an architecture for generic-specific events relation.\n// If needed, creates all events for given eventName, i.e. if the first registered event\n// is foo:bar:abc, it will create foo:bar:abc, foo:bar and foo event and tie them together.\n// It also copies callbacks from more generic events to more specific events when\n// specific events are created.\nfunction createEventNamespace( source, eventName ) {\n\tconst events = getEvents( source );\n\n\t// First, check if the event we want to add to the structure already exists.\n\tif ( events[ eventName ] ) {\n\t\t// If it exists, we don't have to do anything.\n\t\treturn;\n\t}\n\n\t// In other case, we have to create the structure for the event.\n\t// Note, that we might need to create intermediate events too.\n\t// I.e. if foo:bar:abc is being registered and we only have foo in the structure,\n\t// we need to also register foo:bar.\n\n\t// Currently processed event name.\n\tlet name = eventName;\n\t// Name of the event that is a child event for currently processed event.\n\tlet childEventName = null;\n\n\t// Array containing all newly created specific events.\n\tconst newEventNodes = [];\n\n\t// While loop can't check for ':' index because we have to handle generic events too.\n\t// In each loop, we truncate event name, going from the most specific name to the generic one.\n\t// I.e. foo:bar:abc -> foo:bar -> foo.\n\twhile ( name !== '' ) {\n\t\tif ( events[ name ] ) {\n\t\t\t// If the currently processed event name is already registered, we can be sure\n\t\t\t// that it already has all the structure created, so we can break the loop here\n\t\t\t// as no more events need to be registered.\n\t\t\tbreak;\n\t\t}\n\n\t\t// If this event is not yet registered, create a new object for it.\n\t\tevents[ name ] = makeEventNode();\n\t\t// Add it to the array with newly created events.\n\t\tnewEventNodes.push( events[ name ] );\n\n\t\t// Add previously processed event name as a child of this event.\n\t\tif ( childEventName ) {\n\t\t\tevents[ name ].childEvents.push( childEventName );\n\t\t}\n\n\t\tchildEventName = name;\n\t\t// If `.lastIndexOf()` returns -1, `.substr()` will return '' which will break the loop.\n\t\tname = name.substr( 0, name.lastIndexOf( ':' ) );\n\t}\n\n\tif ( name !== '' ) {\n\t\t// If name is not empty, we found an already registered event that was a parent of the\n\t\t// event we wanted to register.\n\n\t\t// Copy that event's callbacks to newly registered events.\n\t\tfor ( const node of newEventNodes ) {\n\t\t\tnode.callbacks = events[ name ].callbacks.slice();\n\t\t}\n\n\t\t// Add last newly created event to the already registered event.\n\t\tevents[ name ].childEvents.push( childEventName );\n\t}\n}\n\n// Gets an array containing callbacks list for a given event and it's more specific events.\n// I.e. if given event is foo:bar and there is also foo:bar:abc event registered, this will\n// return callback list of foo:bar and foo:bar:abc (but not foo).\nfunction getCallbacksListsForNamespace( source, eventName ) {\n\tconst eventNode = getEvents( source )[ eventName ];\n\n\tif ( !eventNode ) {\n\t\treturn [];\n\t}\n\n\tlet callbacksLists = [ eventNode.callbacks ];\n\n\tfor ( let i = 0; i < eventNode.childEvents.length; i++ ) {\n\t\tconst childCallbacksLists = getCallbacksListsForNamespace( source, eventNode.childEvents[ i ] );\n\n\t\tcallbacksLists = callbacksLists.concat( childCallbacksLists );\n\t}\n\n\treturn callbacksLists;\n}\n\n// Get the list of callbacks for a given event, but only if there any callbacks have been registered.\n// If there are no callbacks registered for given event, it checks if this is a specific event and looks\n// for callbacks for it's more generic version.\nfunction getCallbacksForEvent( source, eventName ) {\n\tlet event;\n\n\tif ( !source._events || !( event = source._events[ eventName ] ) || !event.callbacks.length ) {\n\t\t// There are no callbacks registered for specified eventName.\n\t\t// But this could be a specific-type event that is in a namespace.\n\t\tif ( eventName.indexOf( ':' ) > -1 ) {\n\t\t\t// If the eventName is specific, try to find callback lists for more generic event.\n\t\t\treturn getCallbacksForEvent( source, eventName.substr( 0, eventName.lastIndexOf( ':' ) ) );\n\t\t} else {\n\t\t\t// If this is a top-level generic event, return null;\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn event.callbacks;\n}\n\n// Fires delegated events for given map of destinations.\n//\n// @private\n// * @param {Map.<utils.Emitter>} destinations A map containing\n// `[ {@link module:utils/emittermixin~Emitter}, \"event name\" ]` pair destinations.\n// * @param {utils.EventInfo} eventInfo The original event info object.\n// * @param {Array.<*>} fireArgs Arguments the original event was fired with.\nfunction fireDelegatedEvents( destinations, eventInfo, fireArgs ) {\n\tfor ( let [ emitter, name ] of destinations ) {\n\t\tif ( !name ) {\n\t\t\tname = eventInfo.name;\n\t\t} else if ( typeof name == 'function' ) {\n\t\t\tname = name( eventInfo.name );\n\t\t}\n\n\t\tconst delegatedInfo = new EventInfo( eventInfo.source, name );\n\n\t\tdelegatedInfo.path = [ ...eventInfo.path ];\n\n\t\temitter.fire( delegatedInfo, ...fireArgs );\n\t}\n}\n\n// Helper for registering event callback on the emitter.\nfunction addEventListener( listener, emitter, event, callback, options ) {\n\tif ( emitter._addEventListener ) {\n\t\temitter._addEventListener( event, callback, options );\n\t} else {\n\t\t// Allow listening on objects that do not implement Emitter interface.\n\t\t// This is needed in some tests that are using mocks instead of the real objects with EmitterMixin mixed.\n\t\tlistener._addEventListener.call( emitter, event, callback, options );\n\t}\n}\n\n// Helper for removing event callback from the emitter.\nfunction removeEventListener( listener, emitter, event, callback ) {\n\tif ( emitter._removeEventListener ) {\n\t\temitter._removeEventListener( event, callback );\n\t} else {\n\t\t// Allow listening on objects that do not implement Emitter interface.\n\t\t// This is needed in some tests that are using mocks instead of the real objects with EmitterMixin mixed.\n\t\tlistener._removeEventListener.call( emitter, event, callback );\n\t}\n}\n\n/**\n * The return value of {@link ~EmitterMixin#delegate}.\n *\n * @interface module:utils/emittermixin~EmitterMixinDelegateChain\n */\n\n/**\n * Selects destination for {@link module:utils/emittermixin~EmitterMixin#delegate} events.\n *\n * @method #to\n * @param {module:utils/emittermixin~Emitter} emitter An `EmitterMixin` instance which is the destination for delegated events.\n * @param {String|Function} [nameOrFunction] A custom event name or function which converts the original name string.\n */\n","/**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\nfunction isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n}\n\nexport default isObject;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Symbol = root.Symbol;\n\nexport default Symbol;\n","import Symbol from './_Symbol.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the raw `toStringTag`.\n */\nfunction getRawTag(value) {\n var isOwn = hasOwnProperty.call(value, symToStringTag),\n tag = value[symToStringTag];\n\n try {\n value[symToStringTag] = undefined;\n var unmasked = true;\n } catch (e) {}\n\n var result = nativeObjectToString.call(value);\n if (unmasked) {\n if (isOwn) {\n value[symToStringTag] = tag;\n } else {\n delete value[symToStringTag];\n }\n }\n return result;\n}\n\nexport default getRawTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Used to resolve the\n * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)\n * of values.\n */\nvar nativeObjectToString = objectProto.toString;\n\n/**\n * Converts `value` to a string using `Object.prototype.toString`.\n *\n * @private\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n */\nfunction objectToString(value) {\n return nativeObjectToString.call(value);\n}\n\nexport default objectToString;\n","import Symbol from './_Symbol.js';\nimport getRawTag from './_getRawTag.js';\nimport objectToString from './_objectToString.js';\n\n/** `Object#toString` result references. */\nvar nullTag = '[object Null]',\n undefinedTag = '[object Undefined]';\n\n/** Built-in value references. */\nvar symToStringTag = Symbol ? Symbol.toStringTag : undefined;\n\n/**\n * The base implementation of `getTag` without fallbacks for buggy environments.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nfunction baseGetTag(value) {\n if (value == null) {\n return value === undefined ? undefinedTag : nullTag;\n }\n return (symToStringTag && symToStringTag in Object(value))\n ? getRawTag(value)\n : objectToString(value);\n}\n\nexport default baseGetTag;\n","import baseGetTag from './_baseGetTag.js';\nimport isObject from './isObject.js';\n\n/** `Object#toString` result references. */\nvar asyncTag = '[object AsyncFunction]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n proxyTag = '[object Proxy]';\n\n/**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\nfunction isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n}\n\nexport default isFunction;\n","import coreJsData from './_coreJsData.js';\n\n/** Used to detect methods masquerading as native. */\nvar maskSrcKey = (function() {\n var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');\n return uid ? ('Symbol(src)_1.' + uid) : '';\n}());\n\n/**\n * Checks if `func` has its source masked.\n *\n * @private\n * @param {Function} func The function to check.\n * @returns {boolean} Returns `true` if `func` is masked, else `false`.\n */\nfunction isMasked(func) {\n return !!maskSrcKey && (maskSrcKey in func);\n}\n\nexport default isMasked;\n","import root from './_root.js';\n\n/** Used to detect overreaching core-js shims. */\nvar coreJsData = root['__core-js_shared__'];\n\nexport default coreJsData;\n","/** Used for built-in method references. */\nvar funcProto = Function.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/**\n * Converts `func` to its source code.\n *\n * @private\n * @param {Function} func The function to convert.\n * @returns {string} Returns the source code.\n */\nfunction toSource(func) {\n if (func != null) {\n try {\n return funcToString.call(func);\n } catch (e) {}\n try {\n return (func + '');\n } catch (e) {}\n }\n return '';\n}\n\nexport default toSource;\n","import isFunction from './isFunction.js';\nimport isMasked from './_isMasked.js';\nimport isObject from './isObject.js';\nimport toSource from './_toSource.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g;\n\n/** Used to detect host constructors (Safari). */\nvar reIsHostCtor = /^\\[object .+?Constructor\\]$/;\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to detect if a method is native. */\nvar reIsNative = RegExp('^' +\n funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\\\$&')\n .replace(/hasOwnProperty|(function).*?(?=\\\\\\()| for .+?(?=\\\\\\])/g, '$1.*?') + '$'\n);\n\n/**\n * The base implementation of `_.isNative` without bad shim checks.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n */\nfunction baseIsNative(value) {\n if (!isObject(value) || isMasked(value)) {\n return false;\n }\n var pattern = isFunction(value) ? reIsNative : reIsHostCtor;\n return pattern.test(toSource(value));\n}\n\nexport default baseIsNative;\n","/**\n * Gets the value at `key` of `object`.\n *\n * @private\n * @param {Object} [object] The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction getValue(object, key) {\n return object == null ? undefined : object[key];\n}\n\nexport default getValue;\n","import baseIsNative from './_baseIsNative.js';\nimport getValue from './_getValue.js';\n\n/**\n * Gets the native function at `key` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the method to get.\n * @returns {*} Returns the function if it's native, else `undefined`.\n */\nfunction getNative(object, key) {\n var value = getValue(object, key);\n return baseIsNative(value) ? value : undefined;\n}\n\nexport default getNative;\n","import getNative from './_getNative.js';\n\nvar defineProperty = (function() {\n try {\n var func = getNative(Object, 'defineProperty');\n func({}, '', {});\n return func;\n } catch (e) {}\n}());\n\nexport default defineProperty;\n","import defineProperty from './_defineProperty.js';\n\n/**\n * The base implementation of `assignValue` and `assignMergeValue` without\n * value checks.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction baseAssignValue(object, key, value) {\n if (key == '__proto__' && defineProperty) {\n defineProperty(object, key, {\n 'configurable': true,\n 'enumerable': true,\n 'value': value,\n 'writable': true\n });\n } else {\n object[key] = value;\n }\n}\n\nexport default baseAssignValue;\n","/**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\nfunction eq(value, other) {\n return value === other || (value !== value && other !== other);\n}\n\nexport default eq;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Assigns `value` to `key` of `object` if the existing value is not equivalent\n * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * for equality comparisons.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignValue(object, key, value) {\n var objValue = object[key];\n if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||\n (value === undefined && !(key in object))) {\n baseAssignValue(object, key, value);\n }\n}\n\nexport default assignValue;\n","import assignValue from './_assignValue.js';\nimport baseAssignValue from './_baseAssignValue.js';\n\n/**\n * Copies properties of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy properties from.\n * @param {Array} props The property identifiers to copy.\n * @param {Object} [object={}] The object to copy properties to.\n * @param {Function} [customizer] The function to customize copied values.\n * @returns {Object} Returns `object`.\n */\nfunction copyObject(source, props, object, customizer) {\n var isNew = !object;\n object || (object = {});\n\n var index = -1,\n length = props.length;\n\n while (++index < length) {\n var key = props[index];\n\n var newValue = customizer\n ? customizer(object[key], source[key], key, object, source)\n : undefined;\n\n if (newValue === undefined) {\n newValue = source[key];\n }\n if (isNew) {\n baseAssignValue(object, key, newValue);\n } else {\n assignValue(object, key, newValue);\n }\n }\n return object;\n}\n\nexport default copyObject;\n","/**\n * This method returns the first argument it receives.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Util\n * @param {*} value Any value.\n * @returns {*} Returns `value`.\n * @example\n *\n * var object = { 'a': 1 };\n *\n * console.log(_.identity(object) === object);\n * // => true\n */\nfunction identity(value) {\n return value;\n}\n\nexport default identity;\n","/**\n * A faster alternative to `Function#apply`, this function invokes `func`\n * with the `this` binding of `thisArg` and the arguments of `args`.\n *\n * @private\n * @param {Function} func The function to invoke.\n * @param {*} thisArg The `this` binding of `func`.\n * @param {Array} args The arguments to invoke `func` with.\n * @returns {*} Returns the result of `func`.\n */\nfunction apply(func, thisArg, args) {\n switch (args.length) {\n case 0: return func.call(thisArg);\n case 1: return func.call(thisArg, args[0]);\n case 2: return func.call(thisArg, args[0], args[1]);\n case 3: return func.call(thisArg, args[0], args[1], args[2]);\n }\n return func.apply(thisArg, args);\n}\n\nexport default apply;\n","import apply from './_apply.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max;\n\n/**\n * A specialized version of `baseRest` which transforms the rest array.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @param {Function} transform The rest array transform.\n * @returns {Function} Returns the new function.\n */\nfunction overRest(func, start, transform) {\n start = nativeMax(start === undefined ? (func.length - 1) : start, 0);\n return function() {\n var args = arguments,\n index = -1,\n length = nativeMax(args.length - start, 0),\n array = Array(length);\n\n while (++index < length) {\n array[index] = args[start + index];\n }\n index = -1;\n var otherArgs = Array(start + 1);\n while (++index < start) {\n otherArgs[index] = args[index];\n }\n otherArgs[start] = transform(array);\n return apply(func, this, otherArgs);\n };\n}\n\nexport default overRest;\n","/**\n * Creates a function that returns `value`.\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Util\n * @param {*} value The value to return from the new function.\n * @returns {Function} Returns the new constant function.\n * @example\n *\n * var objects = _.times(2, _.constant({ 'a': 1 }));\n *\n * console.log(objects);\n * // => [{ 'a': 1 }, { 'a': 1 }]\n *\n * console.log(objects[0] === objects[1]);\n * // => true\n */\nfunction constant(value) {\n return function() {\n return value;\n };\n}\n\nexport default constant;\n","import constant from './constant.js';\nimport defineProperty from './_defineProperty.js';\nimport identity from './identity.js';\n\n/**\n * The base implementation of `setToString` without support for hot loop shorting.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar baseSetToString = !defineProperty ? identity : function(func, string) {\n return defineProperty(func, 'toString', {\n 'configurable': true,\n 'enumerable': false,\n 'value': constant(string),\n 'writable': true\n });\n};\n\nexport default baseSetToString;\n","/** Used to detect hot functions by number of calls within a span of milliseconds. */\nvar HOT_COUNT = 800,\n HOT_SPAN = 16;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeNow = Date.now;\n\n/**\n * Creates a function that'll short out and invoke `identity` instead\n * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`\n * milliseconds.\n *\n * @private\n * @param {Function} func The function to restrict.\n * @returns {Function} Returns the new shortable function.\n */\nfunction shortOut(func) {\n var count = 0,\n lastCalled = 0;\n\n return function() {\n var stamp = nativeNow(),\n remaining = HOT_SPAN - (stamp - lastCalled);\n\n lastCalled = stamp;\n if (remaining > 0) {\n if (++count >= HOT_COUNT) {\n return arguments[0];\n }\n } else {\n count = 0;\n }\n return func.apply(undefined, arguments);\n };\n}\n\nexport default shortOut;\n","import baseSetToString from './_baseSetToString.js';\nimport shortOut from './_shortOut.js';\n\n/**\n * Sets the `toString` method of `func` to return `string`.\n *\n * @private\n * @param {Function} func The function to modify.\n * @param {Function} string The `toString` result.\n * @returns {Function} Returns `func`.\n */\nvar setToString = shortOut(baseSetToString);\n\nexport default setToString;\n","import identity from './identity.js';\nimport overRest from './_overRest.js';\nimport setToString from './_setToString.js';\n\n/**\n * The base implementation of `_.rest` which doesn't validate or coerce arguments.\n *\n * @private\n * @param {Function} func The function to apply a rest parameter to.\n * @param {number} [start=func.length-1] The start position of the rest parameter.\n * @returns {Function} Returns the new function.\n */\nfunction baseRest(func, start) {\n return setToString(overRest(func, start, identity), func + '');\n}\n\nexport default baseRest;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\nfunction isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n}\n\nexport default isLength;\n","import isFunction from './isFunction.js';\nimport isLength from './isLength.js';\n\n/**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\nfunction isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n}\n\nexport default isArrayLike;\n","/** Used as references for various `Number` constants. */\nvar MAX_SAFE_INTEGER = 9007199254740991;\n\n/** Used to detect unsigned integer values. */\nvar reIsUint = /^(?:0|[1-9]\\d*)$/;\n\n/**\n * Checks if `value` is a valid array-like index.\n *\n * @private\n * @param {*} value The value to check.\n * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.\n * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.\n */\nfunction isIndex(value, length) {\n var type = typeof value;\n length = length == null ? MAX_SAFE_INTEGER : length;\n\n return !!length &&\n (type == 'number' ||\n (type != 'symbol' && reIsUint.test(value))) &&\n (value > -1 && value % 1 == 0 && value < length);\n}\n\nexport default isIndex;\n","import eq from './eq.js';\nimport isArrayLike from './isArrayLike.js';\nimport isIndex from './_isIndex.js';\nimport isObject from './isObject.js';\n\n/**\n * Checks if the given arguments are from an iteratee call.\n *\n * @private\n * @param {*} value The potential iteratee value argument.\n * @param {*} index The potential iteratee index or key argument.\n * @param {*} object The potential iteratee object argument.\n * @returns {boolean} Returns `true` if the arguments are from an iteratee call,\n * else `false`.\n */\nfunction isIterateeCall(value, index, object) {\n if (!isObject(object)) {\n return false;\n }\n var type = typeof index;\n if (type == 'number'\n ? (isArrayLike(object) && isIndex(index, object.length))\n : (type == 'string' && index in object)\n ) {\n return eq(object[index], value);\n }\n return false;\n}\n\nexport default isIterateeCall;\n","import baseRest from './_baseRest.js';\nimport isIterateeCall from './_isIterateeCall.js';\n\n/**\n * Creates a function like `_.assign`.\n *\n * @private\n * @param {Function} assigner The function to assign values.\n * @returns {Function} Returns the new assigner function.\n */\nfunction createAssigner(assigner) {\n return baseRest(function(object, sources) {\n var index = -1,\n length = sources.length,\n customizer = length > 1 ? sources[length - 1] : undefined,\n guard = length > 2 ? sources[2] : undefined;\n\n customizer = (assigner.length > 3 && typeof customizer == 'function')\n ? (length--, customizer)\n : undefined;\n\n if (guard && isIterateeCall(sources[0], sources[1], guard)) {\n customizer = length < 3 ? undefined : customizer;\n length = 1;\n }\n object = Object(object);\n while (++index < length) {\n var source = sources[index];\n if (source) {\n assigner(object, source, index, customizer);\n }\n }\n return object;\n });\n}\n\nexport default createAssigner;\n","/**\n * The base implementation of `_.times` without support for iteratee shorthands\n * or max array length checks.\n *\n * @private\n * @param {number} n The number of times to invoke `iteratee`.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the array of results.\n */\nfunction baseTimes(n, iteratee) {\n var index = -1,\n result = Array(n);\n\n while (++index < n) {\n result[index] = iteratee(index);\n }\n return result;\n}\n\nexport default baseTimes;\n","/**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\nfunction isObjectLike(value) {\n return value != null && typeof value == 'object';\n}\n\nexport default isObjectLike;\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]';\n\n/**\n * The base implementation of `_.isArguments`.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n */\nfunction baseIsArguments(value) {\n return isObjectLike(value) && baseGetTag(value) == argsTag;\n}\n\nexport default baseIsArguments;\n","import baseIsArguments from './_baseIsArguments.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\nvar isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n};\n\nexport default isArguments;\n","/**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\nvar isArray = Array.isArray;\n\nexport default isArray;\n","import baseGetTag from './_baseGetTag.js';\nimport isLength from './isLength.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values of typed arrays. */\nvar typedArrayTags = {};\ntypedArrayTags[float32Tag] = typedArrayTags[float64Tag] =\ntypedArrayTags[int8Tag] = typedArrayTags[int16Tag] =\ntypedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =\ntypedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =\ntypedArrayTags[uint32Tag] = true;\ntypedArrayTags[argsTag] = typedArrayTags[arrayTag] =\ntypedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =\ntypedArrayTags[dataViewTag] = typedArrayTags[dateTag] =\ntypedArrayTags[errorTag] = typedArrayTags[funcTag] =\ntypedArrayTags[mapTag] = typedArrayTags[numberTag] =\ntypedArrayTags[objectTag] = typedArrayTags[regexpTag] =\ntypedArrayTags[setTag] = typedArrayTags[stringTag] =\ntypedArrayTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.isTypedArray` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n */\nfunction baseIsTypedArray(value) {\n return isObjectLike(value) &&\n isLength(value.length) && !!typedArrayTags[baseGetTag(value)];\n}\n\nexport default baseIsTypedArray;\n","/**\n * The base implementation of `_.unary` without support for storing metadata.\n *\n * @private\n * @param {Function} func The function to cap arguments for.\n * @returns {Function} Returns the new capped function.\n */\nfunction baseUnary(func) {\n return function(value) {\n return func(value);\n };\n}\n\nexport default baseUnary;\n","import baseIsTypedArray from './_baseIsTypedArray.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;\n\n/**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\nvar isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\nexport default isTypedArray;\n","import baseTimes from './_baseTimes.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isIndex from './_isIndex.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Creates an array of the enumerable property names of the array-like `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @param {boolean} inherited Specify returning inherited property names.\n * @returns {Array} Returns the array of property names.\n */\nfunction arrayLikeKeys(value, inherited) {\n var isArr = isArray(value),\n isArg = !isArr && isArguments(value),\n isBuff = !isArr && !isArg && isBuffer(value),\n isType = !isArr && !isArg && !isBuff && isTypedArray(value),\n skipIndexes = isArr || isArg || isBuff || isType,\n result = skipIndexes ? baseTimes(value.length, String) : [],\n length = result.length;\n\n for (var key in value) {\n if ((inherited || hasOwnProperty.call(value, key)) &&\n !(skipIndexes && (\n // Safari 9 has enumerable `arguments.length` in strict mode.\n key == 'length' ||\n // Node.js 0.10 has enumerable non-index properties on buffers.\n (isBuff && (key == 'offset' || key == 'parent')) ||\n // PhantomJS 2 has enumerable non-index properties on typed arrays.\n (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||\n // Skip index properties.\n isIndex(key, length)\n ))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default arrayLikeKeys;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/**\n * Checks if `value` is likely a prototype object.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.\n */\nfunction isPrototype(value) {\n var Ctor = value && value.constructor,\n proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;\n\n return value === proto;\n}\n\nexport default isPrototype;\n","/**\n * This function is like\n * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * except that it includes inherited enumerable properties.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction nativeKeysIn(object) {\n var result = [];\n if (object != null) {\n for (var key in Object(object)) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default nativeKeysIn;\n","import isObject from './isObject.js';\nimport isPrototype from './_isPrototype.js';\nimport nativeKeysIn from './_nativeKeysIn.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeysIn(object) {\n if (!isObject(object)) {\n return nativeKeysIn(object);\n }\n var isProto = isPrototype(object),\n result = [];\n\n for (var key in object) {\n if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeysIn;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeysIn from './_baseKeysIn.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own and inherited enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keysIn(new Foo);\n * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n */\nfunction keysIn(object) {\n return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);\n}\n\nexport default keysIn;\n","import copyObject from './_copyObject.js';\nimport createAssigner from './_createAssigner.js';\nimport keysIn from './keysIn.js';\n\n/**\n * This method is like `_.assign` except that it iterates over own and\n * inherited source properties.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @alias extend\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.assign\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * function Bar() {\n * this.c = 3;\n * }\n *\n * Foo.prototype.b = 2;\n * Bar.prototype.d = 4;\n *\n * _.assignIn({ 'a': 0 }, new Foo, new Bar);\n * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }\n */\nvar assignIn = createAssigner(function(object, source) {\n copyObject(source, keysIn(source), object);\n});\n\nexport default assignIn;\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 utils/observablemixin\n */\n\nimport EmitterMixin from './emittermixin';\nimport CKEditorError from './ckeditorerror';\nimport { extend, isObject } from 'lodash-es';\n\nconst observablePropertiesSymbol = Symbol( 'observableProperties' );\nconst boundObservablesSymbol = Symbol( 'boundObservables' );\nconst boundPropertiesSymbol = Symbol( 'boundProperties' );\n\nconst _decoratedMethods = Symbol( 'decoratedMethods' );\nconst _decoratedOriginal = Symbol( 'decoratedOriginal' );\n\n/**\n * A mixin that injects the \"observable properties\" and data binding functionality described in the\n * {@link ~Observable} interface.\n *\n * Read more about the concept of observables in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables \"Event system and observables\"}\n * section of the {@glink framework/guides/architecture/core-editor-architecture \"Core editor architecture\"} guide,\n * * {@glink framework/guides/deep-dive/observables \"Observables\" deep dive} guide.\n *\n * @mixin ObservableMixin\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/observablemixin~Observable\n */\nconst ObservableMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tset( name, value ) {\n\t\t// If the first parameter is an Object, iterate over its properties.\n\t\tif ( isObject( name ) ) {\n\t\t\tObject.keys( name ).forEach( property => {\n\t\t\t\tthis.set( property, name[ property ] );\n\t\t\t}, this );\n\n\t\t\treturn;\n\t\t}\n\n\t\tinitObservable( this );\n\n\t\tconst properties = this[ observablePropertiesSymbol ];\n\n\t\tif ( ( name in this ) && !properties.has( name ) ) {\n\t\t\t/**\n\t\t\t * Cannot override an existing property.\n\t\t\t *\n\t\t\t * This error is thrown when trying to {@link ~Observable#set set} a property with\n\t\t\t * a name of an already existing property. For example:\n\t\t\t *\n\t\t\t *\t\tlet observable = new Model();\n\t\t\t *\t\tobservable.property = 1;\n\t\t\t *\t\tobservable.set( 'property', 2 );\t\t\t// throws\n\t\t\t *\n\t\t\t *\t\tobservable.set( 'property', 1 );\n\t\t\t *\t\tobservable.set( 'property', 2 );\t\t\t// ok, because this is an existing property.\n\t\t\t *\n\t\t\t * @error observable-set-cannot-override\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-set-cannot-override', this );\n\t\t}\n\n\t\tObject.defineProperty( this, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget() {\n\t\t\t\treturn properties.get( name );\n\t\t\t},\n\n\t\t\tset( value ) {\n\t\t\t\tconst oldValue = properties.get( name );\n\n\t\t\t\t// Fire `set` event before the new value will be set to make it possible\n\t\t\t\t// to override observable property without affecting `change` event.\n\t\t\t\t// See https://github.com/ckeditor/ckeditor5-utils/issues/171.\n\t\t\t\tlet newValue = this.fire( 'set:' + name, name, value, oldValue );\n\n\t\t\t\tif ( newValue === undefined ) {\n\t\t\t\t\tnewValue = value;\n\t\t\t\t}\n\n\t\t\t\t// Allow undefined as an initial value like A.define( 'x', undefined ) (#132).\n\t\t\t\t// Note: When properties map has no such own property, then its value is undefined.\n\t\t\t\tif ( oldValue !== newValue || !properties.has( name ) ) {\n\t\t\t\t\tproperties.set( name, newValue );\n\t\t\t\t\tthis.fire( 'change:' + name, name, newValue, oldValue );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tthis[ name ] = value;\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tbind( ...bindProperties ) {\n\t\tif ( !bindProperties.length || !isStringArray( bindProperties ) ) {\n\t\t\t/**\n\t\t\t * All properties must be strings.\n\t\t\t *\n\t\t\t * @error observable-bind-wrong-properties\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-wrong-properties', this );\n\t\t}\n\n\t\tif ( ( new Set( bindProperties ) ).size !== bindProperties.length ) {\n\t\t\t/**\n\t\t\t * Properties must be unique.\n\t\t\t *\n\t\t\t * @error observable-bind-duplicate-properties\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-duplicate-properties', this );\n\t\t}\n\n\t\tinitObservable( this );\n\n\t\tconst boundProperties = this[ boundPropertiesSymbol ];\n\n\t\tbindProperties.forEach( propertyName => {\n\t\t\tif ( boundProperties.has( propertyName ) ) {\n\t\t\t\t/**\n\t\t\t\t * Cannot bind the same property more than once.\n\t\t\t\t *\n\t\t\t\t * @error observable-bind-rebind\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'observable-bind-rebind', this );\n\t\t\t}\n\t\t} );\n\n\t\tconst bindings = new Map();\n\n\t\t// @typedef {Object} Binding\n\t\t// @property {Array} property Property which is bound.\n\t\t// @property {Array} to Array of observableproperty components of the binding (`{ observable: ..., property: .. }`).\n\t\t// @property {Array} callback A function which processes `to` components.\n\t\tbindProperties.forEach( a => {\n\t\t\tconst binding = { property: a, to: [] };\n\n\t\t\tboundProperties.set( a, binding );\n\t\t\tbindings.set( a, binding );\n\t\t} );\n\n\t\t// @typedef {Object} BindChain\n\t\t// @property {Function} to See {@link ~ObservableMixin#_bindTo}.\n\t\t// @property {Function} toMany See {@link ~ObservableMixin#_bindToMany}.\n\t\t// @property {module:utils/observablemixin~Observable} _observable The observable which initializes the binding.\n\t\t// @property {Array} _bindProperties Array of `_observable` properties to be bound.\n\t\t// @property {Array} _to Array of `to()` observableproperties (`{ observable: toObservable, properties: ...toProperties }`).\n\t\t// @property {Map} _bindings Stores bindings to be kept in\n\t\t// {@link ~ObservableMixin#_boundProperties}/{@link ~ObservableMixin#_boundObservables}\n\t\t// initiated in this binding chain.\n\t\treturn {\n\t\t\tto: bindTo,\n\t\t\ttoMany: bindToMany,\n\n\t\t\t_observable: this,\n\t\t\t_bindProperties: bindProperties,\n\t\t\t_to: [],\n\t\t\t_bindings: bindings\n\t\t};\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tunbind( ...unbindProperties ) {\n\t\t// Nothing to do here if not inited yet.\n\t\tif ( !( this[ observablePropertiesSymbol ] ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst boundProperties = this[ boundPropertiesSymbol ];\n\t\tconst boundObservables = this[ boundObservablesSymbol ];\n\n\t\tif ( unbindProperties.length ) {\n\t\t\tif ( !isStringArray( unbindProperties ) ) {\n\t\t\t\t/**\n\t\t\t\t * Properties must be strings.\n\t\t\t\t *\n\t\t\t\t * @error observable-unbind-wrong-properties\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'observable-unbind-wrong-properties', this );\n\t\t\t}\n\n\t\t\tunbindProperties.forEach( propertyName => {\n\t\t\t\tconst binding = boundProperties.get( propertyName );\n\n\t\t\t\t// Nothing to do if the binding is not defined\n\t\t\t\tif ( !binding ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tlet toObservable, toProperty, toProperties, toPropertyBindings;\n\n\t\t\t\tbinding.to.forEach( to => {\n\t\t\t\t\t// TODO: ES6 destructuring.\n\t\t\t\t\ttoObservable = to[ 0 ];\n\t\t\t\t\ttoProperty = to[ 1 ];\n\t\t\t\t\ttoProperties = boundObservables.get( toObservable );\n\t\t\t\t\ttoPropertyBindings = toProperties[ toProperty ];\n\n\t\t\t\t\ttoPropertyBindings.delete( binding );\n\n\t\t\t\t\tif ( !toPropertyBindings.size ) {\n\t\t\t\t\t\tdelete toProperties[ toProperty ];\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !Object.keys( toProperties ).length ) {\n\t\t\t\t\t\tboundObservables.delete( toObservable );\n\t\t\t\t\t\tthis.stopListening( toObservable, 'change' );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tboundProperties.delete( propertyName );\n\t\t\t} );\n\t\t} else {\n\t\t\tboundObservables.forEach( ( bindings, boundObservable ) => {\n\t\t\t\tthis.stopListening( boundObservable, 'change' );\n\t\t\t} );\n\n\t\t\tboundObservables.clear();\n\t\t\tboundProperties.clear();\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdecorate( methodName ) {\n\t\tconst originalMethod = this[ methodName ];\n\n\t\tif ( !originalMethod ) {\n\t\t\t/**\n\t\t\t * Cannot decorate an undefined method.\n\t\t\t *\n\t\t\t * @error observablemixin-cannot-decorate-undefined\n\t\t\t * @param {Object} object The object which method should be decorated.\n\t\t\t * @param {String} methodName Name of the method which does not exist.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'observablemixin-cannot-decorate-undefined',\n\t\t\t\tthis,\n\t\t\t\t{ object: this, methodName }\n\t\t\t);\n\t\t}\n\n\t\tthis.on( methodName, ( evt, args ) => {\n\t\t\tevt.return = originalMethod.apply( this, args );\n\t\t} );\n\n\t\tthis[ methodName ] = function( ...args ) {\n\t\t\treturn this.fire( methodName, args );\n\t\t};\n\n\t\tthis[ methodName ][ _decoratedOriginal ] = originalMethod;\n\n\t\tif ( !this[ _decoratedMethods ] ) {\n\t\t\tthis[ _decoratedMethods ] = [];\n\t\t}\n\n\t\tthis[ _decoratedMethods ].push( methodName );\n\t}\n};\n\nextend( ObservableMixin, EmitterMixin );\n\n// Override the EmitterMixin stopListening method to be able to clean (and restore) decorated methods.\n// This is needed in case of:\n// 1. Have x.foo() decorated.\n// 2. Call x.stopListening()\n// 3. Call x.foo(). Problem: nothing happens (the original foo() method is not executed)\nObservableMixin.stopListening = function( emitter, event, callback ) {\n\t// Removing all listeners so let's clean the decorated methods to the original state.\n\tif ( !emitter && this[ _decoratedMethods ] ) {\n\t\tfor ( const methodName of this[ _decoratedMethods ] ) {\n\t\t\tthis[ methodName ] = this[ methodName ][ _decoratedOriginal ];\n\t\t}\n\n\t\tdelete this[ _decoratedMethods ];\n\t}\n\n\tEmitterMixin.stopListening.call( this, emitter, event, callback );\n};\n\nexport default ObservableMixin;\n\n// Init symbol properties needed for the observable mechanism to work.\n//\n// @private\n// @param {module:utils/observablemixin~ObservableMixin} observable\nfunction initObservable( observable ) {\n\t// Do nothing if already inited.\n\tif ( observable[ observablePropertiesSymbol ] ) {\n\t\treturn;\n\t}\n\n\t// The internal hash containing the observable's state.\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, observablePropertiesSymbol, {\n\t\tvalue: new Map()\n\t} );\n\n\t// Map containing bindings to external observables. It shares the binding objects\n\t// (`{ observable: A, property: 'a', to: ... }`) with {@link module:utils/observablemixin~ObservableMixin#_boundProperties} and\n\t// it is used to observe external observables to update own properties accordingly.\n\t// See {@link module:utils/observablemixin~ObservableMixin#bind}.\n\t//\n\t//\t\tA.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );\n\t//\t\tconsole.log( A._boundObservables );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\tB: {\n\t//\t\t\t\t\tx: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\t\t\t{ observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\ty: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t}\n\t//\t\t\t} )\n\t//\n\t//\t\tA.bind( 'd' ).to( B, 'z' ).to( C, 'w' ).as( callback );\n\t//\t\tconsole.log( A._boundObservables );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\tB: {\n\t//\t\t\t\t\tx: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\t\t\t{ observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\ty: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\t\t] ),\n\t//\t\t\t\t\tz: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t},\n\t//\t\t\t\tC: {\n\t//\t\t\t\t\tw: Set( [\n\t//\t\t\t\t\t\t{ observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t\t\t] )\n\t//\t\t\t\t}\n\t//\t\t\t} )\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, boundObservablesSymbol, {\n\t\tvalue: new Map()\n\t} );\n\n\t// Object that stores which properties of this observable are bound and how. It shares\n\t// the binding objects (`{ observable: A, property: 'a', to: ... }`) with\n\t// {@link module:utils/observablemixin~ObservableMixin#_boundObservables}. This data structure is\n\t// a reverse of {@link module:utils/observablemixin~ObservableMixin#_boundObservables} and it is helpful for\n\t// {@link module:utils/observablemixin~ObservableMixin#unbind}.\n\t//\n\t// See {@link module:utils/observablemixin~ObservableMixin#bind}.\n\t//\n\t//\t\tA.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );\n\t//\t\tconsole.log( A._boundProperties );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\ta: { observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\tb: { observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\tc: { observable: A, property: 'c', to: [ [ B, 'x' ] ] }\n\t//\t\t\t} )\n\t//\n\t//\t\tA.bind( 'd' ).to( B, 'z' ).to( C, 'w' ).as( callback );\n\t//\t\tconsole.log( A._boundProperties );\n\t//\n\t//\t\t\tMap( {\n\t//\t\t\t\ta: { observable: A, property: 'a', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\tb: { observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n\t//\t\t\t\tc: { observable: A, property: 'c', to: [ [ B, 'x' ] ] },\n\t//\t\t\t\td: { observable: A, property: 'd', to: [ [ B, 'z' ], [ C, 'w' ] ], callback: callback }\n\t//\t\t\t} )\n\t//\n\t// @private\n\t// @type {Map}\n\tObject.defineProperty( observable, boundPropertiesSymbol, {\n\t\tvalue: new Map()\n\t} );\n}\n\n// A chaining for {@link module:utils/observablemixin~ObservableMixin#bind} providing `.to()` interface.\n//\n// @private\n// @param {...[Observable|String|Function]} args Arguments of the `.to( args )` binding.\nfunction bindTo( ...args ) {\n\tconst parsedArgs = parseBindToArgs( ...args );\n\tconst bindingsKeys = Array.from( this._bindings.keys() );\n\tconst numberOfBindings = bindingsKeys.length;\n\n\t// Eliminate A.bind( 'x' ).to( B, C )\n\tif ( !parsedArgs.callback && parsedArgs.to.length > 1 ) {\n\t\t/**\n\t\t * Binding multiple observables only possible with callback.\n\t\t *\n\t\t * @error observable-bind-to-no-callback\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-no-callback', this );\n\t}\n\n\t// Eliminate A.bind( 'x', 'y' ).to( B, callback )\n\tif ( numberOfBindings > 1 && parsedArgs.callback ) {\n\t\t/**\n\t\t * Cannot bind multiple properties and use a callback in one binding.\n\t\t *\n\t\t * @error observable-bind-to-extra-callback\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'observable-bind-to-extra-callback',\n\t\t\tthis\n\t\t);\n\t}\n\n\tparsedArgs.to.forEach( to => {\n\t\t// Eliminate A.bind( 'x', 'y' ).to( B, 'a' )\n\t\tif ( to.properties.length && to.properties.length !== numberOfBindings ) {\n\t\t\t/**\n\t\t\t * The number of properties must match.\n\t\t\t *\n\t\t\t * @error observable-bind-to-properties-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'observable-bind-to-properties-length', this );\n\t\t}\n\n\t\t// When no to.properties specified, observing source properties instead i.e.\n\t\t// A.bind( 'x', 'y' ).to( B ) -> Observe B.x and B.y\n\t\tif ( !to.properties.length ) {\n\t\t\tto.properties = this._bindProperties;\n\t\t}\n\t} );\n\n\tthis._to = parsedArgs.to;\n\n\t// Fill {@link BindChain#_bindings} with callback. When the callback is set there's only one binding.\n\tif ( parsedArgs.callback ) {\n\t\tthis._bindings.get( bindingsKeys[ 0 ] ).callback = parsedArgs.callback;\n\t}\n\n\tattachBindToListeners( this._observable, this._to );\n\n\t// Update observable._boundProperties and observable._boundObservables.\n\tupdateBindToBound( this );\n\n\t// Set initial values of bound properties.\n\tthis._bindProperties.forEach( propertyName => {\n\t\tupdateBoundObservableProperty( this._observable, propertyName );\n\t} );\n}\n\n// Binds to an attribute in a set of iterable observables.\n//\n// @private\n// @param {Array.<Observable>} observables\n// @param {String} attribute\n// @param {Function} callback\nfunction bindToMany( observables, attribute, callback ) {\n\tif ( this._bindings.size > 1 ) {\n\t\t/**\n\t\t * Binding one attribute to many observables only possible with one attribute.\n\t\t *\n\t\t * @error observable-bind-to-many-not-one-binding\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-many-not-one-binding', this );\n\t}\n\n\tthis.to(\n\t\t// Bind to #attribute of each observable...\n\t\t...getBindingTargets( observables, attribute ),\n\t\t// ...using given callback to parse attribute values.\n\t\tcallback\n\t);\n}\n\n// Returns an array of binding components for\n// {@link Observable#bind} from a set of iterable observables.\n//\n// @param {Array.<Observable>} observables\n// @param {String} attribute\n// @returns {Array.<String|Observable>}\nfunction getBindingTargets( observables, attribute ) {\n\tconst observableAndAttributePairs = observables.map( observable => [ observable, attribute ] );\n\n\t// Merge pairs to one-dimension array of observables and attributes.\n\treturn Array.prototype.concat.apply( [], observableAndAttributePairs );\n}\n\n// Check if all entries of the array are of `String` type.\n//\n// @private\n// @param {Array} arr An array to be checked.\n// @returns {Boolean}\nfunction isStringArray( arr ) {\n\treturn arr.every( a => typeof a == 'string' );\n}\n\n// Parses and validates {@link Observable#bind}`.to( args )` arguments and returns\n// an object with a parsed structure. For example\n//\n//\t\tA.bind( 'x' ).to( B, 'a', C, 'b', call );\n//\n// becomes\n//\n//\t\t{\n//\t\t\tto: [\n//\t\t\t\t{ observable: B, properties: [ 'a' ] },\n//\t\t\t\t{ observable: C, properties: [ 'b' ] },\n//\t\t\t],\n//\t\t\tcallback: call\n// \t\t}\n//\n// @private\n// @param {...*} args Arguments of {@link Observable#bind}`.to( args )`.\n// @returns {Object}\nfunction parseBindToArgs( ...args ) {\n\t// Eliminate A.bind( 'x' ).to()\n\tif ( !args.length ) {\n\t\t/**\n\t\t * Invalid argument syntax in `to()`.\n\t\t *\n\t\t * @error observable-bind-to-parse-error\n\t\t */\n\t\tthrow new CKEditorError( 'observable-bind-to-parse-error', null );\n\t}\n\n\tconst parsed = { to: [] };\n\tlet lastObservable;\n\n\tif ( typeof args[ args.length - 1 ] == 'function' ) {\n\t\tparsed.callback = args.pop();\n\t}\n\n\targs.forEach( a => {\n\t\tif ( typeof a == 'string' ) {\n\t\t\tlastObservable.properties.push( a );\n\t\t} else if ( typeof a == 'object' ) {\n\t\t\tlastObservable = { observable: a, properties: [] };\n\t\t\tparsed.to.push( lastObservable );\n\t\t} else {\n\t\t\tthrow new CKEditorError( 'observable-bind-to-parse-error', null );\n\t\t}\n\t} );\n\n\treturn parsed;\n}\n\n// Synchronizes {@link module:utils/observablemixin#_boundObservables} with {@link Binding}.\n//\n// @private\n// @param {Binding} binding A binding to store in {@link Observable#_boundObservables}.\n// @param {Observable} toObservable A observable, which is a new component of `binding`.\n// @param {String} toPropertyName A name of `toObservable`'s property, a new component of the `binding`.\nfunction updateBoundObservables( observable, binding, toObservable, toPropertyName ) {\n\tconst boundObservables = observable[ boundObservablesSymbol ];\n\tconst bindingsToObservable = boundObservables.get( toObservable );\n\tconst bindings = bindingsToObservable || {};\n\n\tif ( !bindings[ toPropertyName ] ) {\n\t\tbindings[ toPropertyName ] = new Set();\n\t}\n\n\t// Pass the binding to a corresponding Set in `observable._boundObservables`.\n\tbindings[ toPropertyName ].add( binding );\n\n\tif ( !bindingsToObservable ) {\n\t\tboundObservables.set( toObservable, bindings );\n\t}\n}\n\n// Synchronizes {@link Observable#_boundProperties} and {@link Observable#_boundObservables}\n// with {@link BindChain}.\n//\n// Assuming the following binding being created\n//\n// \t\tA.bind( 'a', 'b' ).to( B, 'x', 'y' );\n//\n// the following bindings were initialized by {@link Observable#bind} in {@link BindChain#_bindings}:\n//\n// \t\t{\n// \t\t\ta: { observable: A, property: 'a', to: [] },\n// \t\t\tb: { observable: A, property: 'b', to: [] },\n// \t\t}\n//\n// Iterate over all bindings in this chain and fill their `to` properties with\n// corresponding to( ... ) arguments (components of the binding), so\n//\n// \t\t{\n// \t\t\ta: { observable: A, property: 'a', to: [ B, 'x' ] },\n// \t\t\tb: { observable: A, property: 'b', to: [ B, 'y' ] },\n// \t\t}\n//\n// Then update the structure of {@link Observable#_boundObservables} with updated\n// binding, so it becomes:\n//\n// \t\tMap( {\n// \t\t\tB: {\n// \t\t\t\tx: Set( [\n// \t\t\t\t\t{ observable: A, property: 'a', to: [ [ B, 'x' ] ] }\n// \t\t\t\t] ),\n// \t\t\t\ty: Set( [\n// \t\t\t\t\t{ observable: A, property: 'b', to: [ [ B, 'y' ] ] },\n// \t\t\t\t] )\n//\t\t\t}\n// \t\t} )\n//\n// @private\n// @param {BindChain} chain The binding initialized by {@link Observable#bind}.\nfunction updateBindToBound( chain ) {\n\tlet toProperty;\n\n\tchain._bindings.forEach( ( binding, propertyName ) => {\n\t\t// Note: For a binding without a callback, this will run only once\n\t\t// like in A.bind( 'x', 'y' ).to( B, 'a', 'b' )\n\t\t// TODO: ES6 destructuring.\n\t\tchain._to.forEach( to => {\n\t\t\ttoProperty = to.properties[ binding.callback ? 0 : chain._bindProperties.indexOf( propertyName ) ];\n\n\t\t\tbinding.to.push( [ to.observable, toProperty ] );\n\t\t\tupdateBoundObservables( chain._observable, binding, to.observable, toProperty );\n\t\t} );\n\t} );\n}\n\n// Updates an property of a {@link Observable} with a value\n// determined by an entry in {@link Observable#_boundProperties}.\n//\n// @private\n// @param {Observable} observable A observable which property is to be updated.\n// @param {String} propertyName An property to be updated.\nfunction updateBoundObservableProperty( observable, propertyName ) {\n\tconst boundProperties = observable[ boundPropertiesSymbol ];\n\tconst binding = boundProperties.get( propertyName );\n\tlet propertyValue;\n\n\t// When a binding with callback is created like\n\t//\n\t// \t\tA.bind( 'a' ).to( B, 'b', C, 'c', callback );\n\t//\n\t// collect B.b and C.c, then pass them to callback to set A.a.\n\tif ( binding.callback ) {\n\t\tpropertyValue = binding.callback.apply( observable, binding.to.map( to => to[ 0 ][ to[ 1 ] ] ) );\n\t} else {\n\t\tpropertyValue = binding.to[ 0 ];\n\t\tpropertyValue = propertyValue[ 0 ][ propertyValue[ 1 ] ];\n\t}\n\n\tif ( Object.prototype.hasOwnProperty.call( observable, propertyName ) ) {\n\t\tobservable[ propertyName ] = propertyValue;\n\t} else {\n\t\tobservable.set( propertyName, propertyValue );\n\t}\n}\n\n// Starts listening to changes in {@link BindChain._to} observables to update\n// {@link BindChain._observable} {@link BindChain._bindProperties}. Also sets the\n// initial state of {@link BindChain._observable}.\n//\n// @private\n// @param {BindChain} chain The chain initialized by {@link Observable#bind}.\nfunction attachBindToListeners( observable, toBindings ) {\n\ttoBindings.forEach( to => {\n\t\tconst boundObservables = observable[ boundObservablesSymbol ];\n\t\tlet bindings;\n\n\t\t// If there's already a chain between the observables (`observable` listens to\n\t\t// `to.observable`), there's no need to create another `change` event listener.\n\t\tif ( !boundObservables.get( to.observable ) ) {\n\t\t\tobservable.listenTo( to.observable, 'change', ( evt, propertyName ) => {\n\t\t\t\tbindings = boundObservables.get( to.observable )[ propertyName ];\n\n\t\t\t\t// Note: to.observable will fire for any property change, react\n\t\t\t\t// to changes of properties which are bound only.\n\t\t\t\tif ( bindings ) {\n\t\t\t\t\tbindings.forEach( binding => {\n\t\t\t\t\t\tupdateBoundObservableProperty( observable, binding.property );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t} );\n}\n\n/**\n * An interface which adds \"observable properties\" and data binding functionality.\n *\n * Can be easily implemented by a class by mixing the {@link module:utils/observablemixin~ObservableMixin} mixin.\n *\n * Read more about the usage of this interface in the:\n * * {@glink framework/guides/architecture/core-editor-architecture#event-system-and-observables \"Event system and observables\"}\n * section of the {@glink framework/guides/architecture/core-editor-architecture \"Core editor architecture\"} guide,\n * * {@glink framework/guides/deep-dive/observables \"Observables\" deep dive} guide.\n *\n * @interface Observable\n * @extends module:utils/emittermixin~Emitter\n */\n\n/**\n * Fired when a property changed value.\n *\n *\t\tobservable.set( 'prop', 1 );\n *\n *\t\tobservable.on( 'change:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `${ propertyName } has changed from ${ oldValue } to ${ newValue }` );\n *\t\t} );\n *\n *\t\tobservable.prop = 2; // -> 'prop has changed from 1 to 2'\n *\n * @event change:{property}\n * @param {String} name The property name.\n * @param {*} value The new property value.\n * @param {*} oldValue The previous property value.\n */\n\n/**\n * Fired when a property value is going to be set but is not set yet (before the `change` event is fired).\n *\n * You can control the final value of the property by using\n * the {@link module:utils/eventinfo~EventInfo#return event's `return` property}.\n *\n *\t\tobservable.set( 'prop', 1 );\n *\n *\t\tobservable.on( 'set:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `Value is going to be changed from ${ oldValue } to ${ newValue }` );\n *\t\t\tconsole.log( `Current property value is ${ observable[ propertyName ] }` );\n *\n *\t\t\t// Let's override the value.\n *\t\t\tevt.return = 3;\n *\t\t} );\n *\n *\t\tobservable.on( 'change:prop', ( evt, propertyName, newValue, oldValue ) => {\n *\t\t\tconsole.log( `Value has changed from ${ oldValue } to ${ newValue }` );\n *\t\t} );\n *\n *\t\tobservable.prop = 2; // -> 'Value is going to be changed from 1 to 2'\n *\t\t // -> 'Current property value is 1'\n *\t\t // -> 'Value has changed from 1 to 3'\n *\n * **Note:** The event is fired even when the new value is the same as the old value.\n *\n * @event set:{property}\n * @param {String} name The property name.\n * @param {*} value The new property value.\n * @param {*} oldValue The previous property value.\n */\n\n/**\n * Creates and sets the value of an observable property of this object. Such a property becomes a part\n * of the state and is observable.\n *\n * It accepts also a single object literal containing key/value pairs with properties to be set.\n *\n * This method throws the `observable-set-cannot-override` error if the observable instance already\n * has a property with the given property name. This prevents from mistakenly overriding existing\n * properties and methods, but means that `foo.set( 'bar', 1 )` may be slightly slower than `foo.bar = 1`.\n *\n * @method #set\n * @param {String|Object} name The property's name or object with `name=>value` pairs.\n * @param {*} [value] The property's value (if `name` was passed in the first parameter).\n */\n\n/**\n * Binds {@link #set observable properties} to other objects implementing the\n * {@link module:utils/observablemixin~Observable} interface.\n *\n * Read more in the {@glink framework/guides/deep-dive/observables#property-bindings dedicated guide}\n * covering the topic of property bindings with some additional examples.\n *\n * Consider two objects: a `button` and an associated `command` (both `Observable`).\n *\n * A simple property binding could be as follows:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isEnabled' );\n *\n * or even shorter:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command );\n *\n * which works in the following way:\n *\n * * `button.isEnabled` **instantly equals** `command.isEnabled`,\n * * whenever `command.isEnabled` changes, `button.isEnabled` will immediately reflect its value.\n *\n * **Note**: To release the binding, use {@link module:utils/observablemixin~Observable#unbind}.\n *\n * You can also \"rename\" the property in the binding by specifying the new name in the `to()` chain:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isWorking' );\n *\n * It is possible to bind more than one property at a time to shorten the code:\n *\n *\t\tbutton.bind( 'isEnabled', 'value' ).to( command );\n *\n * which corresponds to:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command );\n *\t\tbutton.bind( 'value' ).to( command );\n *\n * The binding can include more than one observable, combining multiple data sources in a custom callback:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'isEnabled', ui, 'isVisible',\n *\t\t\t( isCommandEnabled, isUIVisible ) => isCommandEnabled && isUIVisible );\n *\n * Using a custom callback allows processing the value before passing it to the target property:\n *\n *\t\tbutton.bind( 'isEnabled' ).to( command, 'value', value => value === 'heading1' );\n *\n * It is also possible to bind to the same property in an array of observables.\n * To bind a `button` to multiple commands (also `Observables`) so that each and every one of them\n * must be enabled for the button to become enabled, use the following code:\n *\n *\t\tbutton.bind( 'isEnabled' ).toMany( [ commandA, commandB, commandC ], 'isEnabled',\n *\t\t\t( isAEnabled, isBEnabled, isCEnabled ) => isAEnabled && isBEnabled && isCEnabled );\n *\n * @method #bind\n * @param {...String} bindProperties Observable properties that will be bound to other observable(s).\n * @returns {Object} The bind chain with the `to()` and `toMany()` methods.\n */\n\n/**\n * Removes the binding created with {@link #bind}.\n *\n *\t\t// Removes the binding for the 'a' property.\n *\t\tA.unbind( 'a' );\n *\n *\t\t// Removes bindings for all properties.\n *\t\tA.unbind();\n *\n * @method #unbind\n * @param {...String} [unbindProperties] Observable properties to be unbound. All the bindings will\n * be released if no properties are provided.\n */\n\n/**\n * Turns the given methods of this object into event-based ones. This means that the new method will fire an event\n * (named after the method) and the original action will be plugged as a listener to that event.\n *\n * Read more in the {@glink framework/guides/deep-dive/observables#decorating-object-methods dedicated guide}\n * covering the topic of decorating methods with some additional examples.\n *\n * Decorating the method does not change its behavior (it only adds an event),\n * but it allows to modify it later on by listening to the method's event.\n *\n * For example, to cancel the method execution the event can be {@link module:utils/eventinfo~EventInfo#stop stopped}:\n *\n *\t\tclass Foo {\n *\t\t\tconstructor() {\n *\t\t\t\tthis.decorate( 'method' );\n *\t\t\t}\n *\n *\t\t\tmethod() {\n *\t\t\t\tconsole.log( 'called!' );\n *\t\t\t}\n *\t\t}\n *\n *\t\tconst foo = new Foo();\n *\t\tfoo.on( 'method', ( evt ) => {\n *\t\t\tevt.stop();\n *\t\t}, { priority: 'high' } );\n *\n *\t\tfoo.method(); // Nothing is logged.\n *\n *\n * **Note**: The high {@link module:utils/priorities~PriorityString priority} listener\n * has been used to execute this particular callback before the one which calls the original method\n * (which uses the \"normal\" priority).\n *\n * It is also possible to change the returned value:\n *\n *\t\tfoo.on( 'method', ( evt ) => {\n *\t\t\tevt.return = 'Foo!';\n *\t\t} );\n *\n *\t\tfoo.method(); // -> 'Foo'\n *\n * Finally, it is possible to access and modify the arguments the method is called with:\n *\n *\t\tmethod( a, b ) {\n *\t\t\tconsole.log( `${ a }, ${ b }` );\n *\t\t}\n *\n *\t\t// ...\n *\n *\t\tfoo.on( 'method', ( evt, args ) => {\n *\t\t\targs[ 0 ] = 3;\n *\n *\t\t\tconsole.log( args[ 1 ] ); // -> 2\n *\t\t}, { priority: 'high' } );\n *\n *\t\tfoo.method( 1, 2 ); // -> '3, 2'\n *\n * @method #decorate\n * @param {String} methodName Name of the method to decorate.\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 utils/mix\n */\n\n/**\n * Copies enumerable properties and symbols from the objects given as 2nd+ parameters to the\n * prototype of first object (a constructor).\n *\n *\t\tclass Editor {\n *\t\t\t...\n *\t\t}\n *\n *\t\tconst SomeMixin = {\n *\t\t\ta() {\n *\t\t\t\treturn 'a';\n *\t\t\t}\n *\t\t};\n *\n *\t\tmix( Editor, SomeMixin, ... );\n *\n *\t\tnew Editor().a(); // -> 'a'\n *\n * Note: Properties which already exist in the base class will not be overriden.\n *\n * @param {Function} [baseClass] Class which prototype will be extended.\n * @param {Object} [...mixins] Objects from which to get properties.\n */\nexport default function mix( baseClass, ...mixins ) {\n\tmixins.forEach( mixin => {\n\t\tObject.getOwnPropertyNames( mixin ).concat( Object.getOwnPropertySymbols( mixin ) )\n\t\t\t.forEach( key => {\n\t\t\t\tif ( key in baseClass.prototype ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst sourceDescriptor = Object.getOwnPropertyDescriptor( mixin, key );\n\t\t\t\tsourceDescriptor.enumerable = false;\n\n\t\t\t\tObject.defineProperty( baseClass.prototype, key, sourceDescriptor );\n\t\t\t} );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/plugin\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for CKEditor plugin classes.\n *\n * @implements module:core/plugin~PluginInterface\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor instance.\n\t\t *\n\t\t * Note that most editors implement the {@link module:core/editor/editorwithui~EditorWithUI} interface in addition\n\t\t * to the base {@link module:core/editor/editor~Editor} interface. However, editors with an external UI\n\t\t * (i.e. Bootstrap-based) or a headless editor may not implement the {@link module:core/editor/editorwithui~EditorWithUI}\n\t\t * interface.\n\t\t *\n\t\t * Because of above, to make plugins more universal, it is recommended to split features into:\n\t\t * - The \"editing\" part that only uses the {@link module:core/editor/editor~Editor} interface.\n\t\t * - The \"UI\" part that uses both the {@link module:core/editor/editor~Editor} interface and\n\t\t * the {@link module:core/editor/editorwithui~EditorWithUI} interface.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * Flag indicating whether a plugin is enabled or disabled.\n\t\t * A disabled plugin will not transform text.\n\t\t *\n\t\t * Plugin can be simply disabled like that:\n\t\t *\n\t\t *\t\t// Disable the plugin so that no toolbars are visible.\n\t\t *\t\teditor.plugins.get( 'TextTransformation' ).isEnabled = false;\n\t\t *\n\t\t * You can also use {@link #forceDisabled} method.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t/**\n\t\t * Holds identifiers for {@link #forceDisabled} mechanism.\n\t\t *\n\t\t * @type {Set.<String>}\n\t\t * @private\n\t\t */\n\t\tthis._disableStack = new Set();\n\t}\n\n\t/**\n\t * Disables the plugin.\n\t *\n\t * Plugin may be disabled by multiple features or algorithms (at once). When disabling a plugin, unique id should be passed\n\t * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the plugin.\n\t * The plugin becomes enabled only after all features {@link #clearForceDisabled enabled it back}.\n\t *\n\t * Disabling and enabling a plugin:\n\t *\n\t *\t\tplugin.isEnabled; // -> true\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> false\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * Plugin disabled by multiple features:\n\t *\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.forceDisabled( 'OtherFeature' );\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> false\n\t *\t\tplugin.clearForceDisabled( 'OtherFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * Multiple disabling with the same identifier is redundant:\n\t *\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.forceDisabled( 'MyFeature' );\n\t *\t\tplugin.clearForceDisabled( 'MyFeature' );\n\t *\t\tplugin.isEnabled; // -> true\n\t *\n\t * **Note:** some plugins or algorithms may have more complex logic when it comes to enabling or disabling certain plugins,\n\t * so the plugin might be still disabled after {@link #clearForceDisabled} was used.\n\t *\n\t * @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the plugin.\n\t */\n\tforceDisabled( id ) {\n\t\tthis._disableStack.add( id );\n\n\t\tif ( this._disableStack.size == 1 ) {\n\t\t\tthis.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.\n\t *\n\t * @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.\n\t */\n\tclearForceDisabled( id ) {\n\t\tthis._disableStack.delete( id );\n\n\t\tif ( this._disableStack.size == 0 ) {\n\t\t\tthis.off( 'set:isEnabled', forceDisable );\n\t\t\tthis.isEnabled = true;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get isContextPlugin() {\n\t\treturn false;\n\t}\n}\n\nmix( Plugin, ObservableMixin );\n\n/**\n * The base interface for CKEditor plugins.\n *\n * In its minimal form a plugin can be a simple function that accepts {@link module:core/editor/editor~Editor the editor}\n * as a parameter:\n *\n *\t\t// A simple plugin that enables a data processor.\n *\t\tfunction MyPlugin( editor ) {\n *\t\t\teditor.data.processor = new MyDataProcessor();\n *\t\t}\n *\n * In most cases however, you will want to inherit from the {@link module:core/plugin~Plugin} class which implements the\n * {@link module:utils/observablemixin~ObservableMixin} and is, therefore, more convenient:\n *\n *\t\tclass MyPlugin extends Plugin {\n *\t\t\tinit() {\n *\t\t\t\t// `listenTo()` and `editor` are available thanks to `Plugin`.\n *\t\t\t\t// By using `listenTo()` you will ensure that the listener is removed when\n *\t\t\t\t// the plugin is destroyed.\n *\t\t\t\tthis.listenTo( this.editor.data, 'ready', () => {\n *\t\t\t\t\t// Do something when the data is ready.\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n * The plugin can also implement methods (e.g. {@link module:core/plugin~PluginInterface#init `init()`} or\n * {@link module:core/plugin~PluginInterface#destroy `destroy()`}) which, when present, will be used to properly\n * initialize and destroy the plugin.\n *\n * **Note:** When defined as a plain function, the plugin acts as a constructor and will be\n * called in parallel with other plugins' {@link module:core/plugin~PluginInterface#constructor constructors}.\n * This means the code of that plugin will be executed **before** {@link module:core/plugin~PluginInterface#init `init()`} and\n * {@link module:core/plugin~PluginInterface#afterInit `afterInit()`} methods of other plugins and, for instance,\n * you cannot use it to extend other plugins' {@glink framework/guides/architecture/editing-engine#schema schema}\n * rules as they are defined later on during the `init()` stage.\n *\n * @interface PluginInterface\n */\n\n/**\n * Creates a new plugin instance. This is the first step of the plugin initialization.\n * See also {@link #init} and {@link #afterInit}.\n *\n * A plugin is always instantiated after its {@link module:core/plugin~PluginInterface.requires dependencies} and the\n * {@link #init} and {@link #afterInit} methods are called in the same order.\n *\n * Usually, you will want to put your plugin's initialization code in the {@link #init} method.\n * The constructor can be understood as \"before init\" and used in special cases, just like\n * {@link #afterInit} serves the special \"after init\" scenarios (e.g.the code which depends on other\n * plugins, but which does not {@link module:core/plugin~PluginInterface.requires explicitly require} them).\n *\n * @method #constructor\n * @param {module:core/editor/editor~Editor} editor\n */\n\n/**\n * An array of plugins required by this plugin.\n *\n * To keep the plugin class definition tight it is recommended to define this property as a static getter:\n *\n *\t\timport Image from './image.js';\n *\n *\t\texport default class ImageCaption {\n *\t\t\tstatic get requires() {\n *\t\t\t\treturn [ Image ];\n *\t\t\t}\n *\t\t}\n *\n * @static\n * @readonly\n * @member {Array.<Function>|undefined} module:core/plugin~PluginInterface.requires\n */\n\n/**\n * An optional name of the plugin. If set, the plugin will be available in\n * {@link module:core/plugincollection~PluginCollection#get} by its\n * name and its constructor. If not, then only by its constructor.\n *\n * The name should reflect the constructor name.\n *\n * To keep the plugin class definition tight, it is recommended to define this property as a static getter:\n *\n *\t\texport default class ImageCaption {\n *\t\t\tstatic get pluginName() {\n *\t\t\t\treturn 'ImageCaption';\n *\t\t\t}\n *\t\t}\n *\n * Note: The native `Function.name` property could not be used to keep the plugin name because\n * it will be mangled during code minification.\n *\n * Naming a plugin is necessary to enable removing it through the\n * {@link module:core/editor/editorconfig~EditorConfig#removePlugins `config.removePlugins`} option.\n *\n * @static\n * @readonly\n * @member {String|undefined} module:core/plugin~PluginInterface.pluginName\n */\n\n/**\n * The second stage (after plugin {@link #constructor}) of the plugin initialization.\n * Unlike the plugin constructor this method can be asynchronous.\n *\n * A plugin's `init()` method is called after its {@link module:core/plugin~PluginInterface.requires dependencies} are initialized,\n * so in the same order as the constructors of these plugins.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #init\n * @returns {null|Promise}\n */\n\n/**\n * The third (and last) stage of the plugin initialization. See also {@link #constructor} and {@link #init}.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #afterInit\n * @returns {null|Promise}\n */\n\n/**\n * Destroys the plugin.\n *\n * **Note:** This method is optional. A plugin instance does not need to have it defined.\n *\n * @method #destroy\n * @returns {null|Promise}\n */\n\n/**\n * A flag which defines if a plugin is allowed or not allowed to be used directly by a {@link module:core/context~Context}.\n *\n * @static\n * @readonly\n * @member {Boolean} module:core/plugin~PluginInterface.isContextPlugin\n */\n\n/**\n * An array of loaded plugins.\n *\n * @typedef {Array.<module:core/plugin~PluginInterface>} module:core/plugin~LoadedPlugins\n */\n\n// Helper function that forces plugin to be disabled.\nfunction forceDisable( evt ) {\n\tevt.return = false;\n\tevt.stop();\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 core/command\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for CKEditor commands.\n *\n * Commands are the main way to manipulate editor contents and state. They are mostly used by UI elements (or by other\n * commands) to make changes in the model. Commands are available in every part of code that has access to\n * the {@link module:core/editor/editor~Editor editor} instance.\n *\n * Instances of registered commands can be retrieved from {@link module:core/editor/editor~Editor#commands `editor.commands`}.\n * The easiest way to execute a command is through {@link module:core/editor/editor~Editor#execute `editor.execute()`}.\n *\n * By default commands are disabled when the editor is in {@link module:core/editor/editor~Editor#isReadOnly read-only} mode.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Command {\n\t/**\n\t * Creates a new `Command` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor on which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor on which this command will be used.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * The value of the command. A concrete command class should define what it represents for it.\n\t\t *\n\t\t * For example, the `'bold'` command's value indicates whether the selection starts in a bolded text.\n\t\t * And the value of the `'link'` command may be an object with links details.\n\t\t *\n\t\t * It is possible for a command to have no value (e.g. for stateless actions such as `'uploadImage'`).\n\t\t *\n\t\t * A concrete command class should control this value by overriding the {@link #refresh `refresh()`} method.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member #value\n\t\t */\n\t\tthis.set( 'value', undefined );\n\n\t\t/**\n\t\t * Flag indicating whether a command is enabled or disabled.\n\t\t * A disabled command will do nothing when executed.\n\t\t *\n\t\t * A concrete command class should control this value by overriding the {@link #refresh `refresh()`} method.\n\t\t *\n\t\t * It is possible to disable a command from \"outside\". For instance, in your integration you may want to disable\n\t\t * a certain set of commands for the time being. To do that, you can use the fact that `isEnabled` is observable\n\t\t * and it fires the `set:isEnabled` event every time anyone tries to modify its value:\n\t\t *\n\t\t *\t\tfunction disableCommand( cmd ) {\n\t\t *\t\t\tcmd.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t *\n\t\t *\t\t\tcmd.isEnabled = false;\n\t\t *\n\t\t *\t\t\t// Make it possible to enable the command again.\n\t\t *\t\t\treturn () => {\n\t\t *\t\t\t\tcmd.off( 'set:isEnabled', forceDisable );\n\t\t *\t\t\t\tcmd.refresh();\n\t\t *\t\t\t};\n\t\t *\n\t\t *\t\t\tfunction forceDisable( evt ) {\n\t\t *\t\t\t\tevt.return = false;\n\t\t *\t\t\t\tevt.stop();\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t *\t\t// Usage:\n\t\t *\n\t\t *\t\t// Disabling the command.\n\t\t *\t\tconst enableBold = disableCommand( editor.commands.get( 'bold' ) );\n\t\t *\n\t\t *\t\t// Enabling the command again.\n\t\t *\t\tenableBold();\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', false );\n\n\t\t/**\n\t\t * Holds identifiers for {@link #forceDisabled} mechanism.\n\t\t *\n\t\t * @type {Set.<String>}\n\t\t * @private\n\t\t */\n\t\tthis._disableStack = new Set();\n\n\t\tthis.decorate( 'execute' );\n\n\t\t// By default every command is refreshed when changes are applied to the model.\n\t\tthis.listenTo( this.editor.model.document, 'change', () => {\n\t\t\tthis.refresh();\n\t\t} );\n\n\t\tthis.on( 'execute', evt => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// By default commands are disabled when the editor is in read-only mode.\n\t\tthis.listenTo( editor, 'change:isReadOnly', ( evt, name, value ) => {\n\t\t\tif ( value ) {\n\t\t\t\tthis.forceDisabled( 'readOnlyMode' );\n\t\t\t} else {\n\t\t\t\tthis.clearForceDisabled( 'readOnlyMode' );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Refreshes the command. The command should update its {@link #isEnabled} and {@link #value} properties\n\t * in this method.\n\t *\n\t * This method is automatically called when\n\t * {@link module:engine/model/document~Document#event:change any changes are applied to the document}.\n\t */\n\trefresh() {\n\t\tthis.isEnabled = true;\n\t}\n\n\t/**\n\t * Disables the command.\n\t *\n\t * Command may be disabled by multiple features or algorithms (at once). When disabling a command, unique id should be passed\n\t * (e.g. feature name). The same identifier should be used when {@link #clearForceDisabled enabling back} the command.\n\t * The command becomes enabled only after all features {@link #clearForceDisabled enabled it back}.\n\t *\n\t * Disabling and enabling a command:\n\t *\n\t *\t\tcommand.isEnabled; // -> true\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> false\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * Command disabled by multiple features:\n\t *\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.forceDisabled( 'OtherFeature' );\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> false\n\t *\t\tcommand.clearForceDisabled( 'OtherFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * Multiple disabling with the same identifier is redundant:\n\t *\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.forceDisabled( 'MyFeature' );\n\t *\t\tcommand.clearForceDisabled( 'MyFeature' );\n\t *\t\tcommand.isEnabled; // -> true\n\t *\n\t * **Note:** some commands or algorithms may have more complex logic when it comes to enabling or disabling certain commands,\n\t * so the command might be still disabled after {@link #clearForceDisabled} was used.\n\t *\n\t * @param {String} id Unique identifier for disabling. Use the same id when {@link #clearForceDisabled enabling back} the command.\n\t */\n\tforceDisabled( id ) {\n\t\tthis._disableStack.add( id );\n\n\t\tif ( this._disableStack.size == 1 ) {\n\t\t\tthis.on( 'set:isEnabled', forceDisable, { priority: 'highest' } );\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * Clears forced disable previously set through {@link #forceDisabled}. See {@link #forceDisabled}.\n\t *\n\t * @param {String} id Unique identifier, equal to the one passed in {@link #forceDisabled} call.\n\t */\n\tclearForceDisabled( id ) {\n\t\tthis._disableStack.delete( id );\n\n\t\tif ( this._disableStack.size == 0 ) {\n\t\t\tthis.off( 'set:isEnabled', forceDisable );\n\t\t\tthis.refresh();\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * A command may accept parameters. They will be passed from {@link module:core/editor/editor~Editor#execute `editor.execute()`}\n\t * to the command.\n\t *\n\t * The `execute()` method will automatically abort when the command is disabled ({@link #isEnabled} is `false`).\n\t * This behavior is implemented by a high priority listener to the {@link #event:execute} event.\n\t *\n\t * In order to see how to disable a command from \"outside\" see the {@link #isEnabled} documentation.\n\t *\n\t * This method may return a value, which would be forwarded all the way down to the\n\t * {@link module:core/editor/editor~Editor#execute `editor.execute()`}.\n\t *\n\t * @fires execute\n\t */\n\texecute() {}\n\n\t/**\n\t * Destroys the command.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Event fired by the {@link #execute} method. The command action is a listener to this event so it's\n\t * possible to change/cancel the behavior of the command by listening to this event.\n\t *\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * **Note:** This event is fired even if command is disabled. However, it is automatically blocked\n\t * by a high priority listener in order to prevent command execution.\n\t *\n\t * @event execute\n\t */\n}\n\nmix( Command, ObservableMixin );\n\n// Helper function that forces command to be disabled.\nfunction forceDisable( evt ) {\n\tevt.return = false;\n\tevt.stop();\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\nimport Command from './command';\n\n/**\n * @module core/multicommand\n */\n\n/**\n * A CKEditor command that aggregates other commands.\n *\n * This command is used to proxy multiple commands. The multi-command is enabled when\n * at least one of its registered child commands is enabled.\n * When executing a multi-command the first command that is enabled will be executed.\n *\n *\t\tconst multiCommand = new MultiCommand( editor );\n *\n *\t\tconst commandFoo = new Command( editor );\n *\t\tconst commandBar = new Command( editor );\n *\n *\t\t// Register child commands.\n *\t\tmultiCommand.registerChildCommand( commandFoo );\n *\t\tmultiCommand.registerChildCommand( commandBar );\n *\n *\t\t// Enable one of the commands.\n *\t\tcommandBar.isEnabled = true;\n *\n *\t\tmultiCommand.execute(); // Will execute commandBar.\n *\n * @extends module:core/command~Command\n */\nexport default class MultiCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Registered child commands.\n\t\t *\n\t\t * @type {Array.<module:core/command~Command>}\n\t\t * @private\n\t\t */\n\t\tthis._childCommands = [];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\t// Override base command refresh(): the command's state is changed when one of child commands changes states.\n\t}\n\n\t/**\n\t * Executes the first of it registered child commands.\n\t *\n\t * @returns {*} The value returned by the {@link module:core/command~Command#execute `command.execute()`}.\n\t */\n\texecute( ...args ) {\n\t\tconst command = this._getFirstEnabledCommand();\n\n\t\treturn command != null && command.execute( args );\n\t}\n\n\t/**\n\t * Registers a child command.\n\t *\n\t * @param {module:core/command~Command} command\n\t */\n\tregisterChildCommand( command ) {\n\t\tthis._childCommands.push( command );\n\n\t\t// Change multi command enabled state when one of registered commands changes state.\n\t\tcommand.on( 'change:isEnabled', () => this._checkEnabled() );\n\n\t\tthis._checkEnabled();\n\t}\n\n\t/**\n\t * Checks if any of child commands is enabled.\n\t *\n\t * @private\n\t */\n\t_checkEnabled() {\n\t\tthis.isEnabled = !!this._getFirstEnabledCommand();\n\t}\n\n\t/**\n\t * Returns a first enabled command or undefined if none of them is enabled.\n\t *\n\t * @returns {module:core/command~Command|undefined}\n\t * @private\n\t */\n\t_getFirstEnabledCommand() {\n\t\treturn this._childCommands.find( command => command.isEnabled );\n\t}\n}\n","/**\n * Creates a unary function that invokes `func` with its argument transformed.\n *\n * @private\n * @param {Function} func The function to wrap.\n * @param {Function} transform The argument transform.\n * @returns {Function} Returns the new function.\n */\nfunction overArg(func, transform) {\n return function(arg) {\n return func(transform(arg));\n };\n}\n\nexport default overArg;\n","import overArg from './_overArg.js';\n\n/** Built-in value references. */\nvar getPrototype = overArg(Object.getPrototypeOf, Object);\n\nexport default getPrototype;\n","import baseGetTag from './_baseGetTag.js';\nimport getPrototype from './_getPrototype.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar funcProto = Function.prototype,\n objectProto = Object.prototype;\n\n/** Used to resolve the decompiled source of functions. */\nvar funcToString = funcProto.toString;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/** Used to infer the `Object` constructor. */\nvar objectCtorString = funcToString.call(Object);\n\n/**\n * Checks if `value` is a plain object, that is, an object created by the\n * `Object` constructor or one with a `[[Prototype]]` of `null`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\nfunction isPlainObject(value) {\n if (!isObjectLike(value) || baseGetTag(value) != objectTag) {\n return false;\n }\n var proto = getPrototype(value);\n if (proto === null) {\n return true;\n }\n var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n return typeof Ctor == 'function' && Ctor instanceof Ctor &&\n funcToString.call(Ctor) == objectCtorString;\n}\n\nexport default isPlainObject;\n","/**\n * Removes all key-value entries from the list cache.\n *\n * @private\n * @name clear\n * @memberOf ListCache\n */\nfunction listCacheClear() {\n this.__data__ = [];\n this.size = 0;\n}\n\nexport default listCacheClear;\n","import eq from './eq.js';\n\n/**\n * Gets the index at which the `key` is found in `array` of key-value pairs.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {*} key The key to search for.\n * @returns {number} Returns the index of the matched value, else `-1`.\n */\nfunction assocIndexOf(array, key) {\n var length = array.length;\n while (length--) {\n if (eq(array[length][0], key)) {\n return length;\n }\n }\n return -1;\n}\n\nexport default assocIndexOf;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/** Used for built-in method references. */\nvar arrayProto = Array.prototype;\n\n/** Built-in value references. */\nvar splice = arrayProto.splice;\n\n/**\n * Removes `key` and its value from the list cache.\n *\n * @private\n * @name delete\n * @memberOf ListCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction listCacheDelete(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n return false;\n }\n var lastIndex = data.length - 1;\n if (index == lastIndex) {\n data.pop();\n } else {\n splice.call(data, index, 1);\n }\n --this.size;\n return true;\n}\n\nexport default listCacheDelete;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Gets the list cache value for `key`.\n *\n * @private\n * @name get\n * @memberOf ListCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction listCacheGet(key) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n return index < 0 ? undefined : data[index][1];\n}\n\nexport default listCacheGet;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Checks if a list cache value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf ListCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction listCacheHas(key) {\n return assocIndexOf(this.__data__, key) > -1;\n}\n\nexport default listCacheHas;\n","import assocIndexOf from './_assocIndexOf.js';\n\n/**\n * Sets the list cache `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf ListCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the list cache instance.\n */\nfunction listCacheSet(key, value) {\n var data = this.__data__,\n index = assocIndexOf(data, key);\n\n if (index < 0) {\n ++this.size;\n data.push([key, value]);\n } else {\n data[index][1] = value;\n }\n return this;\n}\n\nexport default listCacheSet;\n","import listCacheClear from './_listCacheClear.js';\nimport listCacheDelete from './_listCacheDelete.js';\nimport listCacheGet from './_listCacheGet.js';\nimport listCacheHas from './_listCacheHas.js';\nimport listCacheSet from './_listCacheSet.js';\n\n/**\n * Creates an list cache object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction ListCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `ListCache`.\nListCache.prototype.clear = listCacheClear;\nListCache.prototype['delete'] = listCacheDelete;\nListCache.prototype.get = listCacheGet;\nListCache.prototype.has = listCacheHas;\nListCache.prototype.set = listCacheSet;\n\nexport default ListCache;\n","import ListCache from './_ListCache.js';\n\n/**\n * Removes all key-value entries from the stack.\n *\n * @private\n * @name clear\n * @memberOf Stack\n */\nfunction stackClear() {\n this.__data__ = new ListCache;\n this.size = 0;\n}\n\nexport default stackClear;\n","/**\n * Removes `key` and its value from the stack.\n *\n * @private\n * @name delete\n * @memberOf Stack\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction stackDelete(key) {\n var data = this.__data__,\n result = data['delete'](key);\n\n this.size = data.size;\n return result;\n}\n\nexport default stackDelete;\n","/**\n * Gets the stack value for `key`.\n *\n * @private\n * @name get\n * @memberOf Stack\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction stackGet(key) {\n return this.__data__.get(key);\n}\n\nexport default stackGet;\n","/**\n * Checks if a stack value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Stack\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction stackHas(key) {\n return this.__data__.has(key);\n}\n\nexport default stackHas;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Map = getNative(root, 'Map');\n\nexport default Map;\n","import getNative from './_getNative.js';\n\n/* Built-in method references that are verified to be native. */\nvar nativeCreate = getNative(Object, 'create');\n\nexport default nativeCreate;\n","import nativeCreate from './_nativeCreate.js';\n\n/**\n * Removes all key-value entries from the hash.\n *\n * @private\n * @name clear\n * @memberOf Hash\n */\nfunction hashClear() {\n this.__data__ = nativeCreate ? nativeCreate(null) : {};\n this.size = 0;\n}\n\nexport default hashClear;\n","/**\n * Removes `key` and its value from the hash.\n *\n * @private\n * @name delete\n * @memberOf Hash\n * @param {Object} hash The hash to modify.\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction hashDelete(key) {\n var result = this.has(key) && delete this.__data__[key];\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default hashDelete;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Gets the hash value for `key`.\n *\n * @private\n * @name get\n * @memberOf Hash\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction hashGet(key) {\n var data = this.__data__;\n if (nativeCreate) {\n var result = data[key];\n return result === HASH_UNDEFINED ? undefined : result;\n }\n return hasOwnProperty.call(data, key) ? data[key] : undefined;\n}\n\nexport default hashGet;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Checks if a hash value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf Hash\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction hashHas(key) {\n var data = this.__data__;\n return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);\n}\n\nexport default hashHas;\n","import nativeCreate from './_nativeCreate.js';\n\n/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Sets the hash `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Hash\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the hash instance.\n */\nfunction hashSet(key, value) {\n var data = this.__data__;\n this.size += this.has(key) ? 0 : 1;\n data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;\n return this;\n}\n\nexport default hashSet;\n","import hashClear from './_hashClear.js';\nimport hashDelete from './_hashDelete.js';\nimport hashGet from './_hashGet.js';\nimport hashHas from './_hashHas.js';\nimport hashSet from './_hashSet.js';\n\n/**\n * Creates a hash object.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Hash(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `Hash`.\nHash.prototype.clear = hashClear;\nHash.prototype['delete'] = hashDelete;\nHash.prototype.get = hashGet;\nHash.prototype.has = hashHas;\nHash.prototype.set = hashSet;\n\nexport default Hash;\n","import Hash from './_Hash.js';\nimport ListCache from './_ListCache.js';\nimport Map from './_Map.js';\n\n/**\n * Removes all key-value entries from the map.\n *\n * @private\n * @name clear\n * @memberOf MapCache\n */\nfunction mapCacheClear() {\n this.size = 0;\n this.__data__ = {\n 'hash': new Hash,\n 'map': new (Map || ListCache),\n 'string': new Hash\n };\n}\n\nexport default mapCacheClear;\n","/**\n * Checks if `value` is suitable for use as unique object key.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is suitable, else `false`.\n */\nfunction isKeyable(value) {\n var type = typeof value;\n return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')\n ? (value !== '__proto__')\n : (value === null);\n}\n\nexport default isKeyable;\n","import isKeyable from './_isKeyable.js';\n\n/**\n * Gets the data for `map`.\n *\n * @private\n * @param {Object} map The map to query.\n * @param {string} key The reference key.\n * @returns {*} Returns the map data.\n */\nfunction getMapData(map, key) {\n var data = map.__data__;\n return isKeyable(key)\n ? data[typeof key == 'string' ? 'string' : 'hash']\n : data.map;\n}\n\nexport default getMapData;\n","import getMapData from './_getMapData.js';\n\n/**\n * Removes `key` and its value from the map.\n *\n * @private\n * @name delete\n * @memberOf MapCache\n * @param {string} key The key of the value to remove.\n * @returns {boolean} Returns `true` if the entry was removed, else `false`.\n */\nfunction mapCacheDelete(key) {\n var result = getMapData(this, key)['delete'](key);\n this.size -= result ? 1 : 0;\n return result;\n}\n\nexport default mapCacheDelete;\n","import getMapData from './_getMapData.js';\n\n/**\n * Gets the map value for `key`.\n *\n * @private\n * @name get\n * @memberOf MapCache\n * @param {string} key The key of the value to get.\n * @returns {*} Returns the entry value.\n */\nfunction mapCacheGet(key) {\n return getMapData(this, key).get(key);\n}\n\nexport default mapCacheGet;\n","import getMapData from './_getMapData.js';\n\n/**\n * Checks if a map value for `key` exists.\n *\n * @private\n * @name has\n * @memberOf MapCache\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction mapCacheHas(key) {\n return getMapData(this, key).has(key);\n}\n\nexport default mapCacheHas;\n","import getMapData from './_getMapData.js';\n\n/**\n * Sets the map `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf MapCache\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the map cache instance.\n */\nfunction mapCacheSet(key, value) {\n var data = getMapData(this, key),\n size = data.size;\n\n data.set(key, value);\n this.size += data.size == size ? 0 : 1;\n return this;\n}\n\nexport default mapCacheSet;\n","import mapCacheClear from './_mapCacheClear.js';\nimport mapCacheDelete from './_mapCacheDelete.js';\nimport mapCacheGet from './_mapCacheGet.js';\nimport mapCacheHas from './_mapCacheHas.js';\nimport mapCacheSet from './_mapCacheSet.js';\n\n/**\n * Creates a map cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction MapCache(entries) {\n var index = -1,\n length = entries == null ? 0 : entries.length;\n\n this.clear();\n while (++index < length) {\n var entry = entries[index];\n this.set(entry[0], entry[1]);\n }\n}\n\n// Add methods to `MapCache`.\nMapCache.prototype.clear = mapCacheClear;\nMapCache.prototype['delete'] = mapCacheDelete;\nMapCache.prototype.get = mapCacheGet;\nMapCache.prototype.has = mapCacheHas;\nMapCache.prototype.set = mapCacheSet;\n\nexport default MapCache;\n","import ListCache from './_ListCache.js';\nimport Map from './_Map.js';\nimport MapCache from './_MapCache.js';\n\n/** Used as the size to enable large array optimizations. */\nvar LARGE_ARRAY_SIZE = 200;\n\n/**\n * Sets the stack `key` to `value`.\n *\n * @private\n * @name set\n * @memberOf Stack\n * @param {string} key The key of the value to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns the stack cache instance.\n */\nfunction stackSet(key, value) {\n var data = this.__data__;\n if (data instanceof ListCache) {\n var pairs = data.__data__;\n if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {\n pairs.push([key, value]);\n this.size = ++data.size;\n return this;\n }\n data = this.__data__ = new MapCache(pairs);\n }\n data.set(key, value);\n this.size = data.size;\n return this;\n}\n\nexport default stackSet;\n","import ListCache from './_ListCache.js';\nimport stackClear from './_stackClear.js';\nimport stackDelete from './_stackDelete.js';\nimport stackGet from './_stackGet.js';\nimport stackHas from './_stackHas.js';\nimport stackSet from './_stackSet.js';\n\n/**\n * Creates a stack cache object to store key-value pairs.\n *\n * @private\n * @constructor\n * @param {Array} [entries] The key-value pairs to cache.\n */\nfunction Stack(entries) {\n var data = this.__data__ = new ListCache(entries);\n this.size = data.size;\n}\n\n// Add methods to `Stack`.\nStack.prototype.clear = stackClear;\nStack.prototype['delete'] = stackDelete;\nStack.prototype.get = stackGet;\nStack.prototype.has = stackHas;\nStack.prototype.set = stackSet;\n\nexport default Stack;\n","/**\n * A specialized version of `_.forEach` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns `array`.\n */\nfunction arrayEach(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (iteratee(array[index], index, array) === false) {\n break;\n }\n }\n return array;\n}\n\nexport default arrayEach;\n","import overArg from './_overArg.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeKeys = overArg(Object.keys, Object);\n\nexport default nativeKeys;\n","import isPrototype from './_isPrototype.js';\nimport nativeKeys from './_nativeKeys.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n */\nfunction baseKeys(object) {\n if (!isPrototype(object)) {\n return nativeKeys(object);\n }\n var result = [];\n for (var key in Object(object)) {\n if (hasOwnProperty.call(object, key) && key != 'constructor') {\n result.push(key);\n }\n }\n return result;\n}\n\nexport default baseKeys;\n","import arrayLikeKeys from './_arrayLikeKeys.js';\nimport baseKeys from './_baseKeys.js';\nimport isArrayLike from './isArrayLike.js';\n\n/**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\nfunction keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n}\n\nexport default keys;\n","import copyObject from './_copyObject.js';\nimport keys from './keys.js';\n\n/**\n * The base implementation of `_.assign` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssign(object, source) {\n return object && copyObject(source, keys(source), object);\n}\n\nexport default baseAssign;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * The base implementation of `_.assignIn` without support for multiple sources\n * or `customizer` functions.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @returns {Object} Returns `object`.\n */\nfunction baseAssignIn(object, source) {\n return object && copyObject(source, keysIn(source), object);\n}\n\nexport default baseAssignIn;\n","/**\n * Copies the values of `source` to `array`.\n *\n * @private\n * @param {Array} source The array to copy values from.\n * @param {Array} [array=[]] The array to copy values to.\n * @returns {Array} Returns `array`.\n */\nfunction copyArray(source, array) {\n var index = -1,\n length = source.length;\n\n array || (array = Array(length));\n while (++index < length) {\n array[index] = source[index];\n }\n return array;\n}\n\nexport default copyArray;\n","/**\n * A specialized version of `_.filter` for arrays without support for\n * iteratee shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {Array} Returns the new filtered array.\n */\nfunction arrayFilter(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length,\n resIndex = 0,\n result = [];\n\n while (++index < length) {\n var value = array[index];\n if (predicate(value, index, array)) {\n result[resIndex++] = value;\n }\n }\n return result;\n}\n\nexport default arrayFilter;\n","/**\n * This method returns a new empty array.\n *\n * @static\n * @memberOf _\n * @since 4.13.0\n * @category Util\n * @returns {Array} Returns the new empty array.\n * @example\n *\n * var arrays = _.times(2, _.stubArray);\n *\n * console.log(arrays);\n * // => [[], []]\n *\n * console.log(arrays[0] === arrays[1]);\n * // => false\n */\nfunction stubArray() {\n return [];\n}\n\nexport default stubArray;\n","import arrayFilter from './_arrayFilter.js';\nimport stubArray from './stubArray.js';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Built-in value references. */\nvar propertyIsEnumerable = objectProto.propertyIsEnumerable;\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbols = !nativeGetSymbols ? stubArray : function(object) {\n if (object == null) {\n return [];\n }\n object = Object(object);\n return arrayFilter(nativeGetSymbols(object), function(symbol) {\n return propertyIsEnumerable.call(object, symbol);\n });\n};\n\nexport default getSymbols;\n","import copyObject from './_copyObject.js';\nimport getSymbols from './_getSymbols.js';\n\n/**\n * Copies own symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbols(source, object) {\n return copyObject(source, getSymbols(source), object);\n}\n\nexport default copySymbols;\n","/**\n * Appends the elements of `values` to `array`.\n *\n * @private\n * @param {Array} array The array to modify.\n * @param {Array} values The values to append.\n * @returns {Array} Returns `array`.\n */\nfunction arrayPush(array, values) {\n var index = -1,\n length = values.length,\n offset = array.length;\n\n while (++index < length) {\n array[offset + index] = values[index];\n }\n return array;\n}\n\nexport default arrayPush;\n","import arrayPush from './_arrayPush.js';\nimport getPrototype from './_getPrototype.js';\nimport getSymbols from './_getSymbols.js';\nimport stubArray from './stubArray.js';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeGetSymbols = Object.getOwnPropertySymbols;\n\n/**\n * Creates an array of the own and inherited enumerable symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of symbols.\n */\nvar getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {\n var result = [];\n while (object) {\n arrayPush(result, getSymbols(object));\n object = getPrototype(object);\n }\n return result;\n};\n\nexport default getSymbolsIn;\n","import copyObject from './_copyObject.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\n\n/**\n * Copies own and inherited symbols of `source` to `object`.\n *\n * @private\n * @param {Object} source The object to copy symbols from.\n * @param {Object} [object={}] The object to copy symbols to.\n * @returns {Object} Returns `object`.\n */\nfunction copySymbolsIn(source, object) {\n return copyObject(source, getSymbolsIn(source), object);\n}\n\nexport default copySymbolsIn;\n","import arrayPush from './_arrayPush.js';\nimport isArray from './isArray.js';\n\n/**\n * The base implementation of `getAllKeys` and `getAllKeysIn` which uses\n * `keysFunc` and `symbolsFunc` to get the enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @param {Function} symbolsFunc The function to get the symbols of `object`.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction baseGetAllKeys(object, keysFunc, symbolsFunc) {\n var result = keysFunc(object);\n return isArray(object) ? result : arrayPush(result, symbolsFunc(object));\n}\n\nexport default baseGetAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbols from './_getSymbols.js';\nimport keys from './keys.js';\n\n/**\n * Creates an array of own enumerable property names and symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeys(object) {\n return baseGetAllKeys(object, keys, getSymbols);\n}\n\nexport default getAllKeys;\n","import baseGetAllKeys from './_baseGetAllKeys.js';\nimport getSymbolsIn from './_getSymbolsIn.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Creates an array of own and inherited enumerable property names and\n * symbols of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names and symbols.\n */\nfunction getAllKeysIn(object) {\n return baseGetAllKeys(object, keysIn, getSymbolsIn);\n}\n\nexport default getAllKeysIn;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar DataView = getNative(root, 'DataView');\n\nexport default DataView;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Promise = getNative(root, 'Promise');\n\nexport default Promise;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar Set = getNative(root, 'Set');\n\nexport default Set;\n","import getNative from './_getNative.js';\nimport root from './_root.js';\n\n/* Built-in method references that are verified to be native. */\nvar WeakMap = getNative(root, 'WeakMap');\n\nexport default WeakMap;\n","import DataView from './_DataView.js';\nimport Map from './_Map.js';\nimport Promise from './_Promise.js';\nimport Set from './_Set.js';\nimport WeakMap from './_WeakMap.js';\nimport baseGetTag from './_baseGetTag.js';\nimport toSource from './_toSource.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]',\n objectTag = '[object Object]',\n promiseTag = '[object Promise]',\n setTag = '[object Set]',\n weakMapTag = '[object WeakMap]';\n\nvar dataViewTag = '[object DataView]';\n\n/** Used to detect maps, sets, and weakmaps. */\nvar dataViewCtorString = toSource(DataView),\n mapCtorString = toSource(Map),\n promiseCtorString = toSource(Promise),\n setCtorString = toSource(Set),\n weakMapCtorString = toSource(WeakMap);\n\n/**\n * Gets the `toStringTag` of `value`.\n *\n * @private\n * @param {*} value The value to query.\n * @returns {string} Returns the `toStringTag`.\n */\nvar getTag = baseGetTag;\n\n// Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.\nif ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||\n (Map && getTag(new Map) != mapTag) ||\n (Promise && getTag(Promise.resolve()) != promiseTag) ||\n (Set && getTag(new Set) != setTag) ||\n (WeakMap && getTag(new WeakMap) != weakMapTag)) {\n getTag = function(value) {\n var result = baseGetTag(value),\n Ctor = result == objectTag ? value.constructor : undefined,\n ctorString = Ctor ? toSource(Ctor) : '';\n\n if (ctorString) {\n switch (ctorString) {\n case dataViewCtorString: return dataViewTag;\n case mapCtorString: return mapTag;\n case promiseCtorString: return promiseTag;\n case setCtorString: return setTag;\n case weakMapCtorString: return weakMapTag;\n }\n }\n return result;\n };\n}\n\nexport default getTag;\n","/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * Initializes an array clone.\n *\n * @private\n * @param {Array} array The array to clone.\n * @returns {Array} Returns the initialized clone.\n */\nfunction initCloneArray(array) {\n var length = array.length,\n result = new array.constructor(length);\n\n // Add properties assigned by `RegExp#exec`.\n if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {\n result.index = array.index;\n result.input = array.input;\n }\n return result;\n}\n\nexport default initCloneArray;\n","import root from './_root.js';\n\n/** Built-in value references. */\nvar Uint8Array = root.Uint8Array;\n\nexport default Uint8Array;\n","import Uint8Array from './_Uint8Array.js';\n\n/**\n * Creates a clone of `arrayBuffer`.\n *\n * @private\n * @param {ArrayBuffer} arrayBuffer The array buffer to clone.\n * @returns {ArrayBuffer} Returns the cloned array buffer.\n */\nfunction cloneArrayBuffer(arrayBuffer) {\n var result = new arrayBuffer.constructor(arrayBuffer.byteLength);\n new Uint8Array(result).set(new Uint8Array(arrayBuffer));\n return result;\n}\n\nexport default cloneArrayBuffer;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `dataView`.\n *\n * @private\n * @param {Object} dataView The data view to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned data view.\n */\nfunction cloneDataView(dataView, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;\n return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);\n}\n\nexport default cloneDataView;\n","/** Used to match `RegExp` flags from their coerced string values. */\nvar reFlags = /\\w*$/;\n\n/**\n * Creates a clone of `regexp`.\n *\n * @private\n * @param {Object} regexp The regexp to clone.\n * @returns {Object} Returns the cloned regexp.\n */\nfunction cloneRegExp(regexp) {\n var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));\n result.lastIndex = regexp.lastIndex;\n return result;\n}\n\nexport default cloneRegExp;\n","import Symbol from './_Symbol.js';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * Creates a clone of the `symbol` object.\n *\n * @private\n * @param {Object} symbol The symbol object to clone.\n * @returns {Object} Returns the cloned symbol object.\n */\nfunction cloneSymbol(symbol) {\n return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};\n}\n\nexport default cloneSymbol;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\n\n/**\n * Creates a clone of `typedArray`.\n *\n * @private\n * @param {Object} typedArray The typed array to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the cloned typed array.\n */\nfunction cloneTypedArray(typedArray, isDeep) {\n var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;\n return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);\n}\n\nexport default cloneTypedArray;\n","import cloneArrayBuffer from './_cloneArrayBuffer.js';\nimport cloneDataView from './_cloneDataView.js';\nimport cloneRegExp from './_cloneRegExp.js';\nimport cloneSymbol from './_cloneSymbol.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/**\n * Initializes an object clone based on its `toStringTag`.\n *\n * **Note:** This function only supports cloning values with tags of\n * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.\n *\n * @private\n * @param {Object} object The object to clone.\n * @param {string} tag The `toStringTag` of the object to clone.\n * @param {boolean} [isDeep] Specify a deep clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneByTag(object, tag, isDeep) {\n var Ctor = object.constructor;\n switch (tag) {\n case arrayBufferTag:\n return cloneArrayBuffer(object);\n\n case boolTag:\n case dateTag:\n return new Ctor(+object);\n\n case dataViewTag:\n return cloneDataView(object, isDeep);\n\n case float32Tag: case float64Tag:\n case int8Tag: case int16Tag: case int32Tag:\n case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:\n return cloneTypedArray(object, isDeep);\n\n case mapTag:\n return new Ctor;\n\n case numberTag:\n case stringTag:\n return new Ctor(object);\n\n case regexpTag:\n return cloneRegExp(object);\n\n case setTag:\n return new Ctor;\n\n case symbolTag:\n return cloneSymbol(object);\n }\n}\n\nexport default initCloneByTag;\n","import isObject from './isObject.js';\n\n/** Built-in value references. */\nvar objectCreate = Object.create;\n\n/**\n * The base implementation of `_.create` without support for assigning\n * properties to the created object.\n *\n * @private\n * @param {Object} proto The object to inherit from.\n * @returns {Object} Returns the new object.\n */\nvar baseCreate = (function() {\n function object() {}\n return function(proto) {\n if (!isObject(proto)) {\n return {};\n }\n if (objectCreate) {\n return objectCreate(proto);\n }\n object.prototype = proto;\n var result = new object;\n object.prototype = undefined;\n return result;\n };\n}());\n\nexport default baseCreate;\n","import baseCreate from './_baseCreate.js';\nimport getPrototype from './_getPrototype.js';\nimport isPrototype from './_isPrototype.js';\n\n/**\n * Initializes an object clone.\n *\n * @private\n * @param {Object} object The object to clone.\n * @returns {Object} Returns the initialized clone.\n */\nfunction initCloneObject(object) {\n return (typeof object.constructor == 'function' && !isPrototype(object))\n ? baseCreate(getPrototype(object))\n : {};\n}\n\nexport default initCloneObject;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar mapTag = '[object Map]';\n\n/**\n * The base implementation of `_.isMap` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n */\nfunction baseIsMap(value) {\n return isObjectLike(value) && getTag(value) == mapTag;\n}\n\nexport default baseIsMap;\n","import baseIsMap from './_baseIsMap.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsMap = nodeUtil && nodeUtil.isMap;\n\n/**\n * Checks if `value` is classified as a `Map` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n * @example\n *\n * _.isMap(new Map);\n * // => true\n *\n * _.isMap(new WeakMap);\n * // => false\n */\nvar isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;\n\nexport default isMap;\n","import getTag from './_getTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar setTag = '[object Set]';\n\n/**\n * The base implementation of `_.isSet` without Node.js optimizations.\n *\n * @private\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n */\nfunction baseIsSet(value) {\n return isObjectLike(value) && getTag(value) == setTag;\n}\n\nexport default baseIsSet;\n","import baseIsSet from './_baseIsSet.js';\nimport baseUnary from './_baseUnary.js';\nimport nodeUtil from './_nodeUtil.js';\n\n/* Node.js helper references. */\nvar nodeIsSet = nodeUtil && nodeUtil.isSet;\n\n/**\n * Checks if `value` is classified as a `Set` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n * @example\n *\n * _.isSet(new Set);\n * // => true\n *\n * _.isSet(new WeakSet);\n * // => false\n */\nvar isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;\n\nexport default isSet;\n","import Stack from './_Stack.js';\nimport arrayEach from './_arrayEach.js';\nimport assignValue from './_assignValue.js';\nimport baseAssign from './_baseAssign.js';\nimport baseAssignIn from './_baseAssignIn.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport copyArray from './_copyArray.js';\nimport copySymbols from './_copySymbols.js';\nimport copySymbolsIn from './_copySymbolsIn.js';\nimport getAllKeys from './_getAllKeys.js';\nimport getAllKeysIn from './_getAllKeysIn.js';\nimport getTag from './_getTag.js';\nimport initCloneArray from './_initCloneArray.js';\nimport initCloneByTag from './_initCloneByTag.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isMap from './isMap.js';\nimport isObject from './isObject.js';\nimport isSet from './isSet.js';\nimport keys from './keys.js';\nimport keysIn from './keysIn.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_FLAT_FLAG = 2,\n CLONE_SYMBOLS_FLAG = 4;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n funcTag = '[object Function]',\n genTag = '[object GeneratorFunction]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n objectTag = '[object Object]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]',\n weakMapTag = '[object WeakMap]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]',\n float32Tag = '[object Float32Array]',\n float64Tag = '[object Float64Array]',\n int8Tag = '[object Int8Array]',\n int16Tag = '[object Int16Array]',\n int32Tag = '[object Int32Array]',\n uint8Tag = '[object Uint8Array]',\n uint8ClampedTag = '[object Uint8ClampedArray]',\n uint16Tag = '[object Uint16Array]',\n uint32Tag = '[object Uint32Array]';\n\n/** Used to identify `toStringTag` values supported by `_.clone`. */\nvar cloneableTags = {};\ncloneableTags[argsTag] = cloneableTags[arrayTag] =\ncloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =\ncloneableTags[boolTag] = cloneableTags[dateTag] =\ncloneableTags[float32Tag] = cloneableTags[float64Tag] =\ncloneableTags[int8Tag] = cloneableTags[int16Tag] =\ncloneableTags[int32Tag] = cloneableTags[mapTag] =\ncloneableTags[numberTag] = cloneableTags[objectTag] =\ncloneableTags[regexpTag] = cloneableTags[setTag] =\ncloneableTags[stringTag] = cloneableTags[symbolTag] =\ncloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =\ncloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;\ncloneableTags[errorTag] = cloneableTags[funcTag] =\ncloneableTags[weakMapTag] = false;\n\n/**\n * The base implementation of `_.clone` and `_.cloneDeep` which tracks\n * traversed objects.\n *\n * @private\n * @param {*} value The value to clone.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Deep clone\n * 2 - Flatten inherited properties\n * 4 - Clone symbols\n * @param {Function} [customizer] The function to customize cloning.\n * @param {string} [key] The key of `value`.\n * @param {Object} [object] The parent object of `value`.\n * @param {Object} [stack] Tracks traversed objects and their clone counterparts.\n * @returns {*} Returns the cloned value.\n */\nfunction baseClone(value, bitmask, customizer, key, object, stack) {\n var result,\n isDeep = bitmask & CLONE_DEEP_FLAG,\n isFlat = bitmask & CLONE_FLAT_FLAG,\n isFull = bitmask & CLONE_SYMBOLS_FLAG;\n\n if (customizer) {\n result = object ? customizer(value, key, object, stack) : customizer(value);\n }\n if (result !== undefined) {\n return result;\n }\n if (!isObject(value)) {\n return value;\n }\n var isArr = isArray(value);\n if (isArr) {\n result = initCloneArray(value);\n if (!isDeep) {\n return copyArray(value, result);\n }\n } else {\n var tag = getTag(value),\n isFunc = tag == funcTag || tag == genTag;\n\n if (isBuffer(value)) {\n return cloneBuffer(value, isDeep);\n }\n if (tag == objectTag || tag == argsTag || (isFunc && !object)) {\n result = (isFlat || isFunc) ? {} : initCloneObject(value);\n if (!isDeep) {\n return isFlat\n ? copySymbolsIn(value, baseAssignIn(result, value))\n : copySymbols(value, baseAssign(result, value));\n }\n } else {\n if (!cloneableTags[tag]) {\n return object ? value : {};\n }\n result = initCloneByTag(value, tag, isDeep);\n }\n }\n // Check for circular references and return its corresponding clone.\n stack || (stack = new Stack);\n var stacked = stack.get(value);\n if (stacked) {\n return stacked;\n }\n stack.set(value, result);\n\n if (isSet(value)) {\n value.forEach(function(subValue) {\n result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));\n });\n } else if (isMap(value)) {\n value.forEach(function(subValue, key) {\n result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n }\n\n var keysFunc = isFull\n ? (isFlat ? getAllKeysIn : getAllKeys)\n : (isFlat ? keysIn : keys);\n\n var props = isArr ? undefined : keysFunc(value);\n arrayEach(props || value, function(subValue, key) {\n if (props) {\n key = subValue;\n subValue = value[key];\n }\n // Recursively populate clone (susceptible to call stack limits).\n assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));\n });\n return result;\n}\n\nexport default baseClone;\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.cloneWith` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @param {Function} [customizer] The function to customize cloning.\n * @returns {*} Returns the deep cloned value.\n * @see _.cloneWith\n * @example\n *\n * function customizer(value) {\n * if (_.isElement(value)) {\n * return value.cloneNode(true);\n * }\n * }\n *\n * var el = _.cloneDeepWith(document.body, customizer);\n *\n * console.log(el === document.body);\n * // => false\n * console.log(el.nodeName);\n * // => 'BODY'\n * console.log(el.childNodes.length);\n * // => 20\n */\nfunction cloneDeepWith(value, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);\n}\n\nexport default cloneDeepWith;\n","import isObjectLike from './isObjectLike.js';\nimport isPlainObject from './isPlainObject.js';\n\n/**\n * Checks if `value` is likely a DOM element.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.\n * @example\n *\n * _.isElement(document.body);\n * // => true\n *\n * _.isElement('<body>');\n * // => false\n */\nfunction isElement(value) {\n return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);\n}\n\nexport default isElement;\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 utils/config\n */\n\nimport { isPlainObject, isElement, cloneDeepWith } from 'lodash-es';\n\n/**\n * Handles a configuration dictionary.\n */\nexport default class Config {\n\t/**\n\t * Creates an instance of the {@link ~Config} class.\n\t *\n\t * @param {Object} [configurations] The initial configurations to be set. Usually, provided by the user.\n\t * @param {Object} [defaultConfigurations] The default configurations. Usually, provided by the system.\n\t */\n\tconstructor( configurations, defaultConfigurations ) {\n\t\t/**\n\t\t * Store for the whole configuration.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._config = {};\n\n\t\t// Set default configuration.\n\t\tif ( defaultConfigurations ) {\n\t\t\t// Clone the configuration to make sure that the properties will not be shared\n\t\t\t// between editors and make the watchdog feature work correctly.\n\t\t\tthis.define( cloneConfig( defaultConfigurations ) );\n\t\t}\n\n\t\t// Set initial configuration.\n\t\tif ( configurations ) {\n\t\t\tthis._setObjectToTarget( this._config, configurations );\n\t\t}\n\t}\n\n\t/**\n\t * Set configuration values.\n\t *\n\t * It accepts both a name/value pair or an object, which properties and values will be used to set\n\t * configurations.\n\t *\n\t * It also accepts setting a \"deep configuration\" by using dots in the name. For example, `'resize.width'` sets\n\t * the value for the `width` configuration in the `resize` subset.\n\t *\n\t *\t\tconfig.set( 'width', 500 );\n\t *\t\tconfig.set( 'toolbar.collapsed', true );\n\t *\n\t *\t\t// Equivalent to:\n\t *\t\tconfig.set( {\n\t *\t\t\twidth: 500\n\t *\t\t\ttoolbar: {\n\t *\t\t\t\tcollapsed: true\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Passing an object as the value will amend the configuration, not replace it.\n\t *\n\t *\t\tconfig.set( 'toolbar', {\n\t *\t\t\tcollapsed: true,\n\t *\t\t} );\n\t *\n\t *\t\tconfig.set( 'toolbar', {\n\t *\t\t\tcolor: 'red',\n\t *\t\t} );\n\t *\n\t *\t\tconfig.get( 'toolbar.collapsed' ); // true\n\t *\t\tconfig.get( 'toolbar.color' ); // 'red'\n\t *\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t */\n\tset( name, value ) {\n\t\tthis._setToTarget( this._config, name, value );\n\t}\n\n\t/**\n\t * Does exactly the same as {@link #set} with one exception passed configuration extends\n\t * existing one, but does not overwrite already defined values.\n\t *\n\t * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be\n\t * rarely used for other needs.\n\t *\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t */\n\tdefine( name, value ) {\n\t\tconst isDefine = true;\n\n\t\tthis._setToTarget( this._config, name, value, isDefine );\n\t}\n\n\t/**\n\t * Gets the value for a configuration entry.\n\t *\n\t *\t\tconfig.get( 'name' );\n\t *\n\t * Deep configurations can be retrieved by separating each part with a dot.\n\t *\n\t *\t\tconfig.get( 'toolbar.collapsed' );\n\t *\n\t * @param {String} name The configuration name. Configuration names are case-sensitive.\n\t * @returns {*} The configuration value or `undefined` if the configuration entry was not found.\n\t */\n\tget( name ) {\n\t\treturn this._getFromSource( this._config, name );\n\t}\n\n\t/**\n\t * Iterates over all top level configuration names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tfor ( const name of Object.keys( this._config ) ) {\n\t\t\tyield name;\n\t\t}\n\t}\n\n\t/**\n\t * Saves passed configuration to the specified target (nested object).\n\t *\n\t * @private\n\t * @param {Object} target Nested config object.\n\t * @param {String|Object} name The configuration name or an object from which take properties as\n\t * configuration entries. Configuration names are case-sensitive.\n\t * @param {*} value The configuration value. Used if a name is passed.\n\t * @param {Boolean} [isDefine=false] Define if passed configuration should overwrite existing one.\n\t */\n\t_setToTarget( target, name, value, isDefine = false ) {\n\t\t// In case of an object, iterate through it and call `_setToTarget` again for each property.\n\t\tif ( isPlainObject( name ) ) {\n\t\t\tthis._setObjectToTarget( target, name, isDefine );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].\n\t\tconst parts = name.split( '.' );\n\n\t\t// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.\n\t\tname = parts.pop();\n\n\t\t// Iterate over parts to check if currently stored configuration has proper structure.\n\t\tfor ( const part of parts ) {\n\t\t\t// If there is no object for specified part then create one.\n\t\t\tif ( !isPlainObject( target[ part ] ) ) {\n\t\t\t\ttarget[ part ] = {};\n\t\t\t}\n\n\t\t\t// Nested object becomes a target.\n\t\t\ttarget = target[ part ];\n\t\t}\n\n\t\t// In case of value is an object.\n\t\tif ( isPlainObject( value ) ) {\n\t\t\t// We take care of proper config structure.\n\t\t\tif ( !isPlainObject( target[ name ] ) ) {\n\t\t\t\ttarget[ name ] = {};\n\t\t\t}\n\n\t\t\ttarget = target[ name ];\n\n\t\t\t// And iterate through this object calling `_setToTarget` again for each property.\n\t\t\tthis._setObjectToTarget( target, value, isDefine );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Do nothing if we are defining configuration for non empty name.\n\t\tif ( isDefine && typeof target[ name ] != 'undefined' ) {\n\t\t\treturn;\n\t\t}\n\n\t\ttarget[ name ] = value;\n\t}\n\n\t/**\n\t * Get specified configuration from specified source (nested object).\n\t *\n\t * @private\n\t * @param {Object} source level of nested object.\n\t * @param {String} name The configuration name. Configuration names are case-sensitive.\n\t * @returns {*} The configuration value or `undefined` if the configuration entry was not found.\n\t */\n\t_getFromSource( source, name ) {\n\t\t// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`].\n\t\tconst parts = name.split( '.' );\n\n\t\t// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`.\n\t\tname = parts.pop();\n\n\t\t// Iterate over parts to check if currently stored configuration has proper structure.\n\t\tfor ( const part of parts ) {\n\t\t\tif ( !isPlainObject( source[ part ] ) ) {\n\t\t\t\tsource = null;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Nested object becomes a source.\n\t\t\tsource = source[ part ];\n\t\t}\n\n\t\t// Always returns undefined for non existing configuration.\n\t\treturn source ? cloneConfig( source[ name ] ) : undefined;\n\t}\n\n\t/**\n\t * Iterates through passed object and calls {@link #_setToTarget} method with object key and value for each property.\n\t *\n\t * @private\n\t * @param {Object} target Nested config object.\n\t * @param {Object} configuration Configuration data set\n\t * @param {Boolean} [isDefine] Defines if passed configuration is default configuration or not.\n\t */\n\t_setObjectToTarget( target, configuration, isDefine ) {\n\t\tObject.keys( configuration ).forEach( key => {\n\t\t\tthis._setToTarget( target, key, configuration[ key ], isDefine );\n\t\t} );\n\t}\n}\n\n// Clones configuration object or value.\n// @param {*} source Source configuration\n// @returns {*} Cloned configuration value.\nfunction cloneConfig( source ) {\n\treturn cloneDeepWith( source, leaveDOMReferences );\n}\n\n// A customized function for cloneDeepWith.\n// It will leave references to DOM Elements instead of cloning them.\n//\n// @param {*} value\n// @returns {Element|undefined}\nfunction leaveDOMReferences( value ) {\n\treturn isElement( value ) ? value : undefined;\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 utils/isiterable\n */\n\n/**\n * Checks if value implements iterator interface.\n *\n * @param {*} value The value to check.\n * @returns {Boolean} True if value implements iterator interface.\n */\nexport default function isIterable( value ) {\n\treturn !!( value && value[ Symbol.iterator ] );\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 utils/collection\n */\n\nimport EmitterMixin from './emittermixin';\nimport CKEditorError from './ckeditorerror';\nimport uid from './uid';\nimport isIterable from './isiterable';\nimport mix from './mix';\n\n/**\n * Collections are ordered sets of objects. Items in the collection can be retrieved by their indexes\n * in the collection (like in an array) or by their ids.\n *\n * If an object without an `id` property is being added to the collection, the `id` property will be generated\n * automatically. Note that the automatically generated id is unique only within this single collection instance.\n *\n * By default an item in the collection is identified by its `id` property. The name of the identifier can be\n * configured through the constructor of the collection.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Collection {\n\t/**\n\t * Creates a new Collection instance.\n\t *\n\t * You can provide an iterable of initial items the collection will be created with:\n\t *\n\t *\t\tconst collection = new Collection( [ { id: 'John' }, { id: 'Mike' } ] );\n\t *\n\t *\t\tconsole.log( collection.get( 0 ) ); // -> { id: 'John' }\n\t *\t\tconsole.log( collection.get( 1 ) ); // -> { id: 'Mike' }\n\t *\t\tconsole.log( collection.get( 'Mike' ) ); // -> { id: 'Mike' }\n\t *\n\t * Or you can first create a collection and then add new items using the {@link #add} method:\n\t *\n\t *\t\tconst collection = new Collection();\n\t *\n\t *\t\tcollection.add( { id: 'John' } );\n\t *\t\tconsole.log( collection.get( 0 ) ); // -> { id: 'John' }\n\t *\n\t * Whatever option you choose, you can always pass a configuration object as the last argument\n\t * of the constructor:\n\t *\n\t *\t\tconst emptyCollection = new Collection( { idProperty: 'name' } );\n\t *\t\temptyCollection.add( { name: 'John' } );\n\t *\t\tconsole.log( collection.get( 'John' ) ); // -> { name: 'John' }\n\t *\n\t *\t\tconst nonEmptyCollection = new Collection( [ { name: 'John' } ], { idProperty: 'name' } );\n\t *\t\tnonEmptyCollection.add( { name: 'George' } );\n\t *\t\tconsole.log( collection.get( 'George' ) ); // -> { name: 'George' }\n\t *\t\tconsole.log( collection.get( 'John' ) ); // -> { name: 'John' }\n\t *\n\t * @param {Iterable.<Object>|Object} initialItemsOrOptions The initial items of the collection or\n\t * the options object.\n\t * @param {Object} [options={}] The options object, when the first argument is an array of initial items.\n\t * @param {String} [options.idProperty='id'] The name of the property which is used to identify an item.\n\t * Items that do not have such a property will be assigned one when added to the collection.\n\t */\n\tconstructor( initialItemsOrOptions = {}, options = {} ) {\n\t\tconst hasInitialItems = isIterable( initialItemsOrOptions );\n\n\t\tif ( !hasInitialItems ) {\n\t\t\toptions = initialItemsOrOptions;\n\t\t}\n\n\t\t/**\n\t\t * The internal list of items in the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Object[]}\n\t\t */\n\t\tthis._items = [];\n\n\t\t/**\n\t\t * The internal map of items in the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._itemMap = new Map();\n\n\t\t/**\n\t\t * The name of the property which is considered to identify an item.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._idProperty = options.idProperty || 'id';\n\n\t\t/**\n\t\t * A helper mapping external items of a bound collection ({@link #bindTo})\n\t\t * and actual items of this collection. It provides information\n\t\t * necessary to properly remove items bound to another collection.\n\t\t *\n\t\t * See {@link #_bindToInternalToExternalMap}.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._bindToExternalToInternalMap = new WeakMap();\n\n\t\t/**\n\t\t * A helper mapping items of this collection to external items of a bound collection\n\t\t * ({@link #bindTo}). It provides information necessary to manage the bindings, e.g.\n\t\t * to avoid loops in twoway bindings.\n\t\t *\n\t\t * See {@link #_bindToExternalToInternalMap}.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._bindToInternalToExternalMap = new WeakMap();\n\n\t\t/**\n\t\t * Stores indexes of skipped items from bound external collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Array}\n\t\t */\n\t\tthis._skippedIndexesFromExternal = [];\n\n\t\t// Set the initial content of the collection (if provided in the constructor).\n\t\tif ( hasInitialItems ) {\n\t\t\tfor ( const item of initialItemsOrOptions ) {\n\t\t\t\tthis._items.push( item );\n\t\t\t\tthis._itemMap.set( this._getItemIdBeforeAdding( item ), item );\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * A collection instance this collection is bound to as a result\n\t\t * of calling {@link #bindTo} method.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/collection~Collection} #_bindToCollection\n\t\t */\n\t}\n\n\t/**\n\t * The number of items available in the collection.\n\t *\n\t * @member {Number} #length\n\t */\n\tget length() {\n\t\treturn this._items.length;\n\t}\n\n\t/**\n\t * Returns the first item from the collection or null when collection is empty.\n\t *\n\t * @returns {Object|null} The first item or `null` if collection is empty.\n\t */\n\tget first() {\n\t\treturn this._items[ 0 ] || null;\n\t}\n\n\t/**\n\t * Returns the last item from the collection or null when collection is empty.\n\t *\n\t * @returns {Object|null} The last item or `null` if collection is empty.\n\t */\n\tget last() {\n\t\treturn this._items[ this.length - 1 ] || null;\n\t}\n\n\t/**\n\t * Adds an item into the collection.\n\t *\n\t * If the item does not have an id, then it will be automatically generated and set on the item.\n\t *\n\t * @chainable\n\t * @param {Object} item\n\t * @param {Number} [index] The position of the item in the collection. The item\n\t * is pushed to the collection when `index` not specified.\n\t * @fires add\n\t * @fires change\n\t */\n\tadd( item, index ) {\n\t\treturn this.addMany( [ item ], index );\n\t}\n\n\t/**\n\t * Adds multiple items into the collection.\n\t *\n\t * Any item not containing an id will get an automatically generated one.\n\t *\n\t * @chainable\n\t * @param {Iterable.<Object>} item\n\t * @param {Number} [index] The position of the insertion. Items will be appended if no `index` is specified.\n\t * @fires add\n\t * @fires change\n\t */\n\taddMany( items, index ) {\n\t\tif ( index === undefined ) {\n\t\t\tindex = this._items.length;\n\t\t} else if ( index > this._items.length || index < 0 ) {\n\t\t\t/**\n\t\t\t * The `index` passed to {@link module:utils/collection~Collection#addMany `Collection#addMany()`}\n\t\t\t * is invalid. It must be a number between 0 and the collection's length.\n\t\t\t *\n\t\t\t * @error collection-add-item-invalid-index\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-add-item-invalid-index', this );\n\t\t}\n\n\t\tfor ( let offset = 0; offset < items.length; offset++ ) {\n\t\t\tconst item = items[ offset ];\n\t\t\tconst itemId = this._getItemIdBeforeAdding( item );\n\t\t\tconst currentItemIndex = index + offset;\n\n\t\t\tthis._items.splice( currentItemIndex, 0, item );\n\t\t\tthis._itemMap.set( itemId, item );\n\n\t\t\tthis.fire( 'add', item, currentItemIndex );\n\t\t}\n\n\t\tthis.fire( 'change', {\n\t\t\tadded: items,\n\t\t\tremoved: [],\n\t\t\tindex\n\t\t} );\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets an item by its ID or index.\n\t *\n\t * @param {String|Number} idOrIndex The item ID or index in the collection.\n\t * @returns {Object|null} The requested item or `null` if such item does not exist.\n\t */\n\tget( idOrIndex ) {\n\t\tlet item;\n\n\t\tif ( typeof idOrIndex == 'string' ) {\n\t\t\titem = this._itemMap.get( idOrIndex );\n\t\t} else if ( typeof idOrIndex == 'number' ) {\n\t\t\titem = this._items[ idOrIndex ];\n\t\t} else {\n\t\t\t/**\n\t\t\t * An index or ID must be given.\n\t\t\t *\n\t\t\t * @error collection-get-invalid-arg\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-get-invalid-arg', this );\n\t\t}\n\n\t\treturn item || null;\n\t}\n\n\t/**\n\t * Returns a Boolean indicating whether the collection contains an item.\n\t *\n\t * @param {Object|String} itemOrId The item or its ID in the collection.\n\t * @returns {Boolean} `true` if the collection contains the item, `false` otherwise.\n\t */\n\thas( itemOrId ) {\n\t\tif ( typeof itemOrId == 'string' ) {\n\t\t\treturn this._itemMap.has( itemOrId );\n\t\t} else { // Object\n\t\t\tconst idProperty = this._idProperty;\n\t\t\tconst id = itemOrId[ idProperty ];\n\n\t\t\treturn this._itemMap.has( id );\n\t\t}\n\t}\n\n\t/**\n\t * Gets an index of an item in the collection.\n\t * When an item is not defined in the collection, the index will equal -1.\n\t *\n\t * @param {Object|String} itemOrId The item or its ID in the collection.\n\t * @returns {Number} The index of a given item.\n\t */\n\tgetIndex( itemOrId ) {\n\t\tlet item;\n\n\t\tif ( typeof itemOrId == 'string' ) {\n\t\t\titem = this._itemMap.get( itemOrId );\n\t\t} else {\n\t\t\titem = itemOrId;\n\t\t}\n\n\t\treturn this._items.indexOf( item );\n\t}\n\n\t/**\n\t * Removes an item from the collection.\n\t *\n\t * @param {Object|Number|String} subject The item to remove, its ID or index in the collection.\n\t * @returns {Object} The removed item.\n\t * @fires remove\n\t * @fires change\n\t */\n\tremove( subject ) {\n\t\tconst [ item, index ] = this._remove( subject );\n\n\t\tthis.fire( 'change', {\n\t\t\tadded: [],\n\t\t\tremoved: [ item ],\n\t\t\tindex\n\t\t} );\n\n\t\treturn item;\n\t}\n\n\t/**\n\t * Executes the callback for each item in the collection and composes an array or values returned by this callback.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Array} The result of mapping.\n\t */\n\tmap( callback, ctx ) {\n\t\treturn this._items.map( callback, ctx );\n\t}\n\n\t/**\n\t * Finds the first item in the collection for which the `callback` returns a true value.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Object} The item for which `callback` returned a true value.\n\t */\n\tfind( callback, ctx ) {\n\t\treturn this._items.find( callback, ctx );\n\t}\n\n\t/**\n\t * Returns an array with items for which the `callback` returned a true value.\n\t *\n\t * @param {Function} callback\n\t * @param {Object} callback.item\n\t * @param {Number} callback.index\n\t * @param {Object} ctx Context in which the `callback` will be called.\n\t * @returns {Object[]} The array with matching items.\n\t */\n\tfilter( callback, ctx ) {\n\t\treturn this._items.filter( callback, ctx );\n\t}\n\n\t/**\n\t * Removes all items from the collection and destroys the binding created using\n\t * {@link #bindTo}.\n\t *\n\t * @fires remove\n\t * @fires change\n\t */\n\tclear() {\n\t\tif ( this._bindToCollection ) {\n\t\t\tthis.stopListening( this._bindToCollection );\n\t\t\tthis._bindToCollection = null;\n\t\t}\n\n\t\tconst removedItems = Array.from( this._items );\n\n\t\twhile ( this.length ) {\n\t\t\tthis._remove( 0 );\n\t\t}\n\n\t\tthis.fire( 'change', {\n\t\t\tadded: [],\n\t\t\tremoved: removedItems,\n\t\t\tindex: 0\n\t\t} );\n\t}\n\n\t/**\n\t * Binds and synchronizes the collection with another one.\n\t *\n\t * The binding can be a simple factory:\n\t *\n\t *\t\tclass FactoryClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).as( FactoryClass );\n\t *\n\t *\t\tsource.add( { label: 'foo' } );\n\t *\t\tsource.add( { label: 'bar' } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 1 ).label ); // 'bar'\n\t *\n\t *\t\tsource.remove( 0 );\n\t *\t\tconsole.log( target.length ); // 1\n\t *\t\tconsole.log( target.get( 0 ).label ); // 'bar'\n\t *\n\t * or the factory driven by a custom callback:\n\t *\n\t *\t\tclass FooClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tclass BarClass {\n\t *\t\t\tconstructor( data ) {\n\t *\t\t\t\tthis.label = data.label;\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( ( item ) => {\n\t *\t\t\tif ( item.label == 'foo' ) {\n\t *\t\t\t\treturn new FooClass( item );\n\t *\t\t\t} else {\n\t *\t\t\t\treturn new BarClass( item );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\tsource.add( { label: 'foo' } );\n\t *\t\tsource.add( { label: 'bar' } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 0 ) instanceof FooClass ); // true\n\t *\t\tconsole.log( target.get( 1 ) instanceof BarClass ); // true\n\t *\n\t * or the factory out of property name:\n\t *\n\t *\t\tconst source = new Collection( { idProperty: 'label' } );\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( 'label' );\n\t *\n\t *\t\tsource.add( { label: { value: 'foo' } } );\n\t *\t\tsource.add( { label: { value: 'bar' } } );\n\t *\n\t *\t\tconsole.log( target.length ); // 2\n\t *\t\tconsole.log( target.get( 0 ).value ); // 'foo'\n\t *\t\tconsole.log( target.get( 1 ).value ); // 'bar'\n\t *\n\t * It's possible to skip specified items by returning falsy value:\n\t *\n\t *\t\tconst source = new Collection();\n\t *\t\tconst target = new Collection();\n\t *\n\t *\t\ttarget.bindTo( source ).using( item => {\n\t *\t\t\tif ( item.hidden ) {\n\t *\t\t\t\treturn null;\n\t *\t\t\t}\n\t *\n\t *\t\t\treturn item;\n\t *\t\t} );\n\t *\n\t *\t\tsource.add( { hidden: true } );\n\t *\t\tsource.add( { hidden: false } );\n\t *\n\t *\t\tconsole.log( source.length ); // 2\n\t *\t\tconsole.log( target.length ); // 1\n\t *\n\t * **Note**: {@link #clear} can be used to break the binding.\n\t *\n\t * @param {module:utils/collection~Collection} externalCollection A collection to be bound.\n\t * @returns {Object}\n\t * @returns {module:utils/collection~CollectionBindToChain} The binding chain object.\n\t */\n\tbindTo( externalCollection ) {\n\t\tif ( this._bindToCollection ) {\n\t\t\t/**\n\t\t\t * The collection cannot be bound more than once.\n\t\t\t *\n\t\t\t * @error collection-bind-to-rebind\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-bind-to-rebind', this );\n\t\t}\n\n\t\tthis._bindToCollection = externalCollection;\n\n\t\treturn {\n\t\t\tas: Class => {\n\t\t\t\tthis._setUpBindToBinding( item => new Class( item ) );\n\t\t\t},\n\n\t\t\tusing: callbackOrProperty => {\n\t\t\t\tif ( typeof callbackOrProperty == 'function' ) {\n\t\t\t\t\tthis._setUpBindToBinding( item => callbackOrProperty( item ) );\n\t\t\t\t} else {\n\t\t\t\t\tthis._setUpBindToBinding( item => item[ callbackOrProperty ] );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Finalizes and activates a binding initiated by {#bindTo}.\n\t *\n\t * @protected\n\t * @param {Function} factory A function which produces collection items.\n\t */\n\t_setUpBindToBinding( factory ) {\n\t\tconst externalCollection = this._bindToCollection;\n\n\t\t// Adds the item to the collection once a change has been done to the external collection.\n\t\t//\n\t\t// @private\n\t\tconst addItem = ( evt, externalItem, index ) => {\n\t\t\tconst isExternalBoundToThis = externalCollection._bindToCollection == this;\n\t\t\tconst externalItemBound = externalCollection._bindToInternalToExternalMap.get( externalItem );\n\n\t\t\t// If an external collection is bound to this collection, which makes it a 2way binding,\n\t\t\t// and the particular external collection item is already bound, don't add it here.\n\t\t\t// The external item has been created **out of this collection's item** and (re)adding it will\n\t\t\t// cause a loop.\n\t\t\tif ( isExternalBoundToThis && externalItemBound ) {\n\t\t\t\tthis._bindToExternalToInternalMap.set( externalItem, externalItemBound );\n\t\t\t\tthis._bindToInternalToExternalMap.set( externalItemBound, externalItem );\n\t\t\t} else {\n\t\t\t\tconst item = factory( externalItem );\n\n\t\t\t\t// When there is no item we need to remember skipped index first and then we can skip this item.\n\t\t\t\tif ( !item ) {\n\t\t\t\t\tthis._skippedIndexesFromExternal.push( index );\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Lets try to put item at the same index as index in external collection\n\t\t\t\t// but when there are a skipped items in one or both collections we need to recalculate this index.\n\t\t\t\tlet finalIndex = index;\n\n\t\t\t\t// When we try to insert item after some skipped items from external collection we need\n\t\t\t\t// to include this skipped items and decrease index.\n\t\t\t\t//\n\t\t\t\t// For the following example:\n\t\t\t\t// external -> [ 'A', 'B - skipped for internal', 'C - skipped for internal' ]\n\t\t\t\t// internal -> [ A ]\n\t\t\t\t//\n\t\t\t\t// Another item is been added at the end of external collection:\n\t\t\t\t// external.add( 'D' )\n\t\t\t\t// external -> [ 'A', 'B - skipped for internal', 'C - skipped for internal', 'D' ]\n\t\t\t\t//\n\t\t\t\t// We can't just add 'D' to internal at the same index as index in external because\n\t\t\t\t// this will produce empty indexes what is invalid:\n\t\t\t\t// internal -> [ 'A', empty, empty, 'D' ]\n\t\t\t\t//\n\t\t\t\t// So we need to include skipped items and decrease index\n\t\t\t\t// internal -> [ 'A', 'D' ]\n\t\t\t\tfor ( const skipped of this._skippedIndexesFromExternal ) {\n\t\t\t\t\tif ( index > skipped ) {\n\t\t\t\t\t\tfinalIndex--;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// We need to take into consideration that external collection could skip some items from\n\t\t\t\t// internal collection.\n\t\t\t\t//\n\t\t\t\t// For the following example:\n\t\t\t\t// internal -> [ 'A', 'B - skipped for external', 'C - skipped for external' ]\n\t\t\t\t// external -> [ A ]\n\t\t\t\t//\n\t\t\t\t// Another item is been added at the end of external collection:\n\t\t\t\t// external.add( 'D' )\n\t\t\t\t// external -> [ 'A', 'D' ]\n\t\t\t\t//\n\t\t\t\t// We need to include skipped items and place new item after them:\n\t\t\t\t// internal -> [ 'A', 'B - skipped for external', 'C - skipped for external', 'D' ]\n\t\t\t\tfor ( const skipped of externalCollection._skippedIndexesFromExternal ) {\n\t\t\t\t\tif ( finalIndex >= skipped ) {\n\t\t\t\t\t\tfinalIndex++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis._bindToExternalToInternalMap.set( externalItem, item );\n\t\t\t\tthis._bindToInternalToExternalMap.set( item, externalItem );\n\t\t\t\tthis.add( item, finalIndex );\n\n\t\t\t\t// After adding new element to internal collection we need update indexes\n\t\t\t\t// of skipped items in external collection.\n\t\t\t\tfor ( let i = 0; i < externalCollection._skippedIndexesFromExternal.length; i++ ) {\n\t\t\t\t\tif ( finalIndex <= externalCollection._skippedIndexesFromExternal[ i ] ) {\n\t\t\t\t\t\texternalCollection._skippedIndexesFromExternal[ i ]++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Load the initial content of the collection.\n\t\tfor ( const externalItem of externalCollection ) {\n\t\t\taddItem( null, externalItem, externalCollection.getIndex( externalItem ) );\n\t\t}\n\n\t\t// Synchronize the with collection as new items are added.\n\t\tthis.listenTo( externalCollection, 'add', addItem );\n\n\t\t// Synchronize the with collection as new items are removed.\n\t\tthis.listenTo( externalCollection, 'remove', ( evt, externalItem, index ) => {\n\t\t\tconst item = this._bindToExternalToInternalMap.get( externalItem );\n\n\t\t\tif ( item ) {\n\t\t\t\tthis.remove( item );\n\t\t\t}\n\n\t\t\t// After removing element from external collection we need update/remove indexes\n\t\t\t// of skipped items in internal collection.\n\t\t\tthis._skippedIndexesFromExternal = this._skippedIndexesFromExternal.reduce( ( result, skipped ) => {\n\t\t\t\tif ( index < skipped ) {\n\t\t\t\t\tresult.push( skipped - 1 );\n\t\t\t\t}\n\n\t\t\t\tif ( index > skipped ) {\n\t\t\t\t\tresult.push( skipped );\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}, [] );\n\t\t} );\n\t}\n\n\t/**\n\t * Returns an unique id property for a given `item`.\n\t *\n\t * The method will generate new id and assign it to the `item` if it doesn't have any.\n\t *\n\t * @private\n\t * @param {Object} item Item to be added.\n\t * @returns {String}\n\t */\n\t_getItemIdBeforeAdding( item ) {\n\t\tconst idProperty = this._idProperty;\n\t\tlet itemId;\n\n\t\tif ( ( idProperty in item ) ) {\n\t\t\titemId = item[ idProperty ];\n\n\t\t\tif ( typeof itemId != 'string' ) {\n\t\t\t\t/**\n\t\t\t\t * This item's ID should be a string.\n\t\t\t\t *\n\t\t\t\t * @error collection-add-invalid-id\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'collection-add-invalid-id', this );\n\t\t\t}\n\n\t\t\tif ( this.get( itemId ) ) {\n\t\t\t\t/**\n\t\t\t\t * This item already exists in the collection.\n\t\t\t\t *\n\t\t\t\t * @error collection-add-item-already-exists\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'collection-add-item-already-exists', this );\n\t\t\t}\n\t\t} else {\n\t\t\titem[ idProperty ] = itemId = uid();\n\t\t}\n\n\t\treturn itemId;\n\t}\n\n\t/**\n\t * Core {@link #remove} method implementation shared in other functions.\n\t *\n\t * In contrast this method **does not** fire the {@link #event:change} event.\n\t *\n\t * @private\n\t * @param {Object} subject The item to remove, its id or index in the collection.\n\t * @returns {Array} Returns an array with the removed item and its index.\n\t * @fires remove\n\t */\n\t_remove( subject ) {\n\t\tlet index, id, item;\n\t\tlet itemDoesNotExist = false;\n\t\tconst idProperty = this._idProperty;\n\n\t\tif ( typeof subject == 'string' ) {\n\t\t\tid = subject;\n\t\t\titem = this._itemMap.get( id );\n\t\t\titemDoesNotExist = !item;\n\n\t\t\tif ( item ) {\n\t\t\t\tindex = this._items.indexOf( item );\n\t\t\t}\n\t\t} else if ( typeof subject == 'number' ) {\n\t\t\tindex = subject;\n\t\t\titem = this._items[ index ];\n\t\t\titemDoesNotExist = !item;\n\n\t\t\tif ( item ) {\n\t\t\t\tid = item[ idProperty ];\n\t\t\t}\n\t\t} else {\n\t\t\titem = subject;\n\t\t\tid = item[ idProperty ];\n\t\t\tindex = this._items.indexOf( item );\n\t\t\titemDoesNotExist = ( index == -1 || !this._itemMap.get( id ) );\n\t\t}\n\n\t\tif ( itemDoesNotExist ) {\n\t\t\t/**\n\t\t\t * Item not found.\n\t\t\t *\n\t\t\t * @error collection-remove-404\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'collection-remove-404', this );\n\t\t}\n\n\t\tthis._items.splice( index, 1 );\n\t\tthis._itemMap.delete( id );\n\n\t\tconst externalItem = this._bindToInternalToExternalMap.get( item );\n\t\tthis._bindToInternalToExternalMap.delete( item );\n\t\tthis._bindToExternalToInternalMap.delete( externalItem );\n\n\t\tthis.fire( 'remove', item, index );\n\n\t\treturn [ item, index ];\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._items[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Fired when an item is added to the collection.\n\t *\n\t * @event add\n\t * @param {Object} item The added item.\n\t */\n\n\t/**\n\t * Fired when the collection was changed due to adding or removing items.\n\t *\n\t * @event change\n\t * @param {Iterable.<Object>} added A list of added items.\n\t * @param {Iterable.<Object>} removed A list of removed items.\n\t * @param {Number} index An index where the addition or removal occurred.\n\t */\n\n\t/**\n\t * Fired when an item is removed from the collection.\n\t *\n\t * @event remove\n\t * @param {Object} item The removed item.\n\t * @param {Number} index Index from which item was removed.\n\t */\n}\n\nmix( Collection, EmitterMixin );\n\n/**\n * An object returned by the {@link module:utils/collection~Collection#bindTo `bindTo()`} method\n * providing functions that specify the type of the binding.\n *\n * See the {@link module:utils/collection~Collection#bindTo `bindTo()`} documentation for examples.\n *\n * @interface module:utils/collection~CollectionBindToChain\n */\n\n/**\n * Creates a callback or a property binding.\n *\n * @method #using\n * @param {Function|String} callbackOrProperty When the function is passed, it should return\n * the collection items. When the string is provided, the property value is used to create the bound collection items.\n */\n\n/**\n * Creates the class factory binding in which items of the source collection are passed to\n * the constructor of the specified class.\n *\n * @method #as\n * @param {Function} Class The class constructor used to create instances in the factory.\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 core/plugincollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Manages a list of CKEditor plugins, including loading, resolving dependencies and initialization.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class PluginCollection {\n\t/**\n\t * Creates an instance of the plugin collection class.\n\t * Allows loading and initializing plugins and their dependencies.\n\t * Allows providing a list of already loaded plugins. These plugins will not be destroyed along with this collection.\n\t *\n\t * @param {module:core/editor/editor~Editor|module:core/context~Context} context\n\t * @param {Array.<Function>} [availablePlugins] Plugins (constructors) which the collection will be able to use\n\t * when {@link module:core/plugincollection~PluginCollection#init} is used with the plugin names (strings, instead of constructors).\n\t * Usually, the editor will pass its built-in plugins to the collection so they can later be\n\t * used in `config.plugins` or `config.removePlugins` by names.\n\t * @param {Iterable.<Array>} contextPlugins A list of already initialized plugins represented by a\n\t * `[ PluginConstructor, pluginInstance ]` pair.\n\t */\n\tconstructor( context, availablePlugins = [], contextPlugins = [] ) {\n\t\t/**\n\t\t * @protected\n\t\t * @type {module:core/editor/editor~Editor|module:core/context~Context}\n\t\t */\n\t\tthis._context = context;\n\n\t\t/**\n\t\t * @protected\n\t\t * @type {Map}\n\t\t */\n\t\tthis._plugins = new Map();\n\n\t\t/**\n\t\t * A map of plugin constructors that can be retrieved by their names.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map.<String|Function,Function>}\n\t\t */\n\t\tthis._availablePlugins = new Map();\n\n\t\tfor ( const PluginConstructor of availablePlugins ) {\n\t\t\tif ( PluginConstructor.pluginName ) {\n\t\t\t\tthis._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Map of {@link module:core/contextplugin~ContextPlugin context plugins} which can be retrieved by their constructors or instances.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map<Function,Function>}\n\t\t */\n\t\tthis._contextPlugins = new Map();\n\n\t\tfor ( const [ PluginConstructor, pluginInstance ] of contextPlugins ) {\n\t\t\tthis._contextPlugins.set( PluginConstructor, pluginInstance );\n\t\t\tthis._contextPlugins.set( pluginInstance, PluginConstructor );\n\n\t\t\t// To make it possible to require a plugin by its name.\n\t\t\tif ( PluginConstructor.pluginName ) {\n\t\t\t\tthis._availablePlugins.set( PluginConstructor.pluginName, PluginConstructor );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Returns `[ PluginConstructor, pluginInstance ]` pairs.\n\t *\n\t * @returns {Iterable.<Array>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tfor ( const entry of this._plugins ) {\n\t\t\tif ( typeof entry[ 0 ] == 'function' ) {\n\t\t\t\tyield entry;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets the plugin instance by its constructor or name.\n\t *\n\t *\t\t// Check if 'Clipboard' plugin was loaded.\n\t *\t\tif ( editor.plugins.has( 'ClipboardPipeline' ) ) {\n\t *\t\t\t// Get clipboard plugin instance\n\t *\t\t\tconst clipboard = editor.plugins.get( 'ClipboardPipeline' );\n\t *\n\t *\t\t\tthis.listenTo( clipboard, 'inputTransformation', ( evt, data ) => {\n\t *\t\t\t\t// Do something on clipboard input.\n\t *\t\t\t} );\n\t *\t\t}\n\t *\n\t * **Note**: This method will throw an error if a plugin is not loaded. Use `{@link #has editor.plugins.has()}`\n\t * to check if a plugin is available.\n\t *\n\t * @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.\n\t * @returns {module:core/plugin~PluginInterface}\n\t */\n\tget( key ) {\n\t\tconst plugin = this._plugins.get( key );\n\n\t\tif ( !plugin ) {\n\t\t\tlet pluginName = key;\n\n\t\t\tif ( typeof key == 'function' ) {\n\t\t\t\tpluginName = key.pluginName || key.name;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * The plugin is not loaded and could not be obtained.\n\t\t\t *\n\t\t\t * Plugin classes (constructors) need to be provided to the editor and must be loaded before they can be obtained from\n\t\t\t * the plugin collection.\n\t\t\t * This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}\n\t\t\t * property.\n\t\t\t *\n\t\t\t * **Note**: You can use `{@link module:core/plugincollection~PluginCollection#has editor.plugins.has()}`\n\t\t\t * to check if a plugin was loaded.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-not-loaded\n\t\t\t * @param {String} plugin The name of the plugin which is not loaded.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'plugincollection-plugin-not-loaded', this._context, { plugin: pluginName } );\n\t\t}\n\n\t\treturn plugin;\n\t}\n\n\t/**\n\t * Checks if a plugin is loaded.\n\t *\n\t *\t\t// Check if the 'Clipboard' plugin was loaded.\n\t *\t\tif ( editor.plugins.has( 'ClipboardPipeline' ) ) {\n\t *\t\t\t// Now use the clipboard plugin instance:\n\t *\t\t\tconst clipboard = editor.plugins.get( 'ClipboardPipeline' );\n\t *\n\t *\t\t\t// ...\n\t *\t\t}\n\t *\n\t * @param {Function|String} key The plugin constructor or {@link module:core/plugin~PluginInterface.pluginName name}.\n\t * @returns {Boolean}\n\t */\n\thas( key ) {\n\t\treturn this._plugins.has( key );\n\t}\n\n\t/**\n\t * Initializes a set of plugins and adds them to the collection.\n\t *\n\t * @param {Array.<Function|String>} plugins An array of {@link module:core/plugin~PluginInterface plugin constructors}\n\t * or {@link module:core/plugin~PluginInterface.pluginName plugin names}.\n\t * @param {Array.<String|Function>} [pluginsToRemove] Names of the plugins or plugin constructors\n\t * that should not be loaded (despite being specified in the `plugins` array).\n\t * @param {Array.<Function>} [pluginsSubstitutions] An array of {@link module:core/plugin~PluginInterface plugin constructors}\n\t * that will be used to replace plugins of the same names that were passed in `plugins` or that are in their dependency tree.\n\t * A useful option for replacing built-in plugins while creating tests (for mocking their APIs). Plugins that will be replaced\n\t * must follow these rules:\n\t * * The new plugin must be a class.\n\t * * The new plugin must be named.\n\t * * Both plugins must not depend on other plugins.\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which gets resolved once all plugins are loaded\n\t * and available in the collection.\n\t */\n\tinit( plugins, pluginsToRemove = [], pluginsSubstitutions = [] ) {\n\t\t// Plugin initialization procedure consists of 2 main steps:\n\t\t// 1) collecting all available plugin constructors,\n\t\t// 2) verification whether all required plugins can be instantiated.\n\t\t//\n\t\t// In the first step, all plugin constructors, available in the provided `plugins` array and inside\n\t\t// plugin's dependencies (from the `Plugin.requires` array), are recursively collected and added to the existing\n\t\t// `this._availablePlugins` map, but without any verification at the given moment. Performing the verification\n\t\t// at this point (during the plugin constructor searching) would cause false errors to occur, that some plugin\n\t\t// is missing but in fact it may be defined further in the array as the dependency of other plugin. After\n\t\t// traversing the entire dependency tree, it will be checked if all required \"top level\" plugins are available.\n\t\t//\n\t\t// In the second step, the list of plugins that have not been explicitly removed is traversed to get all the\n\t\t// plugin constructors to be instantiated in the correct order and to validate against some rules. Finally, if\n\t\t// no plugin is missing and no other error has been found, they all will be instantiated.\n\t\tconst that = this;\n\t\tconst context = this._context;\n\n\t\tfindAvailablePluginConstructors( plugins );\n\n\t\tvalidatePlugins( plugins );\n\n\t\tconst pluginsToLoad = plugins.filter( plugin => !isPluginRemoved( plugin, pluginsToRemove ) );\n\n\t\tconst pluginConstructors = [ ...getPluginConstructors( pluginsToLoad ) ];\n\n\t\tsubstitutePlugins( pluginConstructors, pluginsSubstitutions );\n\n\t\tconst pluginInstances = loadPlugins( pluginConstructors );\n\n\t\treturn initPlugins( pluginInstances, 'init' )\n\t\t\t.then( () => initPlugins( pluginInstances, 'afterInit' ) )\n\t\t\t.then( () => pluginInstances );\n\n\t\tfunction isPluginConstructor( plugin ) {\n\t\t\treturn typeof plugin === 'function';\n\t\t}\n\n\t\tfunction isContextPlugin( plugin ) {\n\t\t\treturn isPluginConstructor( plugin ) && plugin.isContextPlugin;\n\t\t}\n\n\t\tfunction isPluginRemoved( plugin, pluginsToRemove ) {\n\t\t\treturn pluginsToRemove.some( removedPlugin => {\n\t\t\t\tif ( removedPlugin === plugin ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif ( getPluginName( plugin ) === removedPlugin ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif ( getPluginName( removedPlugin ) === plugin ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t} );\n\t\t}\n\n\t\tfunction getPluginName( plugin ) {\n\t\t\treturn isPluginConstructor( plugin ) ?\n\t\t\t\tplugin.pluginName || plugin.name :\n\t\t\t\tplugin;\n\t\t}\n\n\t\tfunction findAvailablePluginConstructors( plugins, processed = new Set() ) {\n\t\t\tplugins.forEach( plugin => {\n\t\t\t\tif ( !isPluginConstructor( plugin ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ( processed.has( plugin ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tprocessed.add( plugin );\n\n\t\t\t\tif ( plugin.pluginName && !that._availablePlugins.has( plugin.pluginName ) ) {\n\t\t\t\t\tthat._availablePlugins.set( plugin.pluginName, plugin );\n\t\t\t\t}\n\n\t\t\t\tif ( plugin.requires ) {\n\t\t\t\t\tfindAvailablePluginConstructors( plugin.requires, processed );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tfunction getPluginConstructors( plugins, processed = new Set() ) {\n\t\t\treturn plugins\n\t\t\t\t.map( plugin => {\n\t\t\t\t\treturn isPluginConstructor( plugin ) ?\n\t\t\t\t\t\tplugin :\n\t\t\t\t\t\tthat._availablePlugins.get( plugin );\n\t\t\t\t} )\n\t\t\t\t.reduce( ( result, plugin ) => {\n\t\t\t\t\tif ( processed.has( plugin ) ) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\n\t\t\t\t\tprocessed.add( plugin );\n\n\t\t\t\t\tif ( plugin.requires ) {\n\t\t\t\t\t\tvalidatePlugins( plugin.requires, plugin );\n\n\t\t\t\t\t\tgetPluginConstructors( plugin.requires, processed ).forEach( plugin => result.add( plugin ) );\n\t\t\t\t\t}\n\n\t\t\t\t\treturn result.add( plugin );\n\t\t\t\t}, new Set() );\n\t\t}\n\n\t\tfunction validatePlugins( plugins, parentPluginConstructor = null ) {\n\t\t\tplugins\n\t\t\t\t.map( plugin => {\n\t\t\t\t\treturn isPluginConstructor( plugin ) ?\n\t\t\t\t\t\tplugin :\n\t\t\t\t\t\tthat._availablePlugins.get( plugin ) || plugin;\n\t\t\t\t} )\n\t\t\t\t.forEach( plugin => {\n\t\t\t\t\tcheckMissingPlugin( plugin, parentPluginConstructor );\n\t\t\t\t\tcheckContextPlugin( plugin, parentPluginConstructor );\n\t\t\t\t\tcheckRemovedPlugin( plugin, parentPluginConstructor );\n\t\t\t\t} );\n\t\t}\n\n\t\tfunction checkMissingPlugin( plugin, parentPluginConstructor ) {\n\t\t\tif ( isPluginConstructor( plugin ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( parentPluginConstructor ) {\n\t\t\t\t/**\n\t\t\t\t * A required \"soft\" dependency was not found on the plugin list.\n\t\t\t\t *\n\t\t\t\t * When configuring the editor, either prior to building (via\n\t\t\t\t * {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}) or when\n\t\t\t\t * creating a new instance of the editor (e.g. via\n\t\t\t\t * {@link module:core/editor/editorconfig~EditorConfig#plugins `config.plugins`}), you need to provide\n\t\t\t\t * some of the dependencies for other plugins that you used.\n\t\t\t\t *\n\t\t\t\t * This error is thrown when one of these dependencies was not provided. The name of the missing plugin\n\t\t\t\t * can be found in `missingPlugin` and the plugin that required it in `requiredBy`.\n\t\t\t\t *\n\t\t\t\t * In order to resolve it, you need to import the missing plugin and add it to the\n\t\t\t\t * current list of plugins (`Editor.builtinPlugins` or `config.plugins`/`config.extraPlugins`).\n\t\t\t\t *\n\t\t\t\t * Soft requirements were introduced in version 26.0.0. If you happen to stumble upon this error\n\t\t\t\t * when upgrading to version 26.0.0, read also the\n\t\t\t\t * {@glink builds/guides/migration/migration-to-26.0.0 Migration to 26.0.0} guide.\n\t\t\t\t *\n\t\t\t\t * @error plugincollection-soft-required\n\t\t\t\t * @param {String} missingPlugin The name of the required plugin.\n\t\t\t\t * @param {String} requiredBy The name of the plugin that requires the other plugin.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'plugincollection-soft-required',\n\t\t\t\t\tcontext,\n\t\t\t\t\t{ missingPlugin: plugin, requiredBy: getPluginName( parentPluginConstructor ) }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * A plugin is not available and could not be loaded.\n\t\t\t *\n\t\t\t * Plugin classes (constructors) need to be provided to the editor before they can be loaded by name.\n\t\t\t * This is usually done in CKEditor 5 builds by setting the {@link module:core/editor/editor~Editor.builtinPlugins}\n\t\t\t * property.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}**, it means\n\t\t\t * that you try to enable a plugin which was not included in that build. This may be due to a typo\n\t\t\t * in the plugin name or simply because that plugin is not a part of this build. In the latter scenario,\n\t\t\t * read more about {@glink builds/guides/development/custom-builds custom builds}.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the editor creators directly** (not a build), then it means\n\t\t\t * that you tried loading plugins by name. However, unlike CKEditor 4, CKEditor 5 does not implement a \"plugin loader\".\n\t\t\t * This means that CKEditor 5 does not know where to load the plugin modules from. Therefore, you need to\n\t\t\t * provide each plugin through a reference (as a constructor function). Check out the examples in\n\t\t\t * {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source \"Building from source\"}.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-not-found\n\t\t\t * @param {String} plugin The name of the plugin which could not be loaded.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'plugincollection-plugin-not-found',\n\t\t\t\tcontext,\n\t\t\t\t{ plugin }\n\t\t\t);\n\t\t}\n\n\t\tfunction checkContextPlugin( plugin, parentPluginConstructor ) {\n\t\t\tif ( !isContextPlugin( parentPluginConstructor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isContextPlugin( plugin ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * If a plugin is a context plugin, all plugins it requires should also be context plugins\n\t\t\t * instead of plugins. In other words, if one plugin can be used in the context,\n\t\t\t * all its requirements should also be ready to be used in the context. Note that the context\n\t\t\t * provides only a part of the API provided by the editor. If one plugin needs a full\n\t\t\t * editor API, all plugins which require it are considered as plugins that need a full\n\t\t\t * editor API.\n\t\t\t *\n\t\t\t * @error plugincollection-context-required\n\t\t\t * @param {String} plugin The name of the required plugin.\n\t\t\t * @param {String} requiredBy The name of the parent plugin.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'plugincollection-context-required',\n\t\t\t\tcontext,\n\t\t\t\t{ plugin: getPluginName( plugin ), requiredBy: getPluginName( parentPluginConstructor ) }\n\t\t\t);\n\t\t}\n\n\t\tfunction checkRemovedPlugin( plugin, parentPluginConstructor ) {\n\t\t\tif ( !parentPluginConstructor ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !isPluginRemoved( plugin, pluginsToRemove ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Cannot load a plugin because one of its dependencies is listed in the `removePlugins` option.\n\t\t\t *\n\t\t\t * @error plugincollection-required\n\t\t\t * @param {String} plugin The name of the required plugin.\n\t\t\t * @param {String} requiredBy The name of the parent plugin.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'plugincollection-required',\n\t\t\t\tcontext,\n\t\t\t\t{ plugin: getPluginName( plugin ), requiredBy: getPluginName( parentPluginConstructor ) }\n\t\t\t);\n\t\t}\n\n\t\tfunction loadPlugins( pluginConstructors ) {\n\t\t\treturn pluginConstructors.map( PluginConstructor => {\n\t\t\t\tconst pluginInstance = that._contextPlugins.get( PluginConstructor ) || new PluginConstructor( context );\n\n\t\t\t\tthat._add( PluginConstructor, pluginInstance );\n\n\t\t\t\treturn pluginInstance;\n\t\t\t} );\n\t\t}\n\n\t\tfunction initPlugins( pluginInstances, method ) {\n\t\t\treturn pluginInstances.reduce( ( promise, plugin ) => {\n\t\t\t\tif ( !plugin[ method ] ) {\n\t\t\t\t\treturn promise;\n\t\t\t\t}\n\n\t\t\t\tif ( that._contextPlugins.has( plugin ) ) {\n\t\t\t\t\treturn promise;\n\t\t\t\t}\n\n\t\t\t\treturn promise.then( plugin[ method ].bind( plugin ) );\n\t\t\t}, Promise.resolve() );\n\t\t}\n\n\t\t// Replaces plugin constructors with the specified set of plugins.\n\t\t//\n\t\t// @param {Array.<Function>} pluginConstructors\n\t\t// @param {Array.<Function>} pluginsSubstitutions\n\t\tfunction substitutePlugins( pluginConstructors, pluginsSubstitutions ) {\n\t\t\tfor ( const pluginItem of pluginsSubstitutions ) {\n\t\t\t\tif ( typeof pluginItem != 'function' ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * The plugin replacing an existing plugin must be a function.\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-replace-plugin-invalid-type\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError( 'plugincollection-replace-plugin-invalid-type', null, { pluginItem } );\n\t\t\t\t}\n\t\t\t\tconst pluginName = pluginItem.pluginName;\n\n\t\t\t\tif ( !pluginName ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * The plugin replacing an existing plugin must have a name.\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-replace-plugin-missing-name\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError( 'plugincollection-replace-plugin-missing-name', null, { pluginItem } );\n\t\t\t\t}\n\n\t\t\t\tif ( pluginItem.requires && pluginItem.requires.length ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * The plugin replacing an existing plugin cannot depend on other plugins.\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-plugin-for-replacing-cannot-have-dependencies\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError( 'plugincollection-plugin-for-replacing-cannot-have-dependencies', null, { pluginName } );\n\t\t\t\t}\n\n\t\t\t\tconst pluginToReplace = that._availablePlugins.get( pluginName );\n\n\t\t\t\tif ( !pluginToReplace ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * The replaced plugin does not exist in the\n\t\t\t\t\t * {@link module:core/plugincollection~PluginCollection available plugins} collection.\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-plugin-for-replacing-not-exist\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError( 'plugincollection-plugin-for-replacing-not-exist', null, { pluginName } );\n\t\t\t\t}\n\n\t\t\t\tconst indexInPluginConstructors = pluginConstructors.indexOf( pluginToReplace );\n\n\t\t\t\tif ( indexInPluginConstructors === -1 ) {\n\t\t\t\t\t// The Context feature can substitute plugins as well.\n\t\t\t\t\t// It may happen that the editor will be created with the given context, where the plugin for substitute\n\t\t\t\t\t// was already replaced. In such a case, we don't want to do it again.\n\t\t\t\t\tif ( that._contextPlugins.has( pluginToReplace ) ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t/**\n\t\t\t\t\t * The replaced plugin will not be loaded so it cannot be replaced.\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-plugin-for-replacing-not-loaded\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError( 'plugincollection-plugin-for-replacing-not-loaded', null, { pluginName } );\n\t\t\t\t}\n\n\t\t\t\tif ( pluginToReplace.requires && pluginToReplace.requires.length ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * The replaced plugin cannot depend on other plugins.\n\t\t\t\t\t *\n\t\t\t\t\t * @error plugincollection-replaced-plugin-cannot-have-dependencies\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError( 'plugincollection-replaced-plugin-cannot-have-dependencies', null, { pluginName } );\n\t\t\t\t}\n\n\t\t\t\tpluginConstructors.splice( indexInPluginConstructors, 1, pluginItem );\n\t\t\t\tthat._availablePlugins.set( pluginName, pluginItem );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys all loaded plugins.\n\t *\n\t * @returns {Promise}\n\t */\n\tdestroy() {\n\t\tconst promises = [];\n\n\t\tfor ( const [ , pluginInstance ] of this ) {\n\t\t\tif ( typeof pluginInstance.destroy == 'function' && !this._contextPlugins.has( pluginInstance ) ) {\n\t\t\t\tpromises.push( pluginInstance.destroy() );\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all( promises );\n\t}\n\n\t/**\n\t * Adds the plugin to the collection. Exposed mainly for testing purposes.\n\t *\n\t * @protected\n\t * @param {Function} PluginConstructor The plugin constructor.\n\t * @param {module:core/plugin~PluginInterface} plugin The instance of the plugin.\n\t */\n\t_add( PluginConstructor, plugin ) {\n\t\tthis._plugins.set( PluginConstructor, plugin );\n\n\t\tconst pluginName = PluginConstructor.pluginName;\n\n\t\tif ( !pluginName ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._plugins.has( pluginName ) ) {\n\t\t\t/**\n\t\t\t * Two plugins with the same {@link module:core/plugin~PluginInterface.pluginName} were loaded.\n\t\t\t * This will lead to runtime conflicts between these plugins.\n\t\t\t *\n\t\t\t * In practice, this warning usually means that new plugins were added to an existing CKEditor 5 build.\n\t\t\t * Plugins should always be added to a source version of the editor (`@ckeditor/ckeditor5-editor-*`),\n\t\t\t * not to an editor imported from one of the `@ckeditor/ckeditor5-build-*` packages.\n\t\t\t *\n\t\t\t * Check your import paths and the list of plugins passed to\n\t\t\t * {@link module:core/editor/editor~Editor.create `Editor.create()`}\n\t\t\t * or specified in {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}.\n\t\t\t *\n\t\t\t * The second option is that your `node_modules/` directory contains duplicated versions of the same\n\t\t\t * CKEditor 5 packages. Normally, on clean installations, npm deduplicates packages in `node_modules/`, so\n\t\t\t * it may be enough to call `rm -rf node_modules && npm i`. However, if you installed conflicting versions\n\t\t\t * of some packages, their dependencies may need to be installed in more than one version which may lead to this\n\t\t\t * warning.\n\t\t\t *\n\t\t\t * Technically speaking, this error occurs because after adding a plugin to an existing editor build\n\t\t\t * the dependencies of this plugin are being duplicated.\n\t\t\t * They are already built into that editor build and now get added for the second time as dependencies\n\t\t\t * of the plugin you are installing.\n\t\t\t *\n\t\t\t * Read more about {@glink builds/guides/integration/installing-plugins installing plugins}.\n\t\t\t *\n\t\t\t * @error plugincollection-plugin-name-conflict\n\t\t\t * @param {String} pluginName The duplicated plugin name.\n\t\t\t * @param {Function} plugin1 The first plugin constructor.\n\t\t\t * @param {Function} plugin2 The second plugin constructor.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'plugincollection-plugin-name-conflict',\n\t\t\t\tnull,\n\t\t\t\t{ pluginName, plugin1: this._plugins.get( pluginName ).constructor, plugin2: PluginConstructor }\n\t\t\t);\n\t\t}\n\n\t\tthis._plugins.set( pluginName, plugin );\n\t}\n}\n\nmix( PluginCollection, EmitterMixin );\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 utils/toarray\n */\n\n/**\n * Transforms any value to an array. If the provided value is already an array, it is returned unchanged.\n *\n * @param {*} data The value to transform to an array.\n * @returns {Array} An array created from data.\n */\nexport default function toArray( data ) {\n\treturn Array.isArray( data ) ? data : [ data ];\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/* globals window */\n\n/**\n * @module utils/translation-service\n */\n\nimport CKEditorError from './ckeditorerror';\n\n/* istanbul ignore else */\nif ( !window.CKEDITOR_TRANSLATIONS ) {\n\twindow.CKEDITOR_TRANSLATIONS = {};\n}\n\n/**\n * Adds translations to existing ones or overrides the existing translations. These translations will later\n * be available for the {@link module:utils/locale~Locale#t `t()`} function.\n *\n * The `translations` is an object which consists of `messageId: translation` pairs. Note that the message ID can be\n * either constructed from the message string or from the message ID if it was passed\n * (this happens rarely and mostly for short messages or messages with placeholders).\n * Since the editor displays only the message string, the message ID can be found either in the source code or in the\n * built translations for another language.\n *\n *\t\tadd( 'pl', {\n *\t\t\t'Cancel': 'Anuluj',\n *\t\t\t'IMAGE': 'obraz', // Note that the `IMAGE` comes from the message ID, while the string can be `image`.\n *\t\t} );\n *\n * If the message is supposed to support various plural forms, make sure to provide an array with the singular form and all plural forms:\n *\n *\t\tadd( 'pl', {\n *\t \t\t'Add space': [ 'Dodaj spację', 'Dodaj %0 spacje', 'Dodaj %0 spacji' ]\n * \t\t} );\n *\n * You should also specify the third argument (the `getPluralForm()` function) that will be used to determine the plural form if no\n * language file was loaded for that language. All language files coming from CKEditor 5 sources will have this option set, so\n * these plural form rules will be reused by other translations added to the registered languages. The `getPluralForm()` function\n * can return either a Boolean or a number.\n *\n * \t\tadd( 'en', {\n *\t \t\t// ... Translations.\n * \t\t}, n => n !== 1 );\n * \t\tadd( 'pl', {\n *\t \t\t// ... Translations.\n * \t\t}, n => n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && ( n % 100 < 10 || n % 100 >= 20 ) ? 1 : 2 );\n *\n * All translations extend the global `window.CKEDITOR_TRANSLATIONS` object. An example of this object can be found below:\n *\n * \t\t{\n * \t\t\tpl: {\n *\t\t\t\tdictionary: {\n *\t\t\t\t\t'Cancel': 'Anuluj',\n *\t\t\t\t\t'Add space': [ 'Dodaj spację', 'Dodaj %0 spacje', 'Dodaj %0 spacji' ]\n *\t\t\t\t},\n *\t\t\t\t// A function that returns the plural form index.\n *\t\t\t\tgetPluralForm: n => n !==1\n *\t\t\t}\n *\t\t\t// Other languages.\n *\t\t}\n *\n * If you cannot import this function from this module (e.g. because you use a CKEditor 5 build), you can\n * still add translations by extending the global `window.CKEDITOR_TRANSLATIONS` object by using a function like\n * the one below:\n *\n *\t\tfunction addTranslations( language, translations, getPluralForm ) {\n *\t\t\tif ( !window.CKEDITOR_TRANSLATIONS ) {\n *\t\t\t\twindow.CKEDITOR_TRANSLATIONS = {};\n *\t\t\t}\n\n *\t\t\tif ( !window.CKEDITOR_TRANSLATIONS[ language ] ) {\n *\t\t\t\twindow.CKEDITOR_TRANSLATIONS[ language ] = {};\n *\t\t\t}\n *\n *\t\t\tconst languageTranslations = window.CKEDITOR_TRANSLATIONS[ language ];\n *\n * \t\t\tlanguageTranslations.dictionary = languageTranslations.dictionary || {};\n * \t\t\tlanguageTranslations.getPluralForm = getPluralForm || languageTranslations.getPluralForm;\n *\n *\t\t\t// Extend the dictionary for the given language.\n *\t\t\tObject.assign( languageTranslations.dictionary, translations );\n *\t\t}\n *\n * @param {String} language Target language.\n * @param {Object.<String,*>} translations An object with translations which will be added to the dictionary.\n * For each message ID the value should be either a translation or an array of translations if the message\n * should support plural forms.\n * @param {Function} getPluralForm A function that returns the plural form index (a number).\n */\nexport function add( language, translations, getPluralForm ) {\n\tif ( !window.CKEDITOR_TRANSLATIONS[ language ] ) {\n\t\twindow.CKEDITOR_TRANSLATIONS[ language ] = {};\n\t}\n\n\tconst languageTranslations = window.CKEDITOR_TRANSLATIONS[ language ];\n\n\tlanguageTranslations.dictionary = languageTranslations.dictionary || {};\n\tlanguageTranslations.getPluralForm = getPluralForm || languageTranslations.getPluralForm;\n\n\tObject.assign( languageTranslations.dictionary, translations );\n}\n\n/**\n * **Note:** This method is internal, use {@link module:utils/locale~Locale#t the `t()` function} instead to translate\n * the editor UI parts.\n *\n * This function is responsible for translating messages to the specified language. It uses translations added perviously\n * by {@link module:utils/translation-service~add} (a translations dictionary and the `getPluralForm()` function\n * to provide accurate translations of plural forms).\n *\n * When no translation is defined in the dictionary or the dictionary does not exist, this function returns\n * the original message string or the message plural depending on the number of elements.\n *\n *\t\ttranslate( 'pl', { string: 'Cancel' } ); // 'Cancel'\n *\n * The third optional argument is the number of elements, based on which the single form or one of the plural forms\n * should be picked when the message is supposed to support various plural forms.\n *\n * \t\ttranslate( 'en', { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Add a space'\n * \t\ttranslate( 'en', { string: 'Add a space', plural: 'Add %0 spaces' }, 3 ); // 'Add %0 spaces'\n *\n * The message should provide an ID using the `id` property when the message strings are not unique and their\n * translations should be different.\n *\n *\t\ttranslate( 'en', { string: 'image', id: 'ADD_IMAGE' } );\n *\t\ttranslate( 'en', { string: 'image', id: 'AN_IMAGE' } );\n *\n * @protected\n * @param {String} language Target language.\n * @param {module:utils/translation-service~Message|String} message A message that will be translated.\n * @param {Number} [quantity] The number of elements for which a plural form should be picked from the target language dictionary.\n * @returns {String} Translated sentence.\n */\nexport function _translate( language, message, quantity = 1 ) {\n\tif ( typeof quantity !== 'number' ) {\n\t\t/**\n\t\t * An incorrect value was passed to the translation function. This was probably caused\n\t\t * by an incorrect message interpolation of a plural form. Note that for messages supporting plural forms\n\t\t * the second argument of the `t()` function should always be a number or an array with a number as the first element.\n\t\t *\n\t\t * @error translation-service-quantity-not-a-number\n\t\t */\n\t\tthrow new CKEditorError( 'translation-service-quantity-not-a-number', null, { quantity } );\n\t}\n\n\tconst numberOfLanguages = getNumberOfLanguages();\n\n\tif ( numberOfLanguages === 1 ) {\n\t\t// Override the language to the only supported one.\n\t\t// This can't be done in the `Locale` class, because the translations comes after the `Locale` class initialization.\n\t\tlanguage = Object.keys( window.CKEDITOR_TRANSLATIONS )[ 0 ];\n\t}\n\n\tconst messageId = message.id || message.string;\n\n\tif ( numberOfLanguages === 0 || !hasTranslation( language, messageId ) ) {\n\t\tif ( quantity !== 1 ) {\n\t\t\t// Return the default plural form that was passed in the `message.plural` parameter.\n\t\t\treturn message.plural;\n\t\t}\n\n\t\treturn message.string;\n\t}\n\n\tconst dictionary = window.CKEDITOR_TRANSLATIONS[ language ].dictionary;\n\tconst getPluralForm = window.CKEDITOR_TRANSLATIONS[ language ].getPluralForm || ( n => n === 1 ? 0 : 1 );\n\n\tif ( typeof dictionary[ messageId ] === 'string' ) {\n\t\treturn dictionary[ messageId ];\n\t}\n\n\tconst pluralFormIndex = Number( getPluralForm( quantity ) );\n\n\t// Note: The `translate` function is not responsible for replacing `%0, %1, ...` with values.\n\treturn dictionary[ messageId ][ pluralFormIndex ];\n}\n\n/**\n * Clears dictionaries for test purposes.\n *\n * @protected\n */\nexport function _clear() {\n\twindow.CKEDITOR_TRANSLATIONS = {};\n}\n\n// Checks whether the dictionary exists and translation in that dictionary exists.\nfunction hasTranslation( language, messageId ) {\n\treturn (\n\t\t!!window.CKEDITOR_TRANSLATIONS[ language ] &&\n\t\t!!window.CKEDITOR_TRANSLATIONS[ language ].dictionary[ messageId ]\n\t);\n}\n\nfunction getNumberOfLanguages() {\n\treturn Object.keys( window.CKEDITOR_TRANSLATIONS ).length;\n}\n\n/**\n * The internationalization message interface. A message that implements this interface can be passed to the `t()` function\n * to be translated to the target UI language.\n *\n * @typedef {Object} module:utils/translation-service~Message\n *\n * @property {String} string The message string to translate. Acts as a default translation if the translation for a given language\n * is not defined. When the message is supposed to support plural forms, the string should be the English singular form of the message.\n * @property {String} [id] The message ID. If passed, the message ID is taken from this property instead of the `message.string`.\n * This property is useful when various messages share the same message string, for example, the `editor` string in `in the editor`\n * and `my editor` sentences.\n * @property {String} [plural] The plural form of the message. This property should be skipped when a message is not supposed\n * to support plural forms. Otherwise it should always be set to a string with the English plural form of the message.\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 utils/language\n */\n\nconst RTL_LANGUAGE_CODES = [\n\t'ar', 'ara', // Arabic\n\t'fa', 'per', 'fas', // Persian\n\t'he', 'heb', // Hebrew\n\t'ku', 'kur', // Kurdish\n\t'ug', 'uig' // Uighur, Uyghur\n];\n\n/**\n * Helps determine whether a language text direction is LTR or RTL.\n *\n * @param {String} language The ISO 639-1 or ISO 639-2 language code.\n * @returns {'ltr'|'rtl'}\n */\nexport function getLanguageDirection( languageCode ) {\n\treturn RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr';\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 utils/locale\n */\n\n/* globals console */\n\nimport toArray from './toarray';\nimport { _translate } from './translation-service';\nimport { getLanguageDirection } from './language';\n\n/**\n * Represents the localization services.\n */\nexport default class Locale {\n\t/**\n\t * Creates a new instance of the locale class. Learn more about\n\t * {@glink features/ui-language configuring the language of the editor}.\n\t *\n\t * @param {Object} [options] Locale configuration.\n\t * @param {String} [options.uiLanguage='en'] The editor UI language code in the\n\t * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. See {@link #uiLanguage}.\n\t * @param {String} [options.contentLanguage] The editor content language code in the\n\t * [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. If not specified, the same as `options.language`.\n\t * See {@link #contentLanguage}.\n\t */\n\tconstructor( options = {} ) {\n\t\t/**\n\t\t * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t\t *\n\t\t * If the {@link #contentLanguage content language} was not specified in the `Locale` constructor,\n\t\t * it also defines the language of the content.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.uiLanguage = options.uiLanguage || 'en';\n\n\t\t/**\n\t\t * The editor content language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t\t *\n\t\t * Usually the same as the {@link #uiLanguage editor language}, it can be customized by passing an optional\n\t\t * argument to the `Locale` constructor.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.contentLanguage = options.contentLanguage || this.uiLanguage;\n\n\t\t/**\n\t\t * Text direction of the {@link #uiLanguage editor UI language}. Either `'ltr'` or `'rtl'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.uiLanguageDirection = getLanguageDirection( this.uiLanguage );\n\n\t\t/**\n\t\t * Text direction of the {@link #contentLanguage editor content language}.\n\t\t *\n\t\t * If the content language was passed directly to the `Locale` constructor, this property represents the\n\t\t * direction of that language.\n\t\t *\n\t\t * If the {@link #contentLanguage editor content language} was derived from the {@link #uiLanguage editor language},\n\t\t * the content language direction is the same as the {@link #uiLanguageDirection UI language direction}.\n\t\t *\n\t\t * The value is either `'ltr'` or `'rtl'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.contentLanguageDirection = getLanguageDirection( this.contentLanguage );\n\n\t\t/**\n\t\t * Translates the given message to the {@link #uiLanguage}. This method is also available in\n\t\t * {@link module:core/editor/editor~Editor#t `Editor`} and {@link module:ui/view~View#t `View`}.\n\t\t *\n\t\t * This method's context is statically bound to the `Locale` instance and **should always be called as a function**:\n\t\t *\n\t\t *\t\tconst t = locale.t;\n\t\t *\t\tt( 'Label' );\n\t\t *\n\t\t * The message can be either a string or an object implementing the {@link module:utils/translation-service~Message} interface.\n\t\t *\n\t\t * The message may contain placeholders (`%<index>`) for value(s) that are passed as a `values` parameter.\n\t\t * For an array of values, the `%<index>` will be changed to an element of that array at the given index.\n\t\t * For a single value passed as the second argument, only the `%0` placeholders will be changed to the provided value.\n\t\t *\n\t\t *\t\tt( 'Created file \"%0\" in %1ms.', [ fileName, timeTaken ] );\n\t\t * \t\tt( 'Created file \"%0\", fileName );\n\t\t *\n\t\t * The message supports plural forms. To specify the plural form, use the `plural` property. Singular or plural form\n\t\t * will be chosen depending on the first value from the passed `values`. The value of the `plural` property is used\n\t\t * as a default plural translation when the translation for the target language is missing.\n\t\t *\n\t\t *\t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Add a space' for the English language.\n\t\t *\t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 5 ); // 'Add 5 spaces' for the English language.\n\t\t *\t\tt( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Add 2 spaces' for the English language.\n\t\t *\n\t\t * \t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 1 ); // 'Dodaj spację' for the Polish language.\n\t\t *\t\tt( { string: 'Add a space', plural: 'Add %0 spaces' }, 5 ); // 'Dodaj 5 spacji' for the Polish language.\n\t\t *\t\tt( { string: '%1 a space', plural: '%1 %0 spaces' }, [ 2, 'Add' ] ); // 'Dodaj 2 spacje' for the Polish language.\n\t\t *\n\t\t * * The message should provide an ID using the `id` property when the message strings are not unique and their\n\t\t * translations should be different.\n\t\t *\n\t\t *\t\ttranslate( 'en', { string: 'image', id: 'ADD_IMAGE' } );\n\t\t *\t\ttranslate( 'en', { string: 'image', id: 'AN_IMAGE' } );\n\t\t *\n\t\t * @method #t\n\t\t * @param {String|module:utils/translation-service~Message} message A message that will be localized (translated).\n\t\t * @param {String|Number|Array.<String|Number>} [values] A value or an array of values that will fill message placeholders.\n\t\t * For messages supporting plural forms the first value will determine the plural form.\n\t\t * @returns {String}\n\t\t */\n\t\tthis.t = ( message, values ) => this._t( message, values );\n\t}\n\n\t/**\n\t * The editor UI language code in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format.\n\t *\n\t * **Note**: This property was deprecated. Please use {@link #uiLanguage} and {@link #contentLanguage}\n\t * properties instead.\n\t *\n\t * @deprecated\n\t * @member {String}\n\t */\n\tget language() {\n\t\t/**\n\t\t * The {@link module:utils/locale~Locale#language `Locale#language`} property was deprecated and will\n\t\t * be removed in the near future. Please use the {@link #uiLanguage} and {@link #contentLanguage} properties instead.\n\t\t *\n\t\t * @error locale-deprecated-language-property\n\t\t */\n\t\tconsole.warn(\n\t\t\t'locale-deprecated-language-property: ' +\n\t\t\t'The Locale#language property has been deprecated and will be removed in the near future. ' +\n\t\t\t'Please use #uiLanguage and #contentLanguage properties instead.' );\n\n\t\treturn this.uiLanguage;\n\t}\n\n\t/**\n\t * An unbound version of the {@link #t} method.\n\t *\n\t * @private\n\t * @param {String|module:utils/translation-service~Message} message\n\t * @param {Number|String|Array.<Number|String>} [values]\n\t * @returns {String}\n\t */\n\t_t( message, values = [] ) {\n\t\tvalues = toArray( values );\n\n\t\tif ( typeof message === 'string' ) {\n\t\t\tmessage = { string: message };\n\t\t}\n\n\t\tconst hasPluralForm = !!message.plural;\n\t\tconst quantity = hasPluralForm ? values[ 0 ] : 1;\n\n\t\tconst translatedString = _translate( this.uiLanguage, message, quantity );\n\n\t\treturn interpolateString( translatedString, values );\n\t}\n}\n\n// Fills the `%0, %1, ...` string placeholders with values.\nfunction interpolateString( string, values ) {\n\treturn string.replace( /%(\\d+)/g, ( match, index ) => {\n\t\treturn ( index < values.length ) ? values[ index ] : match;\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/context\n */\n\nimport Config from '@ckeditor/ckeditor5-utils/src/config';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport PluginCollection from './plugincollection';\nimport Locale from '@ckeditor/ckeditor5-utils/src/locale';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Provides a common, higher-level environment for solutions that use multiple {@link module:core/editor/editor~Editor editors}\n * or plugins that work outside the editor. Use it instead of {@link module:core/editor/editor~Editor.create `Editor.create()`}\n * in advanced application integrations.\n *\n * All configuration options passed to a context will be used as default options for editor instances initialized in that context.\n *\n * {@link module:core/contextplugin~ContextPlugin Context plugins} passed to a context instance will be shared among all\n * editor instances initialized in this context. These will be the same plugin instances for all the editors.\n *\n * **Note:** The context can only be initialized with {@link module:core/contextplugin~ContextPlugin context plugins}\n * (e.g. [comments](https://ckeditor.com/collaboration/comments/)). Regular {@link module:core/plugin~Plugin plugins} require an\n * editor instance to work and cannot be added to a context.\n *\n * **Note:** You can add a context plugin to an editor instance, though.\n *\n * If you are using multiple editor instances on one page and use any context plugins, create a context to share the configuration and\n * plugins among these editors. Some plugins will use the information about all existing editors to better integrate between them.\n *\n * If you are using plugins that do not require an editor to work (e.g. [comments](https://ckeditor.com/collaboration/comments/)),\n * enable and configure them using the context.\n *\n * If you are using only a single editor on each page, use {@link module:core/editor/editor~Editor.create `Editor.create()`} instead.\n * In such case, a context instance will be created by the editor instance in a transparent way.\n *\n * See {@link module:core/context~Context.create `Context.create()`} for usage examples.\n */\nexport default class Context {\n\t/**\n\t * Creates a context instance with a given configuration.\n\t *\n\t * Usually not to be used directly. See the static {@link module:core/context~Context.create `create()`} method.\n\t *\n\t * @param {Object} [config={}] The context configuration.\n\t */\n\tconstructor( config ) {\n\t\t/**\n\t\t * Stores all the configurations specific to this context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/config~Config}\n\t\t */\n\t\tthis.config = new Config( config, this.constructor.defaultConfig );\n\n\t\tconst availablePlugins = this.constructor.builtinPlugins;\n\n\t\tthis.config.define( 'plugins', availablePlugins );\n\n\t\t/**\n\t\t * The plugins loaded and in use by this context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:core/plugincollection~PluginCollection}\n\t\t */\n\t\tthis.plugins = new PluginCollection( this, availablePlugins );\n\n\t\tconst languageConfig = this.config.get( 'language' ) || {};\n\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = new Locale( {\n\t\t\tuiLanguage: typeof languageConfig === 'string' ? languageConfig : languageConfig.ui,\n\t\t\tcontentLanguage: this.config.get( 'language.content' )\n\t\t} );\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method #t\n\t\t */\n\t\tthis.t = this.locale.t;\n\n\t\t/**\n\t\t * A list of editors that this context instance is injected to.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.editors = new Collection();\n\n\t\t/**\n\t\t * Reference to the editor which created the context.\n\t\t * Null when the context was created outside of the editor.\n\t\t *\n\t\t * It is used to destroy the context when removing the editor that has created the context.\n\t\t *\n\t\t * @private\n\t\t * @type {module:core/editor/editor~Editor|null}\n\t\t */\n\t\tthis._contextOwner = null;\n\t}\n\n\t/**\n\t * Loads and initializes plugins specified in the configuration.\n\t *\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which resolves\n\t * once the initialization is completed, providing an array of loaded plugins.\n\t */\n\tinitPlugins() {\n\t\tconst plugins = this.config.get( 'plugins' ) || [];\n\t\tconst substitutePlugins = this.config.get( 'substitutePlugins' ) || [];\n\n\t\t// Plugins for substitution should be checked as well.\n\t\tfor ( const Plugin of plugins.concat( substitutePlugins ) ) {\n\t\t\tif ( typeof Plugin != 'function' ) {\n\t\t\t\t/**\n\t\t\t\t * Only a constructor function is allowed as a {@link module:core/contextplugin~ContextPlugin context plugin}.\n\t\t\t\t *\n\t\t\t\t * @error context-initplugins-constructor-only\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'context-initplugins-constructor-only',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ Plugin }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( Plugin.isContextPlugin !== true ) {\n\t\t\t\t/**\n\t\t\t\t * Only a plugin marked as a {@link module:core/contextplugin~ContextPlugin.isContextPlugin context plugin}\n\t\t\t\t * is allowed to be used with a context.\n\t\t\t\t *\n\t\t\t\t * @error context-initplugins-invalid-plugin\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'context-initplugins-invalid-plugin',\n\t\t\t\t\tnull,\n\t\t\t\t\t{ Plugin }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn this.plugins.init( plugins, [], substitutePlugins );\n\t}\n\n\t/**\n\t * Destroys the context instance and all editors used with the context,\n\t * releasing all resources used by the context.\n\t *\n\t * @returns {Promise} A promise that resolves once the context instance is fully destroyed.\n\t */\n\tdestroy() {\n\t\treturn Promise.all( Array.from( this.editors, editor => editor.destroy() ) )\n\t\t\t.then( () => this.plugins.destroy() );\n\t}\n\n\t/**\n\t * Adds a reference to the editor which is used with this context.\n\t *\n\t * When the given editor has created the context, the reference to this editor will be stored\n\t * as a {@link ~Context#_contextOwner}.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Boolean} isContextOwner Stores the given editor as a context owner.\n\t */\n\t_addEditor( editor, isContextOwner ) {\n\t\tif ( this._contextOwner ) {\n\t\t\t/**\n\t\t\t * Cannot add multiple editors to the context which is created by the editor.\n\t\t\t *\n\t\t\t * @error context-addeditor-private-context\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'context-addeditor-private-context' );\n\t\t}\n\n\t\tthis.editors.add( editor );\n\n\t\tif ( isContextOwner ) {\n\t\t\tthis._contextOwner = editor;\n\t\t}\n\t}\n\n\t/**\n\t * Removes a reference to the editor which was used with this context.\n\t * When the context was created by the given editor, the context will be destroyed.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @return {Promise} A promise that resolves once the editor is removed from the context or when the context was destroyed.\n\t */\n\t_removeEditor( editor ) {\n\t\tif ( this.editors.has( editor ) ) {\n\t\t\tthis.editors.remove( editor );\n\t\t}\n\n\t\tif ( this._contextOwner === editor ) {\n\t\t\treturn this.destroy();\n\t\t}\n\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Returns the context configuration which will be copied to the editors created using this context.\n\t *\n\t * The configuration returned by this method has the plugins configuration removed &mdash; plugins are shared with all editors\n\t * through another mechanism.\n\t *\n\t * This method should only be used by the editor.\n\t *\n\t * @protected\n\t * @returns {Object} Configuration as a plain object.\n\t */\n\t_getEditorConfig() {\n\t\tconst result = {};\n\n\t\tfor ( const name of this.config.names() ) {\n\t\t\tif ( ![ 'plugins', 'removePlugins', 'extraPlugins' ].includes( name ) ) {\n\t\t\t\tresult[ name ] = this.config.get( name );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates and initializes a new context instance.\n\t *\n\t *\t\tconst commonConfig = { ... }; // Configuration for all the plugins and editors.\n\t *\t\tconst editorPlugins = [ ... ]; // Regular plugins here.\n\t *\n\t *\t\tContext\n\t *\t\t\t.create( {\n\t *\t\t\t\t// Only context plugins here.\n\t *\t\t\t\tplugins: [ ... ],\n\t *\n\t *\t\t\t\t// Configure the language for all the editors (it cannot be overwritten).\n\t *\t\t\t\tlanguage: { ... },\n\t *\n\t *\t\t\t\t// Configuration for context plugins.\n\t *\t\t\t\tcomments: { ... },\n\t *\t\t\t\t...\n\t *\n\t *\t\t\t\t// Default configuration for editor plugins.\n\t *\t\t\t\ttoolbar: { ... },\n\t *\t\t\t\timage: { ... },\n\t *\t\t\t\t...\n\t *\t\t\t} )\n\t *\t\t\t.then( context => {\n\t *\t\t\t\tconst promises = [];\n\t *\n\t *\t\t\t\tpromises.push( ClassicEditor.create(\n\t *\t\t\t\t\tdocument.getElementById( 'editor1' ),\n\t *\t\t\t\t\t{\n\t *\t\t\t\t\t\teditorPlugins,\n\t *\t\t\t\t\t\tcontext\n\t *\t\t\t\t\t}\n\t *\t\t\t\t) );\n\t *\n\t *\t\t\t\tpromises.push( ClassicEditor.create(\n\t *\t\t\t\t\tdocument.getElementById( 'editor2' ),\n\t *\t\t\t\t\t{\n\t *\t\t\t\t\t\teditorPlugins,\n\t *\t\t\t\t\t\tcontext,\n\t *\t\t\t\t\t\ttoolbar: { ... } // You can overwrite the configuration of the context.\n\t *\t\t\t\t\t}\n\t *\t\t\t\t) );\n\t *\n\t *\t\t\t\treturn Promise.all( promises );\n\t *\t\t\t} );\n\t *\n\t * @param {Object} [config] The context configuration.\n\t * @returns {Promise} A promise resolved once the context is ready. The promise resolves with the created context instance.\n\t */\n\tstatic create( config ) {\n\t\treturn new Promise( resolve => {\n\t\t\tconst context = new this( config );\n\n\t\t\tresolve( context.initPlugins().then( () => context ) );\n\t\t} );\n\t}\n}\n\n/**\n * An array of plugins built into the `Context` class.\n *\n * It is used in CKEditor 5 builds featuring `Context` to provide a list of context plugins which are later automatically initialized\n * during the context initialization.\n *\n * They will be automatically initialized by `Context` unless `config.plugins` is passed.\n *\n *\t\t// Build some context plugins into the Context class first.\n *\t\tContext.builtinPlugins = [ FooPlugin, BarPlugin ];\n *\n *\t\t// Normally, you need to define config.plugins, but since Context.builtinPlugins was\n *\t\t// defined, now you can call create() without any configuration.\n *\t\tContext\n *\t\t\t.create()\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\tcontext.plugins.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n * See also {@link module:core/context~Context.defaultConfig `Context.defaultConfig`}\n * and {@link module:core/editor/editor~Editor.builtinPlugins `Editor.builtinPlugins`}.\n *\n * @static\n * @member {Array.<Function>} module:core/context~Context.builtinPlugins\n */\n\n/**\n * The default configuration which is built into the `Context` class.\n *\n * It is used in CKEditor 5 builds featuring `Context` to provide the default configuration options which are later used during the\n * context initialization.\n *\n *\t\tContext.defaultConfig = {\n *\t\t\tfoo: 1,\n *\t\t\tbar: 2\n *\t\t};\n *\n *\t\tContext\n *\t\t\t.create()\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.config.get( 'foo' ); // -> 1\n *\t\t\t\tcontext.config.get( 'bar' ); // -> 2\n *\t\t\t} );\n *\n *\t\t// The default options can be overridden by the configuration passed to create().\n *\t\tContext\n *\t\t\t.create( { bar: 3 } )\n *\t\t\t.then( context => {\n *\t\t\t\tcontext.config.get( 'foo' ); // -> 1\n *\t\t\t\tcontext.config.get( 'bar' ); // -> 3\n *\t\t\t} );\n *\n * See also {@link module:core/context~Context.builtinPlugins `Context.builtinPlugins`}\n * and {@link module:core/editor/editor~Editor.defaultConfig `Editor.defaultConfig`}.\n *\n * @static\n * @member {Object} module:core/context~Context.defaultConfig\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 core/contextplugin\n */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The base class for {@link module:core/context~Context} plugin classes.\n *\n * A context plugin can either be initialized for an {@link module:core/editor/editor~Editor editor} or for\n * a {@link module:core/context~Context context}. In other words, it can either\n * work within one editor instance or with one or more editor instances that use a single context.\n * It is the context plugin's role to implement handling for both modes.\n *\n * There are a few rules for interaction between the editor plugins and context plugins:\n *\n * * A context plugin can require another context plugin.\n * * An {@link module:core/plugin~Plugin editor plugin} can require a context plugin.\n * * A context plugin MUST NOT require an {@link module:core/plugin~Plugin editor plugin}.\n *\n * @implements module:core/plugin~PluginInterface\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ContextPlugin {\n\t/**\n\t * Creates a new plugin instance.\n\t *\n\t * @param {module:core/context~Context|module:core/editor/editor~Editor} context\n\t */\n\tconstructor( context ) {\n\t\t/**\n\t\t * The context instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:core/context~Context|module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.context = context;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get isContextPlugin() {\n\t\treturn true;\n\t}\n}\n\nmix( ContextPlugin, ObservableMixin );\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 utils/comparearrays\n */\n\n/**\n * Compares how given arrays relate to each other. One array can be: same as another array, prefix of another array\n * or completely different. If arrays are different, first index at which they differ is returned. Otherwise,\n * a flag specifying the relation is returned. Flags are negative numbers, so whenever a number >= 0 is returned\n * it means that arrays differ.\n *\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 2 ] );\t\t// 'same'\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 2, 1 ] );\t\t// 'prefix'\n *\t\tcompareArrays( [ 0, 2 ], [ 0 ] );\t\t\t// 'extension'\n *\t\tcompareArrays( [ 0, 2 ], [ 1, 2 ] );\t\t// 0\n *\t\tcompareArrays( [ 0, 2 ], [ 0, 1 ] );\t\t// 1\n *\n * @param {Array} a Array that is compared.\n * @param {Array} b Array to compare with.\n * @returns {module:utils/comparearrays~ArrayRelation} How array `a` is related to `b`.\n */\nexport default function compareArrays( a, b ) {\n\tconst minLen = Math.min( a.length, b.length );\n\n\tfor ( let i = 0; i < minLen; i++ ) {\n\t\tif ( a[ i ] != b[ i ] ) {\n\t\t\t// The arrays are different.\n\t\t\treturn i;\n\t\t}\n\t}\n\n\t// Both arrays were same at all points.\n\tif ( a.length == b.length ) {\n\t\t// If their length is also same, they are the same.\n\t\treturn 'same';\n\t} else if ( a.length < b.length ) {\n\t\t// Compared array is shorter so it is a prefix of the other array.\n\t\treturn 'prefix';\n\t} else {\n\t\t// Compared array is longer so it is an extension of the other array.\n\t\treturn 'extension';\n\t}\n}\n\n/**\n * @typedef {'extension'|'same'|'prefix'} module:utils/comparearrays~ArrayRelation\n */\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * Creates a shallow clone of `value`.\n *\n * **Note:** This method is loosely based on the\n * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)\n * and supports cloning arrays, array buffers, booleans, date objects, maps,\n * numbers, `Object` objects, regexes, sets, strings, symbols, and typed\n * arrays. The own enumerable properties of `arguments` objects are cloned\n * as plain objects. An empty object is returned for uncloneable values such\n * as error objects, functions, DOM nodes, and WeakMaps.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to clone.\n * @returns {*} Returns the cloned value.\n * @see _.cloneDeep\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var shallow = _.clone(objects);\n * console.log(shallow[0] === objects[0]);\n * // => true\n */\nfunction clone(value) {\n return baseClone(value, CLONE_SYMBOLS_FLAG);\n}\n\nexport default clone;\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/view/node\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport { clone } from 'lodash-es';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Abstract view node class.\n *\n * This is an abstract class. Its constructor should not be used directly.\n * Use the {@link module:engine/view/downcastwriter~DowncastWriter} or {@link module:engine/view/upcastwriter~UpcastWriter}\n * to create new instances of view nodes.\n *\n * @abstract\n */\nexport default class Node {\n\t/**\n\t * Creates a tree view node.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this node belongs.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * The document instance to which this node belongs.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Parent element. Null by default. Set by {@link module:engine/view/element~Element#_insertChild}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t\t */\n\t\tthis.parent = null;\n\t}\n\n\t/**\n\t * Index of the node in the parent element or null if the node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that view tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget index() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// No parent or child doesn't exist in parent's children.\n\t\tif ( ( pos = this.parent.getChildIndex( this ) ) == -1 ) {\n\t\t\t/**\n\t\t\t * The node's parent does not contain this node. It means that the document tree is corrupted.\n\t\t\t *\n\t\t\t * @error view-node-not-found-in-parent\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-node-not-found-in-parent', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Node's next sibling, or `null` if it is the last child.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nextSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index + 1 ) ) || null;\n\t}\n\n\t/**\n\t * Node's previous sibling, or `null` if it is the first child.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget previousSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index - 1 ) ) || null;\n\t}\n\n\t/**\n\t * Top-most ancestor of the node. If the node has no parent it is the root itself.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\tlet root = this; // eslint-disable-line consistent-this\n\n\t\twhile ( root.parent ) {\n\t\t\troot = root.parent;\n\t\t}\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).\n\t *\n\t * @returns {Boolean}\n\t */\n\tisAttached() {\n\t\treturn this.root.is( 'rootElement' );\n\t}\n\n\t/**\n\t * Gets a path to the node. The path is an array containing indices of consecutive ancestors of this node,\n\t * beginning from {@link module:engine/view/node~Node#root root}, down to this node's index.\n\t *\n\t *\t\tconst abc = downcastWriter.createText( 'abc' );\n\t *\t\tconst foo = downcastWriter.createText( 'foo' );\n\t *\t\tconst h1 = downcastWriter.createElement( 'h1', null, downcastWriter.createText( 'header' ) );\n\t *\t\tconst p = downcastWriter.createElement( 'p', null, [ abc, foo ] );\n\t *\t\tconst div = downcastWriter.createElement( 'div', null, [ h1, p ] );\n\t *\t\tfoo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.\n\t *\t\th1.getPath(); // Returns [ 0 ].\n\t *\t\tdiv.getPath(); // Returns [].\n\t *\n\t * @returns {Array.<Number>} The path.\n\t */\n\tgetPath() {\n\t\tconst path = [];\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\twhile ( node.parent ) {\n\t\t\tpath.unshift( node.index );\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this node.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from node's parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/element~Element} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both nodes.\n\t *\n\t * @param {module:engine/view/node~Node} node The second node.\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` both nodes will be considered \"ancestors\" too.\n\t * Which means that if e.g. node A is inside B, then their common ancestor will be B.\n\t * @returns {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( node, options = {} ) {\n\t\tconst ancestorsA = this.getAncestors( options );\n\t\tconst ancestorsB = node.getAncestors( options );\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/view/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/view/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisBefore( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisPath = this.getPath();\n\t\tconst nodePath = node.getPath();\n\n\t\tconst result = compareArrays( thisPath, nodePath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn true;\n\n\t\t\tcase 'extension':\n\t\t\t\treturn false;\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < nodePath[ result ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/view/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/view/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisAfter( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// In other cases, just check if the `node` is before, and return the opposite.\n\t\treturn !this.isBefore( node );\n\t}\n\n\t/**\n\t * Removes node from parent.\n\t *\n\t * @protected\n\t */\n\t_remove() {\n\t\tthis.parent._removeChildren( this.index );\n\t}\n\n\t/**\n\t * @protected\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Changed node.\n\t * @fires change\n\t */\n\t_fireChange( type, node ) {\n\t\tthis.fire( 'change:' + type, node );\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._fireChange( type, node );\n\t\t}\n\t}\n\n\t/**\n\t * Custom toJSON method to solve child-parent circular dependencies.\n\t *\n\t * @returns {Object} Clone of this object with the parent property removed.\n\t */\n\ttoJSON() {\n\t\tconst json = clone( this );\n\n\t\t// Due to circular references we need to remove parent reference.\n\t\tdelete json.parent;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t * This method is useful when processing view objects that are of unknown type. For example, a function\n\t * may return a {@link module:engine/view/documentfragment~DocumentFragment} or a {@link module:engine/view/node~Node}\n\t * that can be either a text node or an element. This method can be used to check what kind of object is returned.\n\t *\n\t *\t\tsomeObject.is( 'element' ); // -> true if this is an element\n\t *\t\tsomeObject.is( 'node' ); // -> true if this is a node (a text node or an element)\n\t *\t\tsomeObject.is( 'documentFragment' ); // -> true if this is a document fragment\n\t *\n\t * Since this method is also available on a range of model objects, you can prefix the type of the object with\n\t * `model:` or `view:` to check, for example, if this is the model's or view's element:\n\t *\n\t *\t\tviewElement.is( 'view:element' ); // -> true\n\t *\t\tviewElement.is( 'model:element' ); // -> false\n\t *\n\t * By using this method it is also possible to check a name of an element:\n\t *\n\t *\t\timgElement.is( 'element', 'img' ); // -> true\n\t *\t\timgElement.is( 'view:element', 'img' ); // -> same as above, but more precise\n\t *\n\t * The list of view objects which implement the `is()` method:\n\t *\n\t * * {@link module:engine/view/attributeelement~AttributeElement#is `AttributeElement#is()`}\n\t * * {@link module:engine/view/containerelement~ContainerElement#is `ContainerElement#is()`}\n\t * * {@link module:engine/view/documentfragment~DocumentFragment#is `DocumentFragment#is()`}\n\t * * {@link module:engine/view/documentselection~DocumentSelection#is `DocumentSelection#is()`}\n\t * * {@link module:engine/view/editableelement~EditableElement#is `EditableElement#is()`}\n\t * * {@link module:engine/view/element~Element#is `Element#is()`}\n\t * * {@link module:engine/view/emptyelement~EmptyElement#is `EmptyElement#is()`}\n\t * * {@link module:engine/view/node~Node#is `Node#is()`}\n\t * * {@link module:engine/view/position~Position#is `Position#is()`}\n\t * * {@link module:engine/view/range~Range#is `Range#is()`}\n\t * * {@link module:engine/view/rooteditableelement~RootEditableElement#is `RootEditableElement#is()`}\n\t * * {@link module:engine/view/selection~Selection#is `Selection#is()`}\n\t * * {@link module:engine/view/text~Text#is `Text#is()`}\n\t * * {@link module:engine/view/textproxy~TextProxy#is `TextProxy#is()`}\n\t * * {@link module:engine/view/uielement~UIElement#is `UIElement#is()`}\n\t *\n\t * @method #is\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'node' || type === 'view:node';\n\t}\n\n\t/**\n\t * Clones this node.\n\t *\n\t * @protected\n\t * @method #_clone\n\t * @returns {module:engine/view/node~Node} Clone of this node.\n\t */\n\n\t/**\n\t * Checks if provided node is similar to this node.\n\t *\n\t * @method #isSimilar\n\t * @returns {Boolean} True if nodes are similar.\n\t */\n}\n\n/**\n * Fired when list of {@link module:engine/view/element~Element elements} children changes.\n *\n * Change event is bubbled it is fired on all ancestors.\n *\n * @event change:children\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * Fired when list of {@link module:engine/view/element~Element elements} attributes changes.\n *\n * Change event is bubbled it is fired on all ancestors.\n *\n * @event change:attributes\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * Fired when {@link module:engine/view/text~Text text nodes} data changes.\n *\n * Change event is bubbled it is fired on all ancestors.\n *\n * @event change:text\n * @param {module:engine/view/node~Node} changedNode\n */\n\n/**\n * @event change\n */\n\nmix( Node, EmitterMixin );\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/view/text\n */\n\nimport Node from './node';\n\n/**\n * Tree view text node.\n *\n * The constructor of this class should not be used directly. To create a new text node instance\n * use the {@link module:engine/view/downcastwriter~DowncastWriter#createText `DowncastWriter#createText()`}\n * method when working on data downcasted from the model or the\n * {@link module:engine/view/upcastwriter~UpcastWriter#createText `UpcastWriter#createText()`}\n * method when working on non-semantic views.\n *\n * @extends module:engine/view/node~Node\n */\nexport default class Text extends Node {\n\t/**\n\t * Creates a tree view text node.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this text node belongs.\n\t * @param {String} data The text's data.\n\t */\n\tconstructor( document, data ) {\n\t\tsuper( document );\n\n\t\t/**\n\t\t * The text content.\n\t\t *\n\t\t * Setting the data fires the {@link module:engine/view/node~Node#event:change:text change event}.\n\t\t *\n\t\t * @protected\n\t\t * @member {String} module:engine/view/text~Text#_textData\n\t\t */\n\t\tthis._textData = data;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\ttext.is( '$text' ); // -> true\n\t *\t\ttext.is( 'node' ); // -> true\n\t *\t\ttext.is( 'view:$text' ); // -> true\n\t *\t\ttext.is( 'view:node' ); // -> true\n\t *\n\t *\t\ttext.is( 'model:$text' ); // -> false\n\t *\t\ttext.is( 'element' ); // -> false\n\t *\t\ttext.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$text'` type. The legacy `'text'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$text' || type === 'view:$text' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'text' || type === 'view:text' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'node' || type === 'view:node';\n\t}\n\n\t/**\n\t * The text content.\n\t *\n\t * @readonly\n\t * @type {String}\n\t */\n\tget data() {\n\t\treturn this._textData;\n\t}\n\n\t/**\n\t * The `_data` property is controlled by a getter and a setter.\n\t *\n\t * The getter is required when using the addition assignment operator on protected property:\n\t *\n\t *\t\tconst foo = downcastWriter.createText( 'foo' );\n\t *\t\tconst bar = downcastWriter.createText( 'bar' );\n\t *\n\t *\t\tfoo._data += bar.data; // executes: `foo._data = foo._data + bar.data`\n\t *\t\tconsole.log( foo.data ); // prints: 'foobar'\n\t *\n\t * If the protected getter didn't exist, `foo._data` will return `undefined` and result of the merge will be invalid.\n\t *\n\t * The setter sets data and fires the {@link module:engine/view/node~Node#event:change:text change event}.\n\t *\n\t * @protected\n\t * @type {String}\n\t */\n\tget _data() {\n\t\treturn this.data;\n\t}\n\n\tset _data( data ) {\n\t\tthis._fireChange( 'text', this );\n\n\t\tthis._textData = data;\n\t}\n\n\t/**\n\t * Checks if this text node is similar to other text node.\n\t * Both nodes should have the same data to be considered as similar.\n\t *\n\t * @param {module:engine/view/text~Text} otherNode Node to check if it is same as this node.\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherNode ) {\n\t\tif ( !( otherNode instanceof Text ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this === otherNode || this.data === otherNode.data;\n\t}\n\n\t/**\n\t * Clones this node.\n\t *\n\t * @protected\n\t * @returns {module:engine/view/text~Text} Text node that is a clone of this node.\n\t */\n\t_clone() {\n\t\treturn new Text( this.document, this.data );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/textproxy\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * TextProxy is a wrapper for substring of {@link module:engine/view/text~Text}. Instance of this class is created by\n * {@link module:engine/view/treewalker~TreeWalker} when only a part of {@link module:engine/view/text~Text} needs to be returned.\n *\n * `TextProxy` has an API similar to {@link module:engine/view/text~Text Text} and allows to do most of the common tasks performed\n * on view nodes.\n *\n * **Note:** Some `TextProxy` instances may represent whole text node, not just a part of it.\n * See {@link module:engine/view/textproxy~TextProxy#isPartial}.\n *\n * **Note:** `TextProxy` is a readonly interface.\n *\n * **Note:** `TextProxy` instances are created on the fly basing on the current state of parent {@link module:engine/view/text~Text}.\n * Because of this it is highly unrecommended to store references to `TextProxy instances because they might get\n * invalidated due to operations on Document. Also TextProxy is not a {@link module:engine/view/node~Node} so it can not be\n * inserted as a child of {@link module:engine/view/element~Element}.\n *\n * `TextProxy` instances are created by {@link module:engine/view/treewalker~TreeWalker view tree walker}. You should not need to create\n * an instance of this class by your own.\n */\nexport default class TextProxy {\n\t/**\n\t * Creates a text proxy.\n\t *\n\t * @protected\n\t * @param {module:engine/view/text~Text} textNode Text node which part is represented by this text proxy.\n\t * @param {Number} offsetInText Offset in {@link module:engine/view/textproxy~TextProxy#textNode text node}\n\t * from which the text proxy starts.\n\t * @param {Number} length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.\n\t * @constructor\n\t */\n\tconstructor( textNode, offsetInText, length ) {\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/text~Text} element which TextProxy is a substring.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/text~Text} module:engine/view/textproxy~TextProxy#textNode\n\t\t */\n\t\tthis.textNode = textNode;\n\n\t\tif ( offsetInText < 0 || offsetInText > textNode.data.length ) {\n\t\t\t/**\n\t\t\t * Given offsetInText value is incorrect.\n\t\t\t *\n\t\t\t * @error view-textproxy-wrong-offsetintext\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-textproxy-wrong-offsetintext', this );\n\t\t}\n\n\t\tif ( length < 0 || offsetInText + length > textNode.data.length ) {\n\t\t\t/**\n\t\t\t * Given length value is incorrect.\n\t\t\t *\n\t\t\t * @error view-textproxy-wrong-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-textproxy-wrong-length', this );\n\t\t}\n\n\t\t/**\n\t\t * Text data represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:engine/view/textproxy~TextProxy#data\n\t\t */\n\t\tthis.data = textNode.data.substring( offsetInText, offsetInText + length );\n\n\t\t/**\n\t\t * Offset in the `textNode` where this `TextProxy` instance starts.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} module:engine/view/textproxy~TextProxy#offsetInText\n\t\t */\n\t\tthis.offsetInText = offsetInText;\n\t}\n\n\t/**\n\t * Offset size of this node.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/view/text~Text text node}\n\t * (`true`) or the whole text node (`false`).\n\t *\n\t * This is `false` when text proxy starts at the very beginning of {@link module:engine/view/textproxy~TextProxy#textNode textNode}\n\t * ({@link module:engine/view/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to\n\t * text node size.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isPartial() {\n\t\treturn this.data.length !== this.textNode.data.length;\n\t}\n\n\t/**\n\t * Parent of this text proxy, which is same as parent of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tget parent() {\n\t\treturn this.textNode.parent;\n\t}\n\n\t/**\n\t * Root of this text proxy, which is same as root of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.textNode.root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/document~Document View document} that owns this text proxy, or `null` if the text proxy is inside\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this.textNode.document;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\ttextProxy.is( '$textProxy' ); // -> true\n\t *\t\ttextProxy.is( 'view:$textProxy' ); // -> true\n\t *\n\t *\t\ttextProxy.is( 'model:$textProxy' ); // -> false\n\t *\t\ttextProxy.is( 'element' ); // -> false\n\t *\t\ttextProxy.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$textProxy'` type. The legacy `'textProxy'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$textProxy' || type === 'view:$textProxy' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'textProxy' || type === 'view:textProxy';\n\t}\n\n\t/**\n\t * Returns ancestors array of this text proxy.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` {#textNode} will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from text proxy parent to\n\t * root element, otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this.textNode : this.parent;\n\n\t\twhile ( parent !== null ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ViewTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/tomap\n */\n\nimport objectToMap from './objecttomap';\nimport isIterable from './isiterable';\n\n/**\n * Transforms object or iterable to map. Iterable needs to be in the format acceptable by the `Map` constructor.\n *\n *\t\tmap = toMap( { 'foo': 1, 'bar': 2 } );\n *\t\tmap = toMap( [ [ 'foo', 1 ], [ 'bar', 2 ] ] );\n *\t\tmap = toMap( anotherMap );\n *\n * @param {Object|Iterable} data Object or iterable to transform.\n * @returns {Map} Map created from data.\n */\nexport default function toMap( data ) {\n\tif ( isIterable( data ) ) {\n\t\treturn new Map( data );\n\t} else {\n\t\treturn objectToMap( data );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/objecttomap\n */\n\n/**\n * Transforms object to map.\n *\n *\t\tconst map = objectToMap( { 'foo': 1, 'bar': 2 } );\n *\t\tmap.get( 'foo' ); // 1\n *\n * **Note**: For mixed data (`Object` or `Iterable`) there's a dedicated {@link module:utils/tomap~toMap} function.\n *\n * @param {Object} obj Object to transform.\n * @returns {Map} Map created from object.\n */\nexport default function objectToMap( obj ) {\n\tconst map = new Map();\n\n\tfor ( const key in obj ) {\n\t\tmap.set( key, obj[ key ] );\n\t}\n\n\treturn map;\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/view/matcher\n */\n\n/**\n * View matcher class.\n * Instance of this class can be used to find {@link module:engine/view/element~Element elements} that match given pattern.\n */\nexport default class Matcher {\n\t/**\n\t * Creates new instance of Matcher.\n\t *\n\t * @param {String|RegExp|Object} [pattern] Match patterns. See {@link module:engine/view/matcher~Matcher#add add method} for\n\t * more information.\n\t */\n\tconstructor( ...pattern ) {\n\t\t/**\n\t\t * @private\n\t\t * @type {Array<String|RegExp|Object>}\n\t\t */\n\t\tthis._patterns = [];\n\n\t\tthis.add( ...pattern );\n\t}\n\n\t/**\n\t * Adds pattern or patterns to matcher instance.\n\t *\n\t *\t\t// String.\n\t *\t\tmatcher.add( 'div' );\n\t *\n\t *\t\t// Regular expression.\n\t *\t\tmatcher.add( /^\\w/ );\n\t *\n\t *\t\t// Single class.\n\t *\t\tmatcher.add( {\n\t *\t\t\tclasses: 'foobar'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/view/matcher~MatcherPattern} for more examples.\n\t *\n\t * Multiple patterns can be added in one call:\n\t *\n\t * \t\tmatcher.add( 'div', { classes: 'foobar' } );\n\t *\n\t * @param {Object|String|RegExp|Function} pattern Object describing pattern details. If string or regular expression\n\t * is provided it will be used to match element's name. Pattern can be also provided in a form\n\t * of a function - then this function will be called with each {@link module:engine/view/element~Element element} as a parameter.\n\t * Function's return value will be stored under `match` key of the object returned from\n\t * {@link module:engine/view/matcher~Matcher#match match} or {@link module:engine/view/matcher~Matcher#matchAll matchAll} methods.\n\t * @param {String|RegExp} [pattern.name] Name or regular expression to match element's name.\n\t * @param {Object} [pattern.attributes] Object with key-value pairs representing attributes to match. Each object key\n\t * represents attribute name. Value under that key can be either:\n\t * * `true` - then attribute is just required (can be empty),\n\t * * a string - then attribute has to be equal, or\n\t * * a regular expression - then attribute has to match the expression.\n\t * @param {String|RegExp|Array} [pattern.classes] Class name or array of class names to match. Each name can be\n\t * provided in a form of string or regular expression.\n\t * @param {Object} [pattern.styles] Object with key-value pairs representing styles to match. Each object key\n\t * represents style name. Value under that key can be either a string or a regular expression and it will be used\n\t * to match style value.\n\t */\n\tadd( ...pattern ) {\n\t\tfor ( let item of pattern ) {\n\t\t\t// String or RegExp pattern is used as element's name.\n\t\t\tif ( typeof item == 'string' || item instanceof RegExp ) {\n\t\t\t\titem = { name: item };\n\t\t\t}\n\n\t\t\t// Single class name/RegExp can be provided.\n\t\t\tif ( item.classes && ( typeof item.classes == 'string' || item.classes instanceof RegExp ) ) {\n\t\t\t\titem.classes = [ item.classes ];\n\t\t\t}\n\n\t\t\tthis._patterns.push( item );\n\t\t}\n\t}\n\n\t/**\n\t * Matches elements for currently stored patterns. Returns match information about first found\n\t * {@link module:engine/view/element~Element element}, otherwise returns `null`.\n\t *\n\t * Example of returned object:\n\t *\n\t *\t\t{\n\t *\t\t\telement: <instance of found element>,\n\t *\t\t\tpattern: <pattern used to match found element>,\n\t *\t\t\tmatch: {\n\t *\t\t\t\tname: true,\n\t *\t\t\t\tattributes: [ 'title', 'href' ],\n\t *\t\t\t\tclasses: [ 'foo' ],\n\t *\t\t\t\tstyles: [ 'color', 'position' ]\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * @see module:engine/view/matcher~Matcher#add\n\t * @see module:engine/view/matcher~Matcher#matchAll\n\t * @param {...module:engine/view/element~Element} element View element to match against stored patterns.\n\t * @returns {Object|null} result\n\t * @returns {module:engine/view/element~Element} result.element Matched view element.\n\t * @returns {Object|String|RegExp|Function} result.pattern Pattern that was used to find matched element.\n\t * @returns {Object} result.match Object representing matched element parts.\n\t * @returns {Boolean} [result.match.name] True if name of the element was matched.\n\t * @returns {Array} [result.match.attributes] Array with matched attribute names.\n\t * @returns {Array} [result.match.classes] Array with matched class names.\n\t * @returns {Array} [result.match.styles] Array with matched style names.\n\t */\n\tmatch( ...element ) {\n\t\tfor ( const singleElement of element ) {\n\t\t\tfor ( const pattern of this._patterns ) {\n\t\t\t\tconst match = isElementMatching( singleElement, pattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\telement: singleElement,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tmatch\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Matches elements for currently stored patterns. Returns array of match information with all found\n\t * {@link module:engine/view/element~Element elements}. If no element is found - returns `null`.\n\t *\n\t * @see module:engine/view/matcher~Matcher#add\n\t * @see module:engine/view/matcher~Matcher#match\n\t * @param {...module:engine/view/element~Element} element View element to match against stored patterns.\n\t * @returns {Array.<Object>|null} Array with match information about found elements or `null`. For more information\n\t * see {@link module:engine/view/matcher~Matcher#match match method} description.\n\t */\n\tmatchAll( ...element ) {\n\t\tconst results = [];\n\n\t\tfor ( const singleElement of element ) {\n\t\t\tfor ( const pattern of this._patterns ) {\n\t\t\t\tconst match = isElementMatching( singleElement, pattern );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\tresults.push( {\n\t\t\t\t\t\telement: singleElement,\n\t\t\t\t\t\tpattern,\n\t\t\t\t\t\tmatch\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn results.length > 0 ? results : null;\n\t}\n\n\t/**\n\t * Returns the name of the element to match if there is exactly one pattern added to the matcher instance\n\t * and it matches element name defined by `string` (not `RegExp`). Otherwise, returns `null`.\n\t *\n\t * @returns {String|null} Element name trying to match.\n\t */\n\tgetElementName() {\n\t\tif ( this._patterns.length !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst pattern = this._patterns[ 0 ];\n\t\tconst name = pattern.name;\n\n\t\treturn ( typeof pattern != 'function' && name && !( name instanceof RegExp ) ) ? name : null;\n\t}\n}\n\n// Returns match information if {@link module:engine/view/element~Element element} is matching provided pattern.\n// If element cannot be matched to provided pattern - returns `null`.\n//\n// @param {module:engine/view/element~Element} element\n// @param {Object|String|RegExp|Function} pattern\n// @returns {Object|null} Returns object with match information or null if element is not matching.\nfunction isElementMatching( element, pattern ) {\n\t// If pattern is provided as function - return result of that function;\n\tif ( typeof pattern == 'function' ) {\n\t\treturn pattern( element );\n\t}\n\n\tconst match = {};\n\t// Check element's name.\n\tif ( pattern.name ) {\n\t\tmatch.name = matchName( pattern.name, element.name );\n\n\t\tif ( !match.name ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Check element's attributes.\n\tif ( pattern.attributes ) {\n\t\tmatch.attributes = matchAttributes( pattern.attributes, element );\n\n\t\tif ( !match.attributes ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// Check element's classes.\n\tif ( pattern.classes ) {\n\t\tmatch.classes = matchClasses( pattern.classes, element );\n\n\t\tif ( !match.classes ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Check element's styles.\n\tif ( pattern.styles ) {\n\t\tmatch.styles = matchStyles( pattern.styles, element );\n\n\t\tif ( !match.styles ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if name can be matched by provided pattern.\n//\n// @param {String|RegExp} pattern\n// @param {String} name\n// @returns {Boolean} Returns `true` if name can be matched, `false` otherwise.\nfunction matchName( pattern, name ) {\n\t// If pattern is provided as RegExp - test against this regexp.\n\tif ( pattern instanceof RegExp ) {\n\t\treturn pattern.test( name );\n\t}\n\n\treturn pattern === name;\n}\n\n// Checks if attributes of provided element can be matched against provided patterns.\n//\n// @param {Object} patterns Object with information about attributes to match. Each key of the object will be\n// used as attribute name. Value of each key can be a string or regular expression to match against attribute value.\n// @param {module:engine/view/element~Element} element Element which attributes will be tested.\n// @returns {Array|null} Returns array with matched attribute names or `null` if no attributes were matched.\nfunction matchAttributes( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const name in patterns ) {\n\t\tconst pattern = patterns[ name ];\n\n\t\tif ( element.hasAttribute( name ) ) {\n\t\t\tconst attribute = element.getAttribute( name );\n\n\t\t\tif ( pattern === true ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else if ( pattern instanceof RegExp ) {\n\t\t\t\tif ( pattern.test( attribute ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else if ( attribute === pattern ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if classes of provided element can be matched against provided patterns.\n//\n// @param {Array.<String|RegExp>} patterns Array of strings or regular expressions to match against element's classes.\n// @param {module:engine/view/element~Element} element Element which classes will be tested.\n// @returns {Array|null} Returns array with matched class names or `null` if no classes were matched.\nfunction matchClasses( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const pattern of patterns ) {\n\t\tif ( pattern instanceof RegExp ) {\n\t\t\tconst classes = element.getClassNames();\n\n\t\t\tfor ( const name of classes ) {\n\t\t\t\tif ( pattern.test( name ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( match.length === 0 ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else if ( element.hasClass( pattern ) ) {\n\t\t\tmatch.push( pattern );\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n// Checks if styles of provided element can be matched against provided patterns.\n//\n// @param {Object} patterns Object with information about styles to match. Each key of the object will be\n// used as style name. Value of each key can be a string or regular expression to match against style value.\n// @param {module:engine/view/element~Element} element Element which styles will be tested.\n// @returns {Array|null} Returns array with matched style names or `null` if no styles were matched.\nfunction matchStyles( patterns, element ) {\n\tconst match = [];\n\n\tfor ( const name in patterns ) {\n\t\tconst pattern = patterns[ name ];\n\n\t\tif ( element.hasStyle( name ) ) {\n\t\t\tconst style = element.getStyle( name );\n\n\t\t\tif ( pattern instanceof RegExp ) {\n\t\t\t\tif ( pattern.test( style ) ) {\n\t\t\t\t\tmatch.push( name );\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else if ( style === pattern ) {\n\t\t\t\tmatch.push( name );\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn match;\n}\n\n/**\n * An entity that is a valid pattern recognized by a matcher. `MatcherPattern` is used by {@link ~Matcher} to recognize\n * if a view element fits in a group of view elements described by the pattern.\n *\n * `MatcherPattern` can be given as a `String`, a `RegExp`, an `Object` or a `Function`.\n *\n * If `MatcherPattern` is given as a `String` or `RegExp`, it will match any view element that has a matching name:\n *\n *\t\t// Match any element with name equal to 'div'.\n *\t\tconst pattern = 'div';\n *\n *\t\t// Match any element which name starts on 'p'.\n *\t\tconst pattern = /^p/;\n *\n * If `MatcherPattern` is given as an `Object`, all the object's properties will be matched with view element properties.\n *\n *\t\t// Match view element's name.\n *\t\tconst pattern = { name: /^p/ };\n *\n *\t\t// Match view element which has matching attributes.\n *\t\tconst pattern = {\n *\t\t\tattributes: {\n *\t\t\t\ttitle: 'foobar',\t// Attribute title should equal 'foobar'.\n *\t\t\t\tfoo: /^\\w+/,\t\t// Attribute foo should match /^\\w+/ regexp.\n *\t\t\t\tbar: true\t\t\t// Attribute bar should be set (can be empty).\n *\t\t\t}\n *\t\t};\n *\n *\t\t// Match view element which has given class.\n *\t\tconst pattern = {\n *\t\t\tclasses: 'foobar'\n *\t\t};\n *\n *\t\t// Match view element class using regular expression.\n *\t\tconst pattern = {\n *\t\t\tclasses: /foo.../\n *\t\t};\n *\n *\t\t// Multiple classes to match.\n *\t\tconst pattern = {\n *\t\t\tclasses: [ 'baz', 'bar', /foo.../ ]\n *\t\t};\n *\n *\t\t// Match view element which has given styles.\n *\t\tconst pattern = {\n *\t\t\tstyles: {\n *\t\t\t\tposition: 'absolute',\n *\t\t\t\tcolor: /^\\w*blue$/\n *\t\t\t}\n *\t\t};\n *\n *\t\t// Pattern with multiple properties.\n *\t\tconst pattern = {\n *\t\t\tname: 'span',\n *\t\t\tstyles: {\n *\t\t\t\t'font-weight': 'bold'\n *\t\t\t},\n *\t\t\tclasses: 'highlighted'\n *\t\t};\n *\n * If `MatcherPattern` is given as a `Function`, the function takes a view element as a first and only parameter and\n * the function should decide whether that element matches. If so, it should return what part of the view element has been matched.\n * Otherwise, the function should return `null`. The returned result will be included in `match` property of the object\n * returned by {@link ~Matcher#match} call.\n *\n *\t\t// Match an empty <div> element.\n *\t\tconst pattern = element => {\n *\t\t\tif ( element.name == 'div' && element.childCount > 0 ) {\n *\t\t\t\t// Return which part of the element was matched.\n *\t\t\t\treturn { name: true };\n *\t\t\t}\n *\n *\t\t\treturn null;\n *\t\t};\n *\n *\t\t// Match a <p> element with big font (\"heading-like\" element).\n *\t\tconst pattern = element => {\n *\t\t\tif ( element.name == 'p' ) {\n *\t\t\t\tconst fontSize = element.getStyle( 'font-size' );\n *\t\t\t\tconst size = fontSize.match( /(\\d+)/px );\n *\n *\t\t\t\tif ( size && Number( size[ 1 ] ) > 26 ) {\n *\t\t\t\t\treturn { name: true, attribute: [ 'font-size' ] };\n *\t\t\t\t}\n *\t\t\t}\n *\n *\t\t\treturn null;\n *\t\t};\n *\n * `MatcherPattern` is defined in a way that it is a superset of {@link module:engine/view/elementdefinition~ElementDefinition},\n * that is, every `ElementDefinition` also can be used as a `MatcherPattern`.\n *\n * @typedef {String|RegExp|Object|Function} module:engine/view/matcher~MatcherPattern\n *\n * @property {String|RegExp} [name] View element name to match.\n * @property {String|RegExp|Array.<String|RegExp>} [classes] View element's class name(s) to match.\n * @property {Object} [styles] Object with key-value pairs representing styles to match.\n * Each object key represents style name. Value can be given as `String` or `RegExp`.\n * @property {Object} [attributes] Object with key-value pairs representing attributes to match.\n * Each object key represents attribute name. Value can be given as `String` or `RegExp`.\n */\n","import baseGetTag from './_baseGetTag.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar symbolTag = '[object Symbol]';\n\n/**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\nfunction isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n}\n\nexport default isSymbol;\n","import isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used to match property names within property paths. */\nvar reIsDeepProp = /\\.|\\[(?:[^[\\]]*|([\"'])(?:(?!\\1)[^\\\\]|\\\\.)*?\\1)\\]/,\n reIsPlainProp = /^\\w*$/;\n\n/**\n * Checks if `value` is a property name and not a property path.\n *\n * @private\n * @param {*} value The value to check.\n * @param {Object} [object] The object to query keys on.\n * @returns {boolean} Returns `true` if `value` is a property name, else `false`.\n */\nfunction isKey(value, object) {\n if (isArray(value)) {\n return false;\n }\n var type = typeof value;\n if (type == 'number' || type == 'symbol' || type == 'boolean' ||\n value == null || isSymbol(value)) {\n return true;\n }\n return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||\n (object != null && value in Object(object));\n}\n\nexport default isKey;\n","import MapCache from './_MapCache.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a function that memoizes the result of `func`. If `resolver` is\n * provided, it determines the cache key for storing the result based on the\n * arguments provided to the memoized function. By default, the first argument\n * provided to the memoized function is used as the map cache key. The `func`\n * is invoked with the `this` binding of the memoized function.\n *\n * **Note:** The cache is exposed as the `cache` property on the memoized\n * function. Its creation may be customized by replacing the `_.memoize.Cache`\n * constructor with one whose instances implement the\n * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)\n * method interface of `clear`, `delete`, `get`, `has`, and `set`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to have its output memoized.\n * @param {Function} [resolver] The function to resolve the cache key.\n * @returns {Function} Returns the new memoized function.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n * var other = { 'c': 3, 'd': 4 };\n *\n * var values = _.memoize(_.values);\n * values(object);\n * // => [1, 2]\n *\n * values(other);\n * // => [3, 4]\n *\n * object.a = 2;\n * values(object);\n * // => [1, 2]\n *\n * // Modify the result cache.\n * values.cache.set(object, ['a', 'b']);\n * values(object);\n * // => ['a', 'b']\n *\n * // Replace `_.memoize.Cache`.\n * _.memoize.Cache = WeakMap;\n */\nfunction memoize(func, resolver) {\n if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n var memoized = function() {\n var args = arguments,\n key = resolver ? resolver.apply(this, args) : args[0],\n cache = memoized.cache;\n\n if (cache.has(key)) {\n return cache.get(key);\n }\n var result = func.apply(this, args);\n memoized.cache = cache.set(key, result) || cache;\n return result;\n };\n memoized.cache = new (memoize.Cache || MapCache);\n return memoized;\n}\n\n// Expose `MapCache`.\nmemoize.Cache = MapCache;\n\nexport default memoize;\n","import memoize from './memoize.js';\n\n/** Used as the maximum memoize cache size. */\nvar MAX_MEMOIZE_SIZE = 500;\n\n/**\n * A specialized version of `_.memoize` which clears the memoized function's\n * cache when it exceeds `MAX_MEMOIZE_SIZE`.\n *\n * @private\n * @param {Function} func The function to have its output memoized.\n * @returns {Function} Returns the new memoized function.\n */\nfunction memoizeCapped(func) {\n var result = memoize(func, function(key) {\n if (cache.size === MAX_MEMOIZE_SIZE) {\n cache.clear();\n }\n return key;\n });\n\n var cache = result.cache;\n return result;\n}\n\nexport default memoizeCapped;\n","import memoizeCapped from './_memoizeCapped.js';\n\n/** Used to match property names within property paths. */\nvar rePropName = /[^.[\\]]+|\\[(?:(-?\\d+(?:\\.\\d+)?)|([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2)\\]|(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))/g;\n\n/** Used to match backslashes in property paths. */\nvar reEscapeChar = /\\\\(\\\\)?/g;\n\n/**\n * Converts `string` to a property path array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the property path array.\n */\nvar stringToPath = memoizeCapped(function(string) {\n var result = [];\n if (string.charCodeAt(0) === 46 /* . */) {\n result.push('');\n }\n string.replace(rePropName, function(match, number, quote, subString) {\n result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));\n });\n return result;\n});\n\nexport default stringToPath;\n","/**\n * A specialized version of `_.map` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @returns {Array} Returns the new mapped array.\n */\nfunction arrayMap(array, iteratee) {\n var index = -1,\n length = array == null ? 0 : array.length,\n result = Array(length);\n\n while (++index < length) {\n result[index] = iteratee(array[index], index, array);\n }\n return result;\n}\n\nexport default arrayMap;\n","import Symbol from './_Symbol.js';\nimport arrayMap from './_arrayMap.js';\nimport isArray from './isArray.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolToString = symbolProto ? symbolProto.toString : undefined;\n\n/**\n * The base implementation of `_.toString` which doesn't convert nullish\n * values to empty strings.\n *\n * @private\n * @param {*} value The value to process.\n * @returns {string} Returns the string.\n */\nfunction baseToString(value) {\n // Exit early for strings to avoid a performance hit in some environments.\n if (typeof value == 'string') {\n return value;\n }\n if (isArray(value)) {\n // Recursively convert values (susceptible to call stack limits).\n return arrayMap(value, baseToString) + '';\n }\n if (isSymbol(value)) {\n return symbolToString ? symbolToString.call(value) : '';\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default baseToString;\n","import baseToString from './_baseToString.js';\n\n/**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\nfunction toString(value) {\n return value == null ? '' : baseToString(value);\n}\n\nexport default toString;\n","import isArray from './isArray.js';\nimport isKey from './_isKey.js';\nimport stringToPath from './_stringToPath.js';\nimport toString from './toString.js';\n\n/**\n * Casts `value` to a path array if it's not one.\n *\n * @private\n * @param {*} value The value to inspect.\n * @param {Object} [object] The object to query keys on.\n * @returns {Array} Returns the cast property path array.\n */\nfunction castPath(value, object) {\n if (isArray(value)) {\n return value;\n }\n return isKey(value, object) ? [value] : stringToPath(toString(value));\n}\n\nexport default castPath;\n","/**\n * Gets the last element of `array`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Array\n * @param {Array} array The array to query.\n * @returns {*} Returns the last element of `array`.\n * @example\n *\n * _.last([1, 2, 3]);\n * // => 3\n */\nfunction last(array) {\n var length = array == null ? 0 : array.length;\n return length ? array[length - 1] : undefined;\n}\n\nexport default last;\n","import isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar INFINITY = 1 / 0;\n\n/**\n * Converts `value` to a string key if it's not a string or symbol.\n *\n * @private\n * @param {*} value The value to inspect.\n * @returns {string|symbol} Returns the key.\n */\nfunction toKey(value) {\n if (typeof value == 'string' || isSymbol(value)) {\n return value;\n }\n var result = (value + '');\n return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;\n}\n\nexport default toKey;\n","import castPath from './_castPath.js';\nimport toKey from './_toKey.js';\n\n/**\n * The base implementation of `_.get` without support for default values.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @returns {*} Returns the resolved value.\n */\nfunction baseGet(object, path) {\n path = castPath(path, object);\n\n var index = 0,\n length = path.length;\n\n while (object != null && index < length) {\n object = object[toKey(path[index++])];\n }\n return (index && index == length) ? object : undefined;\n}\n\nexport default baseGet;\n","/**\n * The base implementation of `_.slice` without an iteratee call guard.\n *\n * @private\n * @param {Array} array The array to slice.\n * @param {number} [start=0] The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the slice of `array`.\n */\nfunction baseSlice(array, start, end) {\n var index = -1,\n length = array.length;\n\n if (start < 0) {\n start = -start > length ? 0 : (length + start);\n }\n end = end > length ? length : end;\n if (end < 0) {\n end += length;\n }\n length = start > end ? 0 : ((end - start) >>> 0);\n start >>>= 0;\n\n var result = Array(length);\n while (++index < length) {\n result[index] = array[index + start];\n }\n return result;\n}\n\nexport default baseSlice;\n","import baseGet from './_baseGet.js';\nimport baseSlice from './_baseSlice.js';\n\n/**\n * Gets the parent value at `path` of `object`.\n *\n * @private\n * @param {Object} object The object to query.\n * @param {Array} path The path to get the parent value of.\n * @returns {*} Returns the parent value.\n */\nfunction parent(object, path) {\n return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));\n}\n\nexport default parent;\n","import castPath from './_castPath.js';\nimport last from './last.js';\nimport parent from './_parent.js';\nimport toKey from './_toKey.js';\n\n/**\n * The base implementation of `_.unset`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The property path to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n */\nfunction baseUnset(object, path) {\n path = castPath(path, object);\n object = parent(object, path);\n return object == null || delete object[toKey(last(path))];\n}\n\nexport default baseUnset;\n","import baseUnset from './_baseUnset.js';\n\n/**\n * Removes the property at `path` of `object`.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 7 } }] };\n * _.unset(object, 'a[0].b.c');\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n *\n * _.unset(object, ['a', '0', 'b', 'c']);\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n */\nfunction unset(object, path) {\n return object == null ? true : baseUnset(object, path);\n}\n\nexport default unset;\n","import baseGet from './_baseGet.js';\n\n/**\n * Gets the value at `path` of `object`. If the resolved value is\n * `undefined`, the `defaultValue` is returned in its place.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @param {*} [defaultValue] The value returned for `undefined` resolved values.\n * @returns {*} Returns the resolved value.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.get(object, 'a[0].b.c');\n * // => 3\n *\n * _.get(object, ['a', '0', 'b', 'c']);\n * // => 3\n *\n * _.get(object, 'a.b.c', 'default');\n * // => 'default'\n */\nfunction get(object, path, defaultValue) {\n var result = object == null ? undefined : baseGet(object, path);\n return result === undefined ? defaultValue : result;\n}\n\nexport default get;\n","import baseAssignValue from './_baseAssignValue.js';\nimport eq from './eq.js';\n\n/**\n * This function is like `assignValue` except that it doesn't assign\n * `undefined` values.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {string} key The key of the property to assign.\n * @param {*} value The value to assign.\n */\nfunction assignMergeValue(object, key, value) {\n if ((value !== undefined && !eq(object[key], value)) ||\n (value === undefined && !(key in object))) {\n baseAssignValue(object, key, value);\n }\n}\n\nexport default assignMergeValue;\n","/**\n * Creates a base function for methods like `_.forIn` and `_.forOwn`.\n *\n * @private\n * @param {boolean} [fromRight] Specify iterating from right to left.\n * @returns {Function} Returns the new base function.\n */\nfunction createBaseFor(fromRight) {\n return function(object, iteratee, keysFunc) {\n var index = -1,\n iterable = Object(object),\n props = keysFunc(object),\n length = props.length;\n\n while (length--) {\n var key = props[fromRight ? length : ++index];\n if (iteratee(iterable[key], key, iterable) === false) {\n break;\n }\n }\n return object;\n };\n}\n\nexport default createBaseFor;\n","import createBaseFor from './_createBaseFor.js';\n\n/**\n * The base implementation of `baseForOwn` which iterates over `object`\n * properties returned by `keysFunc` and invokes `iteratee` for each property.\n * Iteratee functions may exit iteration early by explicitly returning `false`.\n *\n * @private\n * @param {Object} object The object to iterate over.\n * @param {Function} iteratee The function invoked per iteration.\n * @param {Function} keysFunc The function to get the keys of `object`.\n * @returns {Object} Returns `object`.\n */\nvar baseFor = createBaseFor();\n\nexport default baseFor;\n","import isArrayLike from './isArrayLike.js';\nimport isObjectLike from './isObjectLike.js';\n\n/**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n * else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\nfunction isArrayLikeObject(value) {\n return isObjectLike(value) && isArrayLike(value);\n}\n\nexport default isArrayLikeObject;\n","/**\n * Gets the value at `key`, unless `key` is \"__proto__\" or \"constructor\".\n *\n * @private\n * @param {Object} object The object to query.\n * @param {string} key The key of the property to get.\n * @returns {*} Returns the property value.\n */\nfunction safeGet(object, key) {\n if (key === 'constructor' && typeof object[key] === 'function') {\n return;\n }\n\n if (key == '__proto__') {\n return;\n }\n\n return object[key];\n}\n\nexport default safeGet;\n","import copyObject from './_copyObject.js';\nimport keysIn from './keysIn.js';\n\n/**\n * Converts `value` to a plain object flattening inherited enumerable string\n * keyed properties of `value` to own properties of the plain object.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {Object} Returns the converted plain object.\n * @example\n *\n * function Foo() {\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.assign({ 'a': 1 }, new Foo);\n * // => { 'a': 1, 'b': 2 }\n *\n * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));\n * // => { 'a': 1, 'b': 2, 'c': 3 }\n */\nfunction toPlainObject(value) {\n return copyObject(value, keysIn(value));\n}\n\nexport default toPlainObject;\n","import assignMergeValue from './_assignMergeValue.js';\nimport cloneBuffer from './_cloneBuffer.js';\nimport cloneTypedArray from './_cloneTypedArray.js';\nimport copyArray from './_copyArray.js';\nimport initCloneObject from './_initCloneObject.js';\nimport isArguments from './isArguments.js';\nimport isArray from './isArray.js';\nimport isArrayLikeObject from './isArrayLikeObject.js';\nimport isBuffer from './isBuffer.js';\nimport isFunction from './isFunction.js';\nimport isObject from './isObject.js';\nimport isPlainObject from './isPlainObject.js';\nimport isTypedArray from './isTypedArray.js';\nimport safeGet from './_safeGet.js';\nimport toPlainObject from './toPlainObject.js';\n\n/**\n * A specialized version of `baseMerge` for arrays and objects which performs\n * deep merges and tracks traversed objects enabling objects with circular\n * references to be merged.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @param {string} key The key of the value to merge.\n * @param {number} srcIndex The index of `source`.\n * @param {Function} mergeFunc The function to merge values.\n * @param {Function} [customizer] The function to customize assigned values.\n * @param {Object} [stack] Tracks traversed source values and their merged\n * counterparts.\n */\nfunction baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {\n var objValue = safeGet(object, key),\n srcValue = safeGet(source, key),\n stacked = stack.get(srcValue);\n\n if (stacked) {\n assignMergeValue(object, key, stacked);\n return;\n }\n var newValue = customizer\n ? customizer(objValue, srcValue, (key + ''), object, source, stack)\n : undefined;\n\n var isCommon = newValue === undefined;\n\n if (isCommon) {\n var isArr = isArray(srcValue),\n isBuff = !isArr && isBuffer(srcValue),\n isTyped = !isArr && !isBuff && isTypedArray(srcValue);\n\n newValue = srcValue;\n if (isArr || isBuff || isTyped) {\n if (isArray(objValue)) {\n newValue = objValue;\n }\n else if (isArrayLikeObject(objValue)) {\n newValue = copyArray(objValue);\n }\n else if (isBuff) {\n isCommon = false;\n newValue = cloneBuffer(srcValue, true);\n }\n else if (isTyped) {\n isCommon = false;\n newValue = cloneTypedArray(srcValue, true);\n }\n else {\n newValue = [];\n }\n }\n else if (isPlainObject(srcValue) || isArguments(srcValue)) {\n newValue = objValue;\n if (isArguments(objValue)) {\n newValue = toPlainObject(objValue);\n }\n else if (!isObject(objValue) || isFunction(objValue)) {\n newValue = initCloneObject(srcValue);\n }\n }\n else {\n isCommon = false;\n }\n }\n if (isCommon) {\n // Recursively merge objects and arrays (susceptible to call stack limits).\n stack.set(srcValue, newValue);\n mergeFunc(newValue, srcValue, srcIndex, customizer, stack);\n stack['delete'](srcValue);\n }\n assignMergeValue(object, key, newValue);\n}\n\nexport default baseMergeDeep;\n","import Stack from './_Stack.js';\nimport assignMergeValue from './_assignMergeValue.js';\nimport baseFor from './_baseFor.js';\nimport baseMergeDeep from './_baseMergeDeep.js';\nimport isObject from './isObject.js';\nimport keysIn from './keysIn.js';\nimport safeGet from './_safeGet.js';\n\n/**\n * The base implementation of `_.merge` without support for multiple sources.\n *\n * @private\n * @param {Object} object The destination object.\n * @param {Object} source The source object.\n * @param {number} srcIndex The index of `source`.\n * @param {Function} [customizer] The function to customize merged values.\n * @param {Object} [stack] Tracks traversed source values and their merged\n * counterparts.\n */\nfunction baseMerge(object, source, srcIndex, customizer, stack) {\n if (object === source) {\n return;\n }\n baseFor(source, function(srcValue, key) {\n stack || (stack = new Stack);\n if (isObject(srcValue)) {\n baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);\n }\n else {\n var newValue = customizer\n ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)\n : undefined;\n\n if (newValue === undefined) {\n newValue = srcValue;\n }\n assignMergeValue(object, key, newValue);\n }\n }, keysIn);\n}\n\nexport default baseMerge;\n","import baseMerge from './_baseMerge.js';\nimport createAssigner from './_createAssigner.js';\n\n/**\n * This method is like `_.assign` except that it recursively merges own and\n * inherited enumerable string keyed properties of source objects into the\n * destination object. Source properties that resolve to `undefined` are\n * skipped if a destination value exists. Array and plain object properties\n * are merged recursively. Other objects and value types are overridden by\n * assignment. Source objects are applied from left to right. Subsequent\n * sources overwrite property assignments of previous sources.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 0.5.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = {\n * 'a': [{ 'b': 2 }, { 'd': 4 }]\n * };\n *\n * var other = {\n * 'a': [{ 'c': 3 }, { 'e': 5 }]\n * };\n *\n * _.merge(object, other);\n * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }\n */\nvar merge = createAssigner(function(object, source, srcIndex) {\n baseMerge(object, source, srcIndex);\n});\n\nexport default merge;\n","import assignValue from './_assignValue.js';\nimport castPath from './_castPath.js';\nimport isIndex from './_isIndex.js';\nimport isObject from './isObject.js';\nimport toKey from './_toKey.js';\n\n/**\n * The base implementation of `_.set`.\n *\n * @private\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @param {Function} [customizer] The function to customize path creation.\n * @returns {Object} Returns `object`.\n */\nfunction baseSet(object, path, value, customizer) {\n if (!isObject(object)) {\n return object;\n }\n path = castPath(path, object);\n\n var index = -1,\n length = path.length,\n lastIndex = length - 1,\n nested = object;\n\n while (nested != null && ++index < length) {\n var key = toKey(path[index]),\n newValue = value;\n\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n return object;\n }\n\n if (index != lastIndex) {\n var objValue = nested[key];\n newValue = customizer ? customizer(objValue, key, nested) : undefined;\n if (newValue === undefined) {\n newValue = isObject(objValue)\n ? objValue\n : (isIndex(path[index + 1]) ? [] : {});\n }\n }\n assignValue(nested, key, newValue);\n nested = nested[key];\n }\n return object;\n}\n\nexport default baseSet;\n","import baseSet from './_baseSet.js';\n\n/**\n * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,\n * it's created. Arrays are created for missing index properties while objects\n * are created for all other missing properties. Use `_.setWith` to customize\n * `path` creation.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.set(object, 'a[0].b.c', 4);\n * console.log(object.a[0].b.c);\n * // => 4\n *\n * _.set(object, ['x', '0', 'y', 'z'], 5);\n * console.log(object.x[0].y.z);\n * // => 5\n */\nfunction set(object, path, value) {\n return object == null ? object : baseSet(object, path, value);\n}\n\nexport default set;\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/view/stylesmap\n */\n\nimport { get, isObject, merge, set, unset } from 'lodash-es';\n\n/**\n * Styles map. Allows handling (adding, removing, retrieving) a set of style rules (usually, of an element).\n *\n * The styles map is capable of normalizing style names so e.g. the following operations are possible:\n */\nexport default class StylesMap {\n\t/**\n\t * Creates Styles instance.\n\t *\n\t * @param {module:engine/view/stylesmap~StylesProcessor} styleProcessor\n\t */\n\tconstructor( styleProcessor ) {\n\t\t/**\n\t\t * Keeps an internal representation of styles map. Normalized styles are kept as object tree to allow unified modification and\n\t\t * value access model using lodash's get, set, unset, etc methods.\n\t\t *\n\t\t * When no style processor rules are defined the it acts as simple key-value storage.\n\t\t *\n\t\t * @private\n\t\t * @type {Object}\n\t\t */\n\t\tthis._styles = {};\n\n\t\t/**\n\t\t * An instance of the {@link module:engine/view/stylesmap~StylesProcessor}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/stylesmap~StylesProcessor}\n\t\t */\n\t\tthis._styleProcessor = styleProcessor;\n\t}\n\n\t/**\n\t * Returns true if style map has no styles set.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget isEmpty() {\n\t\tconst entries = Object.entries( this._styles );\n\t\tconst from = Array.from( entries );\n\n\t\treturn !from.length;\n\t}\n\n\t/**\n\t * Number of styles defined.\n\t *\n\t * @type {Number}\n\t */\n\tget size() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this.getStyleNames().length;\n\t}\n\n\t/**\n\t * Set styles map to a new value.\n\t *\n\t *\t\tstyles.setTo( 'border:1px solid blue;margin-top:1px;' );\n\t *\n\t * @param {String} inlineStyle\n\t */\n\tsetTo( inlineStyle ) {\n\t\tthis.clear();\n\n\t\tconst parsedStyles = Array.from( parseInlineStyles( inlineStyle ).entries() );\n\n\t\tfor ( const [ key, value ] of parsedStyles ) {\n\t\t\tthis._styleProcessor.toNormalizedForm( key, value, this._styles );\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a given style is set.\n\t *\n\t *\t\tstyles.setTo( 'margin-left:1px;' );\n\t *\n\t *\t\tstyles.has( 'margin-left' ); // -> true\n\t *\t\tstyles.has( 'padding' ); // -> false\n\t *\n\t * **Note**: This check supports normalized style names.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.setTo( 'margin:2px;' );\n\t *\n\t *\t\tstyles.has( 'margin' ); // -> true\n\t *\t\tstyles.has( 'margin-top' ); // -> true\n\t *\t\tstyles.has( 'margin-left' ); // -> true\n\t *\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\n\t *\t\tstyles.has( 'margin' ); // -> false\n\t *\t\tstyles.has( 'margin-top' ); // -> false\n\t *\t\tstyles.has( 'margin-left' ); // -> true\n\t *\n\t * @param {String} name Style name.\n\t * @returns {Boolean}\n\t */\n\thas( name ) {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst styles = this._styleProcessor.getReducedForm( name, this._styles );\n\n\t\tconst propertyDescriptor = styles.find( ( [ property ] ) => property === name );\n\n\t\t// Only return a value if it is set;\n\t\treturn Array.isArray( propertyDescriptor );\n\t}\n\n\t/**\n\t * Sets a given style.\n\t *\n\t * Can insert one by one:\n\t *\n\t *\t\tstyles.set( 'color', 'blue' );\n\t *\t\tstyles.set( 'margin-right', '1em' );\n\t *\n\t * or many styles at once:\n\t *\n\t *\t\tstyles.set( {\n\t *\t\t\tcolor: 'blue',\n\t *\t\t\t'margin-right': '1em'\n\t *\t\t} );\n\t *\n\t * ***Note**:* This method uses {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules\n\t * enabled style processor rules} to normalize passed values.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.set( 'margin', '2px' );\n\t *\n\t * The above code will set margin to:\n\t *\n\t *\t\tstyles.getNormalized( 'margin' );\n\t *\t\t// -> { top: '2px', right: '2px', bottom: '2px', left: '2px' }\n\t *\n\t * Which makes it possible to retrieve a \"sub-value\":\n\t *\n\t *\t\tstyles.get( 'margin-left' ); // -> '2px'\n\t *\n\t * Or modify it:\n\t *\n\t *\t\tstyles.remove( 'margin-left' );\n\t *\n\t *\t\tstyles.getNormalized( 'margin' ); // -> { top: '1px', bottom: '1px', right: '1px' }\n\t *\t\tstyles.toString(); // -> 'margin-bottom:1px;margin-right:1px;margin-top:1px;'\n\t *\n\t * This method also allows to set normalized values directly (if a particular styles processor rule was enabled):\n\t *\n\t *\t\tstyles.set( 'border-color', { top: 'blue' } );\n\t *\t\tstyles.set( 'margin', { right: '2em' } );\n\t *\n\t *\t\tstyles.toString(); // -> 'border-color-top:blue;margin-right:2em;'\n\t *\n\t * @param {String|Object} nameOrObject Style property name or object with multiple properties.\n\t * @param {String|Object} valueOrObject Value to set.\n\t */\n\tset( nameOrObject, valueOrObject ) {\n\t\tif ( isObject( nameOrObject ) ) {\n\t\t\tfor ( const [ key, value ] of Object.entries( nameOrObject ) ) {\n\t\t\t\tthis._styleProcessor.toNormalizedForm( key, value, this._styles );\n\t\t\t}\n\t\t} else {\n\t\t\tthis._styleProcessor.toNormalizedForm( nameOrObject, valueOrObject, this._styles );\n\t\t}\n\t}\n\n\t/**\n\t * Removes given style.\n\t *\n\t *\t\tstyles.setTo( 'background:#f00;margin-right:2px;' );\n\t *\n\t *\t\tstyles.remove( 'background' );\n\t *\n\t *\t\tstyles.toString(); // -> 'margin-right:2px;'\n\t *\n\t * ***Note**:* This method uses {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules\n\t * enabled style processor rules} to normalize passed values.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.setTo( 'margin:1px' );\n\t *\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\t\tstyles.remove( 'margin-right' );\n\t *\n\t *\t\tstyles.toString(); // -> 'margin-bottom:1px;margin-left:1px;'\n\t *\n\t * @param {String} name Style name.\n\t */\n\tremove( name ) {\n\t\tconst path = toPath( name );\n\n\t\tunset( this._styles, path );\n\t\tdelete this._styles[ name ];\n\n\t\tthis._cleanEmptyObjectsOnPath( path );\n\t}\n\n\t/**\n\t * Returns a normalized style object or a single value.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px 2px 3em;' );\n\t *\n\t *\t\tstyles.getNormalized( 'margin' );\n\t *\t\t// will log:\n\t *\t\t// {\n\t *\t\t// top: '1px',\n\t *\t\t// right: '2px',\n\t *\t\t// bottom: '3em',\n\t *\t\t// left: '2px' // normalized value from margin shorthand\n\t *\t\t// }\n\t *\n\t *\t\tstyles.getNormalized( 'margin-left' ); // -> '2px'\n\t *\n\t * **Note**: This method will only return normalized styles if a style processor was defined.\n\t *\n\t * @param {String} name Style name.\n\t * @returns {Object|String|undefined}\n\t */\n\tgetNormalized( name ) {\n\t\treturn this._styleProcessor.getNormalized( name, this._styles );\n\t}\n\n\t/**\n\t * Returns a normalized style string. Styles are sorted by name.\n\t *\n\t *\t\tstyles.set( 'margin' , '1px' );\n\t *\t\tstyles.set( 'background', '#f00' );\n\t *\n\t *\t\tstyles.toString(); // -> 'background:#f00;margin:1px;'\n\t *\n\t * **Note**: This method supports normalized styles if defined.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tstyles.set( 'margin' , '1px' );\n\t *\t\tstyles.set( 'background', '#f00' );\n\t *\t\tstyles.remove( 'margin-top' );\n\t *\t\tstyles.remove( 'margin-right' );\n\t *\n\t *\t\tstyles.toString(); // -> 'background:#f00;margin-bottom:1px;margin-left:1px;'\n\t *\n\t * @returns {String}\n\t */\n\ttoString() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this._getStylesEntries()\n\t\t\t.map( arr => arr.join( ':' ) )\n\t\t\t.sort()\n\t\t\t.join( ';' ) + ';';\n\t}\n\n\t/**\n\t * Returns property as a value string or undefined if property is not set.\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.set( 'margin-bottom', '3em' );\n\t *\n\t *\t\tstyles.getAsString( 'margin' ); // -> 'margin: 1px 1px 3em;'\n\t *\n\t * Note, however, that all sub-values must be set for the longhand property name to return a value:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.remove( 'margin-bottom' );\n\t *\n\t *\t\tstyles.getAsString( 'margin' ); // -> undefined\n\t *\n\t * In the above scenario, it is not possible to return a `margin` value, so `undefined` is returned.\n\t * Instead, you should use:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\t\tstyles.remove( 'margin-bottom' );\n\t *\n\t *\t\tfor ( const styleName of styles.getStyleNames() ) {\n\t *\t\t\tconsole.log( styleName, styles.getAsString( styleName ) );\n\t *\t\t}\n\t *\t\t// 'margin-top', '1px'\n\t *\t\t// 'margin-right', '1px'\n\t *\t\t// 'margin-left', '1px'\n\t *\n\t * In general, it is recommend to iterate over style names like in the example above. This way, you will always get all\n\t * the currently set style values. So, if all the 4 margin values would be set\n\t * the for-of loop above would yield only `'margin'`, `'1px'`:\n\t *\n\t *\t\tconst styles = new Styles();\n\t *\t\tstyles.setTo( 'margin:1px;' );\n\t *\n\t *\t\tfor ( const styleName of styles.getStyleNames() ) {\n\t *\t\t\tconsole.log( styleName, styles.getAsString( styleName ) );\n\t *\t\t}\n\t *\t\t// 'margin', '1px'\n\t *\n\t * **Note**: To get a normalized version of a longhand property use the {@link #getNormalized `#getNormalized()`} method.\n\t *\n\t * @param {String} propertyName\n\t * @returns {String|undefined}\n\t */\n\tgetAsString( propertyName ) {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._styles[ propertyName ] && !isObject( this._styles[ propertyName ] ) ) {\n\t\t\t// Try return styles set directly - values that are not parsed.\n\t\t\treturn this._styles[ propertyName ];\n\t\t}\n\n\t\tconst styles = this._styleProcessor.getReducedForm( propertyName, this._styles );\n\n\t\tconst propertyDescriptor = styles.find( ( [ property ] ) => property === propertyName );\n\n\t\t// Only return a value if it is set;\n\t\tif ( Array.isArray( propertyDescriptor ) ) {\n\t\t\treturn propertyDescriptor[ 1 ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns style property names as they would appear when using {@link #toString `#toString()`}.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tgetStyleNames() {\n\t\tif ( this.isEmpty ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst entries = this._getStylesEntries();\n\n\t\treturn entries.map( ( [ key ] ) => key );\n\t}\n\n\t/**\n\t * Removes all styles.\n\t */\n\tclear() {\n\t\tthis._styles = {};\n\t}\n\n\t/**\n\t * Returns normalized styles entries for further processing.\n\t *\n\t * @private\n\t * @returns {Array.<module:engine/view/stylesmap~PropertyDescriptor>}\n\t */\n\t_getStylesEntries() {\n\t\tconst parsed = [];\n\n\t\tconst keys = Object.keys( this._styles );\n\n\t\tfor ( const key of keys ) {\n\t\t\tparsed.push( ...this._styleProcessor.getReducedForm( key, this._styles ) );\n\t\t}\n\n\t\treturn parsed;\n\t}\n\n\t/**\n\t * Removes empty objects upon removing an entry from internal object.\n\t *\n\t * @param {String} path\n\t * @private\n\t */\n\t_cleanEmptyObjectsOnPath( path ) {\n\t\tconst pathParts = path.split( '.' );\n\t\tconst isChildPath = pathParts.length > 1;\n\n\t\tif ( !isChildPath ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst parentPath = pathParts.splice( 0, pathParts.length - 1 ).join( '.' );\n\n\t\tconst parentObject = get( this._styles, parentPath );\n\n\t\tif ( !parentObject ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isParentEmpty = !Array.from( Object.keys( parentObject ) ).length;\n\n\t\tif ( isParentEmpty ) {\n\t\t\tthis.remove( parentPath );\n\t\t}\n\t}\n}\n\n/**\n * Style processor is responsible for writing and reading a normalized styles object.\n */\nexport class StylesProcessor {\n\t/**\n\t * Creates StylesProcessor instance.\n\t *\n\t * @private\n\t */\n\tconstructor() {\n\t\tthis._normalizers = new Map();\n\t\tthis._extractors = new Map();\n\t\tthis._reducers = new Map();\n\t\tthis._consumables = new Map();\n\t}\n\n\t/**\n\t * Parse style string value to a normalized object and appends it to styles object.\n\t *\n\t *\t\tconst styles = {};\n\t *\n\t *\t\tstylesProcessor.toNormalizedForm( 'margin', '1px', styles );\n\t *\n\t *\t\t// styles will consist: { margin: { top: '1px', right: '1px', bottom: '1px', left: '1px; } }\n\t *\n\t * **Note**: To define normalizer callbacks use {@link #setNormalizer}.\n\t *\n\t * @param {String} name Name of style property.\n\t * @param {String} propertyValue Value of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t */\n\ttoNormalizedForm( name, propertyValue, styles ) {\n\t\tif ( isObject( propertyValue ) ) {\n\t\t\tappendStyleValue( styles, toPath( name ), propertyValue );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this._normalizers.has( name ) ) {\n\t\t\tconst normalizer = this._normalizers.get( name );\n\n\t\t\tconst { path, value } = normalizer( propertyValue );\n\n\t\t\tappendStyleValue( styles, path, value );\n\t\t} else {\n\t\t\tappendStyleValue( styles, name, propertyValue );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a normalized version of a style property.\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: { top: '1px', right: '1px', bottom: '1px', left: '1px; },\n\t *\t\t\tbackground: { color: '#f00' }\n\t *\t\t};\n\t *\n\t *\t\tstylesProcessor.getNormalized( 'background' );\n\t *\t\t// will return: { color: '#f00' }\n\t *\n\t *\t\tstylesProcessor.getNormalized( 'margin-top' );\n\t *\t\t// will return: '1px'\n\t *\n\t * **Note**: In some cases extracting single value requires defining an extractor callback {@link #setExtractor}.\n\t *\n\t * @param {String} name Name of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t * @returns {*}\n\t */\n\tgetNormalized( name, styles ) {\n\t\tif ( !name ) {\n\t\t\treturn merge( {}, styles );\n\t\t}\n\n\t\t// Might be empty string.\n\t\tif ( styles[ name ] !== undefined ) {\n\t\t\treturn styles[ name ];\n\t\t}\n\n\t\tif ( this._extractors.has( name ) ) {\n\t\t\tconst extractor = this._extractors.get( name );\n\n\t\t\tif ( typeof extractor === 'string' ) {\n\t\t\t\treturn get( styles, extractor );\n\t\t\t}\n\n\t\t\tconst value = extractor( name, styles );\n\n\t\t\tif ( value ) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\n\t\treturn get( styles, toPath( name ) );\n\t}\n\n\t/**\n\t * Returns a reduced form of style property form normalized object.\n\t *\n\t * For default margin reducer, the below code:\n\t *\n\t *\t\tstylesProcessor.getReducedForm( 'margin', {\n\t *\t\t\tmargin: { top: '1px', right: '1px', bottom: '2px', left: '1px; }\n\t *\t\t} );\n\t *\n\t * will return:\n\t *\n\t *\t\t[\n\t *\t\t\t[ 'margin', '1px 1px 2px' ]\n\t *\t\t]\n\t *\n\t * because it might be represented as a shorthand 'margin' value. However if one of margin long hand values is missing it should return:\n\t *\n\t *\t\t[\n\t *\t\t\t[ 'margin-top', '1px' ],\n\t *\t\t\t[ 'margin-right', '1px' ],\n\t *\t\t\t[ 'margin-bottom', '2px' ]\n\t *\t\t\t// the 'left' value is missing - cannot use 'margin' shorthand.\n\t *\t\t]\n\t *\n\t * **Note**: To define reducer callbacks use {@link #setReducer}.\n\t *\n\t * @param {String} name\n\t * @param {String} name Name of style property.\n\t * @param {Object} styles Object holding normalized styles.\n\t * @returns {Array.<module:engine/view/stylesmap~PropertyDescriptor>}\n\t */\n\tgetReducedForm( name, styles ) {\n\t\tconst normalizedValue = this.getNormalized( name, styles );\n\n\t\t// Might be empty string.\n\t\tif ( normalizedValue === undefined ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif ( this._reducers.has( name ) ) {\n\t\t\tconst reducer = this._reducers.get( name );\n\n\t\t\treturn reducer( normalizedValue );\n\t\t}\n\n\t\treturn [ [ name, normalizedValue ] ];\n\t}\n\n\t/**\n\t * Returns related style names.\n\t *\n\t *\t\tstylesProcessor.getRelatedStyles( 'margin' );\n\t *\t\t// will return: [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ];\n\t *\n\t *\t\tstylesProcessor.getRelatedStyles( 'margin-top' );\n\t *\t\t// will return: [ 'margin' ];\n\t *\n\t * **Note**: To define new style relations load an existing style processor or use\n\t * {@link module:engine/view/stylesmap~StylesProcessor#setStyleRelation `StylesProcessor.setStyleRelation()`}.\n\t *\n\t * @param {String} name\n\t * @returns {Array.<String>}\n\t */\n\tgetRelatedStyles( name ) {\n\t\treturn this._consumables.get( name ) || [];\n\t}\n\n\t/**\n\t * Adds a normalizer method for a style property.\n\t *\n\t * A normalizer returns describing how the value should be normalized.\n\t *\n\t * For instance 'margin' style is a shorthand for four margin values:\n\t *\n\t * - 'margin-top'\n\t * - 'margin-right'\n\t * - 'margin-bottom'\n\t * - 'margin-left'\n\t *\n\t * and can be written in various ways if some values are equal to others. For instance `'margin: 1px 2em;'` is a shorthand for\n\t * `'margin-top: 1px;margin-right: 2em;margin-bottom: 1px;margin-left: 2em'`.\n\t *\n\t * A normalizer should parse various margin notations as a single object:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: {\n\t *\t\t\t\ttop: '1px',\n\t *\t\t\t\tright: '2em',\n\t *\t\t\t\tbottom: '1px',\n\t *\t\t\t\tleft: '2em'\n\t *\t\t\t}\n\t *\t\t};\n\t *\n\t * Thus a normalizer for 'margin' style should return an object defining style path and value to store:\n\t *\n\t *\t\tconst returnValue = {\n\t *\t\t\tpath: 'margin',\n\t *\t\t\tvalue: {\n\t *\t\t\t\ttop: '1px',\n\t *\t\t\t\tright: '2em',\n\t *\t\t\t\tbottom: '1px',\n\t *\t\t\t\tleft: '2em'\n\t *\t\t\t}\n\t *\t\t};\n\t *\n\t * Additionally to fully support all margin notations there should be also defined 4 normalizers for longhand margin notations. Below\n\t * is an example for 'margin-top' style property normalizer:\n\t *\n\t *\t\tstylesProcessor.setNormalizer( 'margin-top', valueString => {\n\t *\t\t\treturn {\n\t *\t\t\t\tpath: 'margin.top',\n\t *\t\t\t\tvalue: valueString\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function} callback\n\t */\n\tsetNormalizer( name, callback ) {\n\t\tthis._normalizers.set( name, callback );\n\t}\n\n\t/**\n\t * Adds a extractor callback for a style property.\n\t *\n\t * Most normalized style values are stored as one level objects. It is assumed that `'margin-top'` style will be stored as:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tmargin: {\n\t *\t\t\t\ttop: 'value'\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * However, some styles can have conflicting notations and thus it might be harder to extract a style value from shorthand. For instance\n\t * the 'border-top-style' can be defined using `'border-top:solid'`, `'border-style:solid none none none'` or by `'border:solid'`\n\t * shorthands. The default border styles processors stores styles as:\n\t *\n\t *\t\tconst styles = {\n\t *\t\t\tborder: {\n\t *\t\t\t\tstyle: {\n\t *\t\t\t\t\ttop: 'solid'\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * as it is better to modify border style independently from other values. On the other part the output of the border might be\n\t * desired as `border-top`, `border-left`, etc notation.\n\t *\n\t * In the above example a reducer should return a side border value that combines style, color and width:\n\t *\n\t *\t\tstyleProcessor.setExtractor( 'border-top', styles => {\n\t *\t\t\treturn {\n\t *\t\t\t\tcolor: styles.border.color.top,\n\t *\t\t\t\tstyle: styles.border.style.top,\n\t *\t\t\t\twidth: styles.border.width.top\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function|String} callbackOrPath Callback that return a requested value or path string for single values.\n\t */\n\tsetExtractor( name, callbackOrPath ) {\n\t\tthis._extractors.set( name, callbackOrPath );\n\t}\n\n\t/**\n\t * Adds a reducer callback for a style property.\n\t *\n\t * Reducer returns a minimal notation for given style name. For longhand properties it is not required to write a reducer as\n\t * by default the direct value from style path is taken.\n\t *\n\t * For shorthand styles a reducer should return minimal style notation either by returning single name-value tuple or multiple tuples\n\t * if a shorthand cannot be used. For instance for a margin shorthand a reducer might return:\n\t *\n\t *\t\tconst marginShortHandTuple = [\n\t *\t\t\t[ 'margin', '1px 1px 2px' ]\n\t *\t\t];\n\t *\n\t * or a longhand tuples for defined values:\n\t *\n\t *\t\t// Considering margin.bottom and margin.left are undefined.\n\t *\t\tconst marginLonghandsTuples = [\n\t *\t\t\t[ 'margin-top', '1px' ],\n\t *\t\t\t[ 'margin-right', '1px' ]\n\t *\t\t];\n\t *\n\t * A reducer obtains a normalized style value:\n\t *\n\t *\t\t// Simplified reducer that always outputs 4 values which are always present:\n\t *\t\tstylesProcessor.setReducer( 'margin', margin => {\n\t *\t\t\treturn [\n\t *\t\t\t\t[ 'margin', `${ margin.top } ${ margin.right } ${ margin.bottom } ${ margin.left }` ]\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * @param {String} name\n\t * @param {Function} callback\n\t */\n\tsetReducer( name, callback ) {\n\t\tthis._reducers.set( name, callback );\n\t}\n\n\t/**\n\t * Defines a style shorthand relation to other style notations.\n\t *\n\t *\t\tstylesProcessor.setStyleRelation( 'margin', [\n\t *\t\t\t'margin-top',\n\t *\t\t\t'margin-right',\n\t *\t\t\t'margin-bottom',\n\t *\t\t\t'margin-left'\n\t *\t\t] );\n\t *\n\t * This enables expanding of style names for shorthands. For instance, if defined,\n\t * {@link module:engine/conversion/viewconsumable~ViewConsumable view consumable} items are automatically created\n\t * for long-hand margin style notation alongside the `'margin'` item.\n\t *\n\t * This means that when an element being converted has a style `margin`, a converter for `margin-left` will work just\n\t * fine since the view consumable will contain a consumable `margin-left` item (thanks to the relation) and\n\t * `element.getStyle( 'margin-left' )` will work as well assuming that the style processor was correctly configured.\n\t * However, once `margin-left` is consumed, `margin` will not be consumable anymore.\n\t *\n\t * @param {String} shorthandName\n\t * @param {Array.<String>} styleNames\n\t */\n\tsetStyleRelation( shorthandName, styleNames ) {\n\t\tthis._mapStyleNames( shorthandName, styleNames );\n\n\t\tfor ( const alsoName of styleNames ) {\n\t\t\tthis._mapStyleNames( alsoName, [ shorthandName ] );\n\t\t}\n\t}\n\n\t/**\n\t * Set two-way binding of style names.\n\t *\n\t * @param {String} name\n\t * @param {Array.<String>} styleNames\n\t * @private\n\t */\n\t_mapStyleNames( name, styleNames ) {\n\t\tif ( !this._consumables.has( name ) ) {\n\t\t\tthis._consumables.set( name, [] );\n\t\t}\n\n\t\tthis._consumables.get( name ).push( ...styleNames );\n\t}\n}\n\n// Parses inline styles and puts property - value pairs into styles map.\n//\n// @param {String} stylesString Styles to parse.\n// @returns {Map.<String, String>} stylesMap Map of parsed properties and values.\nfunction parseInlineStyles( stylesString ) {\n\t// `null` if no quote was found in input string or last found quote was a closing quote. See below.\n\tlet quoteType = null;\n\tlet propertyNameStart = 0;\n\tlet propertyValueStart = 0;\n\tlet propertyName = null;\n\n\tconst stylesMap = new Map();\n\n\t// Do not set anything if input string is empty.\n\tif ( stylesString === '' ) {\n\t\treturn stylesMap;\n\t}\n\n\t// Fix inline styles that do not end with `;` so they are compatible with algorithm below.\n\tif ( stylesString.charAt( stylesString.length - 1 ) != ';' ) {\n\t\tstylesString = stylesString + ';';\n\t}\n\n\t// Seek the whole string for \"special characters\".\n\tfor ( let i = 0; i < stylesString.length; i++ ) {\n\t\tconst char = stylesString.charAt( i );\n\n\t\tif ( quoteType === null ) {\n\t\t\t// No quote found yet or last found quote was a closing quote.\n\t\t\tswitch ( char ) {\n\t\t\t\tcase ':':\n\t\t\t\t\t// Most of time colon means that property name just ended.\n\t\t\t\t\t// Sometimes however `:` is found inside property value (for example in background image url).\n\t\t\t\t\tif ( !propertyName ) {\n\t\t\t\t\t\t// Treat this as end of property only if property name is not already saved.\n\t\t\t\t\t\t// Save property name.\n\t\t\t\t\t\tpropertyName = stylesString.substr( propertyNameStart, i - propertyNameStart );\n\t\t\t\t\t\t// Save this point as the start of property value.\n\t\t\t\t\t\tpropertyValueStart = i + 1;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '\"':\n\t\t\t\tcase '\\'':\n\t\t\t\t\t// Opening quote found (this is an opening quote, because `quoteType` is `null`).\n\t\t\t\t\tquoteType = char;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ';': {\n\t\t\t\t\t// Property value just ended.\n\t\t\t\t\t// Use previously stored property value start to obtain property value.\n\t\t\t\t\tconst propertyValue = stylesString.substr( propertyValueStart, i - propertyValueStart );\n\n\t\t\t\t\tif ( propertyName ) {\n\t\t\t\t\t\t// Save parsed part.\n\t\t\t\t\t\tstylesMap.set( propertyName.trim(), propertyValue.trim() );\n\t\t\t\t\t}\n\n\t\t\t\t\tpropertyName = null;\n\n\t\t\t\t\t// Save this point as property name start. Property name starts immediately after previous property value ends.\n\t\t\t\t\tpropertyNameStart = i + 1;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( char === quoteType ) {\n\t\t\t// If a quote char is found and it is a closing quote, mark this fact by `null`-ing `quoteType`.\n\t\t\tquoteType = null;\n\t\t}\n\t}\n\n\treturn stylesMap;\n}\n\n// Return lodash compatible path from style name.\nfunction toPath( name ) {\n\treturn name.replace( '-', '.' );\n}\n\n// Appends style definition to the styles object.\n//\n// @param {String} nameOrPath\n// @param {String|Object} valueOrObject\n// @private\nfunction appendStyleValue( stylesObject, nameOrPath, valueOrObject ) {\n\tlet valueToSet = valueOrObject;\n\n\tif ( isObject( valueOrObject ) ) {\n\t\tvalueToSet = merge( {}, get( stylesObject, nameOrPath ), valueOrObject );\n\t}\n\n\tset( stylesObject, nameOrPath, valueToSet );\n}\n\n/**\n * A CSS style property descriptor that contains tuplet of two strings:\n *\n * - first string describes property name\n * - second string describes property value\n *\n *\t\tconst marginDescriptor = [ 'margin', '2px 3em' ];\n *\t\tconst marginTopDescriptor = [ 'margin-top', '2px' ];\n *\n * @typedef {Array.<String, String>} module:engine/view/stylesmap~PropertyDescriptor\n */\n\n/**\n * An object describing values associated with the sides of a box, for instance margins, paddings,\n * border widths, border colors, etc.\n *\n *\t\tconst margin = {\n *\t\t\ttop: '1px',\n *\t\t\tright: '3px',\n *\t\t\tbottom: '3px',\n *\t\t\tleft: '7px'\n *\t\t};\n *\n *\t\tconst borderColor = {\n *\t\t\ttop: 'red',\n *\t\t\tright: 'blue',\n *\t\t\tbottom: 'blue',\n *\t\t\tleft: 'red'\n *\t\t};\n *\n * @typedef {Object} module:engine/view/stylesmap~BoxSides\n *\n * @property {String} top Top side value.\n * @property {String} right Right side value.\n * @property {String} bottom Bottom side value.\n * @property {String} left Left side value.\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/view/element\n */\n\nimport Node from './node';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport Matcher from './matcher';\nimport StylesMap from './stylesmap';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToTags } = require( '../dev-utils/utils' );\n\n/**\n * View element.\n *\n * The editing engine does not define a fixed semantics of its elements (it is \"DTD-free\").\n * This is why the type of the {@link module:engine/view/element~Element} need to\n * be defined by the feature developer. When creating an element you should use one of the following methods:\n *\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `downcastWriter#createContainerElement()`}\n * in order to create a {@link module:engine/view/containerelement~ContainerElement},\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `downcastWriter#createAttributeElement()`}\n * in order to create a {@link module:engine/view/attributeelement~AttributeElement},\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`}\n * in order to create a {@link module:engine/view/emptyelement~EmptyElement}.\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`}\n * in order to create a {@link module:engine/view/uielement~UIElement}.\n * * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`}\n * in order to create a {@link module:engine/view/editableelement~EditableElement}.\n *\n * Note that for view elements which are not created from the model, like elements from mutations, paste or\n * {@link module:engine/controller/datacontroller~DataController#set data.set} it is not possible to define the type of the element.\n * In such cases the {@link module:engine/view/upcastwriter~UpcastWriter#createElement `UpcastWriter#createElement()`} method\n * should be used to create generic view elements.\n *\n * @extends module:engine/view/node~Node\n */\nexport default class Element extends Node {\n\t/**\n\t * Creates a view element.\n\t *\n\t * Attributes can be passed in various formats:\n\t *\n\t *\t\tnew Element( viewDocument, 'div', { class: 'editor', contentEditable: 'true' } ); // object\n\t *\t\tnew Element( viewDocument, 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator\n\t *\t\tnew Element( viewDocument, 'div', mapOfAttributes ); // map\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document );\n\n\t\t/**\n\t\t * Name of the element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Map of attributes, where attributes names are keys and attributes values are values.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map} #_attrs\n\t\t */\n\t\tthis._attrs = parseAttributes( attrs );\n\n\t\t/**\n\t\t * Array of child nodes.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis._children = [];\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\n\t\t/**\n\t\t * Set of classes associated with element instance.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set}\n\t\t */\n\t\tthis._classes = new Set();\n\n\t\tif ( this._attrs.has( 'class' ) ) {\n\t\t\t// Remove class attribute and handle it by class set.\n\t\t\tconst classString = this._attrs.get( 'class' );\n\t\t\tparseClasses( this._classes, classString );\n\t\t\tthis._attrs.delete( 'class' );\n\t\t}\n\n\t\t/**\n\t\t * Normalized styles.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/view/stylesmap~StylesMap} module:engine/view/element~Element#_styles\n\t\t */\n\t\tthis._styles = new StylesMap( this.document.stylesProcessor );\n\n\t\tif ( this._attrs.has( 'style' ) ) {\n\t\t\t// Remove style attribute and handle it by styles map.\n\t\t\tthis._styles.setTo( this._attrs.get( 'style' ) );\n\n\t\t\tthis._attrs.delete( 'style' );\n\t\t}\n\n\t\t/**\n\t\t * Map of custom properties.\n\t\t * Custom properties can be added to element instance, will be cloned but not rendered into DOM.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map}\n\t\t */\n\t\tthis._customProperties = new Map();\n\n\t\t/**\n\t\t * Whether an element is allowed inside an AttributeElement and can be wrapped with\n\t\t * {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isAllowedInsideAttributeElement = false;\n\t}\n\n\t/**\n\t * Number of element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this element, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this._children.length === 0;\n\t}\n\n\t/**\n\t * Whether the element is allowed inside an AttributeElement and can be wrapped with\n\t * {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAllowedInsideAttributeElement() {\n\t\treturn this._isAllowedInsideAttributeElement;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\telement.is( 'element' ); // -> true\n\t *\t\telement.is( 'node' ); // -> true\n\t *\t\telement.is( 'view:element' ); // -> true\n\t *\t\telement.is( 'view:node' ); // -> true\n\t *\n\t *\t\telement.is( 'model:element' ); // -> false\n\t *\t\telement.is( 'documentSelection' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/view/element~Element#name name}:\n\t *\n\t *\t\telement.is( 'element', 'img' ); // -> true if this is an <img> element\n\t *\t\ttext.is( 'element', 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'element' || type === 'view:element' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && ( type === 'element' || type === 'view:element' );\n\t\t}\n\t}\n\n\t/**\n\t * Gets child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/view/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children[ index ];\n\t}\n\n\t/**\n\t * Gets index of the given child node. Returns `-1` if child node is not found.\n\t *\n\t * @param {module:engine/view/node~Node} node Child node.\n\t * @returns {Number} Index of the child node.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.indexOf( node );\n\t}\n\n\t/**\n\t * Gets child nodes iterator.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>} Child nodes iterator.\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an iterator that contains the keys for attributes. Order of inserting attributes is not preserved.\n\t *\n\t * @returns {Iterable.<String>} Keys for attributes.\n\t */\n\t* getAttributeKeys() {\n\t\tif ( this._classes.size > 0 ) {\n\t\t\tyield 'class';\n\t\t}\n\n\t\tif ( !this._styles.isEmpty ) {\n\t\t\tyield 'style';\n\t\t}\n\n\t\tyield* this._attrs.keys();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this element's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t* getAttributes() {\n\t\tyield* this._attrs.entries();\n\n\t\tif ( this._classes.size > 0 ) {\n\t\t\tyield [ 'class', this.getAttribute( 'class' ) ];\n\t\t}\n\n\t\tif ( !this._styles.isEmpty ) {\n\t\t\tyield [ 'style', this.getAttribute( 'style' ) ];\n\t\t}\n\t}\n\n\t/**\n\t * Gets attribute by key. If attribute is not present - returns undefined.\n\t *\n\t * @param {String} key Attribute key.\n\t * @returns {String|undefined} Attribute value.\n\t */\n\tgetAttribute( key ) {\n\t\tif ( key == 'class' ) {\n\t\t\tif ( this._classes.size > 0 ) {\n\t\t\t\treturn [ ...this._classes ].join( ' ' );\n\t\t\t}\n\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif ( key == 'style' ) {\n\t\t\tconst inlineStyle = this._styles.toString();\n\n\t\t\treturn inlineStyle == '' ? undefined : inlineStyle;\n\t\t}\n\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns a boolean indicating whether an attribute with the specified key exists in the element.\n\t *\n\t * @param {String} key Attribute key.\n\t * @returns {Boolean} `true` if attribute with the specified key exists in the element, false otherwise.\n\t */\n\thasAttribute( key ) {\n\t\tif ( key == 'class' ) {\n\t\t\treturn this._classes.size > 0;\n\t\t}\n\n\t\tif ( key == 'style' ) {\n\t\t\treturn !this._styles.isEmpty;\n\t\t}\n\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Checks if this element is similar to other element.\n\t * Both elements should have the same name and attributes to be considered as similar. Two similar elements\n\t * can contain different set of children nodes.\n\t *\n\t * @param {module:engine/view/element~Element} otherElement\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherElement ) {\n\t\tif ( !( otherElement instanceof Element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If exactly the same Element is provided - return true immediately.\n\t\tif ( this === otherElement ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check element name.\n\t\tif ( this.name != otherElement.name ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check isAllowedInsideAttributeElement property.\n\t\tif ( this.isAllowedInsideAttributeElement != otherElement.isAllowedInsideAttributeElement ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check number of attributes, classes and styles.\n\t\tif ( this._attrs.size !== otherElement._attrs.size || this._classes.size !== otherElement._classes.size ||\n\t\t\tthis._styles.size !== otherElement._styles.size ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if attributes are the same.\n\t\tfor ( const [ key, value ] of this._attrs ) {\n\t\t\tif ( !otherElement._attrs.has( key ) || otherElement._attrs.get( key ) !== value ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if classes are the same.\n\t\tfor ( const className of this._classes ) {\n\t\t\tif ( !otherElement._classes.has( className ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if styles are the same.\n\t\tfor ( const property of this._styles.getStyleNames() ) {\n\t\t\tif (\n\t\t\t\t!otherElement._styles.has( property ) ||\n\t\t\t\totherElement._styles.getAsString( property ) !== this._styles.getAsString( property )\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns true if class is present.\n\t * If more then one class is provided - returns true only when all classes are present.\n\t *\n\t *\t\telement.hasClass( 'foo' ); // Returns true if 'foo' class is present.\n\t *\t\telement.hasClass( 'foo', 'bar' ); // Returns true if 'foo' and 'bar' classes are both present.\n\t *\n\t * @param {...String} className\n\t */\n\thasClass( ...className ) {\n\t\tfor ( const name of className ) {\n\t\t\tif ( !this._classes.has( name ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns iterator that contains all class names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetClassNames() {\n\t\treturn this._classes.keys();\n\t}\n\n\t/**\n\t * Returns style value for the given property mae.\n\t * If the style does not exist `undefined` is returned.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#getAsString `StylesMap#getAsString()`} for details.\n\t *\n\t * For an element with style set to `'margin:1px'`:\n\t *\n\t *\t\t// Enable 'margin' shorthand processing:\n\t *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t *\n\t *\t\tconst element = view.change( writer => {\n\t *\t\t\tconst element = writer.createElement();\n\t *\t\t\twriter.setStyle( 'margin', '1px' );\n\t *\t\t\twriter.setStyle( 'margin-bottom', '3em' );\n\t *\n\t *\t\t\treturn element;\n\t *\t\t} );\n\t *\n\t *\t\telement.getStyle( 'margin' ); // -> 'margin: 1px 1px 3em;'\n\t *\n\t * @param {String} property\n\t * @returns {String|undefined}\n\t */\n\tgetStyle( property ) {\n\t\treturn this._styles.getAsString( property );\n\t}\n\n\t/**\n\t * Returns a normalized style object or single style value.\n\t *\n\t * For an element with style set to: margin:1px 2px 3em;\n\t *\n\t *\t\telement.getNormalizedStyle( 'margin' ) );\n\t *\n\t * will return:\n\t *\n\t *\t\t{\n\t *\t\t\ttop: '1px',\n\t *\t\t\tright: '2px',\n\t *\t\t\tbottom: '3em',\n\t *\t\t\tleft: '2px' // a normalized value from margin shorthand\n\t *\t\t}\n\t *\n\t * and reading for single style value:\n\t *\n\t *\t\tstyles.getNormalizedStyle( 'margin-left' );\n\t *\n\t * Will return a `2px` string.\n\t *\n\t * **Note**: This method will return normalized values only if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#getNormalized `StylesMap#getNormalized()`} for details.\n\t *\n\t *\n\t * @param {String} property Name of CSS property\n\t * @returns {Object|String|undefined}\n\t */\n\tgetNormalizedStyle( property ) {\n\t\treturn this._styles.getNormalized( property );\n\t}\n\n\t/**\n\t * Returns iterator that contains all style names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetStyleNames() {\n\t\treturn this._styles.getStyleNames();\n\t}\n\n\t/**\n\t * Returns true if style keys are present.\n\t * If more then one style property is provided - returns true only when all properties are present.\n\t *\n\t *\t\telement.hasStyle( 'color' ); // Returns true if 'border-top' style is present.\n\t *\t\telement.hasStyle( 'color', 'border-top' ); // Returns true if 'color' and 'border-top' styles are both present.\n\t *\n\t * @param {...String} property\n\t */\n\thasStyle( ...property ) {\n\t\tfor ( const name of property ) {\n\t\t\tif ( !this._styles.has( name ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns ancestor element that match specified pattern.\n\t * Provided patterns should be compatible with {@link module:engine/view/matcher~Matcher Matcher} as it is used internally.\n\t *\n\t * @see module:engine/view/matcher~Matcher\n\t * @param {Object|String|RegExp|Function} patterns Patterns used to match correct ancestor.\n\t * See {@link module:engine/view/matcher~Matcher}.\n\t * @returns {module:engine/view/element~Element|null} Found element or `null` if no matching ancestor was found.\n\t */\n\tfindAncestor( ...patterns ) {\n\t\tconst matcher = new Matcher( ...patterns );\n\t\tlet parent = this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( matcher.match( parent ) ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the custom property value for the given key.\n\t *\n\t * @param {String|Symbol} key\n\t * @returns {*}\n\t */\n\tgetCustomProperty( key ) {\n\t\treturn this._customProperties.get( key );\n\t}\n\n\t/**\n\t * Returns an iterator which iterates over this element's custom properties.\n\t * Iterator provides `[ key, value ]` pairs for each stored property.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t* getCustomProperties() {\n\t\tyield* this._customProperties.entries();\n\t}\n\n\t/**\n\t * Returns identity string based on element's name, styles, classes and other attributes.\n\t * Two elements that {@link #isSimilar are similar} will have same identity string.\n\t * It has the following format:\n\t *\n\t *\t\t'name class=\"class1,class2\" style=\"style1:value1;style2:value2\" attr1=\"val1\" attr2=\"val2\"'\n \t *\n\t * For example:\n\t *\n\t *\t\tconst element = writer.createContainerElement( 'foo', {\n\t *\t\t\tbanana: '10',\n\t *\t\t\tapple: '20',\n\t *\t\t\tstyle: 'color: red; border-color: white;',\n\t *\t\t\tclass: 'baz'\n\t *\t\t} );\n\t *\n\t *\t\t// returns 'foo class=\"baz\" style=\"border-color:white;color:red\" apple=\"20\" banana=\"10\"'\n\t *\t\telement.getIdentity();\n\t *\n\t * **Note**: Classes, styles and other attributes are sorted alphabetically.\n\t *\n\t * @returns {String}\n\t */\n\tgetIdentity() {\n\t\tconst classes = Array.from( this._classes ).sort().join( ',' );\n\t\tconst styles = this._styles.toString();\n\t\tconst attributes = Array.from( this._attrs ).map( i => `${ i[ 0 ] }=\"${ i[ 1 ] }\"` ).sort().join( ' ' );\n\n\t\treturn this.name +\n\t\t\t( classes == '' ? '' : ` class=\"${ classes }\"` ) +\n\t\t\t( !styles ? '' : ` style=\"${ styles }\"` ) +\n\t\t\t( attributes == '' ? '' : ` ${ attributes }` );\n\t}\n\n\t/**\n\t * Clones provided element.\n\t *\n\t * @protected\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/element~Element} Clone of this element.\n\t */\n\t_clone( deep = false ) {\n\t\tconst childrenClone = [];\n\n\t\tif ( deep ) {\n\t\t\tfor ( const child of this.getChildren() ) {\n\t\t\t\tchildrenClone.push( child._clone( deep ) );\n\t\t\t}\n\t\t}\n\n\t\t// ContainerElement and AttributeElement should be also cloned properly.\n\t\tconst cloned = new this.constructor( this.document, this.name, this._attrs, childrenClone );\n\n\t\t// Classes and styles are cloned separately - this solution is faster than adding them back to attributes and\n\t\t// parse once again in constructor.\n\t\tcloned._classes = new Set( this._classes );\n\t\tcloned._styles.set( this._styles.getNormalized() );\n\n\t\t// Clone custom properties.\n\t\tcloned._customProperties = new Map( this._customProperties );\n\n\t\t// Clone filler offset method.\n\t\t// We can't define this method in a prototype because it's behavior which\n\t\t// is changed by e.g. toWidget() function from ckeditor5-widget. Perhaps this should be one of custom props.\n\t\tcloned.getFillerOffset = this.getFillerOffset;\n\n\t\tcloned._isAllowedInsideAttributeElement = this.isAllowedInsideAttributeElement;\n\n\t\treturn cloned;\n\t}\n\n\t/**\n\t * {@link module:engine/view/element~Element#_insertChild Insert} a child node or a list of child nodes at the end of this node\n\t * and sets the parent of these nodes to this element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#insert\n\t * @protected\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Number} Number of appended nodes.\n\t */\n\t_appendChild( items ) {\n\t\treturn this._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#insert\n\t * @protected\n\t * @param {Number} index Position where nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\t_insertChild( index, items ) {\n\t\tthis._fireChange( 'children', this );\n\t\tlet count = 0;\n\n\t\tconst nodes = normalize( this.document, items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t\tnode.document = this.document;\n\n\t\t\tthis._children.splice( index, 0, node );\n\t\t\tindex++;\n\t\t\tcount++;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#remove\n\t * @protected\n\t * @param {Number} index Number of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @fires module:engine/view/node~Node#change\n\t * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tthis._fireChange( 'children', this );\n\n\t\tfor ( let i = index; i < index + howMany; i++ ) {\n\t\t\tthis._children[ i ].parent = null;\n\t\t}\n\n\t\treturn this._children.splice( index, howMany );\n\t}\n\n\t/**\n\t * Adds or overwrite attribute with a specified key and value.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setAttribute\n\t * @protected\n\t * @param {String} key Attribute key.\n\t * @param {String} value Attribute value.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_setAttribute( key, value ) {\n\t\tvalue = String( value );\n\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tif ( key == 'class' ) {\n\t\t\tparseClasses( this._classes, value );\n\t\t} else if ( key == 'style' ) {\n\t\t\tthis._styles.setTo( value );\n\t\t} else {\n\t\t\tthis._attrs.set( key, value );\n\t\t}\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeAttribute\n\t * @protected\n\t * @param {String} key Attribute key.\n\t * @returns {Boolean} Returns true if an attribute existed and has been removed.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeAttribute( key ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\t// Remove class attribute.\n\t\tif ( key == 'class' ) {\n\t\t\tif ( this._classes.size > 0 ) {\n\t\t\t\tthis._classes.clear();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t// Remove style attribute.\n\t\tif ( key == 'style' ) {\n\t\t\tif ( !this._styles.isEmpty ) {\n\t\t\t\tthis._styles.clear();\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\t// Remove other attributes.\n\t\treturn this._attrs.delete( key );\n\t}\n\n\t/**\n\t * Adds specified class.\n\t *\n\t *\t\telement._addClass( 'foo' ); // Adds 'foo' class.\n\t *\t\telement._addClass( [ 'foo', 'bar' ] ); // Adds 'foo' and 'bar' classes.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#addClass\n\t * @protected\n\t * @param {Array.<String>|String} className\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_addClass( className ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tfor ( const name of toArray( className ) ) {\n\t\t\tthis._classes.add( name );\n\t\t}\n\t}\n\n\t/**\n\t * Removes specified class.\n\t *\n\t *\t\telement._removeClass( 'foo' ); // Removes 'foo' class.\n\t *\t\telement._removeClass( [ 'foo', 'bar' ] ); // Removes both 'foo' and 'bar' classes.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeClass\n\t * @protected\n\t * @param {Array.<String>|String} className\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeClass( className ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tfor ( const name of toArray( className ) ) {\n\t\t\tthis._classes.delete( name );\n\t\t}\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\telement._setStyle( 'color', 'red' );\n\t *\t\telement._setStyle( {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t} );\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setStyle\n\t * @protected\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_setStyle( property, value ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tthis._styles.set( property, value );\n\t}\n\n\t/**\n\t * Removes specified style.\n\t *\n\t *\t\telement._removeStyle( 'color' ); // Removes 'color' style.\n\t *\t\telement._removeStyle( [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeStyle\n\t * @protected\n\t * @param {Array.<String>|String} property\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_removeStyle( property ) {\n\t\tthis._fireChange( 'attributes', this );\n\n\t\tfor ( const name of toArray( property ) ) {\n\t\t\tthis._styles.remove( name );\n\t\t}\n\t}\n\n\t/**\n\t * Sets a custom property. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#setCustomProperty\n\t * @protected\n\t * @param {String|Symbol} key\n\t * @param {*} value\n\t */\n\t_setCustomProperty( key, value ) {\n\t\tthis._customProperties.set( key, value );\n\t}\n\n\t/**\n\t * Removes the custom property stored under the given key.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#removeCustomProperty\n\t * @protected\n\t * @param {String|Symbol} key\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\t_removeCustomProperty( key ) {\n\t\treturn this._customProperties.delete( key );\n\t}\n\n\t/**\n\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t *\n\t * @abstract\n\t * @method module:engine/view/element~Element#getFillerOffset\n\t */\n\n\t// @if CK_DEBUG_ENGINE // printTree( level = 0) {\n\t// @if CK_DEBUG_ENGINE // \tlet string = '';\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\t'.repeat( level ) + `<${ this.name }${ convertMapToTags( this.getAttributes() ) }>`;\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + '\\t'.repeat( level + 1 ) + child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + child.printTree( level + 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tif ( this.childCount ) {\n\t// @if CK_DEBUG_ENGINE //\t\tstring += '\\n' + '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += `</${ this.name }>`;\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Parses attributes provided to the element constructor before they are applied to an element. If attributes are passed\n// as an object (instead of `Iterable`), the object is transformed to the map. Attributes with `null` value are removed.\n// Attributes with non-`String` value are converted to `String`.\n//\n// @param {Object|Iterable} attrs Attributes to parse.\n// @returns {Map} Parsed attributes.\nfunction parseAttributes( attrs ) {\n\tattrs = toMap( attrs );\n\n\tfor ( const [ key, value ] of attrs ) {\n\t\tif ( value === null ) {\n\t\t\tattrs.delete( key );\n\t\t} else if ( typeof value != 'string' ) {\n\t\t\tattrs.set( key, String( value ) );\n\t\t}\n\t}\n\n\treturn attrs;\n}\n\n// Parses class attribute and puts all classes into classes set.\n// Classes set s cleared before insertion.\n//\n// @param {Set.<String>} classesSet Set to insert parsed classes.\n// @param {String} classesString String with classes to parse.\nfunction parseClasses( classesSet, classesString ) {\n\tconst classArray = classesString.split( /\\s+/ );\n\tclassesSet.clear();\n\tclassArray.forEach( name => classesSet.add( name ) );\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}\n// @returns {Iterable.<module:engine/view/node~Node>}\nfunction normalize( document, nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( document, nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( document, node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( document, node.data );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/containerelement\n */\n\nimport Element from './element';\n\n/**\n * Containers are elements which define document structure. They define boundaries for\n * {@link module:engine/view/attributeelement~AttributeElement attributes}. They are mostly used for block elements like `<p>` or `<div>`.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * The container element should be your default choice when writing a converter, unless:\n *\n * * this element represents a model text attribute (then use {@link module:engine/view/attributeelement~AttributeElement}),\n * * this is an empty element like `<img>` (then use {@link module:engine/view/emptyelement~EmptyElement}),\n * * this is a root element,\n * * this is a nested editable element (then use {@link module:engine/view/editableelement~EditableElement}).\n *\n * To create a new container element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement `DowncastWriter#createContainerElement()`}\n * method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class ContainerElement extends Element {\n\t/**\n\t * Creates a container element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createContainerElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tcontainerElement.is( 'containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'element' ); // -> true\n\t *\t\tcontainerElement.is( 'node' ); // -> true\n\t *\t\tcontainerElement.is( 'view:containerElement' ); // -> true\n\t *\t\tcontainerElement.is( 'view:element' ); // -> true\n\t *\t\tcontainerElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tcontainerElement.is( 'model:element' ); // -> false\n\t *\t\tcontainerElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a container element, you can also check its\n\t * {@link module:engine/view/containerelement~ContainerElement#name name}:\n\t *\n\t *\t\tcontainerElement.is( 'element', 'div' ); // -> true if this is a div container element\n\t *\t\tcontainerElement.is( 'contaienrElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n *\n * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n */\nexport function getFillerOffset() {\n\tconst children = [ ...this.getChildren() ];\n\tconst lastChild = children[ this.childCount - 1 ];\n\n\t// Block filler is required after a `<br>` if it's the last element in its container. See #1422.\n\tif ( lastChild && lastChild.is( 'element', 'br' ) ) {\n\t\treturn this.childCount;\n\t}\n\n\tfor ( const child of children ) {\n\t\t// If there's any non-UI element don't render the bogus.\n\t\tif ( !child.is( 'uiElement' ) ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t// If there are only UI elements render the bogus at the end of the element.\n\treturn this.childCount;\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/view/editableelement\n */\n\nimport ContainerElement from './containerelement';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\n\n/**\n * Editable element which can be a {@link module:engine/view/rooteditableelement~RootEditableElement root}\n * or nested editable area in the editor.\n *\n * Editable is automatically read-only when its {@link module:engine/view/document~Document Document} is read-only.\n *\n * The constructor of this class shouldn't be used directly. To create new `EditableElement` use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEditableElement `downcastWriter#createEditableElement()`} method.\n *\n * @extends module:engine/view/containerelement~ContainerElement\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditableElement extends ContainerElement {\n\t/**\n\t * Creates an editable element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createEditableElement\n\t * @protected\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Whether the editable is in read-write or read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Whether the editable is focused.\n\t\t *\n\t\t * This property updates when {@link module:engine/view/document~Document#isFocused document.isFocused} or view\n\t\t * selection is changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/editableelement~EditableElement#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\tthis.bind( 'isReadOnly' ).to( document );\n\n\t\tthis.bind( 'isFocused' ).to(\n\t\t\tdocument,\n\t\t\t'isFocused',\n\t\t\tisFocused => isFocused && document.selection.editableElement == this\n\t\t);\n\n\t\t// Update focus state based on selection changes.\n\t\tthis.listenTo( document.selection, 'change', () => {\n\t\t\tthis.isFocused = document.isFocused && document.selection.editableElement == this;\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\teditableElement.is( 'editableElement' ); // -> true\n\t *\t\teditableElement.is( 'element' ); // -> true\n\t *\t\teditableElement.is( 'node' ); // -> true\n\t *\t\teditableElement.is( 'view:editableElement' ); // -> true\n\t *\t\teditableElement.is( 'view:element' ); // -> true\n\t *\t\teditableElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\teditableElement.is( 'model:element' ); // -> false\n\t *\t\teditableElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an editbale element, you can also check its\n\t * {@link module:engine/view/editableelement~EditableElement#name name}:\n\t *\n\t *\t\teditableElement.is( 'element', 'div' ); // -> true if this is a div element\n\t *\t\teditableElement.is( 'editableElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n}\n\nmix( EditableElement, ObservableMixin );\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/view/rooteditableelement\n */\n\nimport EditableElement from './editableelement';\n\nconst rootNameSymbol = Symbol( 'rootName' );\n\n/**\n * Class representing a single root in the data view. A root can be either {@link ~RootEditableElement#isReadOnly editable or read-only},\n * but in both cases it is called \"an editable\". Roots can contain other {@link module:engine/view/editableelement~EditableElement\n * editable elements} making them \"nested editables\".\n *\n * @extends module:engine/view/editableelement~EditableElement\n */\nexport default class RootEditableElement extends EditableElement {\n\t/**\n\t * Creates root editable element.\n\t *\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t */\n\tconstructor( document, name ) {\n\t\tsuper( document, name );\n\n\t\t/**\n\t\t * Name of this root inside {@link module:engine/view/document~Document} that is an owner of this root. If no\n\t\t * other name is set, `main` name is used.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.rootName = 'main';\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trootEditableElement.is( 'rootElement' ); // -> true\n\t *\t\trootEditableElement.is( 'editableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'element' ); // -> true\n\t *\t\trootEditableElement.is( 'node' ); // -> true\n\t *\t\trootEditableElement.is( 'view:editableElement' ); // -> true\n\t *\t\trootEditableElement.is( 'view:element' ); // -> true\n\t *\t\trootEditableElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\trootEditableElement.is( 'model:element' ); // -> false\n\t *\t\trootEditableElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a root editable element, you can also check its\n\t * {@link module:engine/view/rooteditableelement~RootEditableElement#name name}:\n\t *\n\t *\t\trootEditableElement.is( 'element', 'div' ); // -> true if this is a div root editable element\n\t *\t\trootEditableElement.is( 'rootElement', 'div' ); // -> same as above\n\t *\t\ttext.is( 'element', 'div' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'rootElement' || type === 'view:rootElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'rootElement' || type === 'view:rootElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'editableElement' || type === 'view:editableElement' ||\n\t\t\t\ttype === 'containerElement' || type === 'view:containerElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\tget rootName() {\n\t\treturn this.getCustomProperty( rootNameSymbol );\n\t}\n\n\tset rootName( rootName ) {\n\t\tthis._setCustomProperty( rootNameSymbol, rootName );\n\t}\n\n\t/**\n\t * Overrides old element name and sets new one.\n\t * This is needed because view roots are created before they are attached to the DOM.\n\t * The name of the root element is temporary at this stage. It has to be changed when the\n\t * view root element is attached to the DOM element.\n\t *\n\t * @protected\n\t * @param {String} name The new name of element.\n\t */\n\tset _name( name ) {\n\t\tthis.name = name;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/treewalker\n */\n\nimport Element from './element';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport Position from './position';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Position iterator class. It allows to iterate forward and backward over the document.\n */\nexport default class TreeWalker {\n\t/**\n\t * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.\n\t *\n\t * @constructor\n\t * @param {Object} options Object with configuration.\n\t * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {module:engine/view/position~Position} [options.startPosition] Starting position.\n\t * @param {'forward'|'backward'} [options.direction='forward'] Walking direction.\n\t * @param {Boolean} [options.singleCharacters=false] Flag indicating whether all characters from\n\t * {@link module:engine/view/text~Text} should be returned as one {@link module:engine/view/text~Text} (`false`) ore one by one as\n\t * {@link module:engine/view/textproxy~TextProxy} (`true`).\n\t * @param {Boolean} [options.shallow=false] Flag indicating whether iterator should enter elements or not. If the\n\t * iterator is shallow child nodes of any iterated node will not be returned along with `elementEnd` tag.\n\t * @param {Boolean} [options.ignoreElementEnd=false] Flag indicating whether iterator should ignore `elementEnd`\n\t * tags. If the option is true walker will not return a parent node of start position. If this option is `true`\n\t * each {@link module:engine/view/element~Element} will be returned once, while if the option is `false` they might be returned\n\t * twice: for `'elementStart'` and `'elementEnd'`.\n\t */\n\tconstructor( options = {} ) {\n\t\tif ( !options.boundaries && !options.startPosition ) {\n\t\t\t/**\n\t\t\t * Neither boundaries nor starting position have been defined.\n\t\t\t *\n\t\t\t * @error view-tree-walker-no-start-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-tree-walker-no-start-position',\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\n\t\tif ( options.direction && options.direction != 'forward' && options.direction != 'backward' ) {\n\t\t\t/**\n\t\t\t * Only `backward` and `forward` direction allowed.\n\t\t\t *\n\t\t\t * @error view-tree-walker-unknown-direction\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-tree-walker-unknown-direction', options.startPosition, { direction: options.direction } );\n\t\t}\n\n\t\t/**\n\t\t * Iterator boundaries.\n\t\t *\n\t\t * When the iterator is walking `'forward'` on the end of boundary or is walking `'backward'`\n\t\t * on the start of boundary, then `{ done: true }` is returned.\n\t\t *\n\t\t * If boundaries are not defined they are set before first and after last child of the root node.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/range~Range} module:engine/view/treewalker~TreeWalker#boundaries\n\t\t */\n\t\tthis.boundaries = options.boundaries || null;\n\n\t\t/**\n\t\t * Iterator position. If start position is not defined then position depends on {@link #direction}. If direction is\n\t\t * `'forward'` position starts form the beginning, when direction is `'backward'` position starts from the end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position} module:engine/view/treewalker~TreeWalker#position\n\t\t */\n\t\tif ( options.startPosition ) {\n\t\t\tthis.position = Position._createAt( options.startPosition );\n\t\t} else {\n\t\t\tthis.position = Position._createAt( options.boundaries[ options.direction == 'backward' ? 'end' : 'start' ] );\n\t\t}\n\n\t\t/**\n\t\t * Walking direction. Defaults `'forward'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'backward'|'forward'} module:engine/view/treewalker~TreeWalker#direction\n\t\t */\n\t\tthis.direction = options.direction || 'forward';\n\n\t\t/**\n\t\t * Flag indicating whether all characters from {@link module:engine/view/text~Text} should be returned as one\n\t\t * {@link module:engine/view/text~Text} or one by one as {@link module:engine/view/textproxy~TextProxy}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#singleCharacters\n\t\t */\n\t\tthis.singleCharacters = !!options.singleCharacters;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should enter elements or not. If the iterator is shallow child nodes of any\n\t\t * iterated node will not be returned along with `elementEnd` tag.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#shallow\n\t\t */\n\t\tthis.shallow = !!options.shallow;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should ignore `elementEnd` tags. If set to `true`, walker will not\n\t\t * return a parent node of the start position. Each {@link module:engine/view/element~Element} will be returned once.\n\t\t * When set to `false` each element might be returned twice: for `'elementStart'` and `'elementEnd'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/view/treewalker~TreeWalker#ignoreElementEnd\n\t\t */\n\t\tthis.ignoreElementEnd = !!options.ignoreElementEnd;\n\n\t\t/**\n\t\t * Start boundary parent.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/node~Node} module:engine/view/treewalker~TreeWalker#_boundaryStartParent\n\t\t */\n\t\tthis._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;\n\n\t\t/**\n\t\t * End boundary parent.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/node~Node} module:engine/view/treewalker~TreeWalker#_boundaryEndParent\n\t\t */\n\t\tthis._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:engine/view/treewalker~TreeWalkerValue>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.\n\t *\n\t * For example:\n\t *\n\t * \t\twalker.skip( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>\n\t * \t\twalker.skip( value => true ); // Move the position to the end: <p>{}foo</p> -> <p>foo</p>[]\n\t * \t\twalker.skip( value => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t */\n\tskip( skip ) {\n\t\tlet done, value, prevPosition;\n\n\t\tdo {\n\t\t\tprevPosition = this.position;\n\n\t\t\t( { done, value } = this.next() );\n\t\t} while ( !done && skip( value ) );\n\n\t\tif ( !done ) {\n\t\t\tthis.position = prevPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the next tree walker's value.\n\t *\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} Object implementing iterator interface, returning\n\t * information about taken step.\n\t */\n\tnext() {\n\t\tif ( this.direction == 'forward' ) {\n\t\t\treturn this._next();\n\t\t} else {\n\t\t\treturn this._previous();\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step forward in view. Moves the {@link #position} to the next position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done `true` if iterator is done, `false` otherwise.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_next() {\n\t\tlet position = this.position.clone();\n\t\tconst previousPosition = this.position;\n\t\tconst parent = position.parent;\n\n\t\t// We are at the end of the root.\n\t\tif ( parent.parent === null && position.offset === parent.childCount ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent === this._boundaryEndParent && position.offset == this.boundaries.end.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just after current position.\n\t\tlet node;\n\n\t\t// Text is a specific parent because it contains string instead of child nodes.\n\t\tif ( parent instanceof Text ) {\n\t\t\tif ( position.isAtEnd ) {\n\t\t\t\t// Prevent returning \"elementEnd\" for Text node. Skip that value and return the next walker step.\n\t\t\t\tthis.position = Position._createAfter( parent );\n\n\t\t\t\treturn this._next();\n\t\t\t}\n\n\t\t\tnode = parent.data[ position.offset ];\n\t\t} else {\n\t\t\tnode = parent.getChild( position.offset );\n\t\t}\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition = new Position( node, 0 );\n\t\t\t} else {\n\t\t\t\tposition.offset++;\n\t\t\t}\n\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t} else if ( node instanceof Text ) {\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tposition = new Position( node, 0 );\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\tlet charactersCount = node.data.length;\n\t\t\t\tlet item;\n\n\t\t\t\t// If text stick out of walker range, we need to cut it and wrap in TextProxy.\n\t\t\t\tif ( node == this._boundaryEndParent ) {\n\t\t\t\t\tcharactersCount = this.boundaries.end.offset;\n\t\t\t\t\titem = new TextProxy( node, 0, charactersCount );\n\t\t\t\t\tposition = Position._createAfter( item );\n\t\t\t\t} else {\n\t\t\t\t\titem = new TextProxy( node, 0, node.data.length );\n\t\t\t\t\t// If not just keep moving forward.\n\t\t\t\t\tposition.offset++;\n\t\t\t\t}\n\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t\t}\n\t\t} else if ( typeof node == 'string' ) {\n\t\t\tlet textLength;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\ttextLength = 1;\n\t\t\t} else {\n\t\t\t\t// Check if text stick out of walker range.\n\t\t\t\tconst endOffset = parent === this._boundaryEndParent ? this.boundaries.end.offset : parent.data.length;\n\n\t\t\t\ttextLength = endOffset - position.offset;\n\t\t\t}\n\n\t\t\tconst textProxy = new TextProxy( parent, position.offset, textLength );\n\n\t\t\tposition.offset += textLength;\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the end of current `parent`.\n\t\t\tposition = Position._createAfter( parent );\n\t\t\tthis.position = position;\n\n\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\treturn this._formatReturnValue( 'elementEnd', parent, previousPosition, position );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step backward in view. Moves the {@link #position} to the previous position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_previous() {\n\t\tlet position = this.position.clone();\n\t\tconst previousPosition = this.position;\n\t\tconst parent = position.parent;\n\n\t\t// We are at the beginning of the root.\n\t\tif ( parent.parent === null && position.offset === 0 ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent == this._boundaryStartParent && position.offset == this.boundaries.start.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just before current position.\n\t\tlet node;\n\n\t\t// Text {@link module:engine/view/text~Text} element is a specific parent because contains string instead of child nodes.\n\t\tif ( parent instanceof Text ) {\n\t\t\tif ( position.isAtStart ) {\n\t\t\t\t// Prevent returning \"elementStart\" for Text node. Skip that value and return the next walker step.\n\t\t\t\tthis.position = Position._createBefore( parent );\n\n\t\t\t\treturn this._previous();\n\t\t\t}\n\n\t\t\tnode = parent.data[ position.offset - 1 ];\n\t\t} else {\n\t\t\tnode = parent.getChild( position.offset - 1 );\n\t\t}\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition = new Position( node, node.childCount );\n\t\t\t\tthis.position = position;\n\n\t\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\t\treturn this._previous();\n\t\t\t\t} else {\n\t\t\t\t\treturn this._formatReturnValue( 'elementEnd', node, previousPosition, position );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tposition.offset--;\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t\t}\n\t\t} else if ( node instanceof Text ) {\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tposition = new Position( node, node.data.length );\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._previous();\n\t\t\t} else {\n\t\t\t\tlet charactersCount = node.data.length;\n\t\t\t\tlet item;\n\n\t\t\t\t// If text stick out of walker range, we need to cut it and wrap in TextProxy.\n\t\t\t\tif ( node == this._boundaryStartParent ) {\n\t\t\t\t\tconst offset = this.boundaries.start.offset;\n\n\t\t\t\t\titem = new TextProxy( node, offset, node.data.length - offset );\n\t\t\t\t\tcharactersCount = item.data.length;\n\t\t\t\t\tposition = Position._createBefore( item );\n\t\t\t\t} else {\n\t\t\t\t\titem = new TextProxy( node, 0, node.data.length );\n\t\t\t\t\t// If not just keep moving backward.\n\t\t\t\t\tposition.offset--;\n\t\t\t\t}\n\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn this._formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t\t}\n\t\t} else if ( typeof node == 'string' ) {\n\t\t\tlet textLength;\n\n\t\t\tif ( !this.singleCharacters ) {\n\t\t\t\t// Check if text stick out of walker range.\n\t\t\t\tconst startOffset = parent === this._boundaryStartParent ? this.boundaries.start.offset : 0;\n\n\t\t\t\ttextLength = position.offset - startOffset;\n\t\t\t} else {\n\t\t\t\ttextLength = 1;\n\t\t\t}\n\n\t\t\tposition.offset -= textLength;\n\n\t\t\tconst textProxy = new TextProxy( parent, position.offset, textLength );\n\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'text', textProxy, previousPosition, position, textLength );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the beginning of current `parent`.\n\t\t\tposition = Position._createBefore( parent );\n\t\t\tthis.position = position;\n\n\t\t\treturn this._formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );\n\t\t}\n\t}\n\n\t/**\n\t * Format returned data and adjust `previousPosition` and `nextPosition` if reach the bound of the {@link module:engine/view/text~Text}.\n\t *\n\t * @private\n\t * @param {module:engine/view/treewalker~TreeWalkerValueType} type Type of step.\n\t * @param {module:engine/view/item~Item} item Item between old and new position.\n\t * @param {module:engine/view/position~Position} previousPosition Previous position of iterator.\n\t * @param {module:engine/view/position~Position} nextPosition Next position of iterator.\n\t * @param {Number} [length] Length of the item.\n\t * @returns {module:engine/view/treewalker~TreeWalkerValue}\n\t */\n\t_formatReturnValue( type, item, previousPosition, nextPosition, length ) {\n\t\t// Text is a specific parent, because contains string instead of children.\n\t\t// Walker doesn't enter to the Text except situations when walker is iterating over every single character,\n\t\t// or the bound starts/ends inside the Text. So when the position is at the beginning or at the end of the Text\n\t\t// we move it just before or just after Text.\n\t\tif ( item instanceof TextProxy ) {\n\t\t\t// Position is at the end of Text.\n\t\t\tif ( item.offsetInText + item.data.length == item.textNode.data.length ) {\n\t\t\t\tif ( this.direction == 'forward' && !( this.boundaries && this.boundaries.end.isEqual( this.position ) ) ) {\n\t\t\t\t\tnextPosition = Position._createAfter( item.textNode );\n\t\t\t\t\t// When we change nextPosition of returned value we need also update walker current position.\n\t\t\t\t\tthis.position = nextPosition;\n\t\t\t\t} else {\n\t\t\t\t\tpreviousPosition = Position._createAfter( item.textNode );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Position is at the begining ot the text.\n\t\t\tif ( item.offsetInText === 0 ) {\n\t\t\t\tif ( this.direction == 'backward' && !( this.boundaries && this.boundaries.start.isEqual( this.position ) ) ) {\n\t\t\t\t\tnextPosition = Position._createBefore( item.textNode );\n\t\t\t\t\t// When we change nextPosition of returned value we need also update walker current position.\n\t\t\t\t\tthis.position = nextPosition;\n\t\t\t\t} else {\n\t\t\t\t\tpreviousPosition = Position._createBefore( item.textNode );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tdone: false,\n\t\t\tvalue: {\n\t\t\t\ttype,\n\t\t\t\titem,\n\t\t\t\tpreviousPosition,\n\t\t\t\tnextPosition,\n\t\t\t\tlength\n\t\t\t}\n\t\t};\n\t}\n}\n\n/**\n * Type of the step made by {@link module:engine/view/treewalker~TreeWalker}.\n * Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end\n * of node, or `'text'` if walker traversed over single and multiple characters.\n * For {@link module:engine/view/text~Text} `elementStart` and `elementEnd` is not returned.\n *\n * @typedef {String} module:engine/view/treewalker~TreeWalkerValueType\n */\n\n/**\n * Object returned by {@link module:engine/view/treewalker~TreeWalker} when traversing tree view.\n *\n * @typedef {Object} module:engine/view/treewalker~TreeWalkerValue\n * @property {module:engine/view/treewalker~TreeWalkerValueType} type\n * @property {module:engine/view/item~Item} item Item between the old and the new positions\n * of the tree walker.\n * @property {module:engine/view/position~Position} previousPosition Previous position of the iterator.\n * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the\n * position before the item.\n * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after item.\n * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the\n * inside of the text to its parent just before or just after that text.\n * @property {module:engine/view/position~Position} nextPosition Next position of the iterator.\n * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after the item.\n * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position\n * before the item.\n * * If the position is at the beginning or at the end of the {@link module:engine/view/text~Text} it is always moved from the\n * inside of the text to its parent just before or just after that text.\n * @property {Number} [length] Length of the item. For `'elementStart'` it is `1`. For `'text'` it is\n * the length of that text. For `'elementEnd'` it is `undefined`.\n */\n\n/**\n * Tree walking directions.\n *\n * @typedef {'forward'|'backward'} module:engine/view/treewalker~TreeWalkerDirection\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/position\n */\n\nimport TreeWalker from './treewalker';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EditableElement from './editableelement';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Position in the view tree. Position is represented by its parent node and an offset in this parent.\n *\n * In order to create a new position instance use the `createPosition*()` factory methods available in:\n *\n * * {@link module:engine/view/view~View}\n * * {@link module:engine/view/downcastwriter~DowncastWriter}\n * * {@link module:engine/view/upcastwriter~UpcastWriter}\n */\nexport default class Position {\n\t/**\n\t * Creates a position.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} parent Position parent.\n\t * @param {Number} offset Position offset.\n\t */\n\tconstructor( parent, offset ) {\n\t\t/**\n\t\t * Position parent.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t\t * module:engine/view/position~Position#parent\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * Position offset.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} module:engine/view/position~Position#offset\n\t\t */\n\t\tthis.offset = offset;\n\t}\n\n\t/**\n\t * Node directly after the position. Equals `null` when there is no node after position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeAfter() {\n\t\tif ( this.parent.is( '$text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset ) || null;\n\t}\n\n\t/**\n\t * Node directly before the position. Equals `null` when there is no node before position or position is located\n\t * inside text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|null}\n\t */\n\tget nodeBefore() {\n\t\tif ( this.parent.is( '$text' ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.parent.getChild( this.offset - 1 ) || null;\n\t}\n\n\t/**\n\t * Is `true` if position is at the beginning of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtStart() {\n\t\treturn this.offset === 0;\n\t}\n\n\t/**\n\t * Is `true` if position is at the end of its {@link module:engine/view/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtEnd() {\n\t\tconst endOffset = this.parent.is( '$text' ) ? this.parent.data.length : this.parent.childCount;\n\n\t\treturn this.offset === endOffset;\n\t}\n\n\t/**\n\t * Position's root, that is the root of the position's parent element.\n\t *\n\t * @readonly\n\t * @type {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.parent.root;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this position, or `null` if\n\t * position is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\tlet editable = this.parent;\n\n\t\twhile ( !( editable instanceof EditableElement ) ) {\n\t\t\tif ( editable.parent ) {\n\t\t\t\teditable = editable.parent;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\treturn editable;\n\t}\n\n\t/**\n\t * Returns a new instance of Position with offset incremented by `shift` value.\n\t *\n\t * @param {Number} shift How position offset should get changed. Accepts negative values.\n\t * @returns {module:engine/view/position~Position} Shifted position.\n\t */\n\tgetShiftedBy( shift ) {\n\t\tconst shifted = Position._createAt( this );\n\n\t\tconst offset = shifted.offset + shift;\n\t\tshifted.offset = offset < 0 ? 0 : offset;\n\n\t\treturn shifted;\n\t}\n\n\t/**\n\t * Gets the farthest position which matches the callback using\n\t * {@link module:engine/view/treewalker~TreeWalker TreeWalker}.\n\t *\n\t * For example:\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text' ); // <p>{}foo</p> -> <p>foo[]</p>\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } ); // <p>foo[]</p> -> <p>{}foo</p>\n\t * \t\tgetLastMatchingPosition( value => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/view/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t *\n\t * @returns {module:engine/view/position~Position} The position after the last item which matches the `skip` callback test.\n\t */\n\tgetLastMatchingPosition( skip, options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\t\ttreeWalker.skip( skip );\n\n\t\treturn treeWalker.position;\n\t}\n\n\t/**\n\t * Returns ancestors array of this position, that is this position's parent and it's ancestors.\n\t *\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors() {\n\t\tif ( this.parent.is( 'documentFragment' ) ) {\n\t\t\treturn [ this.parent ];\n\t\t} else {\n\t\t\treturn this.parent.getAncestors( { includeSelf: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both positions.\n\t *\n\t * @param {module:engine/view/position~Position} position\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( position ) {\n\t\tconst ancestorsA = this.getAncestors();\n\t\tconst ancestorsB = position.getAncestors();\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tposition.is( 'position' ); // -> true\n\t *\t\tposition.is( 'view:position' ); // -> true\n\t *\n\t *\t\tposition.is( 'model:position' ); // -> false\n\t *\t\tposition.is( 'element' ); // -> false\n\t *\t\tposition.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'position' || type === 'view:position';\n\t}\n\n\t/**\n\t * Checks whether this position equals given position.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions are same.\n\t */\n\tisEqual( otherPosition ) {\n\t\treturn ( this.parent == otherPosition.parent && this.offset == otherPosition.offset );\n\t}\n\n\t/**\n\t * Checks whether this position is located before given position. When method returns `false` it does not mean that\n\t * this position is after give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isAfter\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is before given position.\n\t */\n\tisBefore( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'before';\n\t}\n\n\t/**\n\t * Checks whether this position is located after given position. When method returns `false` it does not mean that\n\t * this position is before give one. Two positions may be located inside separate roots and in that situation this\n\t * method will still return `false`.\n\t *\n\t * @see module:engine/view/position~Position#isBefore\n\t * @see module:engine/view/position~Position#compareWith\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} Returns `true` if this position is after given position.\n\t */\n\tisAfter( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'after';\n\t}\n\n\t/**\n\t * Checks whether this position is before, after or in same position that other position. Two positions may be also\n\t * different when they are located in separate roots.\n\t *\n\t * @param {module:engine/view/position~Position} otherPosition Position to compare with.\n\t * @returns {module:engine/view/position~PositionRelation}\n\t */\n\tcompareWith( otherPosition ) {\n\t\tif ( this.root !== otherPosition.root ) {\n\t\t\treturn 'different';\n\t\t}\n\n\t\tif ( this.isEqual( otherPosition ) ) {\n\t\t\treturn 'same';\n\t\t}\n\n\t\t// Get path from root to position's parent element.\n\t\tconst thisPath = this.parent.is( 'node' ) ? this.parent.getPath() : [];\n\t\tconst otherPath = otherPosition.parent.is( 'node' ) ? otherPosition.parent.getPath() : [];\n\n\t\t// Add the positions' offsets to the parents offsets.\n\t\tthisPath.push( this.offset );\n\t\totherPath.push( otherPosition.offset );\n\n\t\t// Compare both path arrays to find common ancestor.\n\t\tconst result = compareArrays( thisPath, otherPath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn 'before';\n\n\t\t\tcase 'extension':\n\t\t\t\treturn 'after';\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < otherPath[ result ] ? 'before' : 'after';\n\t\t}\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this positions as a start position.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}\n\t * @param {module:engine/view/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\tclone() {\n\t\treturn new Position( this.parent, this.offset );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link module:engine/view/position~Position._createBefore},\n\t * * {@link module:engine/view/position~Position._createAfter}.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item|module:engine/view/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/view/item~Item view item}.\n\t */\n\tstatic _createAt( itemOrPosition, offset ) {\n\t\tif ( itemOrPosition instanceof Position ) {\n\t\t\treturn new this( itemOrPosition.parent, itemOrPosition.offset );\n\t\t} else {\n\t\t\tconst node = itemOrPosition;\n\n\t\t\tif ( offset == 'end' ) {\n\t\t\t\toffset = node.is( '$text' ) ? node.data.length : node.childCount;\n\t\t\t} else if ( offset == 'before' ) {\n\t\t\t\treturn this._createBefore( node );\n\t\t\t} else if ( offset == 'after' ) {\n\t\t\t\treturn this._createAfter( node );\n\t\t\t} else if ( offset !== 0 && !offset ) {\n\t\t\t\t/**\n\t\t\t\t * {@link module:engine/view/view~View#createPositionAt `View#createPositionAt()`}\n\t\t\t\t * requires the offset to be specified when the first parameter is a view item.\n\t\t\t\t *\n\t\t\t\t * @error view-createpositionat-offset-required\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-createpositionat-offset-required', node );\n\t\t\t}\n\n\t\t\treturn new Position( node, offset );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createAfter( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText + item.data.length );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position after a root.\n\t\t\t *\n\t\t\t * @error view-position-after-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-after-root', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index + 1 );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tstatic _createBefore( item ) {\n\t\t// TextProxy is not a instance of Node so we need do handle it in specific way.\n\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\treturn new Position( item.textNode, item.offsetInText );\n\t\t}\n\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You cannot make a position before a root.\n\t\t\t *\n\t\t\t * @error view-position-before-root\n\t\t\t * @param {module:engine/view/node~Node} root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-position-before-root', item, { root: item } );\n\t\t}\n\n\t\treturn new Position( item.parent, item.index );\n\t}\n}\n\n/**\n * A flag indicating whether this position is `'before'` or `'after'` or `'same'` as given position.\n * If positions are in different roots `'different'` flag is returned.\n *\n * @typedef {String} module:engine/view/position~PositionRelation\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/view/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\n\n/**\n * Range in the view tree. A range is represented by its start and end {@link module:engine/view/position~Position positions}.\n *\n * In order to create a new position instance use the `createPosition*()` factory methods available in:\n *\n * * {@link module:engine/view/view~View}\n * * {@link module:engine/view/downcastwriter~DowncastWriter}\n * * {@link module:engine/view/upcastwriter~UpcastWriter}\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** Constructor creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at the `start` position.\n\t */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position}\n\t\t */\n\t\tthis.start = start.clone();\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/position~Position}\n\t\t */\n\t\tthis.end = end ? end.clone() : start.clone();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/view/position~Position positions},\n\t * grouped as {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * This iterator uses {@link module:engine/view/treewalker~TreeWalker TreeWalker} with `boundaries` set to this range and\n\t * `ignoreElementEnd` option\n\t * set to `true`.\n\t *\n\t * @returns {Iterable.<module:engine/view/treewalker~TreeWalkerValue>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is it start and end positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link module:engine/view/range~Range#start start} position and\n\t * {@link module:engine/view/range~Range#end end} position are in the same {@link module:engine/view/position~Position#parent parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\treturn this.start.parent === this.end.parent;\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Creates a maximal range that has the same content as this range but is expanded in both ways (at the beginning\n\t * and at the end).\n\t *\n\t * For example:\n\t *\n\t *\t\t<p>Foo</p><p><b>{Bar}</b></p> -> <p>Foo</p>[<p><b>Bar</b>]</p>\n\t *\t\t<p><b>foo</b>{bar}<span></span></p> -> <p><b>foo[</b>bar<span></span>]</p>\n\t *\n\t * Note that in the sample above:\n\t *\n\t * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},\n\t * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},\n\t * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.\n\t *\n\t * @returns {module:engine/view/range~Range} Enlarged range.\n\t */\n\tgetEnlarged() {\n\t\tlet start = this.start.getLastMatchingPosition( enlargeTrimSkip, { direction: 'backward' } );\n\t\tlet end = this.end.getLastMatchingPosition( enlargeTrimSkip );\n\n\t\t// Fix positions, in case if they are in Text node.\n\t\tif ( start.parent.is( '$text' ) && start.isAtStart ) {\n\t\t\tstart = Position._createBefore( start.parent );\n\t\t}\n\n\t\tif ( end.parent.is( '$text' ) && end.isAtEnd ) {\n\t\t\tend = Position._createAfter( end.parent );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a minimum range that has the same content as this range but is trimmed in both ways (at the beginning\n\t * and at the end).\n\t *\n\t * For example:\n\t *\n\t *\t\t<p>Foo</p>[<p><b>Bar</b>]</p> -> <p>Foo</p><p><b>{Bar}</b></p>\n\t *\t\t<p><b>foo[</b>bar<span></span>]</p> -> <p><b>foo</b>{bar}<span></span></p>\n\t *\n\t * Note that in the sample above:\n\t *\n\t * - `<p>` have type of {@link module:engine/view/containerelement~ContainerElement},\n\t * - `<b>` have type of {@link module:engine/view/attributeelement~AttributeElement},\n\t * - `<span>` have type of {@link module:engine/view/uielement~UIElement}.\n\t *\n\t * @returns {module:engine/view/range~Range} Shrink range.\n\t */\n\tgetTrimmed() {\n\t\tlet start = this.start.getLastMatchingPosition( enlargeTrimSkip );\n\n\t\tif ( start.isAfter( this.end ) || start.isEqual( this.end ) ) {\n\t\t\treturn new Range( start, start );\n\t\t}\n\n\t\tlet end = this.end.getLastMatchingPosition( enlargeTrimSkip, { direction: 'backward' } );\n\t\tconst nodeAfterStart = start.nodeAfter;\n\t\tconst nodeBeforeEnd = end.nodeBefore;\n\n\t\t// Because TreeWalker prefers positions next to text node, we need to move them manually into these text nodes.\n\t\tif ( nodeAfterStart && nodeAfterStart.is( '$text' ) ) {\n\t\t\tstart = new Position( nodeAfterStart, 0 );\n\t\t}\n\n\t\tif ( nodeBeforeEnd && nodeBeforeEnd.is( '$text' ) ) {\n\t\t\tend = new Position( nodeBeforeEnd, nodeBeforeEnd.data.length );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Two ranges are equal if their start and end positions are equal.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this == otherRange || ( this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end ) );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/view/position~Position position}.\n\t *\n\t * @param {module:engine/view/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/view/position~Position position} is contained in this range,\n\t * `false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/view/range~Range range}.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link module:engine/view/range~Range range} boundaries are contained by this range, `false`\n\t * otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link module:engine/view/range~Range range} is not a part of given\n\t * {@link module:engine/view/range~Range range}.\n\t * Returned array contains zero, one or two {@link module:engine/view/range~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet foo = downcastWriter.createText( 'foo' );\n\t *\t\tlet img = downcastWriter.createContainerElement( 'img' );\n\t *\t\tlet bar = downcastWriter.createText( 'bar' );\n\t *\t\tlet p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );\n\t *\n\t *\t\tlet range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // \"o\", img, \"b\" are in range.\n\t *\t\tlet otherRange = view.createRange( // \"oo\", img, \"ba\" are in range.\n\t *\t\t\tview.createPositionAt( foo, 1 ),\n\t *\t\t\tview.createPositionAt( bar, 2 )\n\t *\t\t);\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // \"oo\", img are in range.\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from ( p, 2 ) to ( bar, 1 )\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( p, 1 ), view.createPositionAt( p, 2 ) ); // img is in range.\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from ( foo, 1 ) to ( p, 1 ) and from ( p, 2 ) to ( bar, 1 )\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.<module:engine/view/range~Range>} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( this.clone() );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link module:engine/view/range~Range range} and given {@link module:engine/view/range~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet foo = downcastWriter.createText( 'foo' );\n\t *\t\tlet img = downcastWriter.createContainerElement( 'img' );\n\t *\t\tlet bar = downcastWriter.createText( 'bar' );\n\t *\t\tlet p = downcastWriter.createContainerElement( 'p', null, [ foo, img, bar ] );\n\t *\n\t *\t\tlet range = view.createRange( view.createPositionAt( foo, 2 ), view.createPositionAt( bar, 1 ); // \"o\", img, \"b\" are in range.\n\t *\t\tlet otherRange = view.createRange( view.createPositionAt( foo, 1 ), view.createPositionAt( p, 2 ); // \"oo\", img are in range.\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // range from ( foo, 1 ) to ( p, 2 ).\n\t *\n\t *\t\totherRange = view.createRange( view.createPositionAt( bar, 1 ), view.createPositionAt( bar, 3 ); \"ar\" is in range.\n\t *\t\ttransformed = range.getIntersection( otherRange ); // null - no common part.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/view/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/view/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @param {module:engine/view/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t * @returns {module:engine/view/treewalker~TreeWalker}\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/node~Node} or {@link module:engine/view/documentfragment~DocumentFragment}\n\t * which is a common ancestor of range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/view/element~Element Element} contained by the range.\n\t * The element will be returned when it is the **only** node within the range and **fullycontained**\n\t * at the same time.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetContainedElement() {\n\t\tif ( this.isCollapsed ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet nodeAfterStart = this.start.nodeAfter;\n\t\tlet nodeBeforeEnd = this.end.nodeBefore;\n\n\t\t// Handle the situation when the range position is at the beginning / at the end of a text node.\n\t\t// In such situation `.nodeAfter` and `.nodeBefore` are `null` but the range still might be spanning\n\t\t// over one element.\n\t\t//\n\t\t// <p>Foo{<span class=\"widget\"></span>}bar</p> vs <p>Foo[<span class=\"widget\"></span>]bar</p>\n\t\t//\n\t\t// These are basically the same range, only the difference is if the range position is at\n\t\t// at the end/at the beginning of a text node or just before/just after the text node.\n\t\t//\n\t\tif ( this.start.parent.is( '$text' ) && this.start.isAtEnd && this.start.parent.nextSibling ) {\n\t\t\tnodeAfterStart = this.start.parent.nextSibling;\n\t\t}\n\n\t\tif ( this.end.parent.is( '$text' ) && this.end.isAtStart && this.end.parent.previousSibling ) {\n\t\t\tnodeBeforeEnd = this.end.parent.previousSibling;\n\t\t}\n\n\t\tif ( nodeAfterStart && nodeAfterStart.is( 'element' ) && nodeAfterStart === nodeBeforeEnd ) {\n\t\t\treturn nodeAfterStart;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Clones this range.\n\t *\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tclone() {\n\t\treturn new Range( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/view/item~Item view items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/view/item~Item items},\n\t * not {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/view/item~Item>}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/view/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/view/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/view/position~Position positions}, not {@link module:engine/view/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/view/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/view/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/view/position~Position>}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'view:range' ); // -> true\n\t *\n\t *\t\trange.is( 'model:range' ); // -> false\n\t *\t\trange.is( 'element' ); // -> false\n\t *\t\trange.is( 'selection' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'range' || type === 'view:range';\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with the given range.\n\t *\n\t * @param {module:engine/view/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} True if ranges intersect.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Creates a range from the given parents and offsets.\n\t *\n\t * @protected\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} startElement Start position\n\t * parent element.\n\t * @param {Number} startOffset Start position offset.\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} endElement End position\n\t * parent element.\n\t * @param {Number} endOffset End position offset.\n\t * @returns {module:engine/view/range~Range} Created range.\n\t */\n\tstatic _createFromParentsAndOffsets( startElement, startOffset, endElement, endOffset ) {\n\t\treturn new this(\n\t\t\tnew Position( startElement, startOffset ),\n\t\t\tnew Position( endElement, endOffset )\n\t\t);\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/view/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/view/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @protected\n\t * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn this._createFromParentsAndOffsets( element, 0, element, element.childCount );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\tconst size = item.is( '$textProxy' ) ? item.offsetSize : 1;\n\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), size );\n\t}\n}\n\n// Function used by getEnlarged and getTrimmed methods.\nfunction enlargeTrimSkip( value ) {\n\tif ( value.item.is( 'attributeElement' ) || value.item.is( 'uiElement' ) ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/count\n */\n\n/**\n * Returns the number of items return by the iterator.\n *\n *\t\tcount( [ 1, 2, 3, 4, 5 ] ); // 5;\n *\n * @param {Iterable.<*>} iterator Any iterator.\n * @returns {Number} Number of items returned by that iterator.\n */\nexport default function count( iterator ) {\n\tlet count = 0;\n\n\tfor ( const _ of iterator ) { // eslint-disable-line no-unused-vars\n\t\tcount++;\n\t}\n\n\treturn count;\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/view/selection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Range from './range';\nimport Position from './position';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport Node from './node';\nimport count from '@ckeditor/ckeditor5-utils/src/count';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport DocumentSelection from './documentselection';\n\n/**\n * Class representing an arbirtary selection in the view.\n * See also {@link module:engine/view/documentselection~DocumentSelection}.\n *\n * New selection instances can be created via the constructor or one these methods:\n *\n * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},\n * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.\n *\n * A selection can consist of {@link module:engine/view/range~Range ranges} that can be set by using\n * the {@link module:engine/view/selection~Selection#setTo `Selection#setTo()`} method.\n */\nexport default class Selection {\n\t/**\n\t * Creates new selection instance.\n\t *\n\t * **Note**: The selection constructor is available as a factory method:\n\t *\n\t * * {@link module:engine/view/view~View#createSelection `View#createSelection()`},\n\t * * {@link module:engine/view/upcastwriter~UpcastWriter#createSelection `UpcastWriter#createSelection()`}.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tconstructor( selectable = null, placeOrOffset, options ) {\n\t\t/**\n\t\t * Stores all ranges that are selected.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/range~Range>}\n\t\t */\n\t\tthis._ranges = [];\n\n\t\t/**\n\t\t * Specifies whether the last added range was added as a backward or forward range.\n\t\t *\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._lastRangeBackward = false;\n\n\t\t/**\n\t\t * Specifies whether selection instance is fake.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isFake = false;\n\n\t\t/**\n\t\t * Fake selection's label.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._fakeSelectionLabel = '';\n\n\t\tthis.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Returns true if selection instance is marked as `fake`.\n\t *\n\t * @see #setTo\n\t * @returns {Boolean}\n\t */\n\tget isFake() {\n\t\treturn this._isFake;\n\t}\n\n\t/**\n\t * Returns fake selection label.\n\t *\n\t * @see #setTo\n\t * @returns {String}\n\t */\n\tget fakeSelectionLabel() {\n\t\treturn this._fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the selection starts. Together with\n\t * {@link #focus focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.\n\t * It may be a bit unintuitive when there are multiple ranges in selection.\n\t *\n\t * @see #focus\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget anchor() {\n\t\tif ( !this._ranges.length ) {\n\t\t\treturn null;\n\t\t}\n\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\t\tconst anchor = this._lastRangeBackward ? range.end : range.start;\n\n\t\treturn anchor.clone();\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * @see #anchor\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget focus() {\n\t\tif ( !this._ranges.length ) {\n\t\t\treturn null;\n\t\t}\n\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\t\tconst focus = this._lastRangeBackward ? range.start : range.end;\n\n\t\treturn focus.clone();\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.rangeCount === 1 && this._ranges[ 0 ].isCollapsed;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._ranges.length;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus} precedes {@link #anchor}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn !this.isCollapsed && this._lastRangeBackward;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`\n\t * if the selection is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\tif ( this.anchor ) {\n\t\t\treturn this.anchor.editableElement;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns an iterable that contains copies of all ranges added to the selection.\n\t *\n\t * @returns {Iterable.<module:engine/view/range~Range>}\n\t */\n\t* getRanges() {\n\t\tfor ( const range of this._ranges ) {\n\t\t\tyield range.clone();\n\t\t}\n\t}\n\n\t/**\n\t * Returns copy of the first range in the selection. First range is the one which\n\t * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start\n\t * position of all other ranges (not to confuse with the first range added to the selection).\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\tlet first = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !first || range.start.isBefore( first.start ) ) {\n\t\t\t\tfirst = range;\n\t\t\t}\n\t\t}\n\n\t\treturn first ? first.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}\n\t * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse\n\t * with the last range added to the selection). Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\tlet last = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !last || range.end.isAfter( last.end ) ) {\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\treturn last ? last.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the first position in the selection. First position is the position that\n\t * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\tconst firstRange = this.getFirstRange();\n\n\t\treturn firstRange ? firstRange.start.clone() : null;\n\t}\n\n\t/**\n\t * Returns copy of the last position in the selection. Last position is the position that\n\t * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\tconst lastRange = this.getLastRange();\n\n\t\treturn lastRange ? lastRange.end.clone() : null;\n\t}\n\n\t/**\n\t * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,\n\t * same number of ranges and all ranges from one selection equal to a range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\tif ( this.isFake != otherSelection.isFake ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.isFake && this.fakeSelectionLabel != otherSelection.fakeSelectionLabel ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.rangeCount != otherSelection.rangeCount ) {\n\t\t\treturn false;\n\t\t} else if ( this.rangeCount === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( !this.anchor.isEqual( otherSelection.anchor ) || !this.focus.isEqual( otherSelection.focus ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const thisRange of this._ranges ) {\n\t\t\tlet found = false;\n\n\t\t\tfor ( const otherRange of otherSelection._ranges ) {\n\t\t\t\tif ( thisRange.isEqual( otherRange ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same\n\t * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are\n\t * equal to any trimmed range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are similar, `false` otherwise.\n\t */\n\tisSimilar( otherSelection ) {\n\t\tif ( this.isBackward != otherSelection.isBackward ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst numOfRangesA = count( this.getRanges() );\n\t\tconst numOfRangesB = count( otherSelection.getRanges() );\n\n\t\t// If selections have different number of ranges, they cannot be similar.\n\t\tif ( numOfRangesA != numOfRangesB ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If both selections have no ranges, they are similar.\n\t\tif ( numOfRangesA == 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Check if each range in one selection has a similar range in other selection.\n\t\tfor ( let rangeA of this.getRanges() ) {\n\t\t\trangeA = rangeA.getTrimmed();\n\n\t\t\tlet found = false;\n\n\t\t\tfor ( let rangeB of otherSelection.getRanges() ) {\n\t\t\t\trangeB = rangeB.getTrimmed();\n\n\t\t\t\tif ( rangeA.start.isEqual( rangeB.start ) && rangeA.end.isEqual( rangeB.end ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// For `rangeA`, neither range in `otherSelection` was similar. So selections are not similar.\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// There were no ranges that weren't matched. Selections are similar.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\tif ( this.rangeCount !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.getFirstRange().getContainedElement();\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tselection.setTo( 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\tselection.setTo( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tselection.setTo( otherSelection );\n\t *\n\t *\t \t// Sets selection to contents of DocumentSelection.\n\t *\t\tselection.setTo( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, path );\n\t *\t\tselection.setTo( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tselection.setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/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\tselection.setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tselection.setTo( paragraph, 'on' );\n\t *\n\t * \t\t// Clears selection. Removes all ranges.\n\t *\t\tselection.setTo( null );\n\t *\n\t * `Selection#setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\tselection.setTo( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tselection.setTo( range, { fake: true, label: 'foo' } );\n\t *\n\t * @fires change\n\t * @param {module:engine/view/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 * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tsetTo( selectable, placeOrOffset, options ) {\n\t\tif ( selectable === null ) {\n\t\t\tthis._setRanges( [] );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Selection || selectable instanceof DocumentSelection ) {\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t\tthis._setFakeOptions( { fake: selectable.isFake, label: selectable.fakeSelectionLabel } );\n\t\t} else if ( selectable instanceof Range ) {\n\t\t\tthis._setRanges( [ selectable ], placeOrOffset && placeOrOffset.backward );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Position ) {\n\t\t\tthis._setRanges( [ new Range( selectable ) ] );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else if ( selectable instanceof Node ) {\n\t\t\tconst backward = !!options && !!options.backward;\n\t\t\tlet range;\n\n\t\t\tif ( placeOrOffset === undefined ) {\n\t\t\t\t/**\n\t\t\t\t * selection.setTo requires the second parameter when the first parameter is a node.\n\t\t\t\t *\n\t\t\t\t * @error view-selection-setto-required-second-parameter\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-selection-setto-required-second-parameter', this );\n\t\t\t} else if ( placeOrOffset == 'in' ) {\n\t\t\t\trange = Range._createIn( selectable );\n\t\t\t} else if ( placeOrOffset == 'on' ) {\n\t\t\t\trange = Range._createOn( selectable );\n\t\t\t} else {\n\t\t\t\trange = new Range( Position._createAt( selectable, placeOrOffset ) );\n\t\t\t}\n\n\t\t\tthis._setRanges( [ range ], backward );\n\t\t\tthis._setFakeOptions( options );\n\t\t} else if ( isIterable( selectable ) ) {\n\t\t\t// We assume that the selectable is an iterable of ranges.\n\t\t\t// Array.from() is used to prevent setting ranges to the old iterable\n\t\t\tthis._setRanges( selectable, placeOrOffset && placeOrOffset.backward );\n\t\t\tthis._setFakeOptions( placeOrOffset );\n\t\t} else {\n\t\t\t/**\n\t\t\t * Cannot set selection to given place.\n\t\t\t *\n\t\t\t * @error view-selection-setto-not-selectable\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-selection-setto-not-selectable', this );\n\t\t}\n\n\t\tthis.fire( 'change' );\n\t}\n\n\t/**\n\t * Moves {@link #focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @fires change\n\t * @param {module:engine/view/item~Item|module:engine/view/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/view/item~Item view item}.\n\t */\n\tsetFocus( itemOrPosition, offset ) {\n\t\tif ( this.anchor === null ) {\n\t\t\t/**\n\t\t\t * Cannot set selection focus if there are no ranges in selection.\n\t\t\t *\n\t\t\t * @error view-selection-setfocus-no-ranges\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-selection-setfocus-no-ranges', this );\n\t\t}\n\n\t\tconst newFocus = Position._createAt( itemOrPosition, offset );\n\n\t\tif ( newFocus.compareWith( this.focus ) == 'same' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst anchor = this.anchor;\n\n\t\tthis._ranges.pop();\n\n\t\tif ( newFocus.compareWith( anchor ) == 'before' ) {\n\t\t\tthis._addRange( new Range( newFocus, anchor ), true );\n\t\t} else {\n\t\t\tthis._addRange( new Range( anchor, newFocus ) );\n\t\t}\n\n\t\tthis.fire( 'change' );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'view:selection' ); // -> true\n\t *\n\t *\t\tselection.is( 'model:selection' ); // -> false\n\t *\t\tselection.is( 'element' ); // -> false\n\t *\t\tselection.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' || type === 'view:selection';\n\t}\n\n\t/**\n\t * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array\n\t * is treated like the last added range and is used to set {@link #anchor anchor} and {@link #focus focus}.\n\t * Accepts a flag describing in which way the selection is made.\n\t *\n\t * @private\n\t * @param {Iterable.<module:engine/view/range~Range>} newRanges Iterable object of ranges to set.\n\t * @param {Boolean} [isLastBackward=false] Flag describing if last added range was selected forward - from start to end\n\t * (`false`) or backward - from end to start (`true`). Defaults to `false`.\n\t */\n\t_setRanges( newRanges, isLastBackward = false ) {\n\t\t// New ranges should be copied to prevent removing them by setting them to `[]` first.\n\t\t// Only applies to situations when selection is set to the same selection or same selection's ranges.\n\t\tnewRanges = Array.from( newRanges );\n\n\t\tthis._ranges = [];\n\n\t\tfor ( const range of newRanges ) {\n\t\t\tthis._addRange( range );\n\t\t}\n\n\t\tthis._lastRangeBackward = !!isLastBackward;\n\t}\n\n\t/**\n\t * Sets this selection instance to be marked as `fake`. A fake selection does not render as browser native selection\n\t * over selected elements and is hidden to the user. This way, no native selection UI artifacts are displayed to\n\t * the user and selection over elements can be represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM (and be\n\t * properly handled by screen readers).\n\t *\n\t * @private\n\t * @param {Object} [options] Options.\n\t * @param {Boolean} [options.fake] If set to true selection will be marked as `fake`.\n\t * @param {String} [options.label=''] Fake selection label.\n\t */\n\t_setFakeOptions( options = {} ) {\n\t\tthis._isFake = !!options.fake;\n\t\tthis._fakeSelectionLabel = options.fake ? options.label || '' : '';\n\t}\n\n\t/**\n\t * Adds a range to the selection. Added range is copied. This means that passed range is not saved in the\n\t * selection instance and you can safely operate on it.\n\t *\n\t * Accepts a flag describing in which way the selection is made - passed range might be selected from\n\t * {@link module:engine/view/range~Range#start start} to {@link module:engine/view/range~Range#end end}\n\t * or from {@link module:engine/view/range~Range#end end} to {@link module:engine/view/range~Range#start start}.\n\t * The flag is used to set {@link #anchor anchor} and {@link #focus focus} properties.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects\n\t * with ranges already stored in Selection instance.\n\t *\n\t * @private\n\t * @fires change\n\t * @param {module:engine/view/range~Range} range\n\t * @param {Boolean} [isBackward]\n\t */\n\t_addRange( range, isBackward = false ) {\n\t\tif ( !( range instanceof Range ) ) {\n\t\t\t/**\n\t\t\t * Selection range set to an object that is not an instance of {@link module:engine/view/range~Range}.\n\t\t\t *\n\t\t\t * @error view-selection-add-range-not-range\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-selection-add-range-not-range',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tthis._pushRange( range );\n\t\tthis._lastRangeBackward = !!isBackward;\n\t}\n\n\t/**\n\t * Adds range to selection - creates copy of given range so it can be safely used and modified.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-selection-range-intersects` if added range intersects\n\t * with ranges already stored in selection instance.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range\n\t */\n\t_pushRange( range ) {\n\t\tfor ( const storedRange of this._ranges ) {\n\t\t\tif ( range.isIntersecting( storedRange ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to add a range that intersects with another range from selection.\n\t\t\t\t *\n\t\t\t\t * @error view-selection-range-intersects\n\t\t\t\t * @param {module:engine/view/range~Range} addedRange Range that was added to the selection.\n\t\t\t\t * @param {module:engine/view/range~Range} intersectingRange Range from selection that intersects with `addedRange`.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'view-selection-range-intersects',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ addedRange: range, intersectingRange: storedRange }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis._ranges.push( new Range( range.start, range.end ) );\n\t}\n\n\t/**\n\t * Fired whenever selection ranges are changed through {@link ~Selection Selection API}.\n\t *\n\t * @event change\n\t */\n}\n\nmix( Selection, EmitterMixin );\n\n/**\n * An entity that is used to set selection.\n *\n * See also {@link module:engine/view/selection~Selection#setTo}\n *\n * @typedef {\n * module:engine/view/selection~Selection|\n * module:engine/view/documentselection~DocumentSelection|\n * module:engine/view/position~Position|\n * Iterable.<module:engine/view/range~Range>|\n * module:engine/view/range~Range|\n * module:engine/view/item~Item|\n * null\n * } module:engine/view/selection~Selectable\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/view/documentselection\n */\n\nimport Selection from './selection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Class representing the document selection in the view.\n *\n * Its instance is available in {@link module:engine/view/document~Document#selection `Document#selection`}.\n *\n * It is similar to {@link module:engine/view/selection~Selection} but\n * it has a read-only API and can be modified only by the writer available in\n * the {@link module:engine/view/view~View#change `View#change()`} block\n * (so via {@link module:engine/view/downcastwriter~DowncastWriter#setSelection `DowncastWriter#setSelection()`}).\n */\nexport default class DocumentSelection {\n\t/**\n\t * Creates new DocumentSelection instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = new DocumentSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = new DocumentSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tconst selection = new DocumentSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = new DocumentSelection( otherSelection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tconst selection = new DocumentSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = new DocumentSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = new DocumentSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = new DocumentSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = new DocumentSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tconstructor( selectable = null, placeOrOffset, options ) {\n\t\t/**\n\t\t * Selection is used internally (`DocumentSelection` is a proxy to that selection).\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/selection~Selection}\n\t\t */\n\t\tthis._selection = new Selection();\n\n\t\t// Delegate change event to be fired on DocumentSelection instance.\n\t\tthis._selection.delegate( 'change' ).to( this );\n\n\t\t// Set selection data.\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Returns true if selection instance is marked as `fake`.\n\t *\n\t * @see #_setTo\n\t * @returns {Boolean}\n\t */\n\tget isFake() {\n\t\treturn this._selection.isFake;\n\t}\n\n\t/**\n\t * Returns fake selection label.\n\t *\n\t * @see #_setTo\n\t * @returns {String}\n\t */\n\tget fakeSelectionLabel() {\n\t\treturn this._selection.fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the selection starts. Together with\n\t * {@link #focus focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always the start or end of the most recent added range.\n\t * It may be a bit unintuitive when there are multiple ranges in selection.\n\t *\n\t * @see #focus\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget anchor() {\n\t\treturn this._selection.anchor;\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * @see #anchor\n\t * @type {module:engine/view/position~Position}\n\t */\n\tget focus() {\n\t\treturn this._selection.focus;\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this._selection.isCollapsed;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._selection.rangeCount;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus} precedes {@link #anchor}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn this._selection.isBackward;\n\t}\n\n\t/**\n\t * {@link module:engine/view/editableelement~EditableElement EditableElement} instance that contains this selection, or `null`\n\t * if the selection is not inside an editable element.\n\t *\n\t * @type {module:engine/view/editableelement~EditableElement|null}\n\t */\n\tget editableElement() {\n\t\treturn this._selection.editableElement;\n\t}\n\n\t/**\n\t * Used for the compatibility with the {@link module:engine/view/selection~Selection#isEqual} method.\n\t *\n\t * @protected\n\t */\n\tget _ranges() {\n\t\treturn this._selection._ranges;\n\t}\n\n\t/**\n\t * Returns an iterable that contains copies of all ranges added to the selection.\n\t *\n\t * @returns {Iterable.<module:engine/view/range~Range>}\n\t */\n\t* getRanges() {\n\t\tyield* this._selection.getRanges();\n\t}\n\n\t/**\n\t * Returns copy of the first range in the selection. First range is the one which\n\t * {@link module:engine/view/range~Range#start start} position {@link module:engine/view/position~Position#isBefore is before} start\n\t * position of all other ranges (not to confuse with the first range added to the selection).\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\treturn this._selection.getFirstRange();\n\t}\n\n\t/**\n\t * Returns copy of the last range in the selection. Last range is the one which {@link module:engine/view/range~Range#end end}\n\t * position {@link module:engine/view/position~Position#isAfter is after} end position of all other ranges (not to confuse\n\t * with the last range added to the selection). Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\treturn this._selection.getLastRange();\n\t}\n\n\t/**\n\t * Returns copy of the first position in the selection. First position is the position that\n\t * {@link module:engine/view/position~Position#isBefore is before} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\treturn this._selection.getFirstPosition();\n\t}\n\n\t/**\n\t * Returns copy of the last position in the selection. Last position is the position that\n\t * {@link module:engine/view/position~Position#isAfter is after} any other position in the selection ranges.\n\t * Returns `null` if no ranges are added to selection.\n\t *\n\t * @returns {module:engine/view/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\treturn this._selection.getLastPosition();\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/view/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/view/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\treturn this._selection.getSelectedElement();\n\t}\n\n\t/**\n\t * Checks whether, this selection is equal to given selection. Selections are equal if they have same directions,\n\t * same number of ranges and all ranges from one selection equal to a range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\treturn this._selection.isEqual( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this selection is similar to given selection. Selections are similar if they have same directions, same\n\t * number of ranges, and all {@link module:engine/view/range~Range#getTrimmed trimmed} ranges from one selection are\n\t * equal to any trimmed range from other selection.\n\t *\n\t * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are similar, `false` otherwise.\n\t */\n\tisSimilar( otherSelection ) {\n\t\treturn this._selection.isSimilar( otherSelection );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocSelection.is( 'selection' ); // -> true\n\t *\t\tdocSelection.is( 'documentSelection' ); // -> true\n\t *\t\tdocSelection.is( 'view:selection' ); // -> true\n\t *\t\tdocSelection.is( 'view:documentSelection' ); // -> true\n\t *\n\t *\t\tdocSelection.is( 'model:documentSelection' ); // -> false\n\t *\t\tdocSelection.is( 'element' ); // -> false\n\t *\t\tdocSelection.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' ||\n\t\t\ttype == 'documentSelection' ||\n\t\t\ttype == 'view:selection' ||\n\t\t\ttype == 'view:documentSelection';\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to given ranges.\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( start2, end2 ) ];\n\t *\t\tdocumentSelection._setTo( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tdocumentSelection._setTo( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionAt( root, offset );\n\t *\t\tdocumentSelection._setTo( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tdocumentSelection._setTo( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/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\tdocumentSelection._setTo( paragraph, 'in' );\n\t *\n\t * Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends just after the item.\n\t *\n\t *\t\tdocumentSelection._setTo( paragraph, 'on' );\n\t *\n\t * \t\t// Clears selection. Removes all ranges.\n\t *\t\tdocumentSelection._setTo( null );\n\t *\n\t * `Selection#_setTo()` method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Sets selection as backward.\n\t *\t\tdocumentSelection._setTo( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to des cribe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tdocumentSelection._setTo( range, { fake: true, label: 'foo' } );\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/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 * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\t_setTo( selectable, placeOrOffset, options ) {\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link #focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @protected\n\t * @fires change\n\t * @param {module:engine/view/item~Item|module:engine/view/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/view/item~Item view item}.\n\t */\n\t_setFocus( itemOrPosition, offset ) {\n\t\tthis._selection.setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Fired whenever selection ranges are changed through {@link ~DocumentSelection Selection API}.\n\t *\n\t * @event change\n\t */\n}\n\nmix( DocumentSelection, EmitterMixin );\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/view/observer/bubblingeventinfo\n */\n\nimport EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';\n\n/**\n * The event object passed to bubbling event callbacks. It is used to provide information about the event as well as a tool to\n * manipulate it.\n *\n * @extends module:utils/eventinfo~EventInfo\n */\nexport default class BubblingEventInfo extends EventInfo {\n\t/**\n\t * @param {Object} source The emitter.\n\t * @param {String} name The event name.\n\t * @param {module:engine/view/range~Range} startRange The view range that the bubbling should start from.\n\t */\n\tconstructor( source, name, startRange ) {\n\t\tsuper( source, name );\n\n\t\t/**\n\t\t * The view range that the bubbling should start from.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/range~Range}\n\t\t */\n\t\tthis.startRange = startRange;\n\n\t\t/**\n\t\t * The current event phase.\n\t\t *\n\t\t * @protected\n\t\t * @member {'none'|'capturing'|'atTarget'|'bubbling'}\n\t\t */\n\t\tthis._eventPhase = 'none';\n\n\t\t/**\n\t\t * The current bubbling target.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/view/document~Document|module:engine/view/node~Node|null}\n\t\t */\n\t\tthis._currentTarget = null;\n\t}\n\n\t/**\n\t * The current event phase.\n\t *\n\t * @readonly\n\t * @member {'none'|'capturing'|'atTarget'|'bubbling'}\n\t */\n\tget eventPhase() {\n\t\treturn this._eventPhase;\n\t}\n\n\t/**\n\t * The current bubbling target.\n\t *\n\t * @readonly\n\t * @member {module:engine/view/document~Document|module:engine/view/node~Node|null}\n\t */\n\tget currentTarget() {\n\t\treturn this._currentTarget;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/bubblingemittermixin\n */\n\nimport EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\nimport BubblingEventInfo from './bubblingeventinfo';\n\nconst contextsSymbol = Symbol( 'bubbling contexts' );\n\n/**\n * Bubbling emitter mixin for the view document as described in the\n * {@link ~BubblingEmitter} interface.\n *\n * @mixin BubblingEmitterMixin\n * @implements module:engine/view/observer/bubblingemittermixin~BubblingEmitter\n */\nconst BubblingEmitterMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tfire( eventOrInfo, ...eventArgs ) {\n\t\ttry {\n\t\t\tconst eventInfo = eventOrInfo instanceof EventInfo ? eventOrInfo : new EventInfo( this, eventOrInfo );\n\t\t\tconst eventContexts = getBubblingContexts( this );\n\n\t\t\tif ( !eventContexts.size ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tupdateEventInfo( eventInfo, 'capturing', this );\n\n\t\t\t// The capture phase of the event.\n\t\t\tif ( fireListenerFor( eventContexts, '$capture', eventInfo, ...eventArgs ) ) {\n\t\t\t\treturn eventInfo.return;\n\t\t\t}\n\n\t\t\tconst startRange = eventInfo.startRange || this.selection.getFirstRange();\n\t\t\tconst selectedElement = startRange ? startRange.getContainedElement() : null;\n\t\t\tconst isCustomContext = selectedElement ? Boolean( getCustomContext( eventContexts, selectedElement ) ) : false;\n\n\t\t\tlet node = selectedElement || getDeeperRangeParent( startRange );\n\n\t\t\tupdateEventInfo( eventInfo, 'atTarget', node );\n\n\t\t\t// For the not yet bubbling event trigger for $text node if selection can be there and it's not a custom context selected.\n\t\t\tif ( !isCustomContext ) {\n\t\t\t\tif ( fireListenerFor( eventContexts, '$text', eventInfo, ...eventArgs ) ) {\n\t\t\t\t\treturn eventInfo.return;\n\t\t\t\t}\n\n\t\t\t\tupdateEventInfo( eventInfo, 'bubbling', node );\n\t\t\t}\n\n\t\t\twhile ( node ) {\n\t\t\t\t// Root node handling.\n\t\t\t\tif ( node.is( 'rootElement' ) ) {\n\t\t\t\t\tif ( fireListenerFor( eventContexts, '$root', eventInfo, ...eventArgs ) ) {\n\t\t\t\t\t\treturn eventInfo.return;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Element node handling.\n\t\t\t\telse if ( node.is( 'element' ) ) {\n\t\t\t\t\tif ( fireListenerFor( eventContexts, node.name, eventInfo, ...eventArgs ) ) {\n\t\t\t\t\t\treturn eventInfo.return;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check custom contexts (i.e., a widget).\n\t\t\t\tif ( fireListenerFor( eventContexts, node, eventInfo, ...eventArgs ) ) {\n\t\t\t\t\treturn eventInfo.return;\n\t\t\t\t}\n\n\t\t\t\tnode = node.parent;\n\n\t\t\t\tupdateEventInfo( eventInfo, 'bubbling', node );\n\t\t\t}\n\n\t\t\tupdateEventInfo( eventInfo, 'bubbling', this );\n\n\t\t\t// Document context.\n\t\t\tfireListenerFor( eventContexts, '$document', eventInfo, ...eventArgs );\n\n\t\t\treturn eventInfo.return;\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_addEventListener( event, callback, options ) {\n\t\tconst contexts = toArray( options.context || '$document' );\n\t\tconst eventContexts = getBubblingContexts( this );\n\n\t\tfor ( const context of contexts ) {\n\t\t\tlet emitter = eventContexts.get( context );\n\n\t\t\tif ( !emitter ) {\n\t\t\t\temitter = Object.create( EmitterMixin );\n\t\t\t\teventContexts.set( context, emitter );\n\t\t\t}\n\n\t\t\tthis.listenTo( emitter, event, callback, options );\n\t\t}\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_removeEventListener( event, callback ) {\n\t\tconst eventContexts = getBubblingContexts( this );\n\n\t\tfor ( const emitter of eventContexts.values() ) {\n\t\t\tthis.stopListening( emitter, event, callback );\n\t\t}\n\t}\n};\n\nexport default BubblingEmitterMixin;\n\n// Update the event info bubbling fields.\n//\n// @param {module:utils/eventinfo~EventInfo} eventInfo The event info object to update.\n// @param {'none'|'capturing'|'atTarget'|'bubbling'} eventPhase The current event phase.\n// @param {module:engine/view/document~Document|module:engine/view/node~Node} currentTarget The current bubbling target.\nfunction updateEventInfo( eventInfo, eventPhase, currentTarget ) {\n\tif ( eventInfo instanceof BubblingEventInfo ) {\n\t\teventInfo._eventPhase = eventPhase;\n\t\teventInfo._currentTarget = currentTarget;\n\t}\n}\n\n// Fires the listener for the specified context. Returns `true` if event was stopped.\n//\n// @private\n// @param {Map.<String|Function, module:utils/emittermixin~Emitter>} eventContexts\n// @param {String|module:engine/view/node~Node} context\n// @param {module:utils/eventinfo~EventInfo} eventInfo The `EventInfo` object.\n// @param {...*} [eventArgs] Additional arguments to be passed to the callbacks.\n// @returns {Boolean} True if event stop was called.\nfunction fireListenerFor( eventContexts, context, eventInfo, ...eventArgs ) {\n\tconst emitter = typeof context == 'string' ? eventContexts.get( context ) : getCustomContext( eventContexts, context );\n\n\tif ( !emitter ) {\n\t\treturn false;\n\t}\n\n\temitter.fire( eventInfo, ...eventArgs );\n\n\treturn eventInfo.stop.called;\n}\n\n// Returns an emitter for a specified view node.\n//\n// @private\n// @param {Map.<String|Function, module:utils/emittermixin~Emitter>} eventContexts\n// @param {module:engine/view/node~Node} node\n// @returns {module:utils/emittermixin~Emitter|null}\nfunction getCustomContext( eventContexts, node ) {\n\tfor ( const [ context, emitter ] of eventContexts ) {\n\t\tif ( typeof context == 'function' && context( node ) ) {\n\t\t\treturn emitter;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Returns bubbling contexts map for the source (emitter).\nfunction getBubblingContexts( source ) {\n\tif ( !source[ contextsSymbol ] ) {\n\t\tsource[ contextsSymbol ] = new Map();\n\t}\n\n\treturn source[ contextsSymbol ];\n}\n\n// Returns the deeper parent element for the range.\nfunction getDeeperRangeParent( range ) {\n\tif ( !range ) {\n\t\treturn null;\n\t}\n\n\tconst startParent = range.start.parent;\n\tconst endParent = range.end.parent;\n\n\tconst startPath = startParent.getPath();\n\tconst endPath = endParent.getPath();\n\n\treturn startPath.length > endPath.length ? startParent : endParent;\n}\n\n/**\n * Bubbling emitter for the view document.\n *\n * Bubbling emitter is triggering events in the context of specified {@link module:engine/view/element~Element view element} name,\n * predefined `'$text'`, `'$root'`, `'$document'` and `'$capture'` contexts, and context matchers provided as a function.\n *\n * Before bubbling starts, listeners for `'$capture'` context are triggered. Then the bubbling starts from the deeper selection\n * position (by firing event on the `'$text'` context) and propagates the view document tree up to the `'$root'` and finally\n * the listeners at `'$document'` context are fired (this is the default context).\n *\n * Examples:\n *\n *\t\t// Listeners registered in the context of the view element names:\n *\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n *\t\t\t// ...\n *\t\t}, { context: 'blockquote' } );\n *\n *\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n *\t\t\t// ...\n *\t\t}, { context: 'li' } );\n *\n *\t\t// Listeners registered in the context of the '$text' and '$root' nodes.\n *\t\tthis.listenTo( view.document, 'arrowKey', ( evt, data ) => {\n *\t\t\t// ...\n *\t\t}, { context: '$text', priority: 'high' } );\n *\n *\t\tthis.listenTo( view.document, 'arrowKey', ( evt, data ) => {\n *\t\t\t// ...\n *\t\t}, { context: '$root' } );\n *\n *\t\t// Listeners registered in the context of custom callback function.\n *\t\tthis.listenTo( view.document, 'arrowKey', ( evt, data ) => {\n *\t\t\t// ...\n *\t\t}, { context: isWidget } );\n *\n *\t\tthis.listenTo( view.document, 'arrowKey', ( evt, data ) => {\n *\t\t\t// ...\n *\t\t}, { context: isWidget, priority: 'high' } );\n *\n * Example flow for selection in text:\n *\n *\t\t<blockquote><p>Foo[]bar</p></blockquote>\n *\n * Fired events on contexts:\n * 1. `'$capture'`\n * 2. `'$text'`\n * 3. `'p'`\n * 4. `'blockquote'`\n * 5. `'$root'`\n * 6. `'$document'`\n *\n * Example flow for selection on element (i.e., Widget):\n *\n *\t\t<blockquote><p>Foo[<widget/>]bar</p></blockquote>\n *\n * Fired events on contexts:\n * 1. `'$capture'`\n * 2. *widget* (custom matcher)\n * 3. `'p'`\n * 4. `'blockquote'`\n * 5. `'$root'`\n * 6. `'$document'`\n *\n * There could be multiple listeners registered for the same context and at different priority levels:\n *\n *\t\t<p>Foo[]bar</p>\n *\n * 1. `'$capture'` at priorities:\n * 1. `'highest'`\n * 2. `'high'`\n * 3. `'normal'`\n * 4. `'low'`\n * 5. `'lowest'`\n * 2. `'$text'` at priorities:\n * 1. `'highest'`\n * 2. `'high'`\n * 3. `'normal'`\n * 4. `'low'`\n * 5. `'lowest'`\n * 3. `'p'` at priorities:\n * 1. `'highest'`\n * 2. `'high'`\n * 3. `'normal'`\n * 4. `'low'`\n * 5. `'lowest'`\n * 4. `'$root'` at priorities:\n * 1. `'highest'`\n * 2. `'high'`\n * 3. `'normal'`\n * 4. `'low'`\n * 5. `'lowest'`\n * 5. `'$document'` at priorities:\n * 1. `'highest'`\n * 2. `'high'`\n * 3. `'normal'`\n * 4. `'low'`\n * 5. `'lowest'`\n *\n * @interface BubblingEmitter\n * @extends module:utils/emittermixin~Emitter\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/view/document\n */\n\nimport DocumentSelection from './documentselection';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport BubblingEmitterMixin from './observer/bubblingemittermixin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\n\n// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );\n\n/**\n * Document class creates an abstract layer over the content editable area, contains a tree of view elements and\n * {@link module:engine/view/documentselection~DocumentSelection view selection} associated with this document.\n *\n * @mixes module:engine/view/observer/bubblingemittermixin~BubblingEmitterMixin\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Document {\n\t/**\n\t * Creates a Document instance.\n\t *\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( stylesProcessor ) {\n\t\t/**\n\t\t * Selection done on this document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection} module:engine/view/document~Document#selection\n\t\t */\n\t\tthis.selection = new DocumentSelection();\n\n\t\t/**\n\t\t * Roots of the view tree. Collection of the {@link module:engine/view/element~Element view elements}.\n\t\t *\n\t\t * View roots are created as a result of binding between {@link module:engine/view/document~Document#roots} and\n\t\t * {@link module:engine/model/document~Document#roots} and this is handled by\n\t\t * {@link module:engine/controller/editingcontroller~EditingController}, so to create view root we need to create\n\t\t * model root using {@link module:engine/model/document~Document#createRoot}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} module:engine/view/document~Document#roots\n\t\t */\n\t\tthis.roots = new Collection( { idProperty: 'rootName' } );\n\n\t\t/**\n\t\t * The styles processor instance used by this document when normalizing styles.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/stylesmap~StylesProcessor}\n\t\t */\n\t\tthis.stylesProcessor = stylesProcessor;\n\n\t\t/**\n\t\t * Defines whether document is in read-only mode.\n\t\t *\n\t\t * When document is read-ony then all roots are read-only as well and caret placed inside this root is hidden.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * True if document is focused.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/focusobserver~FocusObserver}.\n\t\t * If the {@link module:engine/view/observer/focusobserver~FocusObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * True if composition is in progress inside the document.\n\t\t *\n\t\t * This property is updated by the {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n\t\t * If the {@link module:engine/view/observer/compositionobserver~CompositionObserver} is disabled this property will not change.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} module:engine/view/document~Document#isComposing\n\t\t */\n\t\tthis.set( 'isComposing', false );\n\n\t\t/**\n\t\t * Post-fixer callbacks registered to the view document.\n\t\t *\n\t\t * @private\n\t\t * @member {Set}\n\t\t */\n\t\tthis._postFixers = new Set();\n\t}\n\n\t/**\n\t * Gets a {@link module:engine/view/document~Document#roots view root element} with the specified name. If the name is not\n\t * specific \"main\" root is returned.\n\t *\n\t * @param {String} [name='main'] Name of the root.\n\t * @returns {module:engine/view/rooteditableelement~RootEditableElement|null} The view root element with the specified name\n\t * or null when there is no root of given name.\n\t */\n\tgetRoot( name = 'main' ) {\n\t\treturn this.roots.get( name );\n\t}\n\n\t/**\n\t * Allows registering post-fixer callbacks. A post-fixers mechanism allows to update the view tree just before it is rendered\n\t * to the DOM.\n\t *\n\t * Post-fixers are executed right after all changes from the outermost change block were applied but\n\t * before the {@link module:engine/view/view~View#event:render render event} is fired. If a post-fixer callback made\n\t * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should\n\t * not be fixed in the new document tree state.\n\t *\n\t * View post-fixers are useful when you want to apply some fixes whenever the view structure changes. Keep in mind that\n\t * changes executed in a view post-fixer should not break model-view mapping.\n\t *\n\t * The types of changes which should be safe:\n\t *\n\t * * adding or removing attribute from elements,\n\t * * changes inside of {@link module:engine/view/uielement~UIElement UI elements},\n\t * * {@link module:engine/model/differ~Differ#refreshItem marking some of the model elements to be re-converted}.\n\t *\n\t * Try to avoid changes which touch view structure:\n\t *\n\t * * you should not add or remove nor wrap or unwrap any view elements,\n\t * * you should not change the editor data model in a view post-fixer.\n\t *\n\t * As a parameter, a post-fixer callback receives a {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.\n\t *\n\t * Typically, a post-fixer will look like this:\n\t *\n\t *\t\teditor.editing.view.document.registerPostFixer( writer => {\n\t *\t\t\tif ( checkSomeCondition() ) {\n\t *\t\t\t\twriter.doSomething();\n\t *\n\t *\t\t\t\t// Let other post-fixers know that something changed.\n\t *\t\t\t\treturn true;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Note that nothing happens right after you register a post-fixer (e.g. execute such a code in the console).\n\t * That is because adding a post-fixer does not execute it.\n\t * The post-fixer will be executed as soon as any change in the document needs to cause its rendering.\n\t * If you want to re-render the editor's view after registering the post-fixer then you should do it manually by calling\n\t * {@link module:engine/view/view~View#forceRender `view.forceRender()`}.\n\t *\n\t * If you need to register a callback which is executed when DOM elements are already updated,\n\t * use {@link module:engine/view/view~View#event:render render event}.\n\t *\n\t * @param {Function} postFixer\n\t */\n\tregisterPostFixer( postFixer ) {\n\t\tthis._postFixers.add( postFixer );\n\t}\n\n\t/**\n\t * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.\n\t */\n\tdestroy() {\n\t\tthis.roots.map( root => root.destroy() );\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.\n\t *\n\t * @protected\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\t_callPostFixers( writer ) {\n\t\tlet wasFixed = false;\n\n\t\tdo {\n\t\t\tfor ( const callback of this._postFixers ) {\n\t\t\t\twasFixed = callback( writer );\n\n\t\t\t\tif ( wasFixed ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} while ( wasFixed );\n\t}\n\n\t/**\n\t * Event fired whenever document content layout changes. It is fired whenever content is\n\t * {@link module:engine/view/view~View#event:render rendered}, but should be also fired by observers in case of\n\t * other actions which may change layout, for instance when image loads.\n\t *\n\t * @event layoutChanged\n\t */\n\n\t// @if CK_DEBUG_ENGINE // log( version ) {\n\t// @if CK_DEBUG_ENGINE //\tlogDocument( this, version );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( Document, BubblingEmitterMixin );\nmix( Document, ObservableMixin );\n\n/**\n * Enum representing type of the change.\n *\n * Possible values:\n *\n * * `children` - for child list changes,\n * * `attributes` - for element attributes changes,\n * * `text` - for text nodes changes.\n *\n * @typedef {String} module:engine/view/document~ChangeType\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/view/attributeelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// Default attribute priority.\nconst DEFAULT_PRIORITY = 10;\n\n/**\n * Attribute elements are used to represent formatting elements in the view (think `<b>`, `<span style=\"font-size: 2em\">`, etc.).\n * Most often they are created when downcasting model text attributes.\n *\n * Editing engine does not define a fixed HTML DTD. This is why a feature developer needs to choose between various\n * types (container element, {@link module:engine/view/attributeelement~AttributeElement attribute element},\n * {@link module:engine/view/emptyelement~EmptyElement empty element}, etc) when developing a feature.\n *\n * To create a new attribute element instance use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement `DowncastWriter#createAttributeElement()`} method.\n *\n * **Note:** Attribute elements by default can wrap {@link module:engine/view/text~Text},\n * {@link module:engine/view/emptyelement~EmptyElement}, {@link module:engine/view/uielement~UIElement},\n * {@link module:engine/view/rawelement~RawElement} and other attribute elements with higher priority. Other elements while placed inside\n * an attribute element will split it (or nest in case of an `AttributeElement`). This behavior can be modified by changing\n * the `isAllowedInsideAttributeElement` option while creating\n * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement},\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement},\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} or\n * {@link module:engine/view/downcastwriter~DowncastWriter#createRawElement}.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class AttributeElement extends Element {\n\t/**\n\t * Creates an attribute element.\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createAttributeElement\n\t * @see module:engine/view/element~Element\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t/**\n\t\t * Returns block {@link module:engine/view/filler filler} offset or `null` if block filler is not needed.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {Number|null} Block filler offset or `null` if block filler is not needed.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\n\t\t/**\n\t\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Number}\n\t\t */\n\t\tthis._priority = DEFAULT_PRIORITY;\n\n\t\t/**\n\t\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t\t * and then two elements are considered similar if, and only if they have the same `_id`.\n\t\t *\n\t\t * @protected\n\t\t * @member {String|Number}\n\t\t */\n\t\tthis._id = null;\n\n\t\t/**\n\t\t * Keeps all the attribute elements that have the same {@link module:engine/view/attributeelement~AttributeElement#id ids}\n\t\t * and still exist in the view tree.\n\t\t *\n\t\t * This property is managed by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.<module:engine/view/attributeelement~AttributeElement>|null}\n\t\t */\n\t\tthis._clonesGroup = null;\n\t}\n\n\t/**\n\t * Element priority. Decides in what order elements are wrapped by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget priority() {\n\t\treturn this._priority;\n\t}\n\n\t/**\n\t * Element identifier. If set, it is used by {@link module:engine/view/element~Element#isSimilar},\n\t * and then two elements are considered similar if, and only if they have the same `id`.\n\t *\n\t * @readonly\n\t * @type {String|Number}\n\t */\n\tget id() {\n\t\treturn this._id;\n\t}\n\n\t/**\n\t * Returns all {@link module:engine/view/attributeelement~AttributeElement attribute elements} that has the\n\t * same {@link module:engine/view/attributeelement~AttributeElement#id id} and are in the view tree (were not removed).\n\t *\n\t * Note: If this element has been removed from the tree, returned set will not include it.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError attribute-element-get-elements-with-same-id-no-id}\n\t * if this element has no `id`.\n\t *\n\t * @returns {Set.<module:engine/view/attributeelement~AttributeElement>} Set containing all the attribute elements\n\t * with the same `id` that were added and not removed from the view tree.\n\t */\n\tgetElementsWithSameId() {\n\t\tif ( this.id === null ) {\n\t\t\t/**\n\t\t\t * Cannot get elements with the same id for an attribute element without id.\n\t\t\t *\n\t\t\t * @error attribute-element-get-elements-with-same-id-no-id\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'attribute-element-get-elements-with-same-id-no-id',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\treturn new Set( this._clonesGroup );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tattributeElement.is( 'attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'element' ); // -> true\n\t *\t\tattributeElement.is( 'node' ); // -> true\n\t *\t\tattributeElement.is( 'view:attributeElement' ); // -> true\n\t *\t\tattributeElement.is( 'view:element' ); // -> true\n\t *\t\tattributeElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tattributeElement.is( 'model:element' ); // -> false\n\t *\t\tattributeElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an attribute element, you can also check its\n\t * {@link module:engine/view/attributeelement~AttributeElement#name name}:\n\t *\n\t *\t\tattributeElement.is( 'element', 'b' ); // -> true if this is a bold element\n\t *\t\tattributeElement.is( 'attributeElement', 'b' ); // -> same as above\n\t *\t\ttext.is( 'element', 'b' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'attributeElement' || type === 'view:attributeElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'attributeElement' || type === 'view:attributeElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Checks if this element is similar to other element.\n\t *\n\t * If none of elements has set {@link module:engine/view/attributeelement~AttributeElement#id}, then both elements\n\t * should have the same name, attributes and priority to be considered as similar. Two similar elements can contain\n\t * different set of children nodes.\n\t *\n\t * If at least one element has {@link module:engine/view/attributeelement~AttributeElement#id} set, then both\n\t * elements have to have the same {@link module:engine/view/attributeelement~AttributeElement#id} value to be\n\t * considered similar.\n\t *\n\t * Similarity is important for {@link module:engine/view/downcastwriter~DowncastWriter}. For example:\n\t *\n\t * * two following similar elements can be merged together into one, longer element,\n\t * * {@link module:engine/view/downcastwriter~DowncastWriter#unwrap} checks similarity of passed element and processed element to\n\t * decide whether processed element should be unwrapped,\n\t * * etc.\n\t *\n\t * @param {module:engine/view/element~Element} otherElement\n\t * @returns {Boolean}\n\t */\n\tisSimilar( otherElement ) {\n\t\t// If any element has an `id` set, just compare the ids.\n\t\tif ( this.id !== null || otherElement.id !== null ) {\n\t\t\treturn this.id === otherElement.id;\n\t\t}\n\n\t\treturn super.isSimilar( otherElement ) && this.priority == otherElement.priority;\n\t}\n\n\t/**\n\t * Clones provided element with priority.\n\t *\n\t * @protected\n\t * @param {Boolean} deep If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Clone of this element.\n\t */\n\t_clone( deep ) {\n\t\tconst cloned = super._clone( deep );\n\n\t\t// Clone priority too.\n\t\tcloned._priority = this._priority;\n\n\t\t// And id too.\n\t\tcloned._id = this._id;\n\n\t\treturn cloned;\n\t}\n}\n\n/**\n * Default attribute priority.\n *\n * @member {Number} module:engine/view/attributeelement~AttributeElement.DEFAULT_PRIORITY\n */\nAttributeElement.DEFAULT_PRIORITY = DEFAULT_PRIORITY;\n\n// Returns block {@link module:engine/view/filler~Filler filler} offset or `null` if block filler is not needed.\n//\n// @returns {Number|null} Block filler offset or `null` if block filler is not needed.\nfunction getFillerOffset() {\n\t// <b>foo</b> does not need filler.\n\tif ( nonUiChildrenCount( this ) ) {\n\t\treturn null;\n\t}\n\n\tlet element = this.parent;\n\n\t// <p><b></b></p> needs filler -> <p><b><br></b></p>\n\twhile ( element && element.is( 'attributeElement' ) ) {\n\t\tif ( nonUiChildrenCount( element ) > 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\telement = element.parent;\n\t}\n\n\tif ( !element || nonUiChildrenCount( element ) > 1 ) {\n\t\treturn null;\n\t}\n\n\t// Render block filler at the end of element (after all ui elements).\n\treturn this.childCount;\n}\n\n// Returns total count of children that are not {@link module:engine/view/uielement~UIElement UIElements}.\n//\n// @param {module:engine/view/element~Element} element\n// @returns {Number}\nfunction nonUiChildrenCount( element ) {\n\treturn Array.from( element.getChildren() ).filter( element => !element.is( 'uiElement' ) ).length;\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/view/emptyelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\n\n/**\n * Empty element class. It is used to represent elements that cannot contain any child nodes (for example `<img>` elements).\n *\n * To create a new empty element use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement `downcastWriter#createEmptyElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class EmptyElement extends Element {\n\t/**\n\t * Creates new instance of EmptyElement.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` when third parameter is passed,\n\t * to inform that usage of EmptyElement is incorrect (adding child nodes to EmptyElement is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createEmptyElement\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t// Override the default of the base class.\n\t\tthis._isAllowedInsideAttributeElement = true;\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for EmptyElements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\temptyElement.is( 'emptyElement' ); // -> true\n\t *\t\temptyElement.is( 'element' ); // -> true\n\t *\t\temptyElement.is( 'node' ); // -> true\n\t *\t\temptyElement.is( 'view:emptyElement' ); // -> true\n\t *\t\temptyElement.is( 'view:element' ); // -> true\n\t *\t\temptyElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\temptyElement.is( 'model:element' ); // -> false\n\t *\t\temptyElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an empty element, you can also check its\n\t * {@link module:engine/view/emptyelement~EmptyElement#name name}:\n\t *\n\t *\t\temptyElement.is( 'element', 'img' ); // -> true if this is a img element\n\t *\t\temptyElement.is( 'emptyElement', 'img' ); // -> same as above\n\t *\t\ttext.is( 'element', 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'emptyElement' || type === 'view:emptyElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'emptyElement' || type === 'view:emptyElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Overrides {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-emptyelement-cannot-add` to prevent\n\t * adding any child nodes to EmptyElement.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to {@link module:engine/view/emptyelement~EmptyElement}.\n\t\t\t *\n\t\t\t * @error view-emptyelement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-emptyelement-cannot-add',\n\t\t\t\t[ this, nodes ]\n\t\t\t);\n\t\t}\n\t}\n}\n\n// Returns `null` because block filler is not needed for EmptyElements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\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/* globals navigator:false */\n\n/**\n * @module utils/env\n */\n\nconst userAgent = navigator.userAgent.toLowerCase();\n\n/**\n * A namespace containing environment and browser information.\n *\n * @namespace\n */\nconst env = {\n\t/**\n\t * Indicates that the application is running on Macintosh.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisMac: isMac( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in Firefox (Gecko).\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisGecko: isGecko( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in Safari.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisSafari: isSafari( userAgent ),\n\n\t/**\n\t * Indicates that the application is running on Android mobile device.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisAndroid: isAndroid( userAgent ),\n\n\t/**\n\t * Indicates that the application is running in a browser using the Blink engine.\n\t *\n\t * @static\n\t * @type {Boolean}\n\t */\n\tisBlink: isBlink( userAgent ),\n\n\t/**\n\t * Environment features information.\n\t *\n\t * @memberOf module:utils/env~env\n\t * @namespace\n\t */\n\tfeatures: {\n\t\t/**\n\t\t * Indicates that the environment supports ES2018 Unicode property escapes — like `\\p{P}` or `\\p{L}`.\n\t\t * More information about unicode properties might be found\n\t\t * [in Unicode Standard Annex #44](https://www.unicode.org/reports/tr44/#GC_Values_Table).\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tisRegExpUnicodePropertySupported: isRegExpUnicodePropertySupported()\n\t}\n};\n\nexport default env;\n\n/**\n * Checks if User Agent represented by the string is running on Macintosh.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is running on Macintosh or not.\n */\nexport function isMac( userAgent ) {\n\treturn userAgent.indexOf( 'macintosh' ) > -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Firefox (Gecko).\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Firefox or not.\n */\nexport function isGecko( userAgent ) {\n\treturn !!userAgent.match( /gecko\\/\\d+/ );\n}\n\n/**\n * Checks if User Agent represented by the string is Safari.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Safari or not.\n */\nexport function isSafari( userAgent ) {\n\treturn userAgent.indexOf( ' applewebkit/' ) > -1 && userAgent.indexOf( 'chrome' ) === -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Android mobile device.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Safari or not.\n */\nexport function isAndroid( userAgent ) {\n\treturn userAgent.indexOf( 'android' ) > -1;\n}\n\n/**\n * Checks if User Agent represented by the string is Blink engine.\n *\n * @param {String} userAgent **Lowercase** `navigator.userAgent` string.\n * @returns {Boolean} Whether User Agent is Blink engine or not.\n */\nexport function isBlink( userAgent ) {\n\t// The Edge browser before switching to the Blink engine used to report itself as Chrome (and \"Edge/\")\n\t// but after switching to the Blink it replaced \"Edge/\" with \"Edg/\".\n\treturn userAgent.indexOf( 'chrome/' ) > -1 && userAgent.indexOf( 'edge/' ) < 0;\n}\n\n/**\n * Checks if the current environment supports ES2018 Unicode properties like `\\p{P}` or `\\p{L}`.\n * More information about unicode properties might be found\n * [in Unicode Standard Annex #44](https://www.unicode.org/reports/tr44/#GC_Values_Table).\n *\n * @returns {Boolean}\n */\nexport function isRegExpUnicodePropertySupported() {\n\tlet isSupported = false;\n\n\t// Feature detection for Unicode properties. Added in ES2018. Currently Firefox does not support it.\n\t// See https://github.com/ckeditor/ckeditor5-mention/issues/44#issuecomment-487002174.\n\n\ttry {\n\t\t// Usage of regular expression literal cause error during build (ckeditor/ckeditor5-dev#534).\n\t\tisSupported = 'ć'.search( new RegExp( '[\\\\p{L}]', 'u' ) ) === 0;\n\t} catch ( error ) {\n\t\t// Firefox throws a SyntaxError when the group is unsupported.\n\t}\n\n\treturn isSupported;\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 * A set of utilities related to keyboard support.\n *\n * @module utils/keyboard\n */\n\nimport CKEditorError from './ckeditorerror';\nimport env from './env';\n\nconst modifiersToGlyphsMac = {\n\tctrl: '⌃',\n\tcmd: '⌘',\n\talt: '⌥',\n\tshift: '⇧'\n};\n\nconst modifiersToGlyphsNonMac = {\n\tctrl: 'Ctrl+',\n\talt: 'Alt+',\n\tshift: 'Shift+'\n};\n\n/**\n * An object with `keyName => keyCode` pairs for a set of known keys.\n *\n * Contains:\n *\n * * `a-z`,\n * * `0-9`,\n * * `f1-f12`,\n * * `arrow(left|up|right|bottom)`,\n * * `backspace`, `delete`, `enter`, `esc`, `tab`,\n * * `ctrl`, `cmd`, `shift`, `alt`.\n */\nexport const keyCodes = generateKnownKeyCodes();\n\nconst keyCodeNames = Object.fromEntries(\n\tObject.entries( keyCodes ).map( ( [ name, code ] ) => [ code, name.charAt( 0 ).toUpperCase() + name.slice( 1 ) ] )\n);\n\n/**\n * Converts a key name or {@link module:utils/keyboard~KeystrokeInfo keystroke info} into a key code.\n *\n * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.\n *\n * @param {String|module:utils/keyboard~KeystrokeInfo} A key name (see {@link module:utils/keyboard~keyCodes})\n * or a keystroke data object.\n * @returns {Number} Key or keystroke code.\n */\nexport function getCode( key ) {\n\tlet keyCode;\n\n\tif ( typeof key == 'string' ) {\n\t\tkeyCode = keyCodes[ key.toLowerCase() ];\n\n\t\tif ( !keyCode ) {\n\t\t\t/**\n\t\t\t * Unknown key name. Only key names included in the {@link module:utils/keyboard~keyCodes} can be used.\n\t\t\t *\n\t\t\t * @error keyboard-unknown-key\n\t\t\t * @param {String} key\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'keyboard-unknown-key', null, { key } );\n\t\t}\n\t} else {\n\t\tkeyCode = key.keyCode +\n\t\t\t( key.altKey ? keyCodes.alt : 0 ) +\n\t\t\t( key.ctrlKey ? keyCodes.ctrl : 0 ) +\n\t\t\t( key.shiftKey ? keyCodes.shift : 0 ) +\n\t\t\t( key.metaKey ? keyCodes.cmd : 0 );\n\t}\n\n\treturn keyCode;\n}\n\n/**\n * Parses the keystroke and returns a keystroke code that will match the code returned by\n * {@link module:utils/keyboard~getCode} for the corresponding {@link module:utils/keyboard~KeystrokeInfo keystroke info}.\n *\n * The keystroke can be passed in two formats:\n *\n * * as a single string e.g. `ctrl + A`,\n * * as an array of {@link module:utils/keyboard~keyCodes known key names} and key codes e.g.:\n * * `[ 'ctrl', 32 ]` (ctrl + space),\n * * `[ 'ctrl', 'a' ]` (ctrl + A).\n *\n * Note: Key names are matched with {@link module:utils/keyboard~keyCodes} in a case-insensitive way.\n *\n * Note: Only keystrokes with a single non-modifier key are supported (e.g. `ctrl+A` is OK, but `ctrl+A+B` is not).\n *\n * Note: On macOS, keystroke handling is translating the `Ctrl` key to the `Cmd` key and handling only that keystroke.\n * For example, a registered keystroke `Ctrl+A` will be translated to `Cmd+A` on macOS. To disable the translation of some keystroke,\n * use the forced modifier: `Ctrl!+A` (note the exclamation mark).\n *\n * @param {String|Array.<Number|String>} keystroke The keystroke definition.\n * @returns {Number} Keystroke code.\n */\nexport function parseKeystroke( keystroke ) {\n\tif ( typeof keystroke == 'string' ) {\n\t\tkeystroke = splitKeystrokeText( keystroke );\n\t}\n\n\treturn keystroke\n\t\t.map( key => ( typeof key == 'string' ) ? getEnvKeyCode( key ) : key )\n\t\t.reduce( ( key, sum ) => sum + key, 0 );\n}\n\n/**\n * Translates any keystroke string text like `\"Ctrl+A\"` to an\n * environmentspecific keystroke, i.e. `\"⌘A\"` on macOS.\n *\n * @param {String} keystroke The keystroke text.\n * @returns {String} The keystroke text specific for the environment.\n */\nexport function getEnvKeystrokeText( keystroke ) {\n\tlet keystrokeCode = parseKeystroke( keystroke );\n\n\tconst modifiersToGlyphs = Object.entries( env.isMac ? modifiersToGlyphsMac : modifiersToGlyphsNonMac );\n\n\tconst modifiers = modifiersToGlyphs.reduce( ( modifiers, [ name, glyph ] ) => {\n\t\t// Modifier keys are stored as a bit mask so extract those from the keystroke code.\n\t\tif ( ( keystrokeCode & keyCodes[ name ] ) != 0 ) {\n\t\t\tkeystrokeCode &= ~keyCodes[ name ];\n\t\t\tmodifiers += glyph;\n\t\t}\n\n\t\treturn modifiers;\n\t}, '' );\n\n\treturn modifiers + ( keystrokeCode ? keyCodeNames[ keystrokeCode ] : '' );\n}\n\n/**\n * Returns `true` if the provided key code represents one of the arrow keys.\n *\n * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.\n * @returns {Boolean}\n */\nexport function isArrowKeyCode( keyCode ) {\n\treturn keyCode == keyCodes.arrowright ||\n\t\tkeyCode == keyCodes.arrowleft ||\n\t\tkeyCode == keyCodes.arrowup ||\n\t\tkeyCode == keyCodes.arrowdown;\n}\n\n/**\n * Returns the direction in which the {@link module:engine/model/documentselection~DocumentSelection selection}\n * will move when the provided arrow key code is pressed considering the language direction of the editor content.\n *\n * For instance, in righttoleft (RTL) content languages, pressing the left arrow means moving the selection right (forward)\n * in the model structure. Similarly, pressing the right arrow moves the selection left (backward).\n *\n * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.\n * @param {'ltr'|'rtl'} contentLanguageDirection The content language direction, corresponding to\n * {@link module:utils/locale~Locale#contentLanguageDirection}.\n * @returns {'left'|'up'|'right'|'down'} Localized arrow direction.\n */\nexport function getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirection ) {\n\tconst isLtrContent = contentLanguageDirection === 'ltr';\n\n\tswitch ( keyCode ) {\n\t\tcase keyCodes.arrowleft:\n\t\t\treturn isLtrContent ? 'left' : 'right';\n\n\t\tcase keyCodes.arrowright:\n\t\t\treturn isLtrContent ? 'right' : 'left';\n\n\t\tcase keyCodes.arrowup:\n\t\t\treturn 'up';\n\n\t\tcase keyCodes.arrowdown:\n\t\t\treturn 'down';\n\t}\n}\n\n// Converts a key name to the key code with mapping based on the env.\n//\n// See: {@link module:utils/keyboard~getCode}.\n//\n// @param {String} key The key name (see {@link module:utils/keyboard~keyCodes}).\n// @returns {Number} Key code.\nfunction getEnvKeyCode( key ) {\n\t// Don't remap modifier key for forced modifiers.\n\tif ( key.endsWith( '!' ) ) {\n\t\treturn getCode( key.slice( 0, -1 ) );\n\t}\n\n\tconst code = getCode( key );\n\n\treturn env.isMac && code == keyCodes.ctrl ? keyCodes.cmd : code;\n}\n\n/**\n * Determines if the provided key code moves the {@link module:engine/model/documentselection~DocumentSelection selection}\n * forward or backward considering the language direction of the editor content.\n *\n * For instance, in righttoleft (RTL) languages, pressing the left arrow means moving forward\n * in the model structure. Similarly, pressing the right arrow moves the selection backward.\n *\n * @param {Number} keyCode A key code as in {@link module:utils/keyboard~KeystrokeInfo#keyCode}.\n * @param {'ltr'|'rtl'} contentLanguageDirection The content language direction, corresponding to\n * {@link module:utils/locale~Locale#contentLanguageDirection}.\n * @returns {Boolean}\n */\nexport function isForwardArrowKeyCode( keyCode, contentLanguageDirection ) {\n\tconst localizedKeyCodeDirection = getLocalizedArrowKeyCodeDirection( keyCode, contentLanguageDirection );\n\n\treturn localizedKeyCodeDirection === 'down' || localizedKeyCodeDirection === 'right';\n}\n\nfunction generateKnownKeyCodes() {\n\tconst keyCodes = {\n\t\tarrowleft: 37,\n\t\tarrowup: 38,\n\t\tarrowright: 39,\n\t\tarrowdown: 40,\n\t\tbackspace: 8,\n\t\tdelete: 46,\n\t\tenter: 13,\n\t\tspace: 32,\n\t\tesc: 27,\n\t\ttab: 9,\n\n\t\t// The idea about these numbers is that they do not collide with any real key codes, so we can use them\n\t\t// like bit masks.\n\t\tctrl: 0x110000,\n\t\tshift: 0x220000,\n\t\talt: 0x440000,\n\t\tcmd: 0x880000\n\t};\n\n\t// a-z\n\tfor ( let code = 65; code <= 90; code++ ) {\n\t\tconst letter = String.fromCharCode( code );\n\n\t\tkeyCodes[ letter.toLowerCase() ] = code;\n\t}\n\n\t// 0-9\n\tfor ( let code = 48; code <= 57; code++ ) {\n\t\tkeyCodes[ code - 48 ] = code;\n\t}\n\n\t// F1-F12\n\tfor ( let code = 112; code <= 123; code++ ) {\n\t\tkeyCodes[ 'f' + ( code - 111 ) ] = code;\n\t}\n\n\treturn keyCodes;\n}\n\nfunction splitKeystrokeText( keystroke ) {\n\treturn keystroke.split( '+' ).map( key => key.trim() );\n}\n\n/**\n * Information about the keystroke.\n *\n * @interface module:utils/keyboard~KeystrokeInfo\n */\n\n/**\n * The [key code](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode).\n *\n * @member {Number} module:utils/keyboard~KeystrokeInfo#keyCode\n */\n\n/**\n * Whether the <kbd>Alt</kbd> modifier was pressed.\n *\n * @member {Boolean} module:utils/keyboard~KeystrokeInfo#altKey\n */\n\n/**\n * Whether the <kbd>Ctrl</kbd> modifier was pressed.\n *\n * @member {Boolean} module:utils/keyboard~KeystrokeInfo#ctrlKey\n */\n\n/**\n * Whether the <kbd>Shift</kbd> modifier was pressed.\n *\n * @member {Boolean} module:utils/keyboard~KeystrokeInfo#shiftKey\n */\n\n/**\n * Whether the <kbd>Cmd</kbd> modifier was pressed.\n *\n * @member {Boolean} module:utils/keyboard~KeystrokeInfo#metaKey\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/view/uielement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * UI element class. It should be used to represent editing UI which needs to be injected into the editing view\n * If possible, you should keep your UI outside the editing view. However, if that is not possible,\n * UI elements can be used.\n *\n * How a UI element is rendered is in your control (you pass a callback to\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`}).\n * The editor will ignore your UI element the selection cannot be placed in it, it is skipped (invisible) when\n * the user modifies the selection by using arrow keys and the editor does not listen to any mutations which\n * happen inside your UI elements.\n *\n * The limitation is that you cannot convert a model element to a UI element. UI elements need to be\n * created for {@link module:engine/model/markercollection~Marker markers} or as additinal elements\n * inside normal {@link module:engine/view/containerelement~ContainerElement container elements}.\n *\n * To create a new UI element use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `downcastWriter#createUIElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class UIElement extends Element {\n\t/**\n\t * Creates new instance of UIElement.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` when third parameter is passed,\n\t * to inform that usage of UIElement is incorrect (adding child nodes to UIElement is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createUIElement\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attributes] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t */\n\tconstructor( document, name, attributes, children ) {\n\t\tsuper( document, name, attributes, children );\n\n\t\t// Override the default of the base class.\n\t\tthis._isAllowedInsideAttributeElement = true;\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for UIElements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tuiElement.is( 'uiElement' ); // -> true\n\t *\t\tuiElement.is( 'element' ); // -> true\n\t *\t\tuiElement.is( 'node' ); // -> true\n\t *\t\tuiElement.is( 'view:uiElement' ); // -> true\n\t *\t\tuiElement.is( 'view:element' ); // -> true\n\t *\t\tuiElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\tuiElement.is( 'model:element' ); // -> false\n\t *\t\tuiElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an ui element, you can also check its\n\t * {@link module:engine/view/uielement~UIElement#name name}:\n\t *\n\t *\t\tuiElement.is( 'element', 'span' ); // -> true if this is a span ui element\n\t *\t\tuiElement.is( 'uiElement', 'span' ); // -> same as above\n\t *\t\ttext.is( 'element', 'span' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'uiElement' || type === 'view:uiElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'uiElement' || type === 'view:uiElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Overrides {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-uielement-cannot-add` to prevent adding any child nodes\n\t * to UIElement.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to {@link module:engine/view/uielement~UIElement}.\n\t\t\t *\n\t\t\t * @error view-uielement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-uielement-cannot-add', this );\n\t\t}\n\t}\n\n\t/**\n\t * Renders this {@link module:engine/view/uielement~UIElement} to DOM. This method is called by\n\t * {@link module:engine/view/domconverter~DomConverter}.\n\t * Do not use inheritance to create custom rendering method, replace `render()` method instead:\n\t *\n\t *\t\tconst myUIElement = downcastWriter.createUIElement( 'span' );\n\t *\t\tmyUIElement.render = function( domDocument ) {\n\t *\t\t\tconst domElement = this.toDomElement( domDocument );\n\t *\t\t\tdomElement.innerHTML = '<b>this is ui element</b>';\n\t *\n\t *\t\t\treturn domElement;\n\t *\t\t};\n\t *\n\t * If changes in your UI element should trigger some editor UI update you should call\n\t * the {@link module:core/editor/editorui~EditorUI#update `editor.ui.update()`} method\n\t * after rendering your UI element.\n\t *\n\t * @param {Document} domDocument\n\t * @returns {HTMLElement}\n\t */\n\trender( domDocument ) {\n\t\treturn this.toDomElement( domDocument );\n\t}\n\n\t/**\n\t * Creates DOM element based on this view UIElement.\n\t * Note that each time this method is called new DOM element is created.\n\t *\n\t * @param {Document} domDocument\n\t * @returns {HTMLElement}\n\t */\n\ttoDomElement( domDocument ) {\n\t\tconst domElement = domDocument.createElement( this.name );\n\n\t\tfor ( const key of this.getAttributeKeys() ) {\n\t\t\tdomElement.setAttribute( key, this.getAttribute( key ) );\n\t\t}\n\n\t\treturn domElement;\n\t}\n}\n\n/**\n * This function injects UI element handling to the given {@link module:engine/view/document~Document document}.\n *\n * A callback is added to {@link module:engine/view/document~Document#event:keydown document keydown event}.\n * The callback handles the situation when right arrow key is pressed and selection is collapsed before a UI element.\n * Without this handler, it would be impossible to \"jump over\" UI element using right arrow key.\n *\n * @param {module:engine/view/view~View} view View controller to which the quirks handling will be injected.\n */\nexport function injectUiElementHandling( view ) {\n\tview.document.on( 'arrowKey', ( evt, data ) => jumpOverUiElement( evt, data, view.domConverter ), { priority: 'low' } );\n}\n\n// Returns `null` because block filler is not needed for UIElements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n\n// Selection cannot be placed in a `UIElement`. Whenever it is placed there, it is moved before it. This\n// causes a situation when it is impossible to jump over `UIElement` using right arrow key, because the selection\n// ends up in ui element (in DOM) and is moved back to the left. This handler fixes this situation.\nfunction jumpOverUiElement( evt, data, domConverter ) {\n\tif ( data.keyCode == keyCodes.arrowright ) {\n\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\t\tconst domSelectionCollapsed = domSelection.rangeCount == 1 && domSelection.getRangeAt( 0 ).collapsed;\n\n\t\t// Jump over UI element if selection is collapsed or shift key is pressed. These are the cases when selection would extend.\n\t\tif ( domSelectionCollapsed || data.shiftKey ) {\n\t\t\tconst domParent = domSelection.focusNode;\n\t\t\tconst domOffset = domSelection.focusOffset;\n\n\t\t\tconst viewPosition = domConverter.domPositionToView( domParent, domOffset );\n\n\t\t\t// In case if dom element is not converted to view or is not mapped or something. Happens for example in some tests.\n\t\t\tif ( viewPosition === null ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip all following ui elements.\n\t\t\tlet jumpedOverAnyUiElement = false;\n\n\t\t\tconst nextViewPosition = viewPosition.getLastMatchingPosition( value => {\n\t\t\t\tif ( value.item.is( 'uiElement' ) ) {\n\t\t\t\t\t// Remember that there was at least one ui element.\n\t\t\t\t\tjumpedOverAnyUiElement = true;\n\t\t\t\t}\n\n\t\t\t\t// Jump over ui elements, jump over empty attribute elements, move up from inside of attribute element.\n\t\t\t\tif ( value.item.is( 'uiElement' ) || value.item.is( 'attributeElement' ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// Don't jump over text or don't get out of container element.\n\t\t\t\treturn false;\n\t\t\t} );\n\n\t\t\t// If anything has been skipped, fix position.\n\t\t\t// This `if` could be possibly omitted but maybe it is better not to mess with DOM selection if not needed.\n\t\t\tif ( jumpedOverAnyUiElement ) {\n\t\t\t\tconst newDomPosition = domConverter.viewPositionToDom( nextViewPosition );\n\n\t\t\t\tif ( domSelectionCollapsed ) {\n\t\t\t\t\t// Selection was collapsed, so collapse it at further position.\n\t\t\t\t\tdomSelection.collapse( newDomPosition.parent, newDomPosition.offset );\n\t\t\t\t} else {\n\t\t\t\t\t// Selection was not collapse, so extend it instead of collapsing.\n\t\t\t\t\tdomSelection.extend( newDomPosition.parent, newDomPosition.offset );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/rawelement\n */\n\nimport Element from './element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Node from './node';\n\n/**\n * The raw element class.\n *\n * The raw elements work as data containers (\"wrappers\", \"sandboxes\") but their children are not managed or\n * even recognized by the editor. This encapsulation allows integrations to maintain custom DOM structures\n * in the editor content without, for instance, worrying about compatibility with other editor features.\n * Raw elements are a perfect tool for integration with external frameworks and data sources.\n *\n * Unlike {@link module:engine/view/uielement~UIElement UI elements}, raw elements act like real editor\n * content (similar to {@link module:engine/view/containerelement~ContainerElement} or\n * {@link module:engine/view/emptyelement~EmptyElement}), they are considered by the editor selection and\n * {@link module:widget/utils~toWidget they can work as widgets}.\n *\n * To create a new raw element, use the\n * {@link module:engine/view/downcastwriter~DowncastWriter#createRawElement `downcastWriter#createRawElement()`} method.\n *\n * @extends module:engine/view/element~Element\n */\nexport default class RawElement extends Element {\n\t/**\n\t * Creates a new instance of a raw element.\n\t *\n\t * Throws the `view-rawelement-cannot-add` {@link module:utils/ckeditorerror~CKEditorError CKEditorError} when the `children`\n\t * parameter is passed to inform that the usage of `RawElement` is incorrect (adding child nodes to `RawElement` is forbidden).\n\t *\n\t * @see module:engine/view/downcastwriter~DowncastWriter#createRawElement\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document instance to which this element belongs.\n\t * @param {String} name A node name.\n\t * @param {Object|Iterable} [attrs] The collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created element.\n\t */\n\tconstructor( document, name, attrs, children ) {\n\t\tsuper( document, name, attrs, children );\n\n\t\t// Override the default of the base class.\n\t\tthis._isAllowedInsideAttributeElement = true;\n\n\t\t/**\n\t\t * Returns `null` because filler is not needed for raw elements.\n\t\t *\n\t\t * @method #getFillerOffset\n\t\t * @returns {null} Always returns null.\n\t\t */\n\t\tthis.getFillerOffset = getFillerOffset;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type or name.\n\t *\n\t *\t\trawElement.is( 'rawElement' ); // -> true\n\t *\t\trawElement.is( 'element' ); // -> true\n\t *\t\trawElement.is( 'node' ); // -> true\n\t *\t\trawElement.is( 'view:rawElement' ); // -> true\n\t *\t\trawElement.is( 'view:element' ); // -> true\n\t *\t\trawElement.is( 'view:node' ); // -> true\n\t *\n\t *\t\trawElement.is( 'model:element' ); // -> false\n\t *\t\trawElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is a raw element, you can also check its\n\t * {@link module:engine/view/rawelement~RawElement#name name}:\n\t *\n\t *\t\trawElement.is( 'img' ); // -> true if this is an img element\n\t *\t\trawElement.is( 'rawElement', 'img' ); // -> same as above\n\t *\t\ttext.is( 'img' ); -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type The type to check when the `name` parameter is present.\n\t * Otherwise, it acts like the `name` parameter.\n\t * @param {String} [name] The element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'rawElement' || type === 'view:rawElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === this.name || type === 'view:' + this.name ||\n\t\t\t\ttype === 'element' || type === 'view:element' ||\n\t\t\t\ttype === 'node' || type === 'view:node';\n\t\t} else {\n\t\t\treturn name === this.name && (\n\t\t\t\ttype === 'rawElement' || type === 'view:rawElement' ||\n\t\t\t\ttype === 'element' || type === 'view:element'\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Overrides the {@link module:engine/view/element~Element#_insertChild} method.\n\t * Throws the `view-rawelement-cannot-add` {@link module:utils/ckeditorerror~CKEditorError CKEditorError} to prevent\n\t * adding any child nodes to a raw element.\n\t *\n\t * @protected\n\t */\n\t_insertChild( index, nodes ) {\n\t\tif ( nodes && ( nodes instanceof Node || Array.from( nodes ).length > 0 ) ) {\n\t\t\t/**\n\t\t\t * Cannot add children to a {@link module:engine/view/rawelement~RawElement} instance.\n\t\t\t *\n\t\t\t * @error view-rawelement-cannot-add\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-rawelement-cannot-add',\n\t\t\t\t[ this, nodes ]\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * This allows rendering the children of a {@link module:engine/view/rawelement~RawElement} on the DOM level.\n\t * This method is called by the {@link module:engine/view/domconverter~DomConverter} with the raw DOM element\n\t * passed as an argument, leaving the number and shape of the children up to the integrator.\n\t *\n\t * This method **must be defined** for the raw element to work:\n\t *\n\t *\t\tconst myRawElement = downcastWriter.createRawElement( 'div' );\n\t *\n\t *\t\tmyRawElement.render = function( domElement ) {\n\t *\t\t\tdomElement.innerHTML = '<b>This is the raw content of myRawElement.</b>';\n\t *\t\t};\n\t *\n\t * @method #render\n\t * @param {HTMLElement} domElement The native DOM element representing the raw view element.\n\t */\n}\n\n// Returns `null` because block filler is not needed for raw elements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\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/view/documentfragment\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\n/**\n * Document fragment.\n *\n * To create a new document fragment instance use the\n * {@link module:engine/view/upcastwriter~UpcastWriter#createDocumentFragment `UpcastWriter#createDocumentFragment()`}\n * method.\n */\nexport default class DocumentFragment {\n\t/**\n\t * Creates new DocumentFragment instance.\n\t *\n\t * @protected\n\t * @param {module:engine/view/document~Document} document The document to which this document fragment belongs.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t */\n\tconstructor( document, children ) {\n\t\t/**\n\t\t * The document to which this document fragment belongs.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Array of child nodes.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/view/element~Element>} module:engine/view/documentfragment~DocumentFragment#_children\n\t\t */\n\t\tthis._children = [];\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over nodes added to this document fragment.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Number of child nodes in this document fragment.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this document fragment, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {null}\n\t */\n\tget parent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocFrag.is( 'documentFragment' ); // -> true\n\t *\t\tdocFrag.is( 'view:documentFragment' ); // -> true\n\t *\n\t *\t\tdocFrag.is( 'model:documentFragment' ); // -> false\n\t *\t\tdocFrag.is( 'element' ); // -> false\n\t *\t\tdocFrag.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/view/node~Node#is Check the entire list of view objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'documentFragment' || type === 'view:documentFragment';\n\t}\n\n\t/**\n\t * {@link module:engine/view/documentfragment~DocumentFragment#_insertChild Insert} a child node or a list of child nodes at the end\n\t * and sets the parent of these nodes to this fragment.\n\t *\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @returns {Number} Number of appended nodes.\n\t */\n\t_appendChild( items ) {\n\t\treturn this._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Gets child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/view/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children[ index ];\n\t}\n\n\t/**\n\t * Gets index of the given child node. Returns `-1` if child node is not found.\n\t *\n\t * @param {module:engine/view/node~Node} node Child node.\n\t * @returns {Number} Index of the child node.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.indexOf( node );\n\t}\n\n\t/**\n\t * Gets child nodes iterator.\n\t *\n\t * @returns {Iterable.<module:engine/view/node~Node>} Child nodes iterator.\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this fragment.\n\t *\n\t * @param {Number} index Position where nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\t_insertChild( index, items ) {\n\t\tthis._fireChange( 'children', this );\n\t\tlet count = 0;\n\n\t\tconst nodes = normalize( this.document, items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\n\t\t\tthis._children.splice( index, 0, node );\n\t\t\tindex++;\n\t\t\tcount++;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * Removes number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @param {Number} index Number of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/view/node~Node>} The array of removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tthis._fireChange( 'children', this );\n\n\t\tfor ( let i = index; i < index + howMany; i++ ) {\n\t\t\tthis._children[ i ].parent = null;\n\t\t}\n\n\t\treturn this._children.splice( index, howMany );\n\t}\n\n\t/**\n\t * Fires `change` event with given type of the change.\n\t *\n\t * @private\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Changed node.\n\t * @fires module:engine/view/node~Node#change\n\t */\n\t_fireChange( type, node ) {\n\t\tthis.fire( 'change:' + type, node );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // printTree() {\n\t// @if CK_DEBUG_ENGINE //\tlet string = 'ViewDocumentFragment: [';\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + '\\t'.repeat( 1 ) + child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\n' + child.printTree( 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\n]';\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( DocumentFragment, EmitterMixin );\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/view/item~Item|Iterable.<String|module:engine/view/item~Item>}\n// @returns {Iterable.<module:engine/view/node~Node>}\nfunction normalize( document, nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( document, nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( document, node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( document, node.data );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module module:engine/view/downcastwriter\n */\n\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\nimport ContainerElement from './containerelement';\nimport AttributeElement from './attributeelement';\nimport EmptyElement from './emptyelement';\nimport UIElement from './uielement';\nimport RawElement from './rawelement';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport DocumentFragment from './documentfragment';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\nimport Text from './text';\nimport EditableElement from './editableelement';\nimport { isPlainObject } from 'lodash-es';\n\n/**\n * View downcast writer.\n *\n * It provides a set of methods used to manipulate view nodes.\n *\n * Do not create an instance of this writer manually. To modify a view structure, use\n * the {@link module:engine/view/view~View#change `View#change()`} block.\n *\n * The `DowncastWriter` is designed to work with semantic views which are the views that were/are being downcasted from the model.\n * To work with ordinary views (e.g. parsed from a pasted content) use the\n * {@link module:engine/view/upcastwriter~UpcastWriter upcast writer}.\n *\n * Read more about changing the view in the {@glink framework/guides/architecture/editing-engine#changing-the-view Changing the view}\n * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide.\n */\nexport default class DowncastWriter {\n\t/**\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * The view document instance in which this writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * Holds references to the attribute groups that share the same {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t\t * The keys are `id`s, the values are `Set`s holding {@link module:engine/view/attributeelement~AttributeElement}s.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<String,Set>}\n\t\t */\n\t\tthis._cloneGroups = new Map();\n\t}\n\n\t/**\n\t * Sets {@link module:engine/view/documentselection~DocumentSelection selection's} ranges and direction to the\n\t * specified location based on the given {@link module:engine/view/selection~Selectable selectable}.\n\t *\n\t * Usage:\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 backward 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( start2, end2 ) ];\n\t *\t\twriter.setSelection( range );\n\t *\n\t *\t\t// Sets selection to the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\twriter.setSelection( otherSelection );\n\t *\n\t * \t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\twriter.setSelection( position );\n\t *\n\t * \t\t// Sets collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\twriter.setSelection( paragraph, offset );\n\t *\n\t * Creates a range inside an {@link module:engine/view/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 the {@link module:engine/view/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 ranges.\n\t *\t\twriter.setSelection( null );\n\t *\n\t * `DowncastWriter#setSelection()` allow passing additional options (`backward`, `fake` and `label`) 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 *\t\t// Sets selection as fake.\n\t *\t\t// Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * \t\t// This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * \t\t// represented in other way, for example by applying proper CSS class.\n\t *\t\twriter.setSelection( range, { fake: true } );\n\t *\n\t * \t\t// Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * \t\t// (and be properly handled by screen readers).\n\t *\t\twriter.setSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/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 * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t */\n\tsetSelection( selectable, placeOrOffset, options ) {\n\t\tthis.document.selection._setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/view/documentselection~DocumentSelection#focus selection's focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as {@link module:engine/view/view~View#createPositionAt view.createPositionAt()}\n\t * parameters.\n\t *\n\t * @param {module:engine/view/item~Item|module:engine/view/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/view/item~Item view item}.\n\t */\n\tsetSelectionFocus( itemOrPosition, offset ) {\n\t\tthis.document.selection._setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance.\n\t *\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment.\n\t */\n\tcreateDocumentFragment( children ) {\n\t\treturn new DocumentFragment( this.document, children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/text~Text text node}.\n\t *\n\t *\t\twriter.createText( 'foo' );\n\t *\n\t * @param {String} data The text's data.\n\t * @returns {module:engine/view/text~Text} The created text node.\n\t */\n\tcreateText( data ) {\n\t\treturn new Text( this.document, data );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/attributeelement~AttributeElement}.\n\t *\n\t *\t\twriter.createAttributeElement( 'strong' );\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' } );\n\t *\n\t *\t\t// Make `<a>` element contain other attributes element so the `<a>` element is not broken.\n\t *\t\twriter.createAttributeElement( 'a', { href: 'foo.bar' }, { priority: 5 } );\n\t *\n\t *\t\t// Set `id` of a marker element so it is not joined or merged with \"normal\" elements.\n\t *\t\twriter.createAttributeElement( 'span', { class: 'my-marker' }, { id: 'marker:my' } );\n\t *\n\t * **Note:** By default an `AttributeElement` is split by a\n\t * {@link module:engine/view/containerelement~ContainerElement `ContainerElement`} but this behavior can be modified\n\t * with `isAllowedInsideAttributeElement` option set while {@link #createContainerElement creating the element}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Element's attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Number} [options.priority] Element's {@link module:engine/view/attributeelement~AttributeElement#priority priority}.\n\t * @param {Number|String} [options.id] Element's {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t * @returns {module:engine/view/attributeelement~AttributeElement} Created element.\n\t */\n\tcreateAttributeElement( name, attributes, options = {} ) {\n\t\tconst attributeElement = new AttributeElement( this.document, name, attributes );\n\n\t\tif ( options.priority ) {\n\t\t\tattributeElement._priority = options.priority;\n\t\t}\n\n\t\tif ( options.id ) {\n\t\t\tattributeElement._id = options.id;\n\t\t}\n\n\t\treturn attributeElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/containerelement~ContainerElement}.\n\t *\n\t *\t\twriter.createContainerElement( 'p' );\n\t *\n\t *\t\t// Create element with custom attributes.\n\t *\t\twriter.createContainerElement( 'div', { id: 'foo-bar', 'data-baz': '123' } );\n\t *\n\t *\t\t// Create element with custom styles.\n\t *\t\twriter.createContainerElement( 'p', { style: 'font-weight: bold; padding-bottom: 10px' } );\n\t *\n\t *\t\t// Create element with custom classes.\n\t *\t\twriter.createContainerElement( 'p', { class: 'foo bar baz' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=false] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/containerelement~ContainerElement} Created element.\n\t */\n\tcreateContainerElement( name, attributes, options = {} ) {\n\t\tconst containerElement = new ContainerElement( this.document, name, attributes );\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\tcontainerElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn containerElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t *\t\twriter.createEditableElement( 'div' );\n\t *\t\twriter.createEditableElement( 'div', { id: 'foo-1234' } );\n\t *\n\t * Note: The editable element is to be used in the editing pipeline. Usually, together with\n\t * {@link module:widget/utils~toWidgetEditable `toWidgetEditable()`}.\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @returns {module:engine/view/editableelement~EditableElement} Created element.\n\t */\n\tcreateEditableElement( name, attributes ) {\n\t\tconst editableElement = new EditableElement( this.document, name, attributes );\n\t\teditableElement._document = this.document;\n\n\t\treturn editableElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/emptyelement~EmptyElement}.\n\t *\n\t *\t\twriter.createEmptyElement( 'img' );\n\t *\t\twriter.createEmptyElement( 'img', { id: 'foo-1234' } );\n\t *\n\t * @param {String} name Name of the element.\n\t * @param {Object} [attributes] Elements attributes.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/emptyelement~EmptyElement} Created element.\n\t */\n\tcreateEmptyElement( name, attributes, options = {} ) {\n\t\tconst emptyElement = new EmptyElement( this.document, name, attributes );\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\temptyElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn emptyElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/uielement~UIElement}.\n\t *\n\t *\t\twriter.createUIElement( 'span' );\n\t *\t\twriter.createUIElement( 'span', { id: 'foo-1234' } );\n\t *\n\t * A custom render function can be provided as the third parameter:\n\t *\n\t *\t\twriter.createUIElement( 'span', null, function( domDocument ) {\n\t *\t\t\tconst domElement = this.toDomElement( domDocument );\n\t *\t\t\tdomElement.innerHTML = '<b>this is ui element</b>';\n\t *\n\t *\t\t\treturn domElement;\n\t *\t\t} );\n\t *\n\t * Unlike {@link #createRawElement raw elements}, UI elements are by no means editor content, for instance,\n\t * they are ignored by the editor selection system.\n\t *\n\t * You should not use UI elements as data containers. Check out {@link #createRawElement} instead.\n\t *\n\t * @param {String} name The name of the element.\n\t * @param {Object} [attributes] Element attributes.\n\t * @param {Function} [renderFunction] A custom render function.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/uielement~UIElement} The created element.\n\t */\n\tcreateUIElement( name, attributes, renderFunction, options = {} ) {\n\t\tconst uiElement = new UIElement( this.document, name, attributes );\n\n\t\tif ( renderFunction ) {\n\t\t\tuiElement.render = renderFunction;\n\t\t}\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\tuiElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn uiElement;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/rawelement~RawElement}.\n\t *\n\t *\t\twriter.createRawElement( 'span', { id: 'foo-1234' }, function( domElement ) {\n\t *\t\t\tdomElement.innerHTML = '<b>This is the raw content of the raw element.</b>';\n\t *\t\t} );\n\t *\n\t * Raw elements work as data containers (\"wrappers\", \"sandboxes\") but their children are not managed or\n\t * even recognized by the editor. This encapsulation allows integrations to maintain custom DOM structures\n\t * in the editor content without, for instance, worrying about compatibility with other editor features.\n\t * Raw elements are a perfect tool for integration with external frameworks and data sources.\n\t *\n\t * Unlike {@link #createUIElement UI elements}, raw elements act like \"real\" editor content (similar to\n\t * {@link module:engine/view/containerelement~ContainerElement} or {@link module:engine/view/emptyelement~EmptyElement}),\n\t * and they are considered by the editor selection.\n\t *\n\t * You should not use raw elements to render the UI in the editor content. Check out {@link #createUIElement `#createUIElement()`}\n\t * instead.\n\t *\n\t * @param {String} name The name of the element.\n\t * @param {Object} [attributes] Element attributes.\n\t * @param {Function} [renderFunction] A custom render function.\n\t * @param {Object} [options] Element's options.\n\t * @param {Boolean} [options.isAllowedInsideAttributeElement=true] Whether an element is\n\t * {@link module:engine/view/element~Element#isAllowedInsideAttributeElement allowed inside an AttributeElement} and can be wrapped\n\t * with {@link module:engine/view/attributeelement~AttributeElement} by {@link module:engine/view/downcastwriter~DowncastWriter}.\n\t * @returns {module:engine/view/rawelement~RawElement} The created element.\n\t */\n\tcreateRawElement( name, attributes, renderFunction, options = {} ) {\n\t\tconst rawElement = new RawElement( this.document, name, attributes );\n\n\t\trawElement.render = renderFunction || ( () => {} );\n\n\t\tif ( options.isAllowedInsideAttributeElement !== undefined ) {\n\t\t\trawElement._isAllowedInsideAttributeElement = options.isAllowedInsideAttributeElement;\n\t\t}\n\n\t\treturn rawElement;\n\t}\n\n\t/**\n\t * Adds or overwrites the element's attribute with a specified key and value.\n\t *\n\t *\t\twriter.setAttribute( 'href', 'http://ckeditor.com', linkElement );\n\t *\n\t * @param {String} key The attribute key.\n\t * @param {String} value The attribute value.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetAttribute( key, value, element ) {\n\t\telement._setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t *\t\twriter.removeAttribute( 'href', linkElement );\n\t *\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveAttribute( key, element ) {\n\t\telement._removeAttribute( key );\n\t}\n\n\t/**\n\t * Adds specified class to the element.\n\t *\n\t *\t\twriter.addClass( 'foo', linkElement );\n\t *\t\twriter.addClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.<String>|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\taddClass( className, element ) {\n\t\telement._addClass( className );\n\t}\n\n\t/**\n\t * Removes specified class from the element.\n\t *\n\t *\t\twriter.removeClass( 'foo', linkElement );\n\t *\t\twriter.removeClass( [ 'foo', 'bar' ], linkElement );\n\t *\n\t * @param {Array.<String>|String} className\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveClass( className, element ) {\n\t\telement._removeClass( className );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\twriter.setStyle( 'color', 'red', element );\n\t *\t\twriter.setStyle( {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t}, element );\n\t *\n\t * **Note**: The passed style can be normalized if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @param {module:engine/view/element~Element} element Element to set styles on.\n\t */\n\tsetStyle( property, value, element ) {\n\t\tif ( isPlainObject( property ) && element === undefined ) {\n\t\t\telement = value;\n\t\t}\n\n\t\telement._setStyle( property, value );\n\t}\n\n\t/**\n\t * Removes specified style from the element.\n\t *\n\t *\t\twriter.removeStyle( 'color', element ); // Removes 'color' style.\n\t *\t\twriter.removeStyle( [ 'color', 'border-top' ], element ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @param {Array.<String>|String} property\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tremoveStyle( property, element ) {\n\t\telement._removeStyle( property );\n\t}\n\n\t/**\n\t * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {*} value\n\t * @param {module:engine/view/element~Element} element\n\t */\n\tsetCustomProperty( key, value, element ) {\n\t\telement._setCustomProperty( key, value );\n\t}\n\n\t/**\n\t * Removes a custom property stored under the given key.\n\t *\n\t * @param {String|Symbol} key\n\t * @param {module:engine/view/element~Element} element\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\tremoveCustomProperty( key, element ) {\n\t\treturn element._removeCustomProperty( key );\n\t}\n\n\t/**\n\t * Breaks attribute elements at the provided position or at the boundaries of a provided range. It breaks attribute elements\n\t * up to their first ancestor that is a container element.\n\t *\n\t * In following examples `<p>` is a container, `<b>` and `<u>` are attribute elements:\n\t *\n\t *\t\t<p>foo<b><u>bar{}</u></b></p> -> <p>foo<b><u>bar</u></b>[]</p>\n\t *\t\t<p>foo<b><u>{}bar</u></b></p> -> <p>foo{}<b><u>bar</u></b></p>\n\t *\t\t<p>foo<b><u>b{}ar</u></b></p> -> <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>\n\t *\t\t<p><b>fo{o</b><u>ba}r</u></p> -> <p><b>fo</b><b>o</b><u>ba</u><u>r</u></b></p>\n\t *\n\t * **Note:** {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n\t *\n\t * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer()` assumes that a given `position` is directly in the container element and breaks that container element.\n\t *\n\t * Throws the `view-writer-invalid-range-container` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when the {@link module:engine/view/range~Range#start start}\n\t * and {@link module:engine/view/range~Range#end end} positions of a passed range are not placed inside same parent container.\n\t *\n\t * Throws the `view-writer-cannot-break-empty-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when trying to break attributes inside an {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws the `view-writer-cannot-break-ui-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * when trying to break attributes inside a {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakContainer\n\t * @param {module:engine/view/position~Position|module:engine/view/range~Range} positionOrRange The position where\n\t * to break attribute elements.\n\t * @returns {module:engine/view/position~Position|module:engine/view/range~Range} The new position or range, after breaking the\n\t * attribute elements.\n\t */\n\tbreakAttributes( positionOrRange ) {\n\t\tif ( positionOrRange instanceof Position ) {\n\t\t\treturn this._breakAttributes( positionOrRange );\n\t\t} else {\n\t\t\treturn this._breakAttributesRange( positionOrRange );\n\t\t}\n\t}\n\n\t/**\n\t * Breaks a {@link module:engine/view/containerelement~ContainerElement container view element} into two, at the given position.\n\t * The position has to be directly inside the container element and cannot be in the root. It does not break the conrainer view element\n\t * if the position is at the beginning or at the end of its parent element.\n\t *\n\t *\t\t<p>foo^bar</p> -> <p>foo</p><p>bar</p>\n\t *\t\t<div><p>foo</p>^<p>bar</p></div> -> <div><p>foo</p></div><div><p>bar</p></div>\n\t *\t\t<p>^foobar</p> -> ^<p>foobar</p>\n\t *\t\t<p>foobar^</p> -> <p>foobar</p>^\n\t *\n\t * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,\n\t * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.\n\t * `breakContainer()` assumes that the given `position` is directly in the container element and breaks that container element.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#breakAttributes\n\t * @param {module:engine/view/position~Position} position The position where to break the element.\n\t * @returns {module:engine/view/position~Position} The position between broken elements. If an element has not been broken,\n\t * the returned position is placed either before or after it.\n\t */\n\tbreakContainer( position ) {\n\t\tconst element = position.parent;\n\n\t\tif ( !( element.is( 'containerElement' ) ) ) {\n\t\t\t/**\n\t\t\t * Trying to break an element which is not a container element.\n\t\t\t *\n\t\t\t * @error view-writer-break-non-container-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-break-non-container-element', this.document );\n\t\t}\n\n\t\tif ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Trying to break root element.\n\t\t\t *\n\t\t\t * @error view-writer-break-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-break-root', this.document );\n\t\t}\n\n\t\tif ( position.isAtStart ) {\n\t\t\treturn Position._createBefore( element );\n\t\t} else if ( !position.isAtEnd ) {\n\t\t\tconst newElement = element._clone( false );\n\n\t\t\tthis.insert( Position._createAfter( element ), newElement );\n\n\t\t\tconst sourceRange = new Range( position, Position._createAt( element, 'end' ) );\n\t\t\tconst targetPosition = new Position( newElement, 0 );\n\n\t\t\tthis.move( sourceRange, targetPosition );\n\t\t}\n\n\t\treturn Position._createAfter( element );\n\t}\n\n\t/**\n\t * Merges {@link module:engine/view/attributeelement~AttributeElement attribute elements}. It also merges text nodes if needed.\n\t * Only {@link module:engine/view/attributeelement~AttributeElement#isSimilar similar} attribute elements can be merged.\n\t *\n\t * In following examples `<p>` is a container and `<b>` is an attribute element:\n\t *\n\t *\t\t<p>foo[]bar</p> -> <p>foo{}bar</p>\n\t *\t\t<p><b>foo</b>[]<b>bar</b></p> -> <p><b>foo{}bar</b></p>\n\t *\t\t<p><b foo=\"bar\">a</b>[]<b foo=\"baz\">b</b></p> -> <p><b foo=\"bar\">a</b>[]<b foo=\"baz\">b</b></p>\n\t *\n\t * It will also take care about empty attributes when merging:\n\t *\n\t *\t\t<p><b>[]</b></p> -> <p>[]</p>\n\t *\t\t<p><b>foo</b><i>[]</i><b>bar</b></p> -> <p><b>foo{}bar</b></p>\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeContainers\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeAttributes( position ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// When inside text node - nothing to merge.\n\t\tif ( positionParent.is( '$text' ) ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When inside empty attribute - remove it.\n\t\tif ( positionParent.is( 'attributeElement' ) && positionParent.childCount === 0 ) {\n\t\t\tconst parent = positionParent.parent;\n\t\t\tconst offset = positionParent.index;\n\n\t\t\tpositionParent._remove();\n\t\t\tthis._removeFromClonedElementsGroup( positionParent );\n\n\t\t\treturn this.mergeAttributes( new Position( parent, offset ) );\n\t\t}\n\n\t\tconst nodeBefore = positionParent.getChild( positionOffset - 1 );\n\t\tconst nodeAfter = positionParent.getChild( positionOffset );\n\n\t\t// Position should be placed between two nodes.\n\t\tif ( !nodeBefore || !nodeAfter ) {\n\t\t\treturn position;\n\t\t}\n\n\t\t// When position is between two text nodes.\n\t\tif ( nodeBefore.is( '$text' ) && nodeAfter.is( '$text' ) ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\t\t// When position is between two same attribute elements.\n\t\telse if ( nodeBefore.is( 'attributeElement' ) && nodeAfter.is( 'attributeElement' ) && nodeBefore.isSimilar( nodeAfter ) ) {\n\t\t\t// Move all children nodes from node placed after selection and remove that node.\n\t\t\tconst count = nodeBefore.childCount;\n\t\t\tnodeBefore._appendChild( nodeAfter.getChildren() );\n\n\t\t\tnodeAfter._remove();\n\t\t\tthis._removeFromClonedElementsGroup( nodeAfter );\n\n\t\t\t// New position is located inside the first node, before new nodes.\n\t\t\t// Call this method recursively to merge again if needed.\n\t\t\treturn this.mergeAttributes( new Position( nodeBefore, count ) );\n\t\t}\n\n\t\treturn position;\n\t}\n\n\t/**\n\t * Merges two {@link module:engine/view/containerelement~ContainerElement container elements} that are before and after given position.\n\t * Precisely, the element after the position is removed and it's contents are moved to element before the position.\n\t *\n\t *\t\t<p>foo</p>^<p>bar</p> -> <p>foo^bar</p>\n\t *\t\t<div>foo</div>^<p>bar</p> -> <div>foo^bar</div>\n\t *\n\t * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#mergeAttributes mergeAttributes} and\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#mergeContainers mergeContainers} is that `mergeAttributes` merges two\n\t * {@link module:engine/view/attributeelement~AttributeElement attribute elements} or {@link module:engine/view/text~Text text nodes}\n\t * while `mergeContainer` merges two {@link module:engine/view/containerelement~ContainerElement container elements}.\n\t *\n\t * @see module:engine/view/attributeelement~AttributeElement\n\t * @see module:engine/view/containerelement~ContainerElement\n\t * @see module:engine/view/downcastwriter~DowncastWriter#mergeAttributes\n\t * @param {module:engine/view/position~Position} position Merge position.\n\t * @returns {module:engine/view/position~Position} Position after merge.\n\t */\n\tmergeContainers( position ) {\n\t\tconst prev = position.nodeBefore;\n\t\tconst next = position.nodeAfter;\n\n\t\tif ( !prev || !next || !prev.is( 'containerElement' ) || !next.is( 'containerElement' ) ) {\n\t\t\t/**\n\t\t\t * Element before and after given position cannot be merged.\n\t\t\t *\n\t\t\t * @error view-writer-merge-containers-invalid-position\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-merge-containers-invalid-position', this.document );\n\t\t}\n\n\t\tconst lastChild = prev.getChild( prev.childCount - 1 );\n\t\tconst newPosition = lastChild instanceof Text ? Position._createAt( lastChild, 'end' ) : Position._createAt( prev, 'end' );\n\n\t\tthis.move( Range._createIn( next ), Position._createAt( prev, 'end' ) );\n\t\tthis.remove( Range._createOn( next ) );\n\n\t\treturn newPosition;\n\t}\n\n\t/**\n\t * Inserts a node or nodes at specified position. Takes care about breaking attributes before insertion\n\t * and merging them afterwards.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n\t * contains instances that are not {@link module:engine/view/text~Text Texts},\n\t * {@link module:engine/view/attributeelement~AttributeElement AttributeElements},\n\t * {@link module:engine/view/containerelement~ContainerElement ContainerElements},\n\t * {@link module:engine/view/emptyelement~EmptyElement EmptyElements},\n\t * {@link module:engine/view/rawelement~RawElement RawElements} or\n\t * {@link module:engine/view/uielement~UIElement UIElements}.\n\t *\n\t * @param {module:engine/view/position~Position} position Insertion position.\n\t * @param {module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement|\n\t * module:engine/view/containerelement~ContainerElement|module:engine/view/emptyelement~EmptyElement|\n\t * module:engine/view/rawelement~RawElement|module:engine/view/uielement~UIElement|\n\t * Iterable.<module:engine/view/text~Text|\n\t * module:engine/view/attributeelement~AttributeElement|module:engine/view/containerelement~ContainerElement|\n\t * module:engine/view/emptyelement~EmptyElement|module:engine/view/rawelement~RawElement|\n\t * module:engine/view/uielement~UIElement>} nodes Node or nodes to insert.\n\t * @returns {module:engine/view/range~Range} Range around inserted nodes.\n\t */\n\tinsert( position, nodes ) {\n\t\tnodes = isIterable( nodes ) ? [ ...nodes ] : [ nodes ];\n\n\t\t// Check if nodes to insert are instances of AttributeElements, ContainerElements, EmptyElements, UIElements or Text.\n\t\tvalidateNodesToInsert( nodes, this.document );\n\n\t\t// Group nodes in batches of nodes that require or do not require breaking an AttributeElements.\n\t\tconst nodeGroups = nodes.reduce( ( groups, node ) => {\n\t\t\tconst lastGroup = groups[ groups.length - 1 ];\n\n\t\t\t// Break attributes on nodes that do exist in the model tree so they can have attributes, other elements\n\t\t\t// can't have an attribute in model and won't get wrapped with an AttributeElement while down-casted.\n\t\t\tconst breakAttributes = !( node.is( 'uiElement' ) && node.isAllowedInsideAttributeElement );\n\n\t\t\tif ( !lastGroup || lastGroup.breakAttributes != breakAttributes ) {\n\t\t\t\tgroups.push( {\n\t\t\t\t\tbreakAttributes,\n\t\t\t\t\tnodes: [ node ]\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tlastGroup.nodes.push( node );\n\t\t\t}\n\n\t\t\treturn groups;\n\t\t}, [] );\n\n\t\t// Insert nodes in batches.\n\t\tlet start = null;\n\t\tlet end = position;\n\n\t\tfor ( const { nodes, breakAttributes } of nodeGroups ) {\n\t\t\tconst range = this._insertNodes( end, nodes, breakAttributes );\n\n\t\t\tif ( !start ) {\n\t\t\t\tstart = range.start;\n\t\t\t}\n\n\t\t\tend = range.end;\n\t\t}\n\n\t\t// When no nodes were inserted - return collapsed range.\n\t\tif ( !start ) {\n\t\t\treturn new Range( position );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Removes provided range from the container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range|module:engine/view/item~Item} rangeOrItem Range to remove from container\n\t * or an {@link module:engine/view/item~Item item} to remove. If range is provided, after removing, it will be updated\n\t * to a collapsed range showing the new position.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Document fragment containing removed nodes.\n\t */\n\tremove( rangeOrItem ) {\n\t\tconst range = rangeOrItem instanceof Range ? rangeOrItem : Range._createOn( rangeOrItem );\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to remove.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn new DocumentFragment( this.document );\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\tconst count = breakEnd.offset - breakStart.offset;\n\n\t\t// Remove nodes in range.\n\t\tconst removed = parentContainer._removeChildren( breakStart.offset, count );\n\n\t\tfor ( const node of removed ) {\n\t\t\tthis._removeFromClonedElementsGroup( node );\n\t\t}\n\n\t\t// Merge after removing.\n\t\tconst mergePosition = this.mergeAttributes( breakStart );\n\t\trange.start = mergePosition;\n\t\trange.end = mergePosition.clone();\n\n\t\t// Return removed nodes.\n\t\treturn new DocumentFragment( this.document, removed );\n\t}\n\n\t/**\n\t * Removes matching elements from given range.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to clear.\n\t * @param {module:engine/view/element~Element} element Element to remove.\n\t */\n\tclear( range, element ) {\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Create walker on given range.\n\t\t// We walk backward because when we remove element during walk it modifies range end position.\n\t\tconst walker = range.getWalker( {\n\t\t\tdirection: 'backward',\n\t\t\tignoreElementEnd: true\n\t\t} );\n\n\t\t// Let's walk.\n\t\tfor ( const current of walker ) {\n\t\t\tconst item = current.item;\n\t\t\tlet rangeToRemove;\n\n\t\t\t// When current item matches to the given element.\n\t\t\tif ( item.is( 'element' ) && element.isSimilar( item ) ) {\n\t\t\t\t// Create range on this element.\n\t\t\t\trangeToRemove = Range._createOn( item );\n\t\t\t\t// When range starts inside Text or TextProxy element.\n\t\t\t} else if ( !current.nextPosition.isAfter( range.start ) && item.is( '$textProxy' ) ) {\n\t\t\t\t// We need to check if parent of this text matches to given element.\n\t\t\t\tconst parentElement = item.getAncestors().find( ancestor => {\n\t\t\t\t\treturn ancestor.is( 'element' ) && element.isSimilar( ancestor );\n\t\t\t\t} );\n\n\t\t\t\t// If it is then create range inside this element.\n\t\t\t\tif ( parentElement ) {\n\t\t\t\t\trangeToRemove = Range._createIn( parentElement );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we have found element to remove.\n\t\t\tif ( rangeToRemove ) {\n\t\t\t\t// We need to check if element range stick out of the given range and truncate if it is.\n\t\t\t\tif ( rangeToRemove.end.isAfter( range.end ) ) {\n\t\t\t\t\trangeToRemove.end = range.end;\n\t\t\t\t}\n\n\t\t\t\tif ( rangeToRemove.start.isBefore( range.start ) ) {\n\t\t\t\t\trangeToRemove.start = range.start;\n\t\t\t\t}\n\n\t\t\t\t// At the end we remove range with found element.\n\t\t\t\tthis.remove( rangeToRemove );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Moves nodes from provided range to target position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} sourceRange Range containing nodes to move.\n\t * @param {module:engine/view/position~Position} targetPosition Position to insert.\n\t * @returns {module:engine/view/range~Range} Range in target container. Inserted nodes are placed between\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions.\n\t */\n\tmove( sourceRange, targetPosition ) {\n\t\tlet nodes;\n\n\t\tif ( targetPosition.isAfter( sourceRange.end ) ) {\n\t\t\ttargetPosition = this._breakAttributes( targetPosition, true );\n\n\t\t\tconst parent = targetPosition.parent;\n\t\t\tconst countBefore = parent.childCount;\n\n\t\t\tsourceRange = this._breakAttributesRange( sourceRange, true );\n\n\t\t\tnodes = this.remove( sourceRange );\n\n\t\t\ttargetPosition.offset += ( parent.childCount - countBefore );\n\t\t} else {\n\t\t\tnodes = this.remove( sourceRange );\n\t\t}\n\n\t\treturn this.insert( targetPosition, nodes );\n\t}\n\n\t/**\n\t * Wraps elements within range with provided {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t * If a collapsed range is provided, it will be wrapped only if it is equal to view selection.\n\t *\n\t * If a collapsed range was passed and is same as selection, the selection\n\t * will be moved to the inside of the wrapped attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-invalid-range-container`\n\t * when {@link module:engine/view/range~Range#start}\n\t * and {@link module:engine/view/range~Range#end} positions are not placed inside same parent container.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-nonselection-collapsed-range` when passed range\n\t * is collapsed and different than view selection.\n\t *\n\t * **Note:** Attribute elements by default can wrap {@link module:engine/view/text~Text},\n\t * {@link module:engine/view/emptyelement~EmptyElement}, {@link module:engine/view/uielement~UIElement},\n\t * {@link module:engine/view/rawelement~RawElement} and other attribute elements with higher priority. Other elements while placed\n\t * inside an attribute element will split it (or nest it in case of an `AttributeElement`). This behavior can be modified by changing\n\t * the `isAllowedInsideAttributeElement` option while using\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createContainerElement},\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createEmptyElement},\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement} or\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createRawElement}.\n\t *\n\t * @param {module:engine/view/range~Range} range Range to wrap.\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute Attribute element to use as wrapper.\n\t * @returns {module:engine/view/range~Range} range Range after wrapping, spanning over wrapping attribute element.\n\t */\n\twrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-wrap-invalid-attribute',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\tif ( !range.isCollapsed ) {\n\t\t\t// Non-collapsed range. Wrap it with the attribute element.\n\t\t\treturn this._wrapRange( range, attribute );\n\t\t} else {\n\t\t\t// Collapsed range. Wrap position.\n\t\t\tlet position = range.start;\n\n\t\t\tif ( position.parent.is( 'element' ) && !_hasNonUiChildren( position.parent ) ) {\n\t\t\t\tposition = position.getLastMatchingPosition( value => value.item.is( 'uiElement' ) );\n\t\t\t}\n\n\t\t\tposition = this._wrapPosition( position, attribute );\n\t\t\tconst viewSelection = this.document.selection;\n\n\t\t\t// If wrapping position is equal to view selection, move view selection inside wrapping attribute element.\n\t\t\tif ( viewSelection.isCollapsed && viewSelection.getFirstPosition().isEqual( range.start ) ) {\n\t\t\t\tthis.setSelection( position );\n\t\t\t}\n\n\t\t\treturn new Range( position );\n\t\t}\n\t}\n\n\t/**\n\t * Unwraps nodes within provided range from attribute element.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when\n\t * {@link module:engine/view/range~Range#start start} and {@link module:engine/view/range~Range#end end} positions are not placed inside\n\t * same parent container.\n\t *\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t */\n\tunwrap( range, attribute ) {\n\t\tif ( !( attribute instanceof AttributeElement ) ) {\n\t\t\t/**\n\t\t\t * The `attribute` passed to {@link module:engine/view/downcastwriter~DowncastWriter#unwrap `DowncastWriter#unwrap()`}\n\t\t\t * must be an instance of {@link module:engine/view/attributeelement~AttributeElement `AttributeElement`}.\n\t\t\t *\n\t\t\t * @error view-writer-unwrap-invalid-attribute\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-unwrap-invalid-attribute',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// If range is collapsed - nothing to unwrap.\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn range;\n\t\t}\n\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Unwrap children located between break points.\n\t\tconst newRange = this._unwrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Renames element by creating a copy of renamed element but with changed name and then moving contents of the\n\t * old element to the new one. Keep in mind that this will invalidate all {@link module:engine/view/position~Position positions} which\n\t * has renamed element as {@link module:engine/view/position~Position#parent a parent}.\n\t *\n\t * New element has to be created because `Element#tagName` property in DOM is readonly.\n\t *\n\t * Since this function creates a new element and removes the given one, the new element is returned to keep reference.\n\t *\n\t * @param {String} newName New name for element.\n\t * @param {module:engine/view/containerelement~ContainerElement} viewElement Element to be renamed.\n\t * @returns {module:engine/view/containerelement~ContainerElement} Element created due to rename.\n\t */\n\trename( newName, viewElement ) {\n\t\tconst newElement = new ContainerElement( this.document, newName, viewElement.getAttributes() );\n\n\t\tthis.insert( Position._createAfter( viewElement ), newElement );\n\t\tthis.move( Range._createIn( viewElement ), Position._createAt( newElement, 0 ) );\n\t\tthis.remove( Range._createOn( viewElement ) );\n\n\t\treturn newElement;\n\t}\n\n\t/**\n\t * Cleans up memory by removing obsolete cloned elements group from the writer.\n\t *\n\t * Should be used whenever all {@link module:engine/view/attributeelement~AttributeElement attribute elements}\n\t * with the same {@link module:engine/view/attributeelement~AttributeElement#id id} are going to be removed from the view and\n\t * the group will no longer be needed.\n\t *\n\t * Cloned elements group are not removed automatically in case if the group is still needed after all its elements\n\t * were removed from the view.\n\t *\n\t * Keep in mind that group names are equal to the `id` property of the attribute element.\n\t *\n\t * @param {String} groupName Name of the group to clear.\n\t */\n\tclearClonedElementsGroup( groupName ) {\n\t\tthis._cloneGroups.delete( groupName );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/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/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates its own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/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 * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t Creates new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'p' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Inserts a node or nodes at the specified position. Takes care of breaking attributes before insertion\n\t * and merging them afterwards if requested by the breakAttributes param.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position Insertion position.\n\t * @param {module:engine/view/text~Text|module:engine/view/attributeelement~AttributeElement|\n\t * module:engine/view/containerelement~ContainerElement|module:engine/view/emptyelement~EmptyElement|\n\t * module:engine/view/rawelement~RawElement|module:engine/view/uielement~UIElement|\n\t * Iterable.<module:engine/view/text~Text|\n\t * module:engine/view/attributeelement~AttributeElement|module:engine/view/containerelement~ContainerElement|\n\t * module:engine/view/emptyelement~EmptyElement|module:engine/view/rawelement~RawElement|\n\t * module:engine/view/uielement~UIElement>} nodes Node or nodes to insert.\n\t * @param {Boolean} breakAttributes Whether attributes should be broken.\n\t * @returns {module:engine/view/range~Range} Range around inserted nodes.\n\t */\n\t_insertNodes( position, nodes, breakAttributes ) {\n\t\tlet parentElement;\n\n\t\t// Break attributes on nodes that do exist in the model tree so they can have attributes, other elements\n\t\t// can't have an attribute in model and won't get wrapped with an AttributeElement while down-casted.\n\t\tif ( breakAttributes ) {\n\t\t\tparentElement = getParentContainer( position );\n\t\t} else {\n\t\t\tparentElement = position.parent.is( '$text' ) ? position.parent.parent : position.parent;\n\t\t}\n\n\t\tif ( !parentElement ) {\n\t\t\t/**\n\t\t\t * Position's parent container cannot be found.\n\t\t\t *\n\t\t\t * @error view-writer-invalid-position-container\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'view-writer-invalid-position-container',\n\t\t\t\tthis.document\n\t\t\t);\n\t\t}\n\n\t\tlet insertionPosition;\n\n\t\tif ( breakAttributes ) {\n\t\t\tinsertionPosition = this._breakAttributes( position, true );\n\t\t} else {\n\t\t\tinsertionPosition = position.parent.is( '$text' ) ? breakTextNode( position ) : position;\n\t\t}\n\n\t\tconst length = parentElement._insertChild( insertionPosition.offset, nodes );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tthis._addToClonedElementsGroup( node );\n\t\t}\n\n\t\tconst endPosition = insertionPosition.getShiftedBy( length );\n\t\tconst start = this.mergeAttributes( insertionPosition );\n\n\t\t// If start position was merged - move end position.\n\t\tif ( !start.isEqual( insertionPosition ) ) {\n\t\t\tendPosition.offset--;\n\t\t}\n\n\t\tconst end = this.mergeAttributes( endPosition );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Wraps children with provided `wrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be wrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} wrapElement\n\t */\n\t_wrapChildren( parent, startOffset, endOffset, wrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst wrapPositions = [];\n\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\t\t\tconst isText = child.is( '$text' );\n\t\t\tconst isAttribute = child.is( 'attributeElement' );\n\t\t\tconst isAllowedInsideAttributeElement = child.isAllowedInsideAttributeElement;\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `wrapElement` is `<span class=\"foo\">` element.)\n\t\t\t//\n\t\t\t// Check if `wrapElement` can be joined with the wrapped element. One of requirements is having same name.\n\t\t\t// If possible, join elements.\n\t\t\t//\n\t\t\t// <p><span class=\"bar\">abc</span></p> --> <p><span class=\"foo bar\">abc</span></p>\n\t\t\t//\n\t\t\tif ( isAttribute && this._wrapAttributeElement( wrapElement, child ) ) {\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// Wrap the child if it is not an attribute element or if it is an attribute element that should be inside\n\t\t\t// `wrapElement` (due to priority).\n\t\t\t//\n\t\t\t// <p>abc</p> --> <p><span class=\"foo\">abc</span></p>\n\t\t\t// <p><strong>abc</strong></p> --> <p><span class=\"foo\"><strong>abc</strong></span></p>\n\t\t\telse if ( isText || isAllowedInsideAttributeElement || ( isAttribute && shouldABeOutsideB( wrapElement, child ) ) ) {\n\t\t\t\t// Clone attribute.\n\t\t\t\tconst newAttribute = wrapElement._clone();\n\n\t\t\t\t// Wrap current node with new attribute.\n\t\t\t\tchild._remove();\n\t\t\t\tnewAttribute._appendChild( child );\n\n\t\t\t\tparent._insertChild( i, newAttribute );\n\t\t\t\tthis._addToClonedElementsGroup( newAttribute );\n\n\t\t\t\twrapPositions.push( new Position( parent, i ) );\n\t\t\t}\n\t\t\t//\n\t\t\t// If other nested attribute is found and it wasn't wrapped (see above), continue wrapping inside it.\n\t\t\t//\n\t\t\t// <p><a href=\"foo.html\">abc</a></p> --> <p><a href=\"foo.html\"><span class=\"foo\">abc</span></a></p>\n\t\t\t//\n\t\t\telse if ( isAttribute ) {\n\t\t\t\tthis._wrapChildren( child, 0, child.childCount, wrapElement );\n\t\t\t}\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each wrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of wrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Unwraps children from provided `unwrapElement`. Only children contained in `parent` element between\n\t * `startOffset` and `endOffset` will be unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} parent\n\t * @param {Number} startOffset\n\t * @param {Number} endOffset\n\t * @param {module:engine/view/element~Element} unwrapElement\n\t */\n\t_unwrapChildren( parent, startOffset, endOffset, unwrapElement ) {\n\t\tlet i = startOffset;\n\t\tconst unwrapPositions = [];\n\n\t\t// Iterate over each element between provided offsets inside parent.\n\t\t// We don't use tree walker or range iterator because we will be removing and merging potentially multiple nodes,\n\t\t// so it could get messy. It is safer to it manually in this case.\n\t\twhile ( i < endOffset ) {\n\t\t\tconst child = parent.getChild( i );\n\n\t\t\t// Skip all text nodes. There should be no container element's here either.\n\t\t\tif ( !child.is( 'attributeElement' ) ) {\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// (In all examples, assume that `unwrapElement` is `<span class=\"foo\">` element.)\n\t\t\t//\n\t\t\t// If the child is similar to the given attribute element, unwrap it - it will be completely removed.\n\t\t\t//\n\t\t\t// <p><span class=\"foo\">abc</span>xyz</p> --> <p>abcxyz</p>\n\t\t\t//\n\t\t\tif ( child.isSimilar( unwrapElement ) ) {\n\t\t\t\tconst unwrapped = child.getChildren();\n\t\t\t\tconst count = child.childCount;\n\n\t\t\t\t// Replace wrapper element with its children\n\t\t\t\tchild._remove();\n\t\t\t\tparent._insertChild( i, unwrapped );\n\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\n\t\t\t\t// Save start and end position of moved items.\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + count )\n\t\t\t\t);\n\n\t\t\t\t// Skip elements that were unwrapped. Assuming there won't be another element to unwrap in child elements.\n\t\t\t\ti += count;\n\t\t\t\tendOffset += count - 1;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If the child is not similar but is an attribute element, try partial unwrapping - remove the same attributes/styles/classes.\n\t\t\t// Partial unwrapping will happen only if the elements have the same name.\n\t\t\t//\n\t\t\t// <p><span class=\"foo bar\">abc</span>xyz</p> --> <p><span class=\"bar\">abc</span>xyz</p>\n\t\t\t// <p><i class=\"foo\">abc</i>xyz</p> --> <p><i class=\"foo\">abc</i>xyz</p>\n\t\t\t//\n\t\t\tif ( this._unwrapAttributeElement( unwrapElement, child ) ) {\n\t\t\t\tunwrapPositions.push(\n\t\t\t\t\tnew Position( parent, i ),\n\t\t\t\t\tnew Position( parent, i + 1 )\n\t\t\t\t);\n\n\t\t\t\ti++;\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t//\n\t\t\t// If other nested attribute is found, look through it's children for elements to unwrap.\n\t\t\t//\n\t\t\t// <p><i><span class=\"foo\">abc</span></i><p> --> <p><i>abc</i><p>\n\t\t\t//\n\t\t\tthis._unwrapChildren( child, 0, child.childCount, unwrapElement );\n\n\t\t\ti++;\n\t\t}\n\n\t\t// Merge at each unwrap.\n\t\tlet offsetChange = 0;\n\n\t\tfor ( const position of unwrapPositions ) {\n\t\t\tposition.offset -= offsetChange;\n\n\t\t\t// Do not merge with elements outside selected children.\n\t\t\tif ( position.offset == startOffset || position.offset == endOffset ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst newPosition = this.mergeAttributes( position );\n\n\t\t\t// If nodes were merged - other merge offsets will change.\n\t\t\tif ( !newPosition.isEqual( position ) ) {\n\t\t\t\toffsetChange++;\n\t\t\t\tendOffset--;\n\t\t\t}\n\t\t}\n\n\t\treturn Range._createFromParentsAndOffsets( parent, startOffset, parent, endOffset );\n\t}\n\n\t/**\n\t * Helper function for `view.writer.wrap`. Wraps range with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/range~Range} New range after wrapping, spanning over wrapping attribute element.\n\t */\n\t_wrapRange( range, attribute ) {\n\t\t// Break attributes at range start and end.\n\t\tconst { start: breakStart, end: breakEnd } = this._breakAttributesRange( range, true );\n\t\tconst parentContainer = breakStart.parent;\n\n\t\t// Wrap all children with attribute.\n\t\tconst newRange = this._wrapChildren( parentContainer, breakStart.offset, breakEnd.offset, attribute );\n\n\t\t// Merge attributes at the both ends and return a new range.\n\t\tconst start = this.mergeAttributes( newRange.start );\n\n\t\t// If start position was merged - move end position back.\n\t\tif ( !start.isEqual( newRange.start ) ) {\n\t\t\tnewRange.end.offset--;\n\t\t}\n\t\tconst end = this.mergeAttributes( newRange.end );\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Helper function for {@link #wrap}. Wraps position with provided attribute element.\n\t * This method will also merge newly added attribute element with its siblings whenever possible.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError} `view-writer-wrap-invalid-attribute` when passed attribute element is not\n\t * an instance of {@link module:engine/view/attributeelement~AttributeElement AttributeElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position\n\t * @param {module:engine/view/attributeelement~AttributeElement} attribute\n\t * @returns {module:engine/view/position~Position} New position after wrapping.\n\t */\n\t_wrapPosition( position, attribute ) {\n\t\t// Return same position when trying to wrap with attribute similar to position parent.\n\t\tif ( attribute.isSimilar( position.parent ) ) {\n\t\t\treturn movePositionToTextNode( position.clone() );\n\t\t}\n\n\t\t// When position is inside text node - break it and place new position between two text nodes.\n\t\tif ( position.parent.is( '$text' ) ) {\n\t\t\tposition = breakTextNode( position );\n\t\t}\n\n\t\t// Create fake element that will represent position, and will not be merged with other attributes.\n\t\tconst fakePosition = this.createAttributeElement();\n\t\tfakePosition._priority = Number.POSITIVE_INFINITY;\n\t\tfakePosition.isSimilar = () => false;\n\n\t\t// Insert fake element in position location.\n\t\tposition.parent._insertChild( position.offset, fakePosition );\n\n\t\t// Range around inserted fake attribute element.\n\t\tconst wrapRange = new Range( position, position.getShiftedBy( 1 ) );\n\n\t\t// Wrap fake element with attribute (it will also merge if possible).\n\t\tthis.wrap( wrapRange, attribute );\n\n\t\t// Remove fake element and place new position there.\n\t\tconst newPosition = new Position( fakePosition.parent, fakePosition.index );\n\t\tfakePosition._remove();\n\n\t\t// If position is placed between text nodes - merge them and return position inside.\n\t\tconst nodeBefore = newPosition.nodeBefore;\n\t\tconst nodeAfter = newPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof Text && nodeAfter instanceof Text ) {\n\t\t\treturn mergeTextNodes( nodeBefore, nodeAfter );\n\t\t}\n\n\t\t// If position is next to text node - move position inside.\n\t\treturn movePositionToTextNode( newPosition );\n\t}\n\n\t/**\n\t * \tWraps one {@link module:engine/view/attributeelement~AttributeElement AttributeElement} into another by\n\t * \tmerging them if possible. When merging is possible - all attributes, styles and classes are moved from wrapper\n\t * \telement to element being wrapped.\n\t *\n\t * \t@private\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * \t@param {module:engine/view/attributeelement~AttributeElement} toWrap AttributeElement to wrap using wrapper element.\n\t * \t@returns {Boolean} Returns `true` if elements are merged.\n\t */\n\t_wrapAttributeElement( wrapper, toWrap ) {\n\t\tif ( !canBeJoined( wrapper, toWrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't merge if name or priority differs.\n\t\tif ( wrapper.name !== toWrap.name || wrapper.priority !== toWrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if attributes can be merged.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are different we cannot wrap.\n\t\t\tif ( toWrap.hasAttribute( key ) && toWrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if styles can be merged.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( toWrap.hasStyle( key ) && toWrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Move all attributes/classes/styles from wrapper to wrapped AttributeElement.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Move only these attributes that are not present - other are similar.\n\t\t\tif ( !toWrap.hasAttribute( key ) ) {\n\t\t\t\tthis.setAttribute( key, wrapper.getAttribute( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\tif ( !toWrap.hasStyle( key ) ) {\n\t\t\t\tthis.setStyle( key, wrapper.getStyle( key ), toWrap );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of wrapper.getClassNames() ) {\n\t\t\tif ( !toWrap.hasClass( key ) ) {\n\t\t\t\tthis.addClass( key, toWrap );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Unwraps {@link module:engine/view/attributeelement~AttributeElement AttributeElement} from another by removing\n\t * corresponding attributes, classes and styles. All attributes, classes and styles from wrapper should be present\n\t * inside element being unwrapped.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} wrapper Wrapper AttributeElement.\n\t * @param {module:engine/view/attributeelement~AttributeElement} toUnwrap AttributeElement to unwrap using wrapper element.\n\t * @returns {Boolean} Returns `true` if elements are unwrapped.\n\t **/\n\t_unwrapAttributeElement( wrapper, toUnwrap ) {\n\t\tif ( !canBeJoined( wrapper, toUnwrap ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Can't unwrap if name or priority differs.\n\t\tif ( wrapper.name !== toUnwrap.name || wrapper.priority !== toUnwrap.priority ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper attributes.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If some attributes are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasAttribute( key ) || toUnwrap.getAttribute( key ) !== wrapper.getAttribute( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper classes.\n\t\tif ( !toUnwrap.hasClass( ...wrapper.getClassNames() ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if AttributeElement has all wrapper styles.\n\t\tfor ( const key of wrapper.getStyleNames() ) {\n\t\t\t// If some styles are missing or different we cannot unwrap.\n\t\t\tif ( !toUnwrap.hasStyle( key ) || toUnwrap.getStyle( key ) !== wrapper.getStyle( key ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// Remove all wrapper's attributes from unwrapped element.\n\t\tfor ( const key of wrapper.getAttributeKeys() ) {\n\t\t\t// Classes and styles should be checked separately.\n\t\t\tif ( key === 'class' || key === 'style' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.removeAttribute( key, toUnwrap );\n\t\t}\n\n\t\t// Remove all wrapper's classes from unwrapped element.\n\t\tthis.removeClass( Array.from( wrapper.getClassNames() ), toUnwrap );\n\n\t\t// Remove all wrapper's styles from unwrapped element.\n\t\tthis.removeStyle( Array.from( wrapper.getStyleNames() ), toUnwrap );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at the boundaries of given range.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range Range which `start` and `end` positions will be used to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/range~Range} New range with located at break positions.\n\t */\n\t_breakAttributesRange( range, forceSplitText = false ) {\n\t\tconst rangeStart = range.start;\n\t\tconst rangeEnd = range.end;\n\n\t\tvalidateRangeContainer( range, this.document );\n\n\t\t// Break at the collapsed position. Return new collapsed range.\n\t\tif ( range.isCollapsed ) {\n\t\t\tconst position = this._breakAttributes( range.start, forceSplitText );\n\n\t\t\treturn new Range( position, position );\n\t\t}\n\n\t\tconst breakEnd = this._breakAttributes( rangeEnd, forceSplitText );\n\t\tconst count = breakEnd.parent.childCount;\n\t\tconst breakStart = this._breakAttributes( rangeStart, forceSplitText );\n\n\t\t// Calculate new break end offset.\n\t\tbreakEnd.offset += breakEnd.parent.childCount - count;\n\n\t\treturn new Range( breakStart, breakEnd );\n\t}\n\n\t/**\n\t * Helper function used by other `DowncastWriter` methods. Breaks attribute elements at given position.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element` when break position\n\t * is placed inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element` when break position\n\t * is placed inside {@link module:engine/view/uielement~UIElement UIElement}.\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} position Position where to break attributes.\n\t * @param {Boolean} [forceSplitText=false] If set to `true`, will break text nodes even if they are directly in container element.\n\t * This behavior will result in incorrect view state, but is needed by other view writing methods which then fixes view state.\n\t * @returns {module:engine/view/position~Position} New position after breaking the attributes.\n\t */\n\t_breakAttributes( position, forceSplitText = false ) {\n\t\tconst positionOffset = position.offset;\n\t\tconst positionParent = position.parent;\n\n\t\t// If position is placed inside EmptyElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'emptyElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break an `EmptyElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-empty-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-empty-element', this.document );\n\t\t}\n\n\t\t// If position is placed inside UIElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'uiElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break a `UIElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-ui-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-ui-element', this.document );\n\t\t}\n\n\t\t// If position is placed inside RawElement - throw an exception as we cannot break inside.\n\t\tif ( position.parent.is( 'rawElement' ) ) {\n\t\t\t/**\n\t\t\t * Cannot break a `RawElement` instance.\n\t\t\t *\n\t\t\t * This error is thrown if\n\t\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes `DowncastWriter#breakAttributes()`}\n\t\t\t * was executed in an incorrect position.\n\t\t\t *\n\t\t\t * @error view-writer-cannot-break-raw-element\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-cannot-break-raw-element', this.document );\n\t\t}\n\n\t\t// There are no attributes to break and text nodes breaking is not forced.\n\t\tif ( !forceSplitText && positionParent.is( '$text' ) && isContainerOrFragment( positionParent.parent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Position's parent is container, so no attributes to break.\n\t\tif ( isContainerOrFragment( positionParent ) ) {\n\t\t\treturn position.clone();\n\t\t}\n\n\t\t// Break text and start again in new position.\n\t\tif ( positionParent.is( '$text' ) ) {\n\t\t\treturn this._breakAttributes( breakTextNode( position ), forceSplitText );\n\t\t}\n\n\t\tconst length = positionParent.childCount;\n\n\t\t// <p>foo<b><u>bar{}</u></b></p>\n\t\t// <p>foo<b><u>bar</u>[]</b></p>\n\t\t// <p>foo<b><u>bar</u></b>[]</p>\n\t\tif ( positionOffset == length ) {\n\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index + 1 );\n\n\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t} else {\n\t\t\t// <p>foo<b><u>{}bar</u></b></p>\n\t\t\t// <p>foo<b>[]<u>bar</u></b></p>\n\t\t\t// <p>foo{}<b><u>bar</u></b></p>\n\t\t\tif ( positionOffset === 0 ) {\n\t\t\t\tconst newPosition = new Position( positionParent.parent, positionParent.index );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t\t// <p>foo<b><u>b{}ar</u></b></p>\n\t\t\t// <p>foo<b><u>b[]ar</u></b></p>\n\t\t\t// <p>foo<b><u>b</u>[]<u>ar</u></b></p>\n\t\t\t// <p>foo<b><u>b</u></b>[]<b><u>ar</u></b></p>\n\t\t\telse {\n\t\t\t\tconst offsetAfter = positionParent.index + 1;\n\n\t\t\t\t// Break element.\n\t\t\t\tconst clonedNode = positionParent._clone();\n\n\t\t\t\t// Insert cloned node to position's parent node.\n\t\t\t\tpositionParent.parent._insertChild( offsetAfter, clonedNode );\n\t\t\t\tthis._addToClonedElementsGroup( clonedNode );\n\n\t\t\t\t// Get nodes to move.\n\t\t\t\tconst count = positionParent.childCount - positionOffset;\n\t\t\t\tconst nodesToMove = positionParent._removeChildren( positionOffset, count );\n\n\t\t\t\t// Move nodes to cloned node.\n\t\t\t\tclonedNode._appendChild( nodesToMove );\n\n\t\t\t\t// Create new position to work on.\n\t\t\t\tconst newPosition = new Position( positionParent.parent, offsetAfter );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Stores the information that an {@link module:engine/view/attributeelement~AttributeElement attribute element} was\n\t * added to the tree. Saves the reference to the group in the given element and updates the group, so other elements\n\t * from the group now keep a reference to the given attribute element.\n\t *\n\t * The clones group can be obtained using {@link module:engine/view/attributeelement~AttributeElement#getElementsWithSameId}.\n\t *\n\t * Does nothing if added element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to save.\n\t */\n\t_addToClonedElementsGroup( element ) {\n\t\t// Add only if the element is in document tree.\n\t\tif ( !element.root.is( 'rootElement' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Traverse the element's children recursively to find other attribute elements that also might got inserted.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._addToClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\tgroup = new Set();\n\t\t\tthis._cloneGroups.set( id, group );\n\t\t}\n\n\t\tgroup.add( element );\n\t\telement._clonesGroup = group;\n\t}\n\n\t/**\n\t * Removes all the information about the given {@link module:engine/view/attributeelement~AttributeElement attribute element}\n\t * from its clones group.\n\t *\n\t * Keep in mind, that the element will still keep a reference to the group (but the group will not keep a reference to it).\n\t * This allows to reference the whole group even if the element was already removed from the tree.\n\t *\n\t * Does nothing if the element has no {@link module:engine/view/attributeelement~AttributeElement#id id}.\n\t *\n\t * @private\n\t * @param {module:engine/view/attributeelement~AttributeElement} element Attribute element to remove.\n\t */\n\t_removeFromClonedElementsGroup( element ) {\n\t\t// Traverse the element's children recursively to find other attribute elements that also got removed.\n\t\t// The loop is at the beginning so we can make fast returns later in the code.\n\t\tif ( element.is( 'element' ) ) {\n\t\t\tfor ( const child of element.getChildren() ) {\n\t\t\t\tthis._removeFromClonedElementsGroup( child );\n\t\t\t}\n\t\t}\n\n\t\tconst id = element.id;\n\n\t\tif ( !id ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst group = this._cloneGroups.get( id );\n\n\t\tif ( !group ) {\n\t\t\treturn;\n\t\t}\n\n\t\tgroup.delete( element );\n\t\t// Not removing group from element on purpose!\n\t\t// If other parts of code have reference to this element, they will be able to get references to other elements from the group.\n\t}\n}\n\n// Helper function for `view.writer.wrap`. Checks if given element has any children that are not ui elements.\nfunction _hasNonUiChildren( parent ) {\n\treturn Array.from( parent.getChildren() ).some( child => !child.is( 'uiElement' ) );\n}\n\n/**\n * The `attribute` passed to {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`}\n * must be an instance of {@link module:engine/view/attributeelement~AttributeElement `AttributeElement`}.\n *\n * @error view-writer-wrap-invalid-attribute\n */\n\n// Returns first parent container of specified {@link module:engine/view/position~Position Position}.\n// Position's parent node is checked as first, then next parents are checked.\n// Note that {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.\n//\n// @param {module:engine/view/position~Position} position Position used as a start point to locate parent container.\n// @returns {module:engine/view/containerelement~ContainerElement|module:engine/view/documentfragment~DocumentFragment|undefined}\n// Parent container element or `undefined` if container is not found.\nfunction getParentContainer( position ) {\n\tlet parent = position.parent;\n\n\twhile ( !isContainerOrFragment( parent ) ) {\n\t\tif ( !parent ) {\n\t\t\treturn undefined;\n\t\t}\n\t\tparent = parent.parent;\n\t}\n\n\treturn parent;\n}\n\n// Checks if first {@link module:engine/view/attributeelement~AttributeElement AttributeElement} provided to the function\n// can be wrapped outside second element. It is done by comparing elements'\n// {@link module:engine/view/attributeelement~AttributeElement#priority priorities}, if both have same priority\n// {@link module:engine/view/element~Element#getIdentity identities} are compared.\n//\n// @param {module:engine/view/attributeelement~AttributeElement} a\n// @param {module:engine/view/attributeelement~AttributeElement} b\n// @returns {Boolean}\nfunction shouldABeOutsideB( a, b ) {\n\tif ( a.priority < b.priority ) {\n\t\treturn true;\n\t} else if ( a.priority > b.priority ) {\n\t\treturn false;\n\t}\n\n\t// When priorities are equal and names are different - use identities.\n\treturn a.getIdentity() < b.getIdentity();\n}\n\n// Returns new position that is moved to near text node. Returns same position if there is no text node before of after\n// specified position.\n//\n//\t\t<p>foo[]</p> -> <p>foo{}</p>\n//\t\t<p>[]foo</p> -> <p>{}foo</p>\n//\n// @param {module:engine/view/position~Position} position\n// @returns {module:engine/view/position~Position} Position located inside text node or same position if there is no text nodes\n// before or after position location.\nfunction movePositionToTextNode( position ) {\n\tconst nodeBefore = position.nodeBefore;\n\n\tif ( nodeBefore && nodeBefore.is( '$text' ) ) {\n\t\treturn new Position( nodeBefore, nodeBefore.data.length );\n\t}\n\n\tconst nodeAfter = position.nodeAfter;\n\n\tif ( nodeAfter && nodeAfter.is( '$text' ) ) {\n\t\treturn new Position( nodeAfter, 0 );\n\t}\n\n\treturn position;\n}\n\n// Breaks text node into two text nodes when possible.\n//\n//\t\t<p>foo{}bar</p> -> <p>foo[]bar</p>\n//\t\t<p>{}foobar</p> -> <p>[]foobar</p>\n//\t\t<p>foobar{}</p> -> <p>foobar[]</p>\n//\n// @param {module:engine/view/position~Position} position Position that need to be placed inside text node.\n// @returns {module:engine/view/position~Position} New position after breaking text node.\nfunction breakTextNode( position ) {\n\tif ( position.offset == position.parent.data.length ) {\n\t\treturn new Position( position.parent.parent, position.parent.index + 1 );\n\t}\n\n\tif ( position.offset === 0 ) {\n\t\treturn new Position( position.parent.parent, position.parent.index );\n\t}\n\n\t// Get part of the text that need to be moved.\n\tconst textToMove = position.parent.data.slice( position.offset );\n\n\t// Leave rest of the text in position's parent.\n\tposition.parent._data = position.parent.data.slice( 0, position.offset );\n\n\t// Insert new text node after position's parent text node.\n\tposition.parent.parent._insertChild( position.parent.index + 1, new Text( position.root.document, textToMove ) );\n\n\t// Return new position between two newly created text nodes.\n\treturn new Position( position.parent.parent, position.parent.index + 1 );\n}\n\n// Merges two text nodes into first node. Removes second node and returns merge position.\n//\n// @param {module:engine/view/text~Text} t1 First text node to merge. Data from second text node will be moved at the end of\n// this text node.\n// @param {module:engine/view/text~Text} t2 Second text node to merge. This node will be removed after merging.\n// @returns {module:engine/view/position~Position} Position after merging text nodes.\nfunction mergeTextNodes( t1, t2 ) {\n\t// Merge text data into first text node and remove second one.\n\tconst nodeBeforeLength = t1.data.length;\n\tt1._data += t2.data;\n\tt2._remove();\n\n\treturn new Position( t1, nodeBeforeLength );\n}\n\n// Checks if provided nodes are valid to insert.\n//\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert\n// contains instances that are not supported ones (see error description for valid ones.\n//\n// @param Iterable.<module:engine/view/text~Text|module:engine/view/element~Element> nodes\n// @param {Object} errorContext\nfunction validateNodesToInsert( nodes, errorContext ) {\n\tfor ( const node of nodes ) {\n\t\tif ( !validNodesToInsert.some( ( validNode => node instanceof validNode ) ) ) { // eslint-disable-line no-use-before-define\n\t\t\t/**\n\t\t\t * One of the nodes to be inserted is of an invalid type.\n\t\t\t *\n\t\t\t * Nodes to be inserted with {@link module:engine/view/downcastwriter~DowncastWriter#insert `DowncastWriter#insert()`} should be\n\t\t\t * of the following types:\n\t\t\t *\n\t\t\t * * {@link module:engine/view/attributeelement~AttributeElement AttributeElement},\n\t\t\t * * {@link module:engine/view/containerelement~ContainerElement ContainerElement},\n\t\t\t * * {@link module:engine/view/emptyelement~EmptyElement EmptyElement},\n\t\t\t * * {@link module:engine/view/uielement~UIElement UIElement},\n\t\t\t * * {@link module:engine/view/rawelement~RawElement RawElement},\n\t\t\t * * {@link module:engine/view/text~Text Text}.\n\t\t\t *\n\t\t\t * @error view-writer-insert-invalid-node-type\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-writer-insert-invalid-node-type', errorContext );\n\t\t}\n\n\t\tif ( !node.is( '$text' ) ) {\n\t\t\tvalidateNodesToInsert( node.getChildren(), errorContext );\n\t\t}\n\t}\n}\n\nconst validNodesToInsert = [ Text, AttributeElement, ContainerElement, EmptyElement, RawElement, UIElement ];\n\n// Checks if node is ContainerElement or DocumentFragment, because in most cases they should be treated the same way.\n//\n// @param {module:engine/view/node~Node} node\n// @returns {Boolean} Returns `true` if node is instance of ContainerElement or DocumentFragment.\nfunction isContainerOrFragment( node ) {\n\treturn node && ( node.is( 'containerElement' ) || node.is( 'documentFragment' ) );\n}\n\n// Checks if {@link module:engine/view/range~Range#start range start} and {@link module:engine/view/range~Range#end range end} are placed\n// inside same {@link module:engine/view/containerelement~ContainerElement container element}.\n// Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container` when validation fails.\n//\n// @param {module:engine/view/range~Range} range\n// @param {Object} errorContext\nfunction validateRangeContainer( range, errorContext ) {\n\tconst startContainer = getParentContainer( range.start );\n\tconst endContainer = getParentContainer( range.end );\n\n\tif ( !startContainer || !endContainer || startContainer !== endContainer ) {\n\t\t/**\n\t\t * The container of the given range is invalid.\n\t\t *\n\t\t * This may happen if {@link module:engine/view/range~Range#start range start} and\n\t\t * {@link module:engine/view/range~Range#end range end} positions are not placed inside the same container element or\n\t\t * a parent container for these positions cannot be found.\n\t\t *\n\t\t * Methods like {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#remove()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#clean()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`},\n\t\t * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#unwrap()`} need to be called\n\t\t * on a range that has its start and end positions located in the same container element. Both positions can be\n\t\t * nested within other elements (e.g. an attribute element) but the closest container ancestor must be the same.\n\t\t *\n\t\t * @error view-writer-invalid-range-container\n\t\t */\n\t\tthrow new CKEditorError( 'view-writer-invalid-range-container', errorContext );\n\t}\n}\n\n// Checks if two attribute elements can be joined together. Elements can be joined together if, and only if\n// they do not have ids specified.\n//\n// @private\n// @param {module:engine/view/element~Element} a\n// @param {module:engine/view/element~Element} b\n// @returns {Boolean}\nfunction canBeJoined( a, b ) {\n\treturn a.id === null && b.id === null;\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 utils/dom/istext\n */\n\n/**\n * Checks if the object is a native DOM Text node.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isText( obj ) {\n\treturn Object.prototype.toString.call( obj ) == '[object Text]';\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\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\n\n/**\n * Set of utils related to block and inline fillers handling.\n *\n * Browsers do not allow to put caret in elements which does not have height. Because of it, we need to fill all\n * empty elements which should be selectable with elements or characters called \"fillers\". Unfortunately there is no one\n * universal filler, this is why two types are uses:\n *\n * * Block filler is an element which fill block elements, like `<p>`. CKEditor uses `<br>` as a block filler during the editing,\n * as browsers do natively. So instead of an empty `<p>` there will be `<p><br></p>`. The advantage of block filler is that\n * it is transparent for the selection, so when the caret is before the `<br>` and user presses right arrow he will be\n * moved to the next paragraph, not after the `<br>`. The disadvantage is that it breaks a block, so it can not be used\n * in the middle of a line of text. The {@link module:engine/view/filler~BR_FILLER `<br>` filler} can be replaced with any other\n * character in the data output, for instance {@link module:engine/view/filler~NBSP_FILLER non-breaking space} or\n * {@link module:engine/view/filler~MARKED_NBSP_FILLER marked non-breaking space}.\n *\n * * Inline filler is a filler which does not break a line of text, so it can be used inside the text, for instance in the empty\n * `<b>` surrendered by text: `foo<b></b>bar`, if we want to put the caret there. CKEditor uses a sequence of the zero-width\n * spaces as an {@link module:engine/view/filler~INLINE_FILLER inline filler} having the predetermined\n * {@link module:engine/view/filler~INLINE_FILLER_LENGTH length}. A sequence is used, instead of a single character to\n * avoid treating random zero-width spaces as the inline filler. Disadvantage of the inline filler is that it is not\n * transparent for the selection. The arrow key moves the caret between zero-width spaces characters, so the additional\n * code is needed to handle the caret.\n *\n * Both inline and block fillers are handled by the {@link module:engine/view/renderer~Renderer renderer} and are not present in the\n * view.\n *\n * @module engine/view/filler\n */\n\n/**\n * Non-breaking space filler creator. This is a function which creates `&nbsp;` text node.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~MARKED_NBSP_FILLER\n * @see module:engine/view/filler~BR_FILLER\n * @function\n */\nexport const NBSP_FILLER = domDocument => domDocument.createTextNode( '\\u00A0' );\n\n/**\n * Marked non-breaking space filler creator. This is a function which creates `<span data-cke-filler=\"true\">&nbsp;</span>` element.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~NBSP_FILLER\n * @see module:engine/view/filler~BR_FILLER\n * @function\n */\nexport const MARKED_NBSP_FILLER = domDocument => {\n\tconst span = domDocument.createElement( 'span' );\n\tspan.dataset.ckeFiller = true;\n\tspan.innerHTML = '\\u00A0';\n\n\treturn span;\n};\n\n/**\n * `<br>` filler creator. This is a function which creates `<br data-cke-filler=\"true\">` element.\n * It defines how the filler is created.\n *\n * @see module:engine/view/filler~NBSP_FILLER\n * @see module:engine/view/filler~MARKED_NBSP_FILLER\n * @function\n */\nexport const BR_FILLER = domDocument => {\n\tconst fillerBr = domDocument.createElement( 'br' );\n\tfillerBr.dataset.ckeFiller = true;\n\n\treturn fillerBr;\n};\n\n/**\n * Length of the {@link module:engine/view/filler~INLINE_FILLER INLINE_FILLER}.\n */\nexport const INLINE_FILLER_LENGTH = 7;\n\n/**\n * Inline filler which is a sequence of the word joiners.\n *\n * @type {String}\n */\nexport const INLINE_FILLER = '\\u2060'.repeat( INLINE_FILLER_LENGTH );\n\n/**\n * Checks if the node is a text node which starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // true\n *\t\tstartsWithFiller( document.createTextNode( 'foo' ) ); // false\n *\t\tstartsWithFiller( document.createElement( 'p' ) ); // false\n *\n * @param {Node} domNode DOM node.\n * @returns {Boolean} True if the text node starts with the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function startsWithFiller( domNode ) {\n\treturn isText( domNode ) && ( domNode.data.substr( 0, INLINE_FILLER_LENGTH ) === INLINE_FILLER );\n}\n\n/**\n * Checks if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n *\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER ) ); // true\n *\t\tisInlineFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ); // false\n *\n * @param {Text} domText DOM text node.\n * @returns {Boolean} True if the text node contains only the {@link module:engine/view/filler~INLINE_FILLER inline filler}.\n */\nexport function isInlineFiller( domText ) {\n\treturn domText.data.length == INLINE_FILLER_LENGTH && startsWithFiller( domText );\n}\n\n/**\n * Get string data from the text node, removing an {@link module:engine/view/filler~INLINE_FILLER inline filler} from it,\n * if text node contains it.\n *\n *\t\tgetDataWithoutFiller( document.createTextNode( INLINE_FILLER + 'foo' ) ) == 'foo' // true\n *\t\tgetDataWithoutFiller( document.createTextNode( 'foo' ) ) == 'foo' // true\n *\n * @param {Text} domText DOM text node, possible with inline filler.\n * @returns {String} Data without filler.\n */\nexport function getDataWithoutFiller( domText ) {\n\tif ( startsWithFiller( domText ) ) {\n\t\treturn domText.data.slice( INLINE_FILLER_LENGTH );\n\t} else {\n\t\treturn domText.data;\n\t}\n}\n\n/**\n * Assign key observer which move cursor from the end of the inline filler to the beginning of it when\n * the left arrow is pressed, so the filler does not break navigation.\n *\n * @param {module:engine/view/view~View} view View controller instance we should inject quirks handling on.\n */\nexport function injectQuirksHandling( view ) {\n\tview.document.on( 'arrowKey', jumpOverInlineFiller, { priority: 'low' } );\n}\n\n// Move cursor from the end of the inline filler to the beginning of it when, so the filler does not break navigation.\nfunction jumpOverInlineFiller( evt, data ) {\n\tif ( data.keyCode == keyCodes.arrowleft ) {\n\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\tif ( domSelection.rangeCount == 1 && domSelection.getRangeAt( 0 ).collapsed ) {\n\t\t\tconst domParent = domSelection.getRangeAt( 0 ).startContainer;\n\t\t\tconst domOffset = domSelection.getRangeAt( 0 ).startOffset;\n\n\t\t\tif ( startsWithFiller( domParent ) && domOffset <= INLINE_FILLER_LENGTH ) {\n\t\t\t\tdomSelection.collapse( domParent, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/fastdiff\n */\n\n/**\n * Finds positions of the first and last change in the given string/array and generates a set of changes:\n *\n *\t\tfastDiff( '12a', '12xyza' );\n *\t\t// [ { index: 2, type: 'insert', values: [ 'x', 'y', 'z' ] } ]\n *\n *\t\tfastDiff( '12a', '12aa' );\n *\t\t// [ { index: 3, type: 'insert', values: [ 'a' ] } ]\n *\n *\t\tfastDiff( '12xyza', '12a' );\n *\t\t// [ { index: 2, type: 'delete', howMany: 3 } ]\n *\n *\t\tfastDiff( [ '1', '2', 'a', 'a' ], [ '1', '2', 'a' ] );\n *\t\t// [ { index: 3, type: 'delete', howMany: 1 } ]\n *\n *\t\tfastDiff( [ '1', '2', 'a', 'b', 'c', '3' ], [ '2', 'a', 'b' ] );\n *\t\t// [ { index: 0, type: 'insert', values: [ '2', 'a', 'b' ] }, { index: 3, type: 'delete', howMany: 6 } ]\n *\n * Passed arrays can contain any type of data, however to compare them correctly custom comparator function\n * should be passed as a third parameter:\n *\n *\t\tfastDiff( [ { value: 1 }, { value: 2 } ], [ { value: 1 }, { value: 3 } ], ( a, b ) => {\n *\t\t\treturn a.value === b.value;\n *\t\t} );\n *\t\t// [ { index: 1, type: 'insert', values: [ { value: 3 } ] }, { index: 2, type: 'delete', howMany: 1 } ]\n *\n * The resulted set of changes can be applied to the input in order to transform it into the output, for example:\n *\n *\t\tlet input = '12abc3';\n *\t\tconst output = '2ab';\n *\t\tconst changes = fastDiff( input, output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput = input.substring( 0, change.index ) + change.values.join( '' ) + input.substring( change.index );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput = input.substring( 0, change.index ) + input.substring( change.index + change.howMany );\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// input equals output now\n *\n * or in case of arrays:\n *\n *\t\tlet input = [ '1', '2', 'a', 'b', 'c', '3' ];\n *\t\tconst output = [ '2', 'a', 'b' ];\n *\t\tconst changes = fastDiff( input, output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput = input.slice( 0, change.index ).concat( change.values, input.slice( change.index ) );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput = input.slice( 0, change.index ).concat( input.slice( change.index + change.howMany ) );\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// input equals output now\n *\n * By passing `true` as the fourth parameter (`atomicChanges`) the output of this function will become compatible with\n * the {@link module:utils/diff~diff `diff()`} function:\n *\n *\t\tfastDiff( '12a', '12xyza' );\n *\t\t// [ 'equal', 'equal', 'insert', 'insert', 'insert', 'equal' ]\n *\n * The default output format of this function is compatible with the output format of\n * {@link module:utils/difftochanges~diffToChanges `diffToChanges()`}. The `diffToChanges()` input format is, in turn,\n * compatible with the output of {@link module:utils/diff~diff `diff()`}:\n *\n *\t\tconst a = '1234';\n *\t\tconst b = '12xyz34';\n *\n *\t\t// Both calls will return the same results (grouped changes format).\n *\t\tfastDiff( a, b );\n *\t\tdiffToChanges( diff( a, b ) );\n *\n *\t\t// Again, both calls will return the same results (atomic changes format).\n *\t\tfastDiff( a, b, null, true );\n *\t\tdiff( a, b );\n *\n *\n * @param {Array|String} a Input array or string.\n * @param {Array|String} b Input array or string.\n * @param {Function} [cmp] Optional function used to compare array values, by default `===` (strict equal operator) is used.\n * @param {Boolean} [atomicChanges=false] Whether an array of `inset|delete|equal` operations should\n * be returned instead of changes set. This makes this function compatible with {@link module:utils/diff~diff `diff()`}.\n * @returns {Array} Array of changes.\n */\nexport default function fastDiff( a, b, cmp, atomicChanges = false ) {\n\t// Set the comparator function.\n\tcmp = cmp || function( a, b ) {\n\t\treturn a === b;\n\t};\n\n\t// Convert the string (or any array-like object - eg. NodeList) to an array by using the slice() method because,\n\t// unlike Array.from(), it returns array of UTF-16 code units instead of the code points of a string.\n\t// One code point might be a surrogate pair of two code units. All text offsets are expected to be in code units.\n\t// See ckeditor/ckeditor5#3147.\n\t//\n\t// We need to make sure here that fastDiff() works identical to diff().\n\tif ( !Array.isArray( a ) ) {\n\t\ta = Array.prototype.slice.call( a );\n\t}\n\n\tif ( !Array.isArray( b ) ) {\n\t\tb = Array.prototype.slice.call( b );\n\t}\n\n\t// Find first and last change.\n\tconst changeIndexes = findChangeBoundaryIndexes( a, b, cmp );\n\n\t// Transform into changes array.\n\treturn atomicChanges ? changeIndexesToAtomicChanges( changeIndexes, b.length ) : changeIndexesToChanges( b, changeIndexes );\n}\n\n// Finds position of the first and last change in the given arrays. For example:\n//\n//\t\tconst indexes = findChangeBoundaryIndexes( [ '1', '2', '3', '4' ], [ '1', '3', '4', '2', '4' ] );\n//\t\tconsole.log( indexes ); // { firstIndex: 1, lastIndexOld: 3, lastIndexNew: 4 }\n//\n// The above indexes means that in the first array the modified part is `1[23]4` and in the second array it is `1[342]4`.\n// Based on such indexes, array with `insert`/`delete` operations which allows transforming first value into the second one\n// can be generated.\n//\n// @param {Array} arr1\n// @param {Array} arr2\n// @param {Function} cmp Comparator function.\n// @returns {Object}\n// @returns {Number} return.firstIndex Index of the first change in both values (always the same for both).\n// @returns {Number} result.lastIndexOld Index of the last common value in `arr1`.\n// @returns {Number} result.lastIndexNew Index of the last common value in `arr2`.\nfunction findChangeBoundaryIndexes( arr1, arr2, cmp ) {\n\t// Find the first difference between passed values.\n\tconst firstIndex = findFirstDifferenceIndex( arr1, arr2, cmp );\n\n\t// If arrays are equal return -1 indexes object.\n\tif ( firstIndex === -1 ) {\n\t\treturn { firstIndex: -1, lastIndexOld: -1, lastIndexNew: -1 };\n\t}\n\n\t// Remove the common part of each value and reverse them to make it simpler to find the last difference between them.\n\tconst oldArrayReversed = cutAndReverse( arr1, firstIndex );\n\tconst newArrayReversed = cutAndReverse( arr2, firstIndex );\n\n\t// Find the first difference between reversed values.\n\t// It should be treated as \"how many elements from the end the last difference occurred\".\n\t//\n\t// For example:\n\t//\n\t// \t\t\t\tinitial\t->\tafter cut\t-> reversed:\n\t// oldValue:\t'321ba'\t->\t'21ba'\t\t-> 'ab12'\n\t// newValue:\t'31xba'\t->\t'1xba'\t\t-> 'abx1'\n\t// lastIndex:\t\t\t\t\t\t\t-> 2\n\t//\n\t// So the last change occurred two characters from the end of the arrays.\n\tconst lastIndex = findFirstDifferenceIndex( oldArrayReversed, newArrayReversed, cmp );\n\n\t// Use `lastIndex` to calculate proper offset, starting from the beginning (`lastIndex` kind of starts from the end).\n\tconst lastIndexOld = arr1.length - lastIndex;\n\tconst lastIndexNew = arr2.length - lastIndex;\n\n\treturn { firstIndex, lastIndexOld, lastIndexNew };\n}\n\n// Returns a first index on which given arrays differ. If both arrays are the same, -1 is returned.\n//\n// @param {Array} arr1\n// @param {Array} arr2\n// @param {Function} cmp Comparator function.\n// @returns {Number}\nfunction findFirstDifferenceIndex( arr1, arr2, cmp ) {\n\tfor ( let i = 0; i < Math.max( arr1.length, arr2.length ); i++ ) {\n\t\tif ( arr1[ i ] === undefined || arr2[ i ] === undefined || !cmp( arr1[ i ], arr2[ i ] ) ) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1; // Return -1 if arrays are equal.\n}\n\n// Returns a copy of the given array with `howMany` elements removed starting from the beginning and in reversed order.\n//\n// @param {Array} arr Array to be processed.\n// @param {Number} howMany How many elements from array beginning to remove.\n// @returns {Array} Shortened and reversed array.\nfunction cutAndReverse( arr, howMany ) {\n\treturn arr.slice( howMany ).reverse();\n}\n\n// Generates changes array based on change indexes from `findChangeBoundaryIndexes` function. This function will\n// generate array with 0 (no changes), 1 (deletion or insertion) or 2 records (insertion and deletion).\n//\n// @param {Array} newArray New array for which change indexes were calculated.\n// @param {Object} changeIndexes Change indexes object from `findChangeBoundaryIndexes` function.\n// @returns {Array.<Object>} Array of changes compatible with {@link module:utils/difftochanges~diffToChanges} format.\nfunction changeIndexesToChanges( newArray, changeIndexes ) {\n\tconst result = [];\n\tconst { firstIndex, lastIndexOld, lastIndexNew } = changeIndexes;\n\n\t// Order operations as 'insert', 'delete' array to keep compatibility with {@link module:utils/difftochanges~diffToChanges}\n\t// in most cases. However, 'diffToChanges' does not stick to any order so in some cases\n\t// (for example replacing '12345' with 'abcd') it will generate 'delete', 'insert' order.\n\tif ( lastIndexNew - firstIndex > 0 ) {\n\t\tresult.push( {\n\t\t\tindex: firstIndex,\n\t\t\ttype: 'insert',\n\t\t\tvalues: newArray.slice( firstIndex, lastIndexNew )\n\t\t} );\n\t}\n\n\tif ( lastIndexOld - firstIndex > 0 ) {\n\t\tresult.push( {\n\t\t\tindex: firstIndex + ( lastIndexNew - firstIndex ), // Increase index of what was inserted.\n\t\t\ttype: 'delete',\n\t\t\thowMany: lastIndexOld - firstIndex\n\t\t} );\n\t}\n\n\treturn result;\n}\n\n// Generates array with set `equal|insert|delete` operations based on change indexes from `findChangeBoundaryIndexes` function.\n//\n// @param {Object} changeIndexes Change indexes object from `findChangeBoundaryIndexes` function.\n// @param {Number} newLength Length of the new array on which `findChangeBoundaryIndexes` calculated change indexes.\n// @returns {Array.<String>} Array of changes compatible with {@link module:utils/diff~diff} format.\nfunction changeIndexesToAtomicChanges( changeIndexes, newLength ) {\n\tconst { firstIndex, lastIndexOld, lastIndexNew } = changeIndexes;\n\n\t// No changes.\n\tif ( firstIndex === -1 ) {\n\t\treturn Array( newLength ).fill( 'equal' );\n\t}\n\n\tlet result = [];\n\tif ( firstIndex > 0 ) {\n\t\tresult = result.concat( Array( firstIndex ).fill( 'equal' ) );\n\t}\n\n\tif ( lastIndexNew - firstIndex > 0 ) {\n\t\tresult = result.concat( Array( lastIndexNew - firstIndex ).fill( 'insert' ) );\n\t}\n\n\tif ( lastIndexOld - firstIndex > 0 ) {\n\t\tresult = result.concat( Array( lastIndexOld - firstIndex ).fill( 'delete' ) );\n\t}\n\n\tif ( lastIndexNew < newLength ) {\n\t\tresult = result.concat( Array( newLength - lastIndexNew ).fill( 'equal' ) );\n\t}\n\n\treturn result;\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 utils/diff\n */\n\nimport fastDiff from '../src/fastdiff';\n\n// The following code is based on the \"O(NP) Sequence Comparison Algorithm\"\n// by Sun Wu, Udi Manber, Gene Myers, Webb Miller.\n\n/**\n * Calculates the difference between two arrays or strings producing an array containing a list of changes\n * necessary to transform input into output.\n *\n *\t\tdiff( 'aba', 'acca' ); // [ 'equal', 'insert', 'insert', 'delete', 'equal' ]\n *\n * This function is based on the \"O(NP) Sequence Comparison Algorithm\" by Sun Wu, Udi Manber, Gene Myers, Webb Miller.\n * Unfortunately, while it gives the most precise results, its to complex for longer strings/arrow (above 200 items).\n * Therefore, `diff()` automatically switches to {@link module:utils/fastdiff~fastDiff `fastDiff()`} when detecting\n * such a scenario. The return formats of both functions are identical.\n *\n * @param {Array|String} a Input array or string.\n * @param {Array|String} b Output array or string.\n * @param {Function} [cmp] Optional function used to compare array values, by default === is used.\n * @returns {Array} Array of changes.\n */\nexport default function diff( a, b, cmp ) {\n\t// Set the comparator function.\n\tcmp = cmp || function( a, b ) {\n\t\treturn a === b;\n\t};\n\n\tconst aLength = a.length;\n\tconst bLength = b.length;\n\n\t// Perform `fastDiff` for longer strings/arrays (see #269).\n\tif ( aLength > 200 || bLength > 200 || aLength + bLength > 300 ) {\n\t\treturn diff.fastDiff( a, b, cmp, true );\n\t}\n\n\t// Temporary action type statics.\n\tlet _insert, _delete;\n\n\t// Swapped the arrays to use the shorter one as the first one.\n\tif ( bLength < aLength ) {\n\t\tconst tmp = a;\n\n\t\ta = b;\n\t\tb = tmp;\n\n\t\t// We swap the action types as well.\n\t\t_insert = 'delete';\n\t\t_delete = 'insert';\n\t} else {\n\t\t_insert = 'insert';\n\t\t_delete = 'delete';\n\t}\n\n\tconst m = a.length;\n\tconst n = b.length;\n\tconst delta = n - m;\n\n\t// Edit scripts, for each diagonal.\n\tconst es = {};\n\t// Furthest points, the furthest y we can get on each diagonal.\n\tconst fp = {};\n\n\tfunction snake( k ) {\n\t\t// We use -1 as an alternative below to handle initial values ( instead of filling the fp with -1 first ).\n\t\t// Furthest points (y) on the diagonal below k.\n\t\tconst y1 = ( fp[ k - 1 ] !== undefined ? fp[ k - 1 ] : -1 ) + 1;\n\t\t// Furthest points (y) on the diagonal above k.\n\t\tconst y2 = fp[ k + 1 ] !== undefined ? fp[ k + 1 ] : -1;\n\t\t// The way we should go to get further.\n\t\tconst dir = y1 > y2 ? -1 : 1;\n\n\t\t// Clone previous changes array (if any).\n\t\tif ( es[ k + dir ] ) {\n\t\t\tes[ k ] = es[ k + dir ].slice( 0 );\n\t\t}\n\n\t\t// Create changes array.\n\t\tif ( !es[ k ] ) {\n\t\t\tes[ k ] = [];\n\t\t}\n\n\t\t// Push the action.\n\t\tes[ k ].push( y1 > y2 ? _insert : _delete );\n\n\t\t// Set the beginning coordinates.\n\t\tlet y = Math.max( y1, y2 );\n\t\tlet x = y - k;\n\n\t\t// Traverse the diagonal as long as the values match.\n\t\twhile ( x < m && y < n && cmp( a[ x ], b[ y ] ) ) {\n\t\t\tx++;\n\t\t\ty++;\n\t\t\t// Push no change action.\n\t\t\tes[ k ].push( 'equal' );\n\t\t}\n\n\t\treturn y;\n\t}\n\n\tlet p = 0;\n\tlet k;\n\n\t// Traverse the graph until we reach the end of the longer string.\n\tdo {\n\t\t// Updates furthest points and edit scripts for diagonals below delta.\n\t\tfor ( k = -p; k < delta; k++ ) {\n\t\t\tfp[ k ] = snake( k );\n\t\t}\n\n\t\t// Updates furthest points and edit scripts for diagonals above delta.\n\t\tfor ( k = delta + p; k > delta; k-- ) {\n\t\t\tfp[ k ] = snake( k );\n\t\t}\n\n\t\t// Updates furthest point and edit script for the delta diagonal.\n\t\t// note that the delta diagonal is the one which goes through the sink (m, n).\n\t\tfp[ delta ] = snake( delta );\n\n\t\tp++;\n\t} while ( fp[ delta ] !== n );\n\n\t// Return the final list of edit changes.\n\t// We remove the first item that represents the action for the injected nulls.\n\treturn es[ delta ].slice( 1 );\n}\n\n// Store the API in static property to easily overwrite it in tests.\n// Too bad dependency injection does not work in Webpack + ES 6 (const) + Babel.\ndiff.fastDiff = fastDiff;\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 utils/dom/insertat\n */\n\n/**\n * Inserts node to the parent at given index.\n *\n * @param {Element} parentElement Parent element.\n * @param {Number} index Insertions index.\n * @param {Node} nodeToInsert Node to insert.\n */\nexport default function insertAt( parentElement, index, nodeToInsert ) {\n\tparentElement.insertBefore( nodeToInsert, parentElement.childNodes[ index ] || null );\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 utils/dom/remove\n */\n\n/**\n * Removes given node from parent.\n *\n * @param {Node} node Node to remove.\n */\nexport default function remove( node ) {\n\tconst parent = node.parentNode;\n\n\tif ( parent ) {\n\t\tparent.removeChild( node );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/isnode\n */\n\n/**\n * Checks if the object is a native DOM Node.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isNode( obj ) {\n\tif ( obj ) {\n\t\tif ( obj.defaultView ) {\n\t\t\treturn obj instanceof obj.defaultView.Document;\n\t\t} else if ( obj.ownerDocument && obj.ownerDocument.defaultView ) {\n\t\t\treturn obj instanceof obj.ownerDocument.defaultView.Node;\n\t\t}\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals Node */\n\n/**\n * @module engine/view/renderer\n */\n\nimport ViewText from './text';\nimport ViewPosition from './position';\nimport { INLINE_FILLER, INLINE_FILLER_LENGTH, startsWithFiller, isInlineFiller } from './filler';\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport insertAt from '@ckeditor/ckeditor5-utils/src/dom/insertat';\nimport remove from '@ckeditor/ckeditor5-utils/src/dom/remove';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\nimport isNode from '@ckeditor/ckeditor5-utils/src/dom/isnode';\nimport fastDiff from '@ckeditor/ckeditor5-utils/src/fastdiff';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Renderer is responsible for updating the DOM structure and the DOM selection based on\n * the {@link module:engine/view/renderer~Renderer#markToSync information about updated view nodes}.\n * In other words, it renders the view to the DOM.\n *\n * Its main responsibility is to make only the necessary, minimal changes to the DOM. However, unlike in many\n * virtual DOM implementations, the primary reason for doing minimal changes is not the performance but ensuring\n * that native editing features such as text composition, autocompletion, spell checking, selection's x-index are\n * affected as little as possible.\n *\n * Renderer uses {@link module:engine/view/domconverter~DomConverter} to transform view nodes and positions\n * to and from the DOM.\n */\nexport default class Renderer {\n\t/**\n\t * Creates a renderer instance.\n\t *\n\t * @param {module:engine/view/domconverter~DomConverter} domConverter Converter instance.\n\t * @param {module:engine/view/documentselection~DocumentSelection} selection View selection.\n\t */\n\tconstructor( domConverter, selection ) {\n\t\t/**\n\t\t * Set of DOM Documents instances.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<Document>}\n\t\t */\n\t\tthis.domDocuments = new Set();\n\n\t\t/**\n\t\t * Converter instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = domConverter;\n\n\t\t/**\n\t\t * Set of nodes which attributes changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedAttributes = new Set();\n\n\t\t/**\n\t\t * Set of elements which child lists changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedChildren = new Set();\n\n\t\t/**\n\t\t * Set of text nodes which text data changed and may need to be rendered.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set.<module:engine/view/node~Node>}\n\t\t */\n\t\tthis.markedTexts = new Set();\n\n\t\t/**\n\t\t * View selection. Renderer updates DOM selection based on the view selection.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection}\n\t\t */\n\t\tthis.selection = selection;\n\n\t\t/**\n\t\t * Indicates if the view document is focused and selection can be rendered. Selection will not be rendered if\n\t\t * this is set to `false`.\n\t\t *\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.isFocused = false;\n\n\t\t/**\n\t\t * The text node in which the inline filler was rendered.\n\t\t *\n\t\t * @private\n\t\t * @member {Text}\n\t\t */\n\t\tthis._inlineFiller = null;\n\n\t\t/**\n\t\t * DOM element containing fake selection.\n\t\t *\n\t\t * @private\n\t\t * @type {null|HTMLElement}\n\t\t */\n\t\tthis._fakeSelectionContainer = null;\n\t}\n\n\t/**\n\t * Marks a view node to be updated in the DOM by {@link #render `render()`}.\n\t *\n\t * Note that only view nodes whose parents have corresponding DOM elements need to be marked to be synchronized.\n\t *\n\t * @see #markedAttributes\n\t * @see #markedChildren\n\t * @see #markedTexts\n\t *\n\t * @param {module:engine/view/document~ChangeType} type Type of the change.\n\t * @param {module:engine/view/node~Node} node Node to be marked.\n\t */\n\tmarkToSync( type, node ) {\n\t\tif ( type === 'text' ) {\n\t\t\tif ( this.domConverter.mapViewToDom( node.parent ) ) {\n\t\t\t\tthis.markedTexts.add( node );\n\t\t\t}\n\t\t} else {\n\t\t\t// If the node has no DOM element it is not rendered yet,\n\t\t\t// its children/attributes do not need to be marked to be sync.\n\t\t\tif ( !this.domConverter.mapViewToDom( node ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( type === 'attributes' ) {\n\t\t\t\tthis.markedAttributes.add( node );\n\t\t\t} else if ( type === 'children' ) {\n\t\t\t\tthis.markedChildren.add( node );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * Unknown type passed to Renderer.markToSync.\n\t\t\t\t *\n\t\t\t\t * @error view-renderer-unknown-type\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'view-renderer-unknown-type', this );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Renders all buffered changes ({@link #markedAttributes}, {@link #markedChildren} and {@link #markedTexts}) and\n\t * the current view selection (if needed) to the DOM by applying a minimal set of changes to it.\n\t *\n\t * Renderer tries not to break the text composition (e.g. IME) and x-index of the selection,\n\t * so it does as little as it is needed to update the DOM.\n\t *\n\t * Renderer also handles {@link module:engine/view/filler fillers}. Especially, it checks if the inline filler is needed\n\t * at the selection position and adds or removes it. To prevent breaking text composition inline filler will not be\n\t * removed as long as the selection is in the text node which needed it at first.\n\t */\n\trender() {\n\t\tlet inlineFillerPosition;\n\n\t\t// Refresh mappings.\n\t\tfor ( const element of this.markedChildren ) {\n\t\t\tthis._updateChildrenMappings( element );\n\t\t}\n\n\t\t// There was inline filler rendered in the DOM but it's not\n\t\t// at the selection position any more, so we can remove it\n\t\t// (cause even if it's needed, it must be placed in another location).\n\t\tif ( this._inlineFiller && !this._isSelectionInInlineFiller() ) {\n\t\t\tthis._removeInlineFiller();\n\t\t}\n\n\t\t// If we've got the filler, let's try to guess its position in the view.\n\t\tif ( this._inlineFiller ) {\n\t\t\tinlineFillerPosition = this._getInlineFillerPosition();\n\t\t}\n\t\t// Otherwise, if it's needed, create it at the selection position.\n\t\telse if ( this._needsInlineFillerAtSelection() ) {\n\t\t\tinlineFillerPosition = this.selection.getFirstPosition();\n\n\t\t\t// Do not use `markToSync` so it will be added even if the parent is already added.\n\t\t\tthis.markedChildren.add( inlineFillerPosition.parent );\n\t\t}\n\n\t\tfor ( const element of this.markedAttributes ) {\n\t\t\tthis._updateAttrs( element );\n\t\t}\n\n\t\tfor ( const element of this.markedChildren ) {\n\t\t\tthis._updateChildren( element, { inlineFillerPosition } );\n\t\t}\n\n\t\tfor ( const node of this.markedTexts ) {\n\t\t\tif ( !this.markedChildren.has( node.parent ) && this.domConverter.mapViewToDom( node.parent ) ) {\n\t\t\t\tthis._updateText( node, { inlineFillerPosition } );\n\t\t\t}\n\t\t}\n\n\t\t// Check whether the inline filler is required and where it really is in the DOM.\n\t\t// At this point in most cases it will be in the DOM, but there are exceptions.\n\t\t// For example, if the inline filler was deep in the created DOM structure, it will not be created.\n\t\t// Similarly, if it was removed at the beginning of this function and then neither text nor children were updated,\n\t\t// it will not be present.\n\t\t// Fix those and similar scenarios.\n\t\tif ( inlineFillerPosition ) {\n\t\t\tconst fillerDomPosition = this.domConverter.viewPositionToDom( inlineFillerPosition );\n\t\t\tconst domDocument = fillerDomPosition.parent.ownerDocument;\n\n\t\t\tif ( !startsWithFiller( fillerDomPosition.parent ) ) {\n\t\t\t\t// Filler has not been created at filler position. Create it now.\n\t\t\t\tthis._inlineFiller = addInlineFiller( domDocument, fillerDomPosition.parent, fillerDomPosition.offset );\n\t\t\t} else {\n\t\t\t\t// Filler has been found, save it.\n\t\t\t\tthis._inlineFiller = fillerDomPosition.parent;\n\t\t\t}\n\t\t} else {\n\t\t\t// There is no filler needed.\n\t\t\tthis._inlineFiller = null;\n\t\t}\n\n\t\t// First focus the new editing host, then update the selection.\n\t\t// Otherwise, FF may throw an error (https://github.com/ckeditor/ckeditor5/issues/721).\n\t\tthis._updateFocus();\n\t\tthis._updateSelection();\n\n\t\tthis.markedTexts.clear();\n\t\tthis.markedAttributes.clear();\n\t\tthis.markedChildren.clear();\n\t}\n\n\t/**\n\t * Updates mappings of view element's children.\n\t *\n\t * Children that were replaced in the view structure by similar elements (same tag name) are treated as 'replaced'.\n\t * This means that their mappings can be updated so the new view elements are mapped to the existing DOM elements.\n\t * Thanks to that these elements do not need to be re-rendered completely.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewElement The view element whose children mappings will be updated.\n\t */\n\t_updateChildrenMappings( viewElement ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that it was already removed from DOM and there is no need to process it.\n\t\t\treturn;\n\t\t}\n\n\t\tconst actualDomChildren = this.domConverter.mapViewToDom( viewElement ).childNodes;\n\t\tconst expectedDomChildren = Array.from(\n\t\t\tthis.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { withChildren: false } )\n\t\t);\n\t\tconst diff = this._diffNodeLists( actualDomChildren, expectedDomChildren );\n\t\tconst actions = this._findReplaceActions( diff, actualDomChildren, expectedDomChildren );\n\n\t\tif ( actions.indexOf( 'replace' ) !== -1 ) {\n\t\t\tconst counter = { equal: 0, insert: 0, delete: 0 };\n\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action === 'replace' ) {\n\t\t\t\t\tconst insertIndex = counter.equal + counter.insert;\n\t\t\t\t\tconst deleteIndex = counter.equal + counter.delete;\n\t\t\t\t\tconst viewChild = viewElement.getChild( insertIndex );\n\n\t\t\t\t\t// UIElement and RawElement are special cases. Their children are not stored in a view (#799)\n\t\t\t\t\t// so we cannot use them with replacing flow (since they use view children during rendering\n\t\t\t\t\t// which will always result in rendering empty elements).\n\t\t\t\t\tif ( viewChild && !( viewChild.is( 'uiElement' ) || viewChild.is( 'rawElement' ) ) ) {\n\t\t\t\t\t\tthis._updateElementMappings( viewChild, actualDomChildren[ deleteIndex ] );\n\t\t\t\t\t}\n\n\t\t\t\t\tremove( expectedDomChildren[ insertIndex ] );\n\t\t\t\t\tcounter.equal++;\n\t\t\t\t} else {\n\t\t\t\t\tcounter[ action ]++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Updates mappings of a given view element.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewElement The view element whose mappings will be updated.\n\t * @param {Node} domElement The DOM element representing the given view element.\n\t */\n\t_updateElementMappings( viewElement, domElement ) {\n\t\t// Remap 'DomConverter' bindings.\n\t\tthis.domConverter.unbindDomElement( domElement );\n\t\tthis.domConverter.bindElements( domElement, viewElement );\n\n\t\t// View element may have children which needs to be updated, but are not marked, mark them to update.\n\t\tthis.markedChildren.add( viewElement );\n\n\t\t// Because we replace new view element mapping with the existing one, the corresponding DOM element\n\t\t// will not be rerendered. The new view element may have different attributes than the previous one.\n\t\t// Since its corresponding DOM element will not be rerendered, new attributes will not be added\n\t\t// to the DOM, so we need to mark it here to make sure its attributes gets updated. See #1427 for more\n\t\t// detailed case study.\n\t\t// Also there are cases where replaced element is removed from the view structure and then has\n\t\t// its attributes changed or removed. In such cases the element will not be present in `markedAttributes`\n\t\t// and also may be the same (`element.isSimilar()`) as the reused element not having its attributes updated.\n\t\t// To prevent such situations we always mark reused element to have its attributes rerenderd (#1560).\n\t\tthis.markedAttributes.add( viewElement );\n\t}\n\n\t/**\n\t * Gets the position of the inline filler based on the current selection.\n\t * Here, we assume that we know that the filler is needed and\n\t * {@link #_isSelectionInInlineFiller is at the selection position}, and, since it is needed,\n\t * it is somewhere at the selection position.\n\t *\n\t * Note: The filler position cannot be restored based on the filler's DOM text node, because\n\t * when this method is called (before rendering), the bindings will often be broken. View-to-DOM\n\t * bindings are only dependable after rendering.\n\t *\n\t * @private\n\t * @returns {module:engine/view/position~Position}\n\t */\n\t_getInlineFillerPosition() {\n\t\tconst firstPos = this.selection.getFirstPosition();\n\n\t\tif ( firstPos.parent.is( '$text' ) ) {\n\t\t\treturn ViewPosition._createBefore( this.selection.getFirstPosition().parent );\n\t\t} else {\n\t\t\treturn firstPos;\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` if the selection has not left the inline filler's text node.\n\t * If it is `true`, it means that the filler had been added for a reason and the selection did not\n\t * leave the filler's text node. For example, the user can be in the middle of a composition so it should not be touched.\n\t *\n\t * @private\n\t * @returns {Boolean} `true` if the inline filler and selection are in the same place.\n\t */\n\t_isSelectionInInlineFiller() {\n\t\tif ( this.selection.rangeCount != 1 || !this.selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note, we can't check if selection's position equals position of the\n\t\t// this._inlineFiller node, because of #663. We may not be able to calculate\n\t\t// the filler's position in the view at this stage.\n\t\t// Instead, we check it the other way whether selection is anchored in\n\t\t// that text node or next to it.\n\n\t\t// Possible options are:\n\t\t// \"FILLER{}\"\n\t\t// \"FILLERadded-text{}\"\n\t\tconst selectionPosition = this.selection.getFirstPosition();\n\t\tconst position = this.domConverter.viewPositionToDom( selectionPosition );\n\n\t\tif ( position && isText( position.parent ) && startsWithFiller( position.parent ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Removes the inline filler.\n\t *\n\t * @private\n\t */\n\t_removeInlineFiller() {\n\t\tconst domFillerNode = this._inlineFiller;\n\n\t\t// Something weird happened and the stored node doesn't contain the filler's text.\n\t\tif ( !startsWithFiller( domFillerNode ) ) {\n\t\t\t/**\n\t\t\t * The inline filler node was lost. Most likely, something overwrote the filler text node\n\t\t\t * in the DOM.\n\t\t\t *\n\t\t\t * @error view-renderer-filler-was-lost\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-renderer-filler-was-lost', this );\n\t\t}\n\n\t\tif ( isInlineFiller( domFillerNode ) ) {\n\t\t\tdomFillerNode.parentNode.removeChild( domFillerNode );\n\t\t} else {\n\t\t\tdomFillerNode.data = domFillerNode.data.substr( INLINE_FILLER_LENGTH );\n\t\t}\n\n\t\tthis._inlineFiller = null;\n\t}\n\n\t/**\n\t * Checks if the inline {@link module:engine/view/filler filler} should be added.\n\t *\n\t * @private\n\t * @returns {Boolean} `true` if the inline filler should be added.\n\t */\n\t_needsInlineFillerAtSelection() {\n\t\tif ( this.selection.rangeCount != 1 || !this.selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst selectionPosition = this.selection.getFirstPosition();\n\t\tconst selectionParent = selectionPosition.parent;\n\t\tconst selectionOffset = selectionPosition.offset;\n\n\t\t// If there is no DOM root we do not care about fillers.\n\t\tif ( !this.domConverter.mapViewToDom( selectionParent.root ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !( selectionParent.is( 'element' ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Prevent adding inline filler inside elements with contenteditable=false.\n\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/1170\n\t\tif ( !isEditable( selectionParent ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We have block filler, we do not need inline one.\n\t\tif ( selectionOffset === selectionParent.getFillerOffset() ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst nodeBefore = selectionPosition.nodeBefore;\n\t\tconst nodeAfter = selectionPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof ViewText || nodeAfter instanceof ViewText ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks if text needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} viewText View text to update.\n\t * @param {Object} options\n\t * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n\t * filler should be rendered.\n\t */\n\t_updateText( viewText, options ) {\n\t\tconst domText = this.domConverter.findCorrespondingDomText( viewText );\n\t\tconst newDomText = this.domConverter.viewToDom( viewText, domText.ownerDocument );\n\n\t\tconst actualText = domText.data;\n\t\tlet expectedText = newDomText.data;\n\n\t\tconst filler = options.inlineFillerPosition;\n\n\t\tif ( filler && filler.parent == viewText.parent && filler.offset == viewText.index ) {\n\t\t\texpectedText = INLINE_FILLER + expectedText;\n\t\t}\n\n\t\tif ( actualText != expectedText ) {\n\t\t\tconst actions = fastDiff( actualText, expectedText );\n\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action.type === 'insert' ) {\n\t\t\t\t\tdomText.insertData( action.index, action.values.join( '' ) );\n\t\t\t\t} else { // 'delete'\n\t\t\t\t\tdomText.deleteData( action.index, action.howMany );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if attribute list needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewElement The view element to update.\n\t */\n\t_updateAttrs( viewElement ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that 'viewElement' is outdated as its mapping was updated\n\t\t\t// in 'this._updateChildrenMappings()'. There is no need to process it as new view element which\n\t\t\t// replaced old 'viewElement' mapping was also added to 'this.markedAttributes'\n\t\t\t// in 'this._updateChildrenMappings()' so it will be processed separately.\n\t\t\treturn;\n\t\t}\n\n\t\tconst domAttrKeys = Array.from( domElement.attributes ).map( attr => attr.name );\n\t\tconst viewAttrKeys = viewElement.getAttributeKeys();\n\n\t\t// Add or overwrite attributes.\n\t\tfor ( const key of viewAttrKeys ) {\n\t\t\tdomElement.setAttribute( key, viewElement.getAttribute( key ) );\n\t\t}\n\n\t\t// Remove from DOM attributes which do not exists in the view.\n\t\tfor ( const key of domAttrKeys ) {\n\t\t\tif ( !viewElement.hasAttribute( key ) ) {\n\t\t\t\tdomElement.removeAttribute( key );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if elements child list needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewElement View element to update.\n\t * @param {Object} options\n\t * @param {module:engine/view/position~Position} options.inlineFillerPosition The position where the inline\n\t * filler should be rendered.\n\t */\n\t_updateChildren( viewElement, options ) {\n\t\tconst domElement = this.domConverter.mapViewToDom( viewElement );\n\n\t\tif ( !domElement ) {\n\t\t\t// If there is no `domElement` it means that it was already removed from DOM.\n\t\t\t// There is no need to process it. It will be processed when re-inserted.\n\t\t\treturn;\n\t\t}\n\n\t\tconst inlineFillerPosition = options.inlineFillerPosition;\n\t\tconst actualDomChildren = this.domConverter.mapViewToDom( viewElement ).childNodes;\n\t\tconst expectedDomChildren = Array.from(\n\t\t\tthis.domConverter.viewChildrenToDom( viewElement, domElement.ownerDocument, { bind: true, inlineFillerPosition } )\n\t\t);\n\n\t\t// Inline filler element has to be created as it is present in the DOM, but not in the view. It is required\n\t\t// during diffing so text nodes could be compared correctly and also during rendering to maintain\n\t\t// proper order and indexes while updating the DOM.\n\t\tif ( inlineFillerPosition && inlineFillerPosition.parent === viewElement ) {\n\t\t\taddInlineFiller( domElement.ownerDocument, expectedDomChildren, inlineFillerPosition.offset );\n\t\t}\n\n\t\tconst diff = this._diffNodeLists( actualDomChildren, expectedDomChildren );\n\n\t\tlet i = 0;\n\t\tconst nodesToUnbind = new Set();\n\n\t\t// Handle deletions first.\n\t\t// This is to prevent a situation where an element that already exists in `actualDomChildren` is inserted at a different\n\t\t// index in `actualDomChildren`. Since `actualDomChildren` is a `NodeList`, this works like move, not like an insert,\n\t\t// and it disrupts the whole algorithm. See https://github.com/ckeditor/ckeditor5/issues/6367.\n\t\t//\n\t\t// It doesn't matter in what order we remove or add nodes, as long as we remove and add correct nodes at correct indexes.\n\t\tfor ( const action of diff ) {\n\t\t\tif ( action === 'delete' ) {\n\t\t\t\tnodesToUnbind.add( actualDomChildren[ i ] );\n\t\t\t\tremove( actualDomChildren[ i ] );\n\t\t\t} else if ( action === 'equal' ) {\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\n\t\ti = 0;\n\n\t\tfor ( const action of diff ) {\n\t\t\tif ( action === 'insert' ) {\n\t\t\t\tinsertAt( domElement, i, expectedDomChildren[ i ] );\n\t\t\t\ti++;\n\t\t\t} else if ( action === 'equal' ) {\n\t\t\t\t// Force updating text nodes inside elements which did not change and do not need to be re-rendered (#1125).\n\t\t\t\t// Do it here (not in the loop above) because only after insertions the `i` index is correct.\n\t\t\t\tthis._markDescendantTextToSync( this.domConverter.domToView( expectedDomChildren[ i ] ) );\n\t\t\t\ti++;\n\t\t\t}\n\t\t}\n\n\t\t// Unbind removed nodes. When node does not have a parent it means that it was removed from DOM tree during\n\t\t// comparison with the expected DOM. We don't need to check child nodes, because if child node was reinserted,\n\t\t// it was moved to DOM tree out of the removed node.\n\t\tfor ( const node of nodesToUnbind ) {\n\t\t\tif ( !node.parentNode ) {\n\t\t\t\tthis.domConverter.unbindDomElement( node );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Shorthand for diffing two arrays or node lists of DOM nodes.\n\t *\n\t * @private\n\t * @param {Array.<Node>|NodeList} actualDomChildren Actual DOM children\n\t * @param {Array.<Node>|NodeList} expectedDomChildren Expected DOM children.\n\t * @returns {Array.<String>} The list of actions based on the {@link module:utils/diff~diff} function.\n\t */\n\t_diffNodeLists( actualDomChildren, expectedDomChildren ) {\n\t\tactualDomChildren = filterOutFakeSelectionContainer( actualDomChildren, this._fakeSelectionContainer );\n\n\t\treturn diff( actualDomChildren, expectedDomChildren, sameNodes.bind( null, this.domConverter ) );\n\t}\n\n\t/**\n\t * Finds DOM nodes that were replaced with the similar nodes (same tag name) in the view. All nodes are compared\n\t * within one `insert`/`delete` action group, for example:\n\t *\n\t * \t\tActual DOM:\t\t<p><b>Foo</b>Bar<i>Baz</i><b>Bax</b></p>\n\t * \t\tExpected DOM:\t<p>Bar<b>123</b><i>Baz</i><b>456</b></p>\n\t * \t\tInput actions:\t[ insert, insert, delete, delete, equal, insert, delete ]\n\t * \t\tOutput actions:\t[ insert, replace, delete, equal, replace ]\n\t *\n\t * @private\n\t * @param {Array.<String>} actions Actions array which is a result of the {@link module:utils/diff~diff} function.\n\t * @param {Array.<Node>|NodeList} actualDom Actual DOM children\n\t * @param {Array.<Node>} expectedDom Expected DOM children.\n\t * @returns {Array.<String>} Actions array modified with the `replace` actions.\n\t */\n\t_findReplaceActions( actions, actualDom, expectedDom ) {\n\t\t// If there is no both 'insert' and 'delete' actions, no need to check for replaced elements.\n\t\tif ( actions.indexOf( 'insert' ) === -1 || actions.indexOf( 'delete' ) === -1 ) {\n\t\t\treturn actions;\n\t\t}\n\n\t\tlet newActions = [];\n\t\tlet actualSlice = [];\n\t\tlet expectedSlice = [];\n\n\t\tconst counter = { equal: 0, insert: 0, delete: 0 };\n\n\t\tfor ( const action of actions ) {\n\t\t\tif ( action === 'insert' ) {\n\t\t\t\texpectedSlice.push( expectedDom[ counter.equal + counter.insert ] );\n\t\t\t} else if ( action === 'delete' ) {\n\t\t\t\tactualSlice.push( actualDom[ counter.equal + counter.delete ] );\n\t\t\t} else { // equal\n\t\t\t\tnewActions = newActions.concat( diff( actualSlice, expectedSlice, areSimilar ).map( x => x === 'equal' ? 'replace' : x ) );\n\t\t\t\tnewActions.push( 'equal' );\n\t\t\t\t// Reset stored elements on 'equal'.\n\t\t\t\tactualSlice = [];\n\t\t\t\texpectedSlice = [];\n\t\t\t}\n\t\t\tcounter[ action ]++;\n\t\t}\n\n\t\treturn newActions.concat( diff( actualSlice, expectedSlice, areSimilar ).map( x => x === 'equal' ? 'replace' : x ) );\n\t}\n\n\t/**\n\t * Marks text nodes to be synchronized.\n\t *\n\t * If a text node is passed, it will be marked. If an element is passed, all descendant text nodes inside it will be marked.\n\t *\n\t * @private\n\t * @param {module:engine/view/node~Node} viewNode View node to sync.\n\t */\n\t_markDescendantTextToSync( viewNode ) {\n\t\tif ( !viewNode ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( viewNode.is( '$text' ) ) {\n\t\t\tthis.markedTexts.add( viewNode );\n\t\t} else if ( viewNode.is( 'element' ) ) {\n\t\t\tfor ( const child of viewNode.getChildren() ) {\n\t\t\t\tthis._markDescendantTextToSync( child );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the selection needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t */\n\t_updateSelection() {\n\t\t// If there is no selection - remove DOM and fake selections.\n\t\tif ( this.selection.rangeCount === 0 ) {\n\t\t\tthis._removeDomSelection();\n\t\t\tthis._removeFakeSelection();\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst domRoot = this.domConverter.mapViewToDom( this.selection.editableElement );\n\n\t\t// Do nothing if there is no focus, or there is no DOM element corresponding to selection's editable element.\n\t\tif ( !this.isFocused || !domRoot ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Render selection.\n\t\tif ( this.selection.isFake ) {\n\t\t\tthis._updateFakeSelection( domRoot );\n\t\t} else {\n\t\t\tthis._removeFakeSelection();\n\t\t\tthis._updateDomSelection( domRoot );\n\t\t}\n\t}\n\n\t/**\n\t * Updates the fake selection.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where the fake selection container should be added.\n\t */\n\t_updateFakeSelection( domRoot ) {\n\t\tconst domDocument = domRoot.ownerDocument;\n\n\t\tif ( !this._fakeSelectionContainer ) {\n\t\t\tthis._fakeSelectionContainer = createFakeSelectionContainer( domDocument );\n\t\t}\n\n\t\tconst container = this._fakeSelectionContainer;\n\n\t\t// Bind fake selection container with the current selection *position*.\n\t\tthis.domConverter.bindFakeSelection( container, this.selection );\n\n\t\tif ( !this._fakeSelectionNeedsUpdate( domRoot ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !container.parentElement || container.parentElement != domRoot ) {\n\t\t\tdomRoot.appendChild( container );\n\t\t}\n\n\t\tcontainer.textContent = this.selection.fakeSelectionLabel || '\\u00A0';\n\n\t\tconst domSelection = domDocument.getSelection();\n\t\tconst domRange = domDocument.createRange();\n\n\t\tdomSelection.removeAllRanges();\n\t\tdomRange.selectNodeContents( container );\n\t\tdomSelection.addRange( domRange );\n\t}\n\n\t/**\n\t * Updates the DOM selection.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where the DOM selection should be rendered.\n\t */\n\t_updateDomSelection( domRoot ) {\n\t\tconst domSelection = domRoot.ownerDocument.defaultView.getSelection();\n\n\t\t// Let's check whether DOM selection needs updating at all.\n\t\tif ( !this._domSelectionNeedsUpdate( domSelection ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Multi-range selection is not available in most browsers, and, at least in Chrome, trying to\n\t\t// set such selection, that is not continuous, throws an error. Because of that, we will just use anchor\n\t\t// and focus of view selection.\n\t\t// Since we are not supporting multi-range selection, we also do not need to check if proper editable is\n\t\t// selected. If there is any editable selected, it is okay (editable is taken from selection anchor).\n\t\tconst anchor = this.domConverter.viewPositionToDom( this.selection.anchor );\n\t\tconst focus = this.domConverter.viewPositionToDom( this.selection.focus );\n\n\t\tdomSelection.collapse( anchor.parent, anchor.offset );\n\t\tdomSelection.extend( focus.parent, focus.offset );\n\n\t\t// Firefoxspecific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n\t\tif ( env.isGecko ) {\n\t\t\tfixGeckoSelectionAfterBr( focus, domSelection );\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether a given DOM selection needs to be updated.\n\t *\n\t * @private\n\t * @param {Selection} domSelection The DOM selection to check.\n\t * @returns {Boolean}\n\t */\n\t_domSelectionNeedsUpdate( domSelection ) {\n\t\tif ( !this.domConverter.isDomSelectionCorrect( domSelection ) ) {\n\t\t\t// Current DOM selection is in incorrect position. We need to update it.\n\t\t\treturn true;\n\t\t}\n\n\t\tconst oldViewSelection = domSelection && this.domConverter.domSelectionToView( domSelection );\n\n\t\tif ( oldViewSelection && this.selection.isEqual( oldViewSelection ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If selection is not collapsed, it does not need to be updated if it is similar.\n\t\tif ( !this.selection.isCollapsed && this.selection.isSimilar( oldViewSelection ) ) {\n\t\t\t// Selection did not changed and is correct, do not update.\n\t\t\treturn false;\n\t\t}\n\n\t\t// Selections are not similar.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether the fake selection needs to be updated.\n\t *\n\t * @private\n\t * @param {HTMLElement} domRoot A valid DOM root where a new fake selection container should be added.\n\t * @returns {Boolean}\n\t */\n\t_fakeSelectionNeedsUpdate( domRoot ) {\n\t\tconst container = this._fakeSelectionContainer;\n\t\tconst domSelection = domRoot.ownerDocument.getSelection();\n\n\t\t// Fake selection needs to be updated if there's no fake selection container, or the container currently sits\n\t\t// in a different root.\n\t\tif ( !container || container.parentElement !== domRoot ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Make sure that the selection actually is within the fake selection.\n\t\tif ( domSelection.anchorNode !== container && !container.contains( domSelection.anchorNode ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn container.textContent !== this.selection.fakeSelectionLabel;\n\t}\n\n\t/**\n\t * Removes the DOM selection.\n\t *\n\t * @private\n\t */\n\t_removeDomSelection() {\n\t\tfor ( const doc of this.domDocuments ) {\n\t\t\tconst domSelection = doc.getSelection();\n\n\t\t\tif ( domSelection.rangeCount ) {\n\t\t\t\tconst activeDomElement = doc.activeElement;\n\t\t\t\tconst viewElement = this.domConverter.mapDomToView( activeDomElement );\n\n\t\t\t\tif ( activeDomElement && viewElement ) {\n\t\t\t\t\tdoc.getSelection().removeAllRanges();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Removes the fake selection.\n\t *\n\t * @private\n\t */\n\t_removeFakeSelection() {\n\t\tconst container = this._fakeSelectionContainer;\n\n\t\tif ( container ) {\n\t\t\tcontainer.remove();\n\t\t}\n\t}\n\n\t/**\n\t * Checks if focus needs to be updated and possibly updates it.\n\t *\n\t * @private\n\t */\n\t_updateFocus() {\n\t\tif ( this.isFocused ) {\n\t\t\tconst editable = this.selection.editableElement;\n\n\t\t\tif ( editable ) {\n\t\t\t\tthis.domConverter.focus( editable );\n\t\t\t}\n\t\t}\n\t}\n}\n\nmix( Renderer, ObservableMixin );\n\n// Checks if provided element is editable.\n//\n// @private\n// @param {module:engine/view/element~Element} element\n// @returns {Boolean}\nfunction isEditable( element ) {\n\tif ( element.getAttribute( 'contenteditable' ) == 'false' ) {\n\t\treturn false;\n\t}\n\n\tconst parent = element.findAncestor( element => element.hasAttribute( 'contenteditable' ) );\n\n\treturn !parent || parent.getAttribute( 'contenteditable' ) == 'true';\n}\n\n// Adds inline filler at a given position.\n//\n// The position can be given as an array of DOM nodes and an offset in that array,\n// or a DOM parent element and an offset in that element.\n//\n// @private\n// @param {Document} domDocument\n// @param {Element|Array.<Node>} domParentOrArray\n// @param {Number} offset\n// @returns {Text} The DOM text node that contains an inline filler.\nfunction addInlineFiller( domDocument, domParentOrArray, offset ) {\n\tconst childNodes = domParentOrArray instanceof Array ? domParentOrArray : domParentOrArray.childNodes;\n\tconst nodeAfterFiller = childNodes[ offset ];\n\n\tif ( isText( nodeAfterFiller ) ) {\n\t\tnodeAfterFiller.data = INLINE_FILLER + nodeAfterFiller.data;\n\n\t\treturn nodeAfterFiller;\n\t} else {\n\t\tconst fillerNode = domDocument.createTextNode( INLINE_FILLER );\n\n\t\tif ( Array.isArray( domParentOrArray ) ) {\n\t\t\tchildNodes.splice( offset, 0, fillerNode );\n\t\t} else {\n\t\t\tinsertAt( domParentOrArray, offset, fillerNode );\n\t\t}\n\n\t\treturn fillerNode;\n\t}\n}\n\n// Whether two DOM nodes should be considered as similar.\n// Nodes are considered similar if they have the same tag name.\n//\n// @private\n// @param {Node} node1\n// @param {Node} node2\n// @returns {Boolean}\nfunction areSimilar( node1, node2 ) {\n\treturn isNode( node1 ) && isNode( node2 ) &&\n\t\t!isText( node1 ) && !isText( node2 ) &&\n\t\tnode1.nodeType !== Node.COMMENT_NODE && node2.nodeType !== Node.COMMENT_NODE &&\n\t\tnode1.tagName.toLowerCase() === node2.tagName.toLowerCase();\n}\n\n// Whether two dom nodes should be considered as the same.\n// Two nodes which are considered the same are:\n//\n//\t\t* Text nodes with the same text.\n//\t\t* Element nodes represented by the same object.\n//\t\t* Two block filler elements.\n//\n// @private\n// @param {String} blockFillerMode Block filler mode, see {@link module:engine/view/domconverter~DomConverter#blockFillerMode}.\n// @param {Node} node1\n// @param {Node} node2\n// @returns {Boolean}\nfunction sameNodes( domConverter, actualDomChild, expectedDomChild ) {\n\t// Elements.\n\tif ( actualDomChild === expectedDomChild ) {\n\t\treturn true;\n\t}\n\t// Texts.\n\telse if ( isText( actualDomChild ) && isText( expectedDomChild ) ) {\n\t\treturn actualDomChild.data === expectedDomChild.data;\n\t}\n\t// Block fillers.\n\telse if ( domConverter.isBlockFiller( actualDomChild ) &&\n\t\tdomConverter.isBlockFiller( expectedDomChild ) ) {\n\t\treturn true;\n\t}\n\n\t// Not matching types.\n\treturn false;\n}\n\n// The following is a Firefoxspecific hack (https://github.com/ckeditor/ckeditor5-engine/issues/1439).\n// When the native DOM selection is at the end of the block and preceded by <br /> e.g.\n//\n//\t\t<p>foo<br/>[]</p>\n//\n// which happens a lot when using the soft line break, the browser fails to (visually) move the\n// caret to the new line. A quick fix is as simple as forcerefreshing the selection with the same range.\nfunction fixGeckoSelectionAfterBr( focus, domSelection ) {\n\tconst parent = focus.parent;\n\n\t// This fix works only when the focus point is at the very end of an element.\n\t// There is no point in running it in cases unrelated to the browser bug.\n\tif ( parent.nodeType != Node.ELEMENT_NODE || focus.offset != parent.childNodes.length - 1 ) {\n\t\treturn;\n\t}\n\n\tconst childAtOffset = parent.childNodes[ focus.offset ];\n\n\t// To stay on the safe side, the fix being as specific as possible, it targets only the\n\t// selection which is at the very end of the element and preceded by <br />.\n\tif ( childAtOffset && childAtOffset.tagName == 'BR' ) {\n\t\tdomSelection.addRange( domSelection.getRangeAt( 0 ) );\n\t}\n}\n\nfunction filterOutFakeSelectionContainer( domChildList, fakeSelectionContainer ) {\n\tconst childList = Array.from( domChildList );\n\n\tif ( childList.length == 0 || !fakeSelectionContainer ) {\n\t\treturn childList;\n\t}\n\n\tconst last = childList[ childList.length - 1 ];\n\n\tif ( last == fakeSelectionContainer ) {\n\t\tchildList.pop();\n\t}\n\n\treturn childList;\n}\n\n// Creates a fake selection container for a given document.\n//\n// @private\n// @param {Document} domDocument\n// @returns {HTMLElement}\nfunction createFakeSelectionContainer( domDocument ) {\n\tconst container = domDocument.createElement( 'div' );\n\n\tcontainer.className = 'ck-fake-selection-container';\n\n\tObject.assign( container.style, {\n\t\tposition: 'fixed',\n\t\ttop: 0,\n\t\tleft: '-9999px',\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/752.\n\t\twidth: '42px'\n\t} );\n\n\t// Fill it with a text node so we can update it later.\n\tcontainer.textContent = '\\u00A0';\n\n\treturn container;\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/* globals window, document */\n\n/**\n * @module utils/dom/global\n */\n\n/**\n * A helper (module) giving an access to the global DOM objects such as `window` and\n * `document`. Accessing these objects using this helper allows easy and bulletproof\n * testing, i.e. stubbing native properties:\n *\n *\t\timport global from 'ckeditor5/utils/dom/global.js';\n *\n *\t\t// This stub will work for any code using global module.\n *\t\ttestUtils.sinon.stub( global, 'window', {\n *\t\t\tinnerWidth: 10000\n *\t\t} );\n *\n *\t\tconsole.log( global.window.innerWidth );\n */\nexport default { window, document };\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 utils/dom/indexof\n */\n\n/**\n * Returns index of the node in the parent element.\n *\n * @param {Node} node Node which index is tested.\n * @returns {Number} Index of the node in the parent element. Returns 0 if node has no parent.\n */\nexport default function indexOf( node ) {\n\tlet index = 0;\n\n\twhile ( node.previousSibling ) {\n\t\tnode = node.previousSibling;\n\t\tindex++;\n\t}\n\n\treturn index;\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/* globals Node */\n\n/**\n * @module utils/dom/getancestors\n */\n\n/**\n * Returns all ancestors of given DOM node, starting from the top-most (root). Includes the given node itself. If the\n * node is a part of `DocumentFragment` that `DocumentFragment` will be returned. In contrary, if the node is\n * appended to a `Document`, that `Document` will not be returned (algorithms operating on DOM tree care for `Document#documentElement`\n * at most, which will be returned).\n *\n * @param {Node} node DOM node.\n * @returns {Array.<Node|DocumentFragment>} Array of given `node` parents.\n */\nexport default function getAncestors( node ) {\n\tconst nodes = [];\n\n\t// We are interested in `Node`s `DocumentFragment`s only.\n\twhile ( node && node.nodeType != Node.DOCUMENT_NODE ) {\n\t\tnodes.unshift( node );\n\t\tnode = node.parentNode;\n\t}\n\n\treturn nodes;\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/view/domconverter\n */\n\n/* globals document, Node, NodeFilter, Text */\n\nimport ViewText from './text';\nimport ViewElement from './element';\nimport ViewPosition from './position';\nimport ViewRange from './range';\nimport ViewSelection from './selection';\nimport ViewDocumentFragment from './documentfragment';\nimport ViewTreeWalker from './treewalker';\nimport Matcher from './matcher';\nimport {\n\tBR_FILLER, INLINE_FILLER_LENGTH, NBSP_FILLER, MARKED_NBSP_FILLER,\n\tgetDataWithoutFiller, isInlineFiller, startsWithFiller\n} from './filler';\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport indexOf from '@ckeditor/ckeditor5-utils/src/dom/indexof';\nimport getAncestors from '@ckeditor/ckeditor5-utils/src/dom/getancestors';\nimport getCommonAncestor from '@ckeditor/ckeditor5-utils/src/dom/getcommonancestor';\nimport isText from '@ckeditor/ckeditor5-utils/src/dom/istext';\nimport { isElement } from 'lodash-es';\n\nconst BR_FILLER_REF = BR_FILLER( document ); // eslint-disable-line new-cap\nconst NBSP_FILLER_REF = NBSP_FILLER( document ); // eslint-disable-line new-cap\nconst MARKED_NBSP_FILLER_REF = MARKED_NBSP_FILLER( document ); // eslint-disable-line new-cap\n\n/**\n * `DomConverter` is a set of tools to do transformations between DOM nodes and view nodes. It also handles\n * {@link module:engine/view/domconverter~DomConverter#bindElements bindings} between these nodes.\n *\n * An instance of the DOM converter is available under\n * {@link module:engine/view/view~View#domConverter `editor.editing.view.domConverter`}.\n *\n * The DOM converter does not check which nodes should be rendered (use {@link module:engine/view/renderer~Renderer}), does not keep the\n * state of a tree nor keeps the synchronization between the tree view and the DOM tree (use {@link module:engine/view/document~Document}).\n *\n * The DOM converter keeps DOM elements to view element bindings, so when the converter gets destroyed, the bindings are lost.\n * Two converters will keep separate binding maps, so one tree view can be bound with two DOM trees.\n */\nexport default class DomConverter {\n\t/**\n\t * Creates a DOM converter.\n\t *\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t * @param {Object} options An object with configuration options.\n\t * @param {module:engine/view/filler~BlockFillerMode} [options.blockFillerMode='br'] The type of the block filler to use.\n\t */\n\tconstructor( document, options = {} ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\n\t\t/**\n\t\t * The mode of a block filler used by the DOM converter.\n\t\t *\n\t\t * @member {'br'|'nbsp'|'markedNbsp'} module:engine/view/domconverter~DomConverter#blockFillerMode\n\t\t */\n\t\tthis.blockFillerMode = options.blockFillerMode || 'br';\n\n\t\t/**\n\t\t * Elements which are considered pre-formatted elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>} module:engine/view/domconverter~DomConverter#preElements\n\t\t */\n\t\tthis.preElements = [ 'pre' ];\n\n\t\t/**\n\t\t * Elements which are considered block elements (and hence should be filled with a\n\t\t * {@link #isBlockFiller block filler}).\n\t\t *\n\t\t * Whether an element is considered a block element also affects handling of trailing whitespaces.\n\t\t *\n\t\t * You can extend this array if you introduce support for block elements which are not yet recognized here.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>} module:engine/view/domconverter~DomConverter#blockElements\n\t\t */\n\t\tthis.blockElements = [ 'p', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'li', 'dd', 'dt', 'figcaption', 'td', 'th' ];\n\n\t\t/**\n\t\t * The DOM-to-view mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_domToViewMapping\n\t\t */\n\t\tthis._domToViewMapping = new WeakMap();\n\n\t\t/**\n\t\t * The view-to-DOM mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_viewToDomMapping\n\t\t */\n\t\tthis._viewToDomMapping = new WeakMap();\n\n\t\t/**\n\t\t * Holds the mapping between fake selection containers and corresponding view selections.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap} module:engine/view/domconverter~DomConverter#_fakeSelectionMapping\n\t\t */\n\t\tthis._fakeSelectionMapping = new WeakMap();\n\n\t\t/**\n\t\t * Matcher for view elements whose content should be treated as raw data\n\t\t * and not processed during the conversion from DOM nodes to view elements.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/matcher~Matcher}\n\t\t */\n\t\tthis._rawContentElementMatcher = new Matcher();\n\n\t\t/**\n\t\t * A set of encountered raw content DOM nodes. It is used for preventing left trimming of the following text node.\n\t\t *\n\t\t * @private\n\t\t * @type {WeakSet.<Node>}\n\t\t */\n\t\tthis._encounteredRawContentDomNodes = new WeakSet();\n\t}\n\n\t/**\n\t * Binds a given DOM element that represents fake selection to a **position** of a\n\t * {@link module:engine/view/documentselection~DocumentSelection document selection}.\n\t * Document selection copy is stored and can be retrieved by the\n\t * {@link module:engine/view/domconverter~DomConverter#fakeSelectionToView} method.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @param {module:engine/view/documentselection~DocumentSelection} viewDocumentSelection\n\t */\n\tbindFakeSelection( domElement, viewDocumentSelection ) {\n\t\tthis._fakeSelectionMapping.set( domElement, new ViewSelection( viewDocumentSelection ) );\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/view/selection~Selection view selection} instance corresponding to a given\n\t * DOM element that represents fake selection. Returns `undefined` if binding to the given DOM element does not exist.\n\t *\n\t * @param {HTMLElement} domElement\n\t * @returns {module:engine/view/selection~Selection|undefined}\n\t */\n\tfakeSelectionToView( domElement ) {\n\t\treturn this._fakeSelectionMapping.get( domElement );\n\t}\n\n\t/**\n\t * Binds DOM and view elements, so it will be possible to get corresponding elements using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {HTMLElement} domElement The DOM element to bind.\n\t * @param {module:engine/view/element~Element} viewElement The view element to bind.\n\t */\n\tbindElements( domElement, viewElement ) {\n\t\tthis._domToViewMapping.set( domElement, viewElement );\n\t\tthis._viewToDomMapping.set( viewElement, domElement );\n\t}\n\n\t/**\n\t * Unbinds a given DOM element from the view element it was bound to. Unbinding is deep, meaning that all children of\n\t * the DOM element will be unbound too.\n\t *\n\t * @param {HTMLElement} domElement The DOM element to unbind.\n\t */\n\tunbindDomElement( domElement ) {\n\t\tconst viewElement = this._domToViewMapping.get( domElement );\n\n\t\tif ( viewElement ) {\n\t\t\tthis._domToViewMapping.delete( domElement );\n\t\t\tthis._viewToDomMapping.delete( viewElement );\n\n\t\t\tfor ( const child of domElement.childNodes ) {\n\t\t\t\tthis.unbindDomElement( child );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Binds DOM and view document fragments, so it will be possible to get corresponding document fragments using\n\t * {@link module:engine/view/domconverter~DomConverter#mapDomToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#mapViewToDom}.\n\t *\n\t * @param {DocumentFragment} domFragment The DOM document fragment to bind.\n\t * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment The view document fragment to bind.\n\t */\n\tbindDocumentFragments( domFragment, viewFragment ) {\n\t\tthis._domToViewMapping.set( domFragment, viewFragment );\n\t\tthis._viewToDomMapping.set( viewFragment, domFragment );\n\t}\n\n\t/**\n\t * Converts the view to the DOM. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments the method will return corresponding items.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View node or document fragment to transform.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @returns {Node|DocumentFragment} Converted node or DocumentFragment.\n\t */\n\tviewToDom( viewNode, domDocument, options = {} ) {\n\t\tif ( viewNode.is( '$text' ) ) {\n\t\t\tconst textData = this._processDataFromViewText( viewNode );\n\n\t\t\treturn domDocument.createTextNode( textData );\n\t\t} else {\n\t\t\tif ( this.mapViewToDom( viewNode ) ) {\n\t\t\t\treturn this.mapViewToDom( viewNode );\n\t\t\t}\n\n\t\t\tlet domElement;\n\n\t\t\tif ( viewNode.is( 'documentFragment' ) ) {\n\t\t\t\t// Create DOM document fragment.\n\t\t\t\tdomElement = domDocument.createDocumentFragment();\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domElement, viewNode );\n\t\t\t\t}\n\t\t\t} else if ( viewNode.is( 'uiElement' ) ) {\n\t\t\t\t// UIElement has its own render() method (see #799).\n\t\t\t\tdomElement = viewNode.render( domDocument );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\treturn domElement;\n\t\t\t} else {\n\t\t\t\t// Create DOM element.\n\t\t\t\tif ( viewNode.hasAttribute( 'xmlns' ) ) {\n\t\t\t\t\tdomElement = domDocument.createElementNS( viewNode.getAttribute( 'xmlns' ), viewNode.name );\n\t\t\t\t} else {\n\t\t\t\t\tdomElement = domDocument.createElement( viewNode.name );\n\t\t\t\t}\n\n\t\t\t\t// RawElement take care of their children in RawElement#render() method which can be customized\n\t\t\t\t// (see https://github.com/ckeditor/ckeditor5/issues/4469).\n\t\t\t\tif ( viewNode.is( 'rawElement' ) ) {\n\t\t\t\t\tviewNode.render( domElement );\n\t\t\t\t}\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domElement, viewNode );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tfor ( const key of viewNode.getAttributeKeys() ) {\n\t\t\t\t\tdomElement.setAttribute( key, viewNode.getAttribute( key ) );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren !== false ) {\n\t\t\t\tfor ( const child of this.viewChildrenToDom( viewNode, domDocument, options ) ) {\n\t\t\t\t\tdomElement.appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn domElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the view element to DOM using the\n\t * {@link module:engine/view/domconverter~DomConverter#viewToDom} method.\n\t * Additionally, this method adds block {@link module:engine/view/filler filler} to the list of children, if needed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElement Parent view element.\n\t * @param {Document} domDocument Document which will be used to create DOM nodes.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#viewToDom} options parameter.\n\t * @returns {Iterable.<Node>} DOM nodes.\n\t */\n\t* viewChildrenToDom( viewElement, domDocument, options = {} ) {\n\t\tconst fillerPositionOffset = viewElement.getFillerOffset && viewElement.getFillerOffset();\n\t\tlet offset = 0;\n\n\t\tfor ( const childView of viewElement.getChildren() ) {\n\t\t\tif ( fillerPositionOffset === offset ) {\n\t\t\t\tyield this._getBlockFiller( domDocument );\n\t\t\t}\n\n\t\t\tyield this.viewToDom( childView, domDocument, options );\n\n\t\t\toffset++;\n\t\t}\n\n\t\tif ( fillerPositionOffset === offset ) {\n\t\t\tyield this._getBlockFiller( domDocument );\n\t\t}\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/range~Range} to DOM range.\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t *\n\t * @param {module:engine/view/range~Range} viewRange View range.\n\t * @returns {Range} DOM range.\n\t */\n\tviewRangeToDom( viewRange ) {\n\t\tconst domStart = this.viewPositionToDom( viewRange.start );\n\t\tconst domEnd = this.viewPositionToDom( viewRange.end );\n\n\t\tconst domRange = document.createRange();\n\t\tdomRange.setStart( domStart.parent, domStart.offset );\n\t\tdomRange.setEnd( domEnd.parent, domEnd.offset );\n\n\t\treturn domRange;\n\t}\n\n\t/**\n\t * Converts view {@link module:engine/view/position~Position} to DOM parent and offset.\n\t *\n\t * Inline and block {@link module:engine/view/filler fillers} are handled during the conversion.\n\t * If the converted position is directly before inline filler it is moved inside the filler.\n\t *\n\t * @param {module:engine/view/position~Position} viewPosition View position.\n\t * @returns {Object|null} position DOM position or `null` if view position could not be converted to DOM.\n\t * @returns {Node} position.parent DOM position parent.\n\t * @returns {Number} position.offset DOM position offset.\n\t */\n\tviewPositionToDom( viewPosition ) {\n\t\tconst viewParent = viewPosition.parent;\n\n\t\tif ( viewParent.is( '$text' ) ) {\n\t\t\tconst domParent = this.findCorrespondingDomText( viewParent );\n\n\t\t\tif ( !domParent ) {\n\t\t\t\t// Position is in a view text node that has not been rendered to DOM yet.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tlet offset = viewPosition.offset;\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset += INLINE_FILLER_LENGTH;\n\t\t\t}\n\n\t\t\treturn { parent: domParent, offset };\n\t\t} else {\n\t\t\t// viewParent is instance of ViewElement.\n\t\t\tlet domParent, domBefore, domAfter;\n\n\t\t\tif ( viewPosition.offset === 0 ) {\n\t\t\t\tdomParent = this.mapViewToDom( viewParent );\n\n\t\t\t\tif ( !domParent ) {\n\t\t\t\t\t// Position is in a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomAfter = domParent.childNodes[ 0 ];\n\t\t\t} else {\n\t\t\t\tconst nodeBefore = viewPosition.nodeBefore;\n\n\t\t\t\tdomBefore = nodeBefore.is( '$text' ) ?\n\t\t\t\t\tthis.findCorrespondingDomText( nodeBefore ) :\n\t\t\t\t\tthis.mapViewToDom( viewPosition.nodeBefore );\n\n\t\t\t\tif ( !domBefore ) {\n\t\t\t\t\t// Position is after a view element that has not been rendered to DOM yet.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdomParent = domBefore.parentNode;\n\t\t\t\tdomAfter = domBefore.nextSibling;\n\t\t\t}\n\n\t\t\t// If there is an inline filler at position return position inside the filler. We should never return\n\t\t\t// the position before the inline filler.\n\t\t\tif ( isText( domAfter ) && startsWithFiller( domAfter ) ) {\n\t\t\t\treturn { parent: domAfter, offset: INLINE_FILLER_LENGTH };\n\t\t\t}\n\n\t\t\tconst offset = domBefore ? indexOf( domBefore ) + 1 : 0;\n\n\t\t\treturn { parent: domParent, offset };\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM to view. For all text nodes, not bound elements and document fragments new items will\n\t * be created. For bound elements and document fragments function will return corresponding items. For\n\t * {@link module:engine/view/filler fillers} `null` will be returned.\n\t * For all DOM elements rendered by {@link module:engine/view/uielement~UIElement} that UIElement will be returned.\n\t *\n\t * @param {Node|DocumentFragment} domNode DOM node or document fragment to transform.\n\t * @param {Object} [options] Conversion options.\n\t * @param {Boolean} [options.bind=false] Determines whether new elements will be bound.\n\t * @param {Boolean} [options.withChildren=true] If `true`, node's and document fragment's children will be converted too.\n\t * @param {Boolean} [options.keepOriginalCase=false] If `false`, node's tag name will be converter to lower case.\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} Converted node or document fragment\n\t * or `null` if DOM node is a {@link module:engine/view/filler filler} or the given node is an empty text node.\n\t */\n\tdomToView( domNode, options = {} ) {\n\t\tif ( this.isBlockFiller( domNode ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// When node is inside a UIElement or a RawElement return that parent as it's view representation.\n\t\tconst hostElement = this.getHostViewElement( domNode );\n\n\t\tif ( hostElement ) {\n\t\t\treturn hostElement;\n\t\t}\n\n\t\tif ( isText( domNode ) ) {\n\t\t\tif ( isInlineFiller( domNode ) ) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\tconst textData = this._processDataFromDomText( domNode );\n\n\t\t\t\treturn textData === '' ? null : new ViewText( this.document, textData );\n\t\t\t}\n\t\t} else if ( this.isComment( domNode ) ) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\tif ( this.mapDomToView( domNode ) ) {\n\t\t\t\treturn this.mapDomToView( domNode );\n\t\t\t}\n\n\t\t\tlet viewElement;\n\n\t\t\tif ( this.isDocumentFragment( domNode ) ) {\n\t\t\t\t// Create view document fragment.\n\t\t\t\tviewElement = new ViewDocumentFragment( this.document );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindDocumentFragments( domNode, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Create view element.\n\t\t\t\tconst viewName = options.keepOriginalCase ? domNode.tagName : domNode.tagName.toLowerCase();\n\t\t\t\tviewElement = new ViewElement( this.document, viewName );\n\n\t\t\t\tif ( options.bind ) {\n\t\t\t\t\tthis.bindElements( domNode, viewElement );\n\t\t\t\t}\n\n\t\t\t\t// Copy element's attributes.\n\t\t\t\tconst attrs = domNode.attributes;\n\n\t\t\t\tfor ( let i = attrs.length - 1; i >= 0; i-- ) {\n\t\t\t\t\tviewElement._setAttribute( attrs[ i ].name, attrs[ i ].value );\n\t\t\t\t}\n\n\t\t\t\t// Treat this element's content as a raw data if it was registered as such.\n\t\t\t\tif ( options.withChildren !== false && this._rawContentElementMatcher.match( viewElement ) ) {\n\t\t\t\t\tviewElement._setCustomProperty( '$rawContent', domNode.innerHTML );\n\n\t\t\t\t\t// Store a DOM node to prevent left trimming of the following text node.\n\t\t\t\t\tthis._encounteredRawContentDomNodes.add( domNode );\n\n\t\t\t\t\treturn viewElement;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( options.withChildren !== false ) {\n\t\t\t\tfor ( const child of this.domChildrenToView( domNode, options ) ) {\n\t\t\t\t\tviewElement._appendChild( child );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn viewElement;\n\t\t}\n\t}\n\n\t/**\n\t * Converts children of the DOM element to view nodes using\n\t * the {@link module:engine/view/domconverter~DomConverter#domToView} method.\n\t * Additionally this method omits block {@link module:engine/view/filler filler}, if it exists in the DOM parent.\n\t *\n\t * @param {HTMLElement} domElement Parent DOM element.\n\t * @param {Object} options See {@link module:engine/view/domconverter~DomConverter#domToView} options parameter.\n\t * @returns {Iterable.<module:engine/view/node~Node>} View nodes.\n\t */\n\t* domChildrenToView( domElement, options = {} ) {\n\t\tfor ( let i = 0; i < domElement.childNodes.length; i++ ) {\n\t\t\tconst domChild = domElement.childNodes[ i ];\n\t\t\tconst viewChild = this.domToView( domChild, options );\n\n\t\t\tif ( viewChild !== null ) {\n\t\t\t\tyield viewChild;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Converts DOM selection to view {@link module:engine/view/selection~Selection}.\n\t * Ranges which cannot be converted will be omitted.\n\t *\n\t * @param {Selection} domSelection DOM selection.\n\t * @returns {module:engine/view/selection~Selection} View selection.\n\t */\n\tdomSelectionToView( domSelection ) {\n\t\t// DOM selection might be placed in fake selection container.\n\t\t// If container contains fake selection - return corresponding view selection.\n\t\tif ( domSelection.rangeCount === 1 ) {\n\t\t\tlet container = domSelection.getRangeAt( 0 ).startContainer;\n\n\t\t\t// The DOM selection might be moved to the text node inside the fake selection container.\n\t\t\tif ( isText( container ) ) {\n\t\t\t\tcontainer = container.parentNode;\n\t\t\t}\n\n\t\t\tconst viewSelection = this.fakeSelectionToView( container );\n\n\t\t\tif ( viewSelection ) {\n\t\t\t\treturn viewSelection;\n\t\t\t}\n\t\t}\n\n\t\tconst isBackward = this.isDomSelectionBackward( domSelection );\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( let i = 0; i < domSelection.rangeCount; i++ ) {\n\t\t\t// DOM Range have correct start and end, no matter what is the DOM Selection direction. So we don't have to fix anything.\n\t\t\tconst domRange = domSelection.getRangeAt( i );\n\t\t\tconst viewRange = this.domRangeToView( domRange );\n\n\t\t\tif ( viewRange ) {\n\t\t\t\tviewRanges.push( viewRange );\n\t\t\t}\n\t\t}\n\n\t\treturn new ViewSelection( viewRanges, { backward: isBackward } );\n\t}\n\n\t/**\n\t * Converts DOM Range to view {@link module:engine/view/range~Range}.\n\t * If the start or end position can not be converted `null` is returned.\n\t *\n\t * @param {Range} domRange DOM range.\n\t * @returns {module:engine/view/range~Range|null} View range.\n\t */\n\tdomRangeToView( domRange ) {\n\t\tconst viewStart = this.domPositionToView( domRange.startContainer, domRange.startOffset );\n\t\tconst viewEnd = this.domPositionToView( domRange.endContainer, domRange.endOffset );\n\n\t\tif ( viewStart && viewEnd ) {\n\t\t\treturn new ViewRange( viewStart, viewEnd );\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts DOM parent and offset to view {@link module:engine/view/position~Position}.\n\t *\n\t * If the position is inside a {@link module:engine/view/filler filler} which has no corresponding view node,\n\t * position of the filler will be converted and returned.\n\t *\n\t * If the position is inside DOM element rendered by {@link module:engine/view/uielement~UIElement}\n\t * that position will be converted to view position before that UIElement.\n\t *\n\t * If structures are too different and it is not possible to find corresponding position then `null` will be returned.\n\t *\n\t * @param {Node} domParent DOM position parent.\n\t * @param {Number} domOffset DOM position offset.\n\t * @returns {module:engine/view/position~Position} viewPosition View position.\n\t */\n\tdomPositionToView( domParent, domOffset ) {\n\t\tif ( this.isBlockFiller( domParent ) ) {\n\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t}\n\n\t\t// If position is somewhere inside UIElement or a RawElement - return position before that element.\n\t\tconst viewElement = this.mapDomToView( domParent );\n\n\t\tif ( viewElement && ( viewElement.is( 'uiElement' ) || viewElement.is( 'rawElement' ) ) ) {\n\t\t\treturn ViewPosition._createBefore( viewElement );\n\t\t}\n\n\t\tif ( isText( domParent ) ) {\n\t\t\tif ( isInlineFiller( domParent ) ) {\n\t\t\t\treturn this.domPositionToView( domParent.parentNode, indexOf( domParent ) );\n\t\t\t}\n\n\t\t\tconst viewParent = this.findCorrespondingViewText( domParent );\n\t\t\tlet offset = domOffset;\n\n\t\t\tif ( !viewParent ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( startsWithFiller( domParent ) ) {\n\t\t\t\toffset -= INLINE_FILLER_LENGTH;\n\t\t\t\toffset = offset < 0 ? 0 : offset;\n\t\t\t}\n\n\t\t\treturn new ViewPosition( viewParent, offset );\n\t\t}\n\t\t// domParent instanceof HTMLElement.\n\t\telse {\n\t\t\tif ( domOffset === 0 ) {\n\t\t\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t\t\tif ( viewParent ) {\n\t\t\t\t\treturn new ViewPosition( viewParent, 0 );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst domBefore = domParent.childNodes[ domOffset - 1 ];\n\t\t\t\tconst viewBefore = isText( domBefore ) ?\n\t\t\t\t\tthis.findCorrespondingViewText( domBefore ) :\n\t\t\t\t\tthis.mapDomToView( domBefore );\n\n\t\t\t\t// TODO #663\n\t\t\t\tif ( viewBefore && viewBefore.parent ) {\n\t\t\t\t\treturn new ViewPosition( viewBefore.parent, viewBefore.index + 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Returns corresponding view {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment} for provided DOM element or\n\t * document fragment. If there is no view item {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * to the given DOM - `undefined` is returned.\n\t *\n\t * For all DOM elements rendered by a {@link module:engine/view/uielement~UIElement} or\n\t * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.\n\t *\n\t * @param {DocumentFragment|Element} domElementOrDocumentFragment DOM element or document fragment.\n\t * @returns {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment|undefined}\n\t * Corresponding view element, document fragment or `undefined` if no element was bound.\n\t */\n\tmapDomToView( domElementOrDocumentFragment ) {\n\t\tconst hostElement = this.getHostViewElement( domElementOrDocumentFragment );\n\n\t\treturn hostElement || this._domToViewMapping.get( domElementOrDocumentFragment );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * For all text nodes rendered by a {@link module:engine/view/uielement~UIElement} or\n\t * a {@link module:engine/view/rawelement~RawElement}, the parent `UIElement` or `RawElement` will be returned.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * Note that for the block or inline {@link module:engine/view/filler filler} this method returns `null`.\n\t *\n\t * @param {Text} domText DOM text node.\n\t * @returns {module:engine/view/text~Text|null} Corresponding view text node or `null`, if it was not possible to find a\n\t * corresponding node.\n\t */\n\tfindCorrespondingViewText( domText ) {\n\t\tif ( isInlineFiller( domText ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If DOM text was rendered by a UIElement or a RawElement - return this parent element.\n\t\tconst hostElement = this.getHostViewElement( domText );\n\n\t\tif ( hostElement ) {\n\t\t\treturn hostElement;\n\t\t}\n\n\t\tconst previousSibling = domText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling ) {\n\t\t\tif ( !( this.isElement( previousSibling ) ) ) {\n\t\t\t\t// The previous is text or comment.\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewElement = this.mapDomToView( previousSibling );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst nextSibling = viewElement.nextSibling;\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( nextSibling instanceof ViewText ) {\n\t\t\t\t\treturn viewElement.nextSibling;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Try to use parent to find the corresponding text node.\n\t\telse {\n\t\t\tconst viewElement = this.mapDomToView( domText.parentNode );\n\n\t\t\tif ( viewElement ) {\n\t\t\t\tconst firstChild = viewElement.getChild( 0 );\n\n\t\t\t\t// It might be filler which has no corresponding view node.\n\t\t\t\tif ( firstChild instanceof ViewText ) {\n\t\t\t\t\treturn firstChild;\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns corresponding DOM item for provided {@link module:engine/view/element~Element Element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment}.\n\t * To find a corresponding text for {@link module:engine/view/text~Text view Text instance}\n\t * use {@link #findCorrespondingDomText}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewNode\n\t * View element or document fragment.\n\t * @returns {Node|DocumentFragment|undefined} Corresponding DOM node or document fragment.\n\t */\n\tmapViewToDom( documentFragmentOrElement ) {\n\t\treturn this._viewToDomMapping.get( documentFragmentOrElement );\n\t}\n\n\t/**\n\t * Finds corresponding text node. Text nodes are not {@link module:engine/view/domconverter~DomConverter#bindElements bound},\n\t * corresponding text node is returned based on the sibling or parent.\n\t *\n\t * If the directly previous sibling is a {@link module:engine/view/domconverter~DomConverter#bindElements bound} element, it is used\n\t * to find the corresponding text node.\n\t *\n\t * If this is a first child in the parent and the parent is a {@link module:engine/view/domconverter~DomConverter#bindElements bound}\n\t * element, it is used to find the corresponding text node.\n\t *\n\t * Otherwise `null` is returned.\n\t *\n\t * @param {module:engine/view/text~Text} viewText View text node.\n\t * @returns {Text|null} Corresponding DOM text node or `null`, if it was not possible to find a corresponding node.\n\t */\n\tfindCorrespondingDomText( viewText ) {\n\t\tconst previousSibling = viewText.previousSibling;\n\n\t\t// Try to use previous sibling to find the corresponding text node.\n\t\tif ( previousSibling && this.mapViewToDom( previousSibling ) ) {\n\t\t\treturn this.mapViewToDom( previousSibling ).nextSibling;\n\t\t}\n\n\t\t// If this is a first node, try to use parent to find the corresponding text node.\n\t\tif ( !previousSibling && viewText.parent && this.mapViewToDom( viewText.parent ) ) {\n\t\t\treturn this.mapViewToDom( viewText.parent ).childNodes[ 0 ];\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Focuses DOM editable that is corresponding to provided {@link module:engine/view/editableelement~EditableElement}.\n\t *\n\t * @param {module:engine/view/editableelement~EditableElement} viewEditable\n\t */\n\tfocus( viewEditable ) {\n\t\tconst domEditable = this.mapViewToDom( viewEditable );\n\n\t\tif ( domEditable && domEditable.ownerDocument.activeElement !== domEditable ) {\n\t\t\t// Save the scrollX and scrollY positions before the focus.\n\t\t\tconst { scrollX, scrollY } = global.window;\n\t\t\tconst scrollPositions = [];\n\n\t\t\t// Save all scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst { scrollLeft, scrollTop } = node;\n\n\t\t\t\tscrollPositions.push( [ scrollLeft, scrollTop ] );\n\t\t\t} );\n\n\t\t\tdomEditable.focus();\n\n\t\t\t// Restore scrollLeft and scrollTop values starting from domEditable up to\n\t\t\t// document#documentElement.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/957\n\t\t\tforEachDomNodeAncestor( domEditable, node => {\n\t\t\t\tconst [ scrollLeft, scrollTop ] = scrollPositions.shift();\n\n\t\t\t\tnode.scrollLeft = scrollLeft;\n\t\t\t\tnode.scrollTop = scrollTop;\n\t\t\t} );\n\n\t\t\t// Restore the scrollX and scrollY positions after the focus.\n\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/951\n\t\t\tglobal.window.scrollTo( scrollX, scrollY );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.ELEMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisElement( node ) {\n\t\treturn node && node.nodeType == Node.ELEMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.DOCUMENT_FRAGMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisDocumentFragment( node ) {\n\t\treturn node && node.nodeType == Node.DOCUMENT_FRAGMENT_NODE;\n\t}\n\n\t/**\n\t * Returns `true` when `node.nodeType` equals `Node.COMMENT_NODE`.\n\t *\n\t * @param {Node} node Node to check.\n\t * @returns {Boolean}\n\t */\n\tisComment( node ) {\n\t\treturn node && node.nodeType == Node.COMMENT_NODE;\n\t}\n\n\t/**\n\t * Checks if the node is an instance of the block filler for this DOM converter.\n\t *\n\t *\t\tconst converter = new DomConverter( viewDocument, { blockFillerMode: 'br' } );\n\t *\n\t *\t\tconverter.isBlockFiller( BR_FILLER( document ) ); // true\n\t *\t\tconverter.isBlockFiller( NBSP_FILLER( document ) ); // false\n\t *\n\t * **Note:**: For the `'nbsp'` mode the method also checks context of a node so it cannot be a detached node.\n\t *\n\t * **Note:** A special case in the `'nbsp'` mode exists where the `<br>` in `<p><br></p>` is treated as a block filler.\n\t *\n\t * @param {Node} domNode DOM node to check.\n\t * @returns {Boolean} True if a node is considered a block filler for given mode.\n\t */\n\tisBlockFiller( domNode ) {\n\t\tif ( this.blockFillerMode == 'br' ) {\n\t\t\treturn domNode.isEqualNode( BR_FILLER_REF );\n\t\t}\n\n\t\t// Special case for <p><br></p> in which <br> should be treated as filler even when we are not in the 'br' mode. See ckeditor5#5564.\n\t\tif ( domNode.tagName === 'BR' && hasBlockParent( domNode, this.blockElements ) && domNode.parentNode.childNodes.length === 1 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// If not in 'br' mode, try recognizing both marked and regular nbsp block fillers.\n\t\treturn domNode.isEqualNode( MARKED_NBSP_FILLER_REF ) || isNbspBlockFiller( domNode, this.blockElements );\n\t}\n\n\t/**\n\t * Returns `true` if given selection is a backward selection, that is, if it's `focus` is before `anchor`.\n\t *\n\t * @param {Selection} DOM Selection instance to check.\n\t * @returns {Boolean}\n\t */\n\tisDomSelectionBackward( selection ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Since it takes multiple lines of code to check whether a \"DOM Position\" is before/after another \"DOM Position\",\n\t\t// we will use the fact that range will collapse if it's end is before it's start.\n\t\tconst range = document.createRange();\n\n\t\trange.setStart( selection.anchorNode, selection.anchorOffset );\n\t\trange.setEnd( selection.focusNode, selection.focusOffset );\n\n\t\tconst backward = range.collapsed;\n\n\t\trange.detach();\n\n\t\treturn backward;\n\t}\n\n\t/**\n\t * Returns a parent {@link module:engine/view/uielement~UIElement} or {@link module:engine/view/rawelement~RawElement}\n\t * that hosts the provided DOM node. Returns `null` if there is no such parent.\n\t *\n\t * @param {Node} domNode\n\t * @returns {module:engine/view/uielement~UIElement|module:engine/view/rawelement~RawElement|null}\n\t */\n\tgetHostViewElement( domNode ) {\n\t\tconst ancestors = getAncestors( domNode );\n\n\t\t// Remove domNode from the list.\n\t\tancestors.pop();\n\n\t\twhile ( ancestors.length ) {\n\t\t\tconst domNode = ancestors.pop();\n\t\t\tconst viewNode = this._domToViewMapping.get( domNode );\n\n\t\t\tif ( viewNode && ( viewNode.is( 'uiElement' ) || viewNode.is( 'rawElement' ) ) ) {\n\t\t\t\treturn viewNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks if the given selection's boundaries are at correct places.\n\t *\n\t * The following places are considered as incorrect for selection boundaries:\n\t *\n\t * * before or in the middle of an inline filler sequence,\n\t * * inside a DOM element which represents {@link module:engine/view/uielement~UIElement a view UI element},\n\t * * inside a DOM element which represents {@link module:engine/view/rawelement~RawElement a view raw element}.\n\t *\n\t * @param {Selection} domSelection The DOM selection object to be checked.\n\t * @returns {Boolean} `true` if the given selection is at a correct place, `false` otherwise.\n\t */\n\tisDomSelectionCorrect( domSelection ) {\n\t\treturn this._isDomSelectionPositionCorrect( domSelection.anchorNode, domSelection.anchorOffset ) &&\n\t\t\tthis._isDomSelectionPositionCorrect( domSelection.focusNode, domSelection.focusOffset );\n\t}\n\n\t/**\n\t * Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as raw data\n\t * and not processed during the conversion from DOM nodes to view elements.\n\t *\n\t * This is affecting how {@link module:engine/view/domconverter~DomConverter#domToView} and\n\t * {@link module:engine/view/domconverter~DomConverter#domChildrenToView} process DOM nodes.\n\t *\n\t * The raw data can be later accessed by a\n\t * {@link module:engine/view/element~Element#getCustomProperty custom property of a view element} called `\"$rawContent\"`.\n\t *\n\t * @param {module:engine/view/matcher~MatcherPattern} pattern Pattern matching a view element whose content should\n\t * be treated as raw data.\n\t */\n\tregisterRawContentMatcher( pattern ) {\n\t\tthis._rawContentElementMatcher.add( pattern );\n\t}\n\n\t/**\n\t * Returns block {@link module:engine/view/filler filler} node based on current {@link #blockFillerMode} setting.\n\t *\n\t * @private\n\t * @params {Document} domDocument\n\t * @returns {Node} filler\n\t */\n\t_getBlockFiller( domDocument ) {\n\t\tswitch ( this.blockFillerMode ) {\n\t\t\tcase 'nbsp':\n\t\t\t\treturn NBSP_FILLER( domDocument ); // eslint-disable-line new-cap\n\t\t\tcase 'markedNbsp':\n\t\t\t\treturn MARKED_NBSP_FILLER( domDocument ); // eslint-disable-line new-cap\n\t\t\tcase 'br':\n\t\t\t\treturn BR_FILLER( domDocument ); // eslint-disable-line new-cap\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the given DOM position is a correct place for selection boundary. See {@link #isDomSelectionCorrect}.\n\t *\n\t * @private\n\t * @param {Element} domParent Position parent.\n\t * @param {Number} offset Position offset.\n\t * @returns {Boolean} `true` if given position is at a correct place for selection boundary, `false` otherwise.\n\t */\n\t_isDomSelectionPositionCorrect( domParent, offset ) {\n\t\t// If selection is before or in the middle of inline filler string, it is incorrect.\n\t\tif ( isText( domParent ) && startsWithFiller( domParent ) && offset < INLINE_FILLER_LENGTH ) {\n\t\t\t// Selection in a text node, at wrong position (before or in the middle of filler).\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this.isElement( domParent ) && startsWithFiller( domParent.childNodes[ offset ] ) ) {\n\t\t\t// Selection in an element node, before filler text node.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst viewParent = this.mapDomToView( domParent );\n\n\t\t// The position is incorrect when anchored inside a UIElement or a RawElement.\n\t\t// Note: In case of UIElement and RawElement, mapDomToView() returns a parent element for any DOM child\n\t\t// so there's no need to perform any additional checks.\n\t\tif ( viewParent && ( viewParent.is( 'uiElement' ) || viewParent.is( 'rawElement' ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Takes text data from a given {@link module:engine/view/text~Text#data} and processes it so\n\t * it is correctly displayed in the DOM.\n\t *\n\t * Following changes are done:\n\t *\n\t * * a space at the beginning is changed to `&nbsp;` if this is the first text node in its container\n\t * element or if a previous text node ends with a space character,\n\t * * space at the end of the text node is changed to `&nbsp;` if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container,\n\t * * remaining spaces are replaced to a chain of spaces and `&nbsp;` (e.g. `'x x'` becomes `'x &nbsp; x'`).\n\t *\n\t * Content of {@link #preElements} is not processed.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node View text node to process.\n\t * @returns {String} Processed text data.\n\t */\n\t_processDataFromViewText( node ) {\n\t\tlet data = node.data;\n\n\t\t// If any of node ancestors has a name which is in `preElements` array, then currently processed\n\t\t// view text node is (will be) in preformatted element. We should not change whitespaces then.\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn data;\n\t\t}\n\n\t\t// 1. Replace the first space with a nbsp if the previous node ends with a space or there is no previous node\n\t\t// (container element boundary).\n\t\tif ( data.charAt( 0 ) == ' ' ) {\n\t\t\tconst prevNode = this._getTouchingViewTextNode( node, false );\n\t\t\tconst prevEndsWithSpace = prevNode && this._nodeEndsWithSpace( prevNode );\n\n\t\t\tif ( prevEndsWithSpace || !prevNode ) {\n\t\t\t\tdata = '\\u00A0' + data.substr( 1 );\n\t\t\t}\n\t\t}\n\n\t\t// 2. Replace the last space with nbsp if there are two spaces at the end or if the next node starts with space or there is no\n\t\t// next node (container element boundary).\n\t\t//\n\t\t// Keep in mind that Firefox prefers $nbsp; before tag, not inside it:\n\t\t//\n\t\t// Foo <span>&nbsp;bar</span> <-- bad.\n\t\t// Foo&nbsp;<span> bar</span> <-- good.\n\t\t//\n\t\t// More here: https://github.com/ckeditor/ckeditor5-engine/issues/1747.\n\t\tif ( data.charAt( data.length - 1 ) == ' ' ) {\n\t\t\tconst nextNode = this._getTouchingViewTextNode( node, true );\n\n\t\t\tif ( data.charAt( data.length - 2 ) == ' ' || !nextNode || nextNode.data.charAt( 0 ) == ' ' ) {\n\t\t\t\tdata = data.substr( 0, data.length - 1 ) + '\\u00A0';\n\t\t\t}\n\t\t}\n\n\t\t// 3. Create space+nbsp pairs.\n\t\treturn data.replace( / {2}/g, ' \\u00A0' );\n\t}\n\n\t/**\n\t * Checks whether given node ends with a space character after changing appropriate space characters to `&nbsp;`s.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node Node to check.\n\t * @returns {Boolean} `true` if given `node` ends with space, `false` otherwise.\n\t */\n\t_nodeEndsWithSpace( node ) {\n\t\tif ( node.getAncestors().some( parent => this.preElements.includes( parent.name ) ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst data = this._processDataFromViewText( node );\n\n\t\treturn data.charAt( data.length - 1 ) == ' ';\n\t}\n\n\t/**\n\t * Takes text data from native `Text` node and processes it to a correct {@link module:engine/view/text~Text view text node} data.\n\t *\n\t * Following changes are done:\n\t *\n\t * * multiple whitespaces are replaced to a single space,\n\t * * space at the beginning of a text node is removed if it is the first text node in its container\n\t * element or if the previous text node ends with a space character,\n\t * * space at the end of the text node is removed if there are two spaces at the end of a node or if next node\n\t * starts with a space or if it is the last text node in its container\n\t * * nbsps are converted to spaces.\n\t *\n\t * @param {Node} node DOM text node to process.\n\t * @returns {String} Processed data.\n\t * @private\n\t */\n\t_processDataFromDomText( node ) {\n\t\tlet data = node.data;\n\n\t\tif ( _hasDomParentOfType( node, this.preElements ) ) {\n\t\t\treturn getDataWithoutFiller( node );\n\t\t}\n\n\t\t// Change all consecutive whitespace characters (from the [ \\n\\t\\r] set \n\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/822#issuecomment-311670249) to a single space character.\n\t\t// That's how multiple whitespaces are treated when rendered, so we normalize those whitespaces.\n\t\t// We're replacing 1+ (and not 2+) to also normalize singular \\n\\t\\r characters (#822).\n\t\tdata = data.replace( /[ \\n\\t\\r]{1,}/g, ' ' );\n\n\t\tconst prevNode = this._getTouchingInlineDomNode( node, false );\n\t\tconst nextNode = this._getTouchingInlineDomNode( node, true );\n\n\t\tconst shouldLeftTrim = this._checkShouldLeftTrimDomText( node, prevNode );\n\t\tconst shouldRightTrim = this._checkShouldRightTrimDomText( node, nextNode );\n\n\t\t// If the previous dom text node does not exist or it ends by whitespace character, remove space character from the beginning\n\t\t// of this text node. Such space character is treated as a whitespace.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^ /, '' );\n\t\t}\n\n\t\t// If the next text node does not exist remove space character from the end of this text node.\n\t\tif ( shouldRightTrim ) {\n\t\t\tdata = data.replace( / $/, '' );\n\t\t}\n\n\t\t// At the beginning and end of a block element, Firefox inserts normal space + <br> instead of non-breaking space.\n\t\t// This means that the text node starts/end with normal space instead of non-breaking space.\n\t\t// This causes a problem because the normal space would be removed in `.replace` calls above. To prevent that,\n\t\t// the inline filler is removed only after the data is initially processed (by the `.replace` above). See ckeditor5#692.\n\t\tdata = getDataWithoutFiller( new Text( data ) );\n\n\t\t// At this point we should have removed all whitespaces from DOM text data.\n\t\t//\n\t\t// Now, We will reverse the process that happens in `_processDataFromViewText`.\n\t\t//\n\t\t// We have to change &nbsp; chars, that were in DOM text data because of rendering reasons, to spaces.\n\t\t// First, change all ` \\u00A0` pairs (space + &nbsp;) to two spaces. DOM converter changes two spaces from model/view to\n\t\t// ` \\u00A0` to ensure proper rendering. Since here we convert back, we recognize those pairs and change them back to ` `.\n\t\tdata = data.replace( / \\u00A0/g, ' ' );\n\n\t\t// Then, let's change the last nbsp to a space.\n\t\tif ( /( |\\u00A0)\\u00A0$/.test( data ) || !nextNode || ( nextNode.data && nextNode.data.charAt( 0 ) == ' ' ) ) {\n\t\t\tdata = data.replace( /\\u00A0$/, ' ' );\n\t\t}\n\n\t\t// Then, change &nbsp; character that is at the beginning of the text node to space character.\n\t\t// We do that replacement only if this is the first node or the previous node ends on whitespace character.\n\t\tif ( shouldLeftTrim ) {\n\t\t\tdata = data.replace( /^\\u00A0/, ' ' );\n\t\t}\n\n\t\t// At this point, all whitespaces should be removed and all &nbsp; created for rendering reasons should be\n\t\t// changed to normal space. All left &nbsp; are &nbsp; inserted intentionally.\n\t\treturn data;\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, preceded by the given `prevNode` should\n\t * be trimmed from the left side.\n\t *\n\t * @private\n\t * @param {Node} node\n\t * @param {Node} prevNode\n\t */\n\t_checkShouldLeftTrimDomText( node, prevNode ) {\n\t\tif ( !prevNode ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( isElement( prevNode ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Shouldn't left trim if previous node is a node that was encountered as a raw content node.\n\t\tif ( this._encounteredRawContentDomNodes.has( node.previousSibling ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn /[^\\S\\u00A0]/.test( prevNode.data.charAt( prevNode.data.length - 1 ) );\n\t}\n\n\t/**\n\t * Helper function which checks if a DOM text node, succeeded by the given `nextNode` should\n\t * be trimmed from the right side.\n\t *\n\t * @private\n\t * @param {Node} node\n\t * @param {Node} nextNode\n\t */\n\t_checkShouldRightTrimDomText( node, nextNode ) {\n\t\tif ( nextNode ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !startsWithFiller( node );\n\t}\n\n\t/**\n\t * Helper function. For given {@link module:engine/view/text~Text view text node}, it finds previous or next sibling\n\t * that is contained in the same container element. If there is no such sibling, `null` is returned.\n\t *\n\t * @private\n\t * @param {module:engine/view/text~Text} node Reference node.\n\t * @param {Boolean} getNext\n\t * @returns {module:engine/view/text~Text|null} Touching text node or `null` if there is no next or previous touching text node.\n\t */\n\t_getTouchingViewTextNode( node, getNext ) {\n\t\tconst treeWalker = new ViewTreeWalker( {\n\t\t\tstartPosition: getNext ? ViewPosition._createAfter( node ) : ViewPosition._createBefore( node ),\n\t\t\tdirection: getNext ? 'forward' : 'backward'\n\t\t} );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\t// ViewContainerElement is found on a way to next ViewText node, so given `node` was first/last\n\t\t\t// text node in its container element.\n\t\t\tif ( value.item.is( 'containerElement' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// <br> found it works like a block boundary, so do not scan further.\n\t\t\telse if ( value.item.is( 'element', 'br' ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// Found a text node in the same container element.\n\t\t\telse if ( value.item.is( '$textProxy' ) ) {\n\t\t\t\treturn value.item;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Helper function. For the given text node, it finds the closest touching node which is either\n\t * a text node or a `<br>`. The search is terminated at block element boundaries and if a matching node\n\t * wasn't found so far, `null` is returned.\n\t *\n\t * In the following DOM structure:\n\t *\n\t *\t\t<p>foo<b>bar</b><br>bom</p>\n\t *\n\t * * `foo` doesn't have its previous touching inline node (`null` is returned),\n\t * * `foo`'s next touching inline node is `bar`\n\t * * `bar`'s next touching inline node is `<br>`\n\t *\n\t * This method returns text nodes and `<br>` elements because these types of nodes affect how\n\t * spaces in the given text node need to be converted.\n\t *\n\t * @private\n\t * @param {Text} node\n\t * @param {Boolean} getNext\n\t * @returns {Text|Element|null}\n\t */\n\t_getTouchingInlineDomNode( node, getNext ) {\n\t\tif ( !node.parentNode ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst direction = getNext ? 'nextNode' : 'previousNode';\n\t\tconst document = node.ownerDocument;\n\t\tconst topmostParent = getAncestors( node )[ 0 ];\n\n\t\tconst treeWalker = document.createTreeWalker( topmostParent, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT, {\n\t\t\tacceptNode( node ) {\n\t\t\t\tif ( isText( node ) ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\tif ( node.tagName == 'BR' ) {\n\t\t\t\t\treturn NodeFilter.FILTER_ACCEPT;\n\t\t\t\t}\n\n\t\t\t\treturn NodeFilter.FILTER_SKIP;\n\t\t\t}\n\t\t} );\n\n\t\ttreeWalker.currentNode = node;\n\n\t\tconst touchingNode = treeWalker[ direction ]();\n\n\t\tif ( touchingNode !== null ) {\n\t\t\tconst lca = getCommonAncestor( node, touchingNode );\n\n\t\t\t// If there is common ancestor between the text node and next/prev text node,\n\t\t\t// and there are no block elements on a way from the text node to that ancestor,\n\t\t\t// and there are no block elements on a way from next/prev text node to that ancestor...\n\t\t\tif (\n\t\t\t\tlca &&\n\t\t\t\t!_hasDomParentOfType( node, this.blockElements, lca ) &&\n\t\t\t\t!_hasDomParentOfType( touchingNode, this.blockElements, lca )\n\t\t\t) {\n\t\t\t\t// Then they are in the same container element.\n\t\t\t\treturn touchingNode;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n// Helper function.\n// Used to check if given native `Element` or `Text` node has parent with tag name from `types` array.\n//\n// @param {Node} node\n// @param {Array.<String>} types\n// @param {Boolean} [boundaryParent] Can be given if parents should be checked up to a given element (excluding that element).\n// @returns {Boolean} `true` if such parent exists or `false` if it does not.\nfunction _hasDomParentOfType( node, types, boundaryParent ) {\n\tlet parents = getAncestors( node );\n\n\tif ( boundaryParent ) {\n\t\tparents = parents.slice( parents.indexOf( boundaryParent ) + 1 );\n\t}\n\n\treturn parents.some( parent => parent.tagName && types.includes( parent.tagName.toLowerCase() ) );\n}\n\n// A helper that executes given callback for each DOM node's ancestor, starting from the given node\n// and ending in document#documentElement.\n//\n// @param {Node} node\n// @param {Function} callback A callback to be executed for each ancestor.\nfunction forEachDomNodeAncestor( node, callback ) {\n\twhile ( node && node != global.document ) {\n\t\tcallback( node );\n\t\tnode = node.parentNode;\n\t}\n}\n\n// Checks if given node is a nbsp block filler.\n//\n// A &nbsp; is a block filler only if it is a single child of a block element.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction isNbspBlockFiller( domNode, blockElements ) {\n\tconst isNBSP = domNode.isEqualNode( NBSP_FILLER_REF );\n\n\treturn isNBSP && hasBlockParent( domNode, blockElements ) && domNode.parentNode.childNodes.length === 1;\n}\n\n// Checks if domNode has block parent.\n//\n// @param {Node} domNode DOM node.\n// @returns {Boolean}\nfunction hasBlockParent( domNode, blockElements ) {\n\tconst parent = domNode.parentNode;\n\n\treturn parent && parent.tagName && blockElements.includes( parent.tagName.toLowerCase() );\n}\n\n/**\n * Enum representing type of the block filler.\n *\n * Possible values:\n *\n * * `br` - for `<br data-cke-filler=\"true\">` block filler used in the editing view,\n * * `nbsp` - for `&nbsp;` block fillers used in the data,\n * * `markedNbsp` - for nbsp block fillers wrapped in a span: `<span data-cke-filler=\"true\">&nbsp;</span>` used in the data.\n *\n * @typedef {String} module:engine/view/filler~BlockFillerMode\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 utils/dom/getcommonancestor\n */\n\nimport getAncestors from './getancestors';\n\n/**\n * Searches and returns the lowest common ancestor of two given nodes.\n *\n * @param {Node} nodeA First node.\n * @param {Node} nodeB Second node.\n * @returns {Node|DocumentFragment|Document|null} Lowest common ancestor of both nodes or `null` if nodes do not have a common ancestor.\n */\nexport default function getCommonAncestor( nodeA, nodeB ) {\n\tconst ancestorsA = getAncestors( nodeA );\n\tconst ancestorsB = getAncestors( nodeB );\n\n\tlet i = 0;\n\n\t// It does not matter which array is shorter.\n\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\ti++;\n\t}\n\n\treturn i === 0 ? null : ancestorsA[ i - 1 ];\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 utils/dom/iswindow\n */\n\n/**\n * Checks if the object is a native DOM Window.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isWindow( obj ) {\n\tconst stringifiedObject = Object.prototype.toString.apply( obj );\n\n\t// Returns `true` for the `window` object in browser environments.\n\tif ( stringifiedObject == '[object Window]' ) {\n\t\treturn true;\n\t}\n\n\t// Returns `true` for the `window` object in the Electron environment.\n\tif ( stringifiedObject == '[object global]' ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/emittermixin\n */\n\nimport { default as EmitterMixin, _getEmitterListenedTo, _setEmitterId } from '../emittermixin';\nimport uid from '../uid';\nimport isNode from './isnode';\nimport isWindow from './iswindow';\nimport { extend } from 'lodash-es';\n\n/**\n * Mixin that injects the DOM events API into its host. It provides the API\n * compatible with {@link module:utils/emittermixin~EmitterMixin}.\n *\n * DOM emitter mixin is by default available in the {@link module:ui/view~View} class,\n * but it can also be mixed into any other class:\n *\n *\t\timport mix from '../utils/mix.js';\n *\t\timport DomEmitterMixin from '../utils/dom/emittermixin.js';\n *\n *\t\tclass SomeView {}\n *\t\tmix( SomeView, DomEmitterMixin );\n *\n *\t\tconst view = new SomeView();\n *\t\tview.listenTo( domElement, ( evt, domEvt ) => {\n *\t\t\tconsole.log( evt, domEvt );\n *\t\t} );\n *\n * @mixin EmitterMixin\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/dom/emittermixin~Emitter\n */\nconst DomEmitterMixin = extend( {}, EmitterMixin, {\n\t/**\n\t * Registers a callback function to be executed when an event is fired in a specific Emitter or DOM Node.\n\t * It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#listenTo}.\n\t *\n\t * @param {module:utils/emittermixin~Emitter|Node} emitter The object that fires the event.\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n\t * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n\t * order they were added.\n\t * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered\n\t * listener before being dispatched to any EventTarget beneath it in the DOM tree.\n\t * @param {Boolean} [options.usePassive=false] Indicates that the function specified by listener will never call preventDefault()\n\t * and prevents blocking browser's main thread by this event handler.\n\t */\n\tlistenTo( emitter, ...rest ) {\n\t\t// Check if emitter is an instance of DOM Node. If so, replace the argument with\n\t\t// corresponding ProxyEmitter (or create one if not existing).\n\t\tif ( isNode( emitter ) || isWindow( emitter ) ) {\n\t\t\tconst proxy = this._getProxyEmitter( emitter ) || new ProxyEmitter( emitter );\n\n\t\t\tproxy.attach( ...rest );\n\n\t\t\temitter = proxy;\n\t\t}\n\n\t\t// Execute parent class method with Emitter (or ProxyEmitter) instance.\n\t\tEmitterMixin.listenTo.call( this, emitter, ...rest );\n\t},\n\n\t/**\n\t * Stops listening for events. It can be used at different levels:\n\t * It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#listenTo}.\n\t *\n\t * * To stop listening to a specific callback.\n\t * * To stop listening to a specific event.\n\t * * To stop listening to all events fired by a specific object.\n\t * * To stop listening to all events fired by all object.\n\t *\n\t * @param {module:utils/emittermixin~Emitter|Node} [emitter] The object to stop listening to. If omitted, stops it for all objects.\n\t * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it\n\t * for all events from `emitter`.\n\t * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given\n\t * `event`.\n\t */\n\tstopListening( emitter, event, callback ) {\n\t\t// Check if emitter is an instance of DOM Node. If so, replace the argument with corresponding ProxyEmitter.\n\t\tif ( isNode( emitter ) || isWindow( emitter ) ) {\n\t\t\tconst proxy = this._getProxyEmitter( emitter );\n\n\t\t\t// Element has no listeners.\n\t\t\tif ( !proxy ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\temitter = proxy;\n\t\t}\n\n\t\t// Execute parent class method with Emitter (or ProxyEmitter) instance.\n\t\tEmitterMixin.stopListening.call( this, emitter, event, callback );\n\n\t\tif ( emitter instanceof ProxyEmitter ) {\n\t\t\temitter.detach( event );\n\t\t}\n\t},\n\n\t/**\n\t * Retrieves ProxyEmitter instance for given DOM Node residing in this Host.\n\t *\n\t * @private\n\t * @param {Node} node DOM Node of the ProxyEmitter.\n\t * @returns {module:utils/dom/emittermixin~ProxyEmitter} ProxyEmitter instance or null.\n\t */\n\t_getProxyEmitter( node ) {\n\t\treturn _getEmitterListenedTo( this, getNodeUID( node ) );\n\t}\n} );\n\nexport default DomEmitterMixin;\n\n/**\n * Creates a ProxyEmitter instance. Such an instance is a bridge between a DOM Node firing events\n * and any Host listening to them. It is backwards compatible with {@link module:utils/emittermixin~EmitterMixin#on}.\n *\n * listenTo( click, ... )\n * +-----------------------------------------+\n * | stopListening( ... ) |\n * +----------------------------+ | addEventListener( click, ... )\n * | Host | | +---------------------------------------------+\n * +----------------------------+ | | removeEventListener( click, ... ) |\n * | _listeningTo: { | +----------v-------------+ |\n * | UID: { | | ProxyEmitter | |\n * | emitter: ProxyEmitter, | +------------------------+ +------------v----------+\n * | callbacks: { | | events: { | | Node (HTMLElement) |\n * | click: [ callbacks ] | | click: [ callbacks ] | +-----------------------+\n * | } | | }, | | data-ck-expando: UID |\n * | } | | _domNode: Node, | +-----------------------+\n * | } | | _domListeners: {}, | |\n * | +------------------------+ | | _emitterId: UID | |\n * | | DomEmitterMixin | | +--------------^---------+ |\n * | +------------------------+ | | | |\n * +--------------^-------------+ | +---------------------------------------------+\n * | | click (DOM Event)\n * +-----------------------------------------+\n * fire( click, DOM Event )\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n * @implements module:utils/dom/emittermixin~Emitter\n * @private\n */\nclass ProxyEmitter {\n\t/**\n\t * @param {Node} node DOM Node that fires events.\n\t * @returns {Object} ProxyEmitter instance bound to the DOM Node.\n\t */\n\tconstructor( node ) {\n\t\t// Set emitter ID to match DOM Node \"expando\" property.\n\t\t_setEmitterId( this, getNodeUID( node ) );\n\n\t\t// Remember the DOM Node this ProxyEmitter is bound to.\n\t\tthis._domNode = node;\n\t}\n}\n\nextend( ProxyEmitter.prototype, EmitterMixin, {\n\t/**\n\t * Collection of native DOM listeners.\n\t *\n\t * @private\n\t * @member {Object} module:utils/dom/emittermixin~ProxyEmitter#_domListeners\n\t */\n\n\t/**\n\t * Registers a callback function to be executed when an event is fired.\n\t *\n\t * It attaches a native DOM listener to the DOM Node. When fired,\n\t * a corresponding Emitter event will also fire with DOM Event object as an argument.\n\t *\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#attach\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered\n\t * listener before being dispatched to any EventTarget beneath it in the DOM tree.\n\t * @param {Boolean} [options.usePassive=false] Indicates that the function specified by listener will never call preventDefault()\n\t * and prevents blocking browser's main thread by this event handler.\n\t */\n\tattach( event, callback, options = {} ) {\n\t\t// If the DOM Listener for given event already exist it is pointless\n\t\t// to attach another one.\n\t\tif ( this._domListeners && this._domListeners[ event ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst listenerOptions = {\n\t\t\tcapture: !!options.useCapture,\n\t\t\tpassive: !!options.usePassive\n\t\t};\n\n\t\tconst domListener = this._createDomListener( event, listenerOptions );\n\n\t\t// Attach the native DOM listener to DOM Node.\n\t\tthis._domNode.addEventListener( event, domListener, listenerOptions );\n\n\t\tif ( !this._domListeners ) {\n\t\t\tthis._domListeners = {};\n\t\t}\n\n\t\t// Store the native DOM listener in this ProxyEmitter. It will be helpful\n\t\t// when stopping listening to the event.\n\t\tthis._domListeners[ event ] = domListener;\n\t},\n\n\t/**\n\t * Stops executing the callback on the given event.\n\t *\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#detach\n\t * @param {String} event The name of the event.\n\t */\n\tdetach( event ) {\n\t\tlet events;\n\n\t\t// Remove native DOM listeners which are orphans. If no callbacks\n\t\t// are awaiting given event, detach native DOM listener from DOM Node.\n\t\t// See: {@link attach}.\n\n\t\tif ( this._domListeners[ event ] && ( !( events = this._events[ event ] ) || !events.callbacks.length ) ) {\n\t\t\tthis._domListeners[ event ].removeListener();\n\t\t}\n\t},\n\n\t/**\n\t * Creates a native DOM listener callback. When the native DOM event\n\t * is fired it will fire corresponding event on this ProxyEmitter.\n\t * Note: A native DOM Event is passed as an argument.\n\t *\n\t * @private\n\t * @method module:utils/dom/emittermixin~ProxyEmitter#_createDomListener\n\t * @param {String} event The name of the event.\n\t * @param {Object} [options] Additional options.\n\t * @param {Boolean} [options.capture=false] Indicates whether the listener was created for capturing event.\n\t * @param {Boolean} [options.passive=false] Indicates that the function specified by listener will never call preventDefault()\n\t * and prevents blocking browser's main thread by this event handler.\n\t * @returns {Function} The DOM listener callback.\n\t */\n\t_createDomListener( event, options ) {\n\t\tconst domListener = domEvt => {\n\t\t\tthis.fire( event, domEvt );\n\t\t};\n\n\t\t// Supply the DOM listener callback with a function that will help\n\t\t// detach it from the DOM Node, when it is no longer necessary.\n\t\t// See: {@link detach}.\n\t\tdomListener.removeListener = () => {\n\t\t\tthis._domNode.removeEventListener( event, domListener, options );\n\t\t\tdelete this._domListeners[ event ];\n\t\t};\n\n\t\treturn domListener;\n\t}\n} );\n\n// Gets an unique DOM Node identifier. The identifier will be set if not defined.\n//\n// @private\n// @param {Node} node\n// @returns {String} UID for given DOM Node.\nfunction getNodeUID( node ) {\n\treturn node[ 'data-ck-expando' ] || ( node[ 'data-ck-expando' ] = uid() );\n}\n\n/**\n * Interface representing classes which mix in {@link module:utils/dom/emittermixin~EmitterMixin}.\n *\n * @interface Emitter\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/view/observer/observer\n */\n\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Abstract base observer class. Observers are classes which listen to DOM events, do the preliminary\n * processing and fire events on the {@link module:engine/view/document~Document} objects.\n * Observers can also add features to the view, for instance by updating its status or marking elements\n * which need a refresh on DOM events.\n *\n * @abstract\n */\nexport default class Observer {\n\t/**\n\t * Creates an instance of the observer.\n\t *\n\t * @param {module:engine/view/view~View} view\n\t */\n\tconstructor( view ) {\n\t\t/**\n\t\t * An instance of the view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View}\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * A reference to the {@link module:engine/view/document~Document} object.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = view.document;\n\n\t\t/**\n\t\t * The state of the observer. If it is disabled, no events will be fired.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.isEnabled = false;\n\t}\n\n\t/**\n\t * Enables the observer. This method is called when the observer is registered to the\n\t * {@link module:engine/view/view~View} and after {@link module:engine/view/view~View#forceRender rendering}\n\t * (all observers are {@link #disable disabled} before rendering).\n\t *\n\t * A typical use case for disabling observers is that mutation observers need to be disabled for the rendering.\n\t * However, a child class may not need to be disabled, so it can implement an empty method.\n\t *\n\t * @see module:engine/view/observer/observer~Observer#disable\n\t */\n\tenable() {\n\t\tthis.isEnabled = true;\n\t}\n\n\t/**\n\t * Disables the observer. This method is called before\n\t * {@link module:engine/view/view~View#forceRender rendering} to prevent firing events during rendering.\n\t *\n\t * @see module:engine/view/observer/observer~Observer#enable\n\t */\n\tdisable() {\n\t\tthis.isEnabled = false;\n\t}\n\n\t/**\n\t * Disables and destroys the observer, among others removes event listeners created by the observer.\n\t */\n\tdestroy() {\n\t\tthis.disable();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether a given DOM event should be ignored (should not be turned into a synthetic view document event).\n\t *\n\t * Currently, an event will be ignored only if its target or any of its ancestors has the `data-cke-ignore-events` attribute.\n\t * This attribute can be used inside the structures generated by\n\t * {@link module:engine/view/downcastwriter~DowncastWriter#createUIElement `DowncastWriter#createUIElement()`} to ignore events\n\t * fired within a UI that should be excluded from CKEditor 5's realms.\n\t *\n\t * @param {Node} domTarget The DOM event target to check (usually an element, sometimes a text node and\n\t * potentially sometimes a document, too).\n\t * @returns {Boolean} Whether this event should be ignored by the observer.\n\t */\n\tcheckShouldIgnoreEventFromTarget( domTarget ) {\n\t\tif ( domTarget && domTarget.nodeType === 3 ) {\n\t\t\tdomTarget = domTarget.parentNode;\n\t\t}\n\n\t\tif ( !domTarget || domTarget.nodeType !== 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn domTarget.matches( '[data-cke-ignore-events], [data-cke-ignore-events] *' );\n\t}\n\n\t/**\n\t * Starts observing the given root element.\n\t *\n\t * @method #observe\n\t * @param {HTMLElement} domElement\n\t * @param {String} name The name of the root element.\n\t */\n}\n\nmix( Observer, DomEmitterMixin );\n","/** Used to stand-in for `undefined` hash values. */\nvar HASH_UNDEFINED = '__lodash_hash_undefined__';\n\n/**\n * Adds `value` to the array cache.\n *\n * @private\n * @name add\n * @memberOf SetCache\n * @alias push\n * @param {*} value The value to cache.\n * @returns {Object} Returns the cache instance.\n */\nfunction setCacheAdd(value) {\n this.__data__.set(value, HASH_UNDEFINED);\n return this;\n}\n\nexport default setCacheAdd;\n","/**\n * Checks if `value` is in the array cache.\n *\n * @private\n * @name has\n * @memberOf SetCache\n * @param {*} value The value to search for.\n * @returns {number} Returns `true` if `value` is found, else `false`.\n */\nfunction setCacheHas(value) {\n return this.__data__.has(value);\n}\n\nexport default setCacheHas;\n","import MapCache from './_MapCache.js';\nimport setCacheAdd from './_setCacheAdd.js';\nimport setCacheHas from './_setCacheHas.js';\n\n/**\n *\n * Creates an array cache object to store unique values.\n *\n * @private\n * @constructor\n * @param {Array} [values] The values to cache.\n */\nfunction SetCache(values) {\n var index = -1,\n length = values == null ? 0 : values.length;\n\n this.__data__ = new MapCache;\n while (++index < length) {\n this.add(values[index]);\n }\n}\n\n// Add methods to `SetCache`.\nSetCache.prototype.add = SetCache.prototype.push = setCacheAdd;\nSetCache.prototype.has = setCacheHas;\n\nexport default SetCache;\n","/**\n * A specialized version of `_.some` for arrays without support for iteratee\n * shorthands.\n *\n * @private\n * @param {Array} [array] The array to iterate over.\n * @param {Function} predicate The function invoked per iteration.\n * @returns {boolean} Returns `true` if any element passes the predicate check,\n * else `false`.\n */\nfunction arraySome(array, predicate) {\n var index = -1,\n length = array == null ? 0 : array.length;\n\n while (++index < length) {\n if (predicate(array[index], index, array)) {\n return true;\n }\n }\n return false;\n}\n\nexport default arraySome;\n","/**\n * Checks if a `cache` value for `key` exists.\n *\n * @private\n * @param {Object} cache The cache to query.\n * @param {string} key The key of the entry to check.\n * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.\n */\nfunction cacheHas(cache, key) {\n return cache.has(key);\n}\n\nexport default cacheHas;\n","import SetCache from './_SetCache.js';\nimport arraySome from './_arraySome.js';\nimport cacheHas from './_cacheHas.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/**\n * A specialized version of `baseIsEqualDeep` for arrays with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Array} array The array to compare.\n * @param {Array} other The other array to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `array` and `other` objects.\n * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.\n */\nfunction equalArrays(array, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n arrLength = array.length,\n othLength = other.length;\n\n if (arrLength != othLength && !(isPartial && othLength > arrLength)) {\n return false;\n }\n // Check that cyclic values are equal.\n var arrStacked = stack.get(array);\n var othStacked = stack.get(other);\n if (arrStacked && othStacked) {\n return arrStacked == other && othStacked == array;\n }\n var index = -1,\n result = true,\n seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;\n\n stack.set(array, other);\n stack.set(other, array);\n\n // Ignore non-index properties.\n while (++index < arrLength) {\n var arrValue = array[index],\n othValue = other[index];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, arrValue, index, other, array, stack)\n : customizer(arrValue, othValue, index, array, other, stack);\n }\n if (compared !== undefined) {\n if (compared) {\n continue;\n }\n result = false;\n break;\n }\n // Recursively compare arrays (susceptible to call stack limits).\n if (seen) {\n if (!arraySome(other, function(othValue, othIndex) {\n if (!cacheHas(seen, othIndex) &&\n (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {\n return seen.push(othIndex);\n }\n })) {\n result = false;\n break;\n }\n } else if (!(\n arrValue === othValue ||\n equalFunc(arrValue, othValue, bitmask, customizer, stack)\n )) {\n result = false;\n break;\n }\n }\n stack['delete'](array);\n stack['delete'](other);\n return result;\n}\n\nexport default equalArrays;\n","/**\n * Converts `map` to its key-value pairs.\n *\n * @private\n * @param {Object} map The map to convert.\n * @returns {Array} Returns the key-value pairs.\n */\nfunction mapToArray(map) {\n var index = -1,\n result = Array(map.size);\n\n map.forEach(function(value, key) {\n result[++index] = [key, value];\n });\n return result;\n}\n\nexport default mapToArray;\n","/**\n * Converts `set` to an array of its values.\n *\n * @private\n * @param {Object} set The set to convert.\n * @returns {Array} Returns the values.\n */\nfunction setToArray(set) {\n var index = -1,\n result = Array(set.size);\n\n set.forEach(function(value) {\n result[++index] = value;\n });\n return result;\n}\n\nexport default setToArray;\n","import Symbol from './_Symbol.js';\nimport Uint8Array from './_Uint8Array.js';\nimport eq from './eq.js';\nimport equalArrays from './_equalArrays.js';\nimport mapToArray from './_mapToArray.js';\nimport setToArray from './_setToArray.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1,\n COMPARE_UNORDERED_FLAG = 2;\n\n/** `Object#toString` result references. */\nvar boolTag = '[object Boolean]',\n dateTag = '[object Date]',\n errorTag = '[object Error]',\n mapTag = '[object Map]',\n numberTag = '[object Number]',\n regexpTag = '[object RegExp]',\n setTag = '[object Set]',\n stringTag = '[object String]',\n symbolTag = '[object Symbol]';\n\nvar arrayBufferTag = '[object ArrayBuffer]',\n dataViewTag = '[object DataView]';\n\n/** Used to convert symbols to primitives and strings. */\nvar symbolProto = Symbol ? Symbol.prototype : undefined,\n symbolValueOf = symbolProto ? symbolProto.valueOf : undefined;\n\n/**\n * A specialized version of `baseIsEqualDeep` for comparing objects of\n * the same `toStringTag`.\n *\n * **Note:** This function only supports comparing values with tags of\n * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {string} tag The `toStringTag` of the objects to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {\n switch (tag) {\n case dataViewTag:\n if ((object.byteLength != other.byteLength) ||\n (object.byteOffset != other.byteOffset)) {\n return false;\n }\n object = object.buffer;\n other = other.buffer;\n\n case arrayBufferTag:\n if ((object.byteLength != other.byteLength) ||\n !equalFunc(new Uint8Array(object), new Uint8Array(other))) {\n return false;\n }\n return true;\n\n case boolTag:\n case dateTag:\n case numberTag:\n // Coerce booleans to `1` or `0` and dates to milliseconds.\n // Invalid dates are coerced to `NaN`.\n return eq(+object, +other);\n\n case errorTag:\n return object.name == other.name && object.message == other.message;\n\n case regexpTag:\n case stringTag:\n // Coerce regexes to strings and treat strings, primitives and objects,\n // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring\n // for more details.\n return object == (other + '');\n\n case mapTag:\n var convert = mapToArray;\n\n case setTag:\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG;\n convert || (convert = setToArray);\n\n if (object.size != other.size && !isPartial) {\n return false;\n }\n // Assume cyclic values are equal.\n var stacked = stack.get(object);\n if (stacked) {\n return stacked == other;\n }\n bitmask |= COMPARE_UNORDERED_FLAG;\n\n // Recursively compare objects (susceptible to call stack limits).\n stack.set(object, other);\n var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);\n stack['delete'](object);\n return result;\n\n case symbolTag:\n if (symbolValueOf) {\n return symbolValueOf.call(object) == symbolValueOf.call(other);\n }\n }\n return false;\n}\n\nexport default equalByTag;\n","import getAllKeys from './_getAllKeys.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of `baseIsEqualDeep` for objects with support for\n * partial deep comparisons.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} stack Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction equalObjects(object, other, bitmask, customizer, equalFunc, stack) {\n var isPartial = bitmask & COMPARE_PARTIAL_FLAG,\n objProps = getAllKeys(object),\n objLength = objProps.length,\n othProps = getAllKeys(other),\n othLength = othProps.length;\n\n if (objLength != othLength && !isPartial) {\n return false;\n }\n var index = objLength;\n while (index--) {\n var key = objProps[index];\n if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {\n return false;\n }\n }\n // Check that cyclic values are equal.\n var objStacked = stack.get(object);\n var othStacked = stack.get(other);\n if (objStacked && othStacked) {\n return objStacked == other && othStacked == object;\n }\n var result = true;\n stack.set(object, other);\n stack.set(other, object);\n\n var skipCtor = isPartial;\n while (++index < objLength) {\n key = objProps[index];\n var objValue = object[key],\n othValue = other[key];\n\n if (customizer) {\n var compared = isPartial\n ? customizer(othValue, objValue, key, other, object, stack)\n : customizer(objValue, othValue, key, object, other, stack);\n }\n // Recursively compare objects (susceptible to call stack limits).\n if (!(compared === undefined\n ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))\n : compared\n )) {\n result = false;\n break;\n }\n skipCtor || (skipCtor = key == 'constructor');\n }\n if (result && !skipCtor) {\n var objCtor = object.constructor,\n othCtor = other.constructor;\n\n // Non `Object` object instances with different constructors are not equal.\n if (objCtor != othCtor &&\n ('constructor' in object && 'constructor' in other) &&\n !(typeof objCtor == 'function' && objCtor instanceof objCtor &&\n typeof othCtor == 'function' && othCtor instanceof othCtor)) {\n result = false;\n }\n }\n stack['delete'](object);\n stack['delete'](other);\n return result;\n}\n\nexport default equalObjects;\n","import Stack from './_Stack.js';\nimport equalArrays from './_equalArrays.js';\nimport equalByTag from './_equalByTag.js';\nimport equalObjects from './_equalObjects.js';\nimport getTag from './_getTag.js';\nimport isArray from './isArray.js';\nimport isBuffer from './isBuffer.js';\nimport isTypedArray from './isTypedArray.js';\n\n/** Used to compose bitmasks for value comparisons. */\nvar COMPARE_PARTIAL_FLAG = 1;\n\n/** `Object#toString` result references. */\nvar argsTag = '[object Arguments]',\n arrayTag = '[object Array]',\n objectTag = '[object Object]';\n\n/** Used for built-in method references. */\nvar objectProto = Object.prototype;\n\n/** Used to check objects for own properties. */\nvar hasOwnProperty = objectProto.hasOwnProperty;\n\n/**\n * A specialized version of `baseIsEqual` for arrays and objects which performs\n * deep comparisons and tracks traversed objects enabling objects with circular\n * references to be compared.\n *\n * @private\n * @param {Object} object The object to compare.\n * @param {Object} other The other object to compare.\n * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.\n * @param {Function} customizer The function to customize comparisons.\n * @param {Function} equalFunc The function to determine equivalents of values.\n * @param {Object} [stack] Tracks traversed `object` and `other` objects.\n * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.\n */\nfunction baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {\n var objIsArr = isArray(object),\n othIsArr = isArray(other),\n objTag = objIsArr ? arrayTag : getTag(object),\n othTag = othIsArr ? arrayTag : getTag(other);\n\n objTag = objTag == argsTag ? objectTag : objTag;\n othTag = othTag == argsTag ? objectTag : othTag;\n\n var objIsObj = objTag == objectTag,\n othIsObj = othTag == objectTag,\n isSameTag = objTag == othTag;\n\n if (isSameTag && isBuffer(object)) {\n if (!isBuffer(other)) {\n return false;\n }\n objIsArr = true;\n objIsObj = false;\n }\n if (isSameTag && !objIsObj) {\n stack || (stack = new Stack);\n return (objIsArr || isTypedArray(object))\n ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)\n : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);\n }\n if (!(bitmask & COMPARE_PARTIAL_FLAG)) {\n var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),\n othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');\n\n if (objIsWrapped || othIsWrapped) {\n var objUnwrapped = objIsWrapped ? object.value() : object,\n othUnwrapped = othIsWrapped ? other.value() : other;\n\n stack || (stack = new Stack);\n return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);\n }\n }\n if (!isSameTag) {\n return false;\n }\n stack || (stack = new Stack);\n return equalObjects(object, other, bitmask, customizer, equalFunc, stack);\n}\n\nexport default baseIsEqualDeep;\n","import baseIsEqualDeep from './_baseIsEqualDeep.js';\nimport isObjectLike from './isObjectLike.js';\n\n/**\n * The base implementation of `_.isEqual` which supports partial comparisons\n * and tracks traversed objects.\n *\n * @private\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {boolean} bitmask The bitmask flags.\n * 1 - Unordered comparison\n * 2 - Partial comparison\n * @param {Function} [customizer] The function to customize comparisons.\n * @param {Object} [stack] Tracks traversed `value` and `other` objects.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n */\nfunction baseIsEqual(value, other, bitmask, customizer, stack) {\n if (value === other) {\n return true;\n }\n if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {\n return value !== value && other !== other;\n }\n return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);\n}\n\nexport default baseIsEqual;\n","import baseIsEqual from './_baseIsEqual.js';\n\n/**\n * This method is like `_.isEqual` except that it accepts `customizer` which\n * is invoked to compare values. If `customizer` returns `undefined`, comparisons\n * are handled by the method instead. The `customizer` is invoked with up to\n * six arguments: (objValue, othValue [, index|key, object, other, stack]).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {Function} [customizer] The function to customize comparisons.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * function isGreeting(value) {\n * return /^h(?:i|ello)$/.test(value);\n * }\n *\n * function customizer(objValue, othValue) {\n * if (isGreeting(objValue) && isGreeting(othValue)) {\n * return true;\n * }\n * }\n *\n * var array = ['hello', 'goodbye'];\n * var other = ['hi', 'goodbye'];\n *\n * _.isEqualWith(array, other, customizer);\n * // => true\n */\nfunction isEqualWith(value, other, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n var result = customizer ? customizer(value, other) : undefined;\n return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;\n}\n\nexport default isEqualWith;\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/view/observer/mutationobserver\n */\n\n/* globals window */\n\nimport Observer from './observer';\nimport ViewSelection from '../selection';\nimport { startsWithFiller, getDataWithoutFiller } from '../filler';\nimport { isEqualWith } from 'lodash-es';\n\n/**\n * Mutation observer class observes changes in the DOM, fires {@link module:engine/view/document~Document#event:mutations} event, mark view\n * elements as changed and call {@link module:engine/view/renderer~Renderer#render}.\n * Because all mutated nodes are marked as \"to be rendered\" and the\n * {@link module:engine/view/renderer~Renderer#render} is called, all changes will be reverted, unless the mutation will be handled by the\n * {@link module:engine/view/document~Document#event:mutations} event listener. It means user will see only handled changes, and the editor\n * will block all changes which are not handled.\n *\n * Mutation Observer also take care of reducing number of mutations which are fired. It removes duplicates and\n * mutations on elements which do not have corresponding view elements. Also\n * {@link module:engine/view/observer/mutationobserver~MutatedText text mutation} is fired only if parent element do not change child list.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class MutationObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Native mutation observer config.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._config = {\n\t\t\tchildList: true,\n\t\t\tcharacterData: true,\n\t\t\tcharacterDataOldValue: true,\n\t\t\tsubtree: true\n\t\t};\n\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#domConverter}.\n\t\t *\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = view.domConverter;\n\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#_renderer}.\n\t\t *\n\t\t * @member {module:engine/view/renderer~Renderer}\n\t\t */\n\t\tthis.renderer = view._renderer;\n\n\t\t/**\n\t\t * Observed DOM elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<HTMLElement>}\n\t\t */\n\t\tthis._domElements = [];\n\n\t\t/**\n\t\t * Native mutation observer.\n\t\t *\n\t\t * @private\n\t\t * @member {MutationObserver}\n\t\t */\n\t\tthis._mutationObserver = new window.MutationObserver( this._onMutations.bind( this ) );\n\t}\n\n\t/**\n\t * Synchronously fires {@link module:engine/view/document~Document#event:mutations} event with all mutations in record queue.\n\t * At the same time empties the queue so mutations will not be fired twice.\n\t */\n\tflush() {\n\t\tthis._onMutations( this._mutationObserver.takeRecords() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tthis._domElements.push( domElement );\n\n\t\tif ( this.isEnabled ) {\n\t\t\tthis._mutationObserver.observe( domElement, this._config );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tenable() {\n\t\tsuper.enable();\n\n\t\tfor ( const domElement of this._domElements ) {\n\t\t\tthis._mutationObserver.observe( domElement, this._config );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdisable() {\n\t\tsuper.disable();\n\n\t\tthis._mutationObserver.disconnect();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._mutationObserver.disconnect();\n\t}\n\n\t/**\n\t * Handles mutations. Deduplicates, mark view elements to sync, fire event and call render.\n\t *\n\t * @private\n\t * @param {Array.<Object>} domMutations Array of native mutations.\n\t */\n\t_onMutations( domMutations ) {\n\t\t// As a result of this.flush() we can have an empty collection.\n\t\tif ( domMutations.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domConverter = this.domConverter;\n\n\t\t// Use map and set for deduplication.\n\t\tconst mutatedTexts = new Map();\n\t\tconst mutatedElements = new Set();\n\n\t\t// Handle `childList` mutations first, so we will be able to check if the `characterData` mutation is in the\n\t\t// element with changed structure anyway.\n\t\tfor ( const mutation of domMutations ) {\n\t\t\tif ( mutation.type === 'childList' ) {\n\t\t\t\tconst element = domConverter.mapDomToView( mutation.target );\n\n\t\t\t\t// Do not collect mutations from UIElements and RawElements.\n\t\t\t\tif ( element && ( element.is( 'uiElement' ) || element.is( 'rawElement' ) ) ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif ( element && !this._isBogusBrMutation( mutation ) ) {\n\t\t\t\t\tmutatedElements.add( element );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Handle `characterData` mutations later, when we have the full list of nodes which changed structure.\n\t\tfor ( const mutation of domMutations ) {\n\t\t\tconst element = domConverter.mapDomToView( mutation.target );\n\n\t\t\t// Do not collect mutations from UIElements and RawElements.\n\t\t\tif ( element && ( element.is( 'uiElement' ) || element.is( 'rawElement' ) ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif ( mutation.type === 'characterData' ) {\n\t\t\t\tconst text = domConverter.findCorrespondingViewText( mutation.target );\n\n\t\t\t\tif ( text && !mutatedElements.has( text.parent ) ) {\n\t\t\t\t\t// Use text as a key, for deduplication. If there will be another mutation on the same text element\n\t\t\t\t\t// we will have only one in the map.\n\t\t\t\t\tmutatedTexts.set( text, {\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\toldText: text.data,\n\t\t\t\t\t\tnewText: getDataWithoutFiller( mutation.target ),\n\t\t\t\t\t\tnode: text\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t// When we added first letter to the text node which had only inline filler, for the DOM it is mutation\n\t\t\t\t// on text, but for the view, where filler text node did not existed, new text node was created, so we\n\t\t\t\t// need to fire 'children' mutation instead of 'text'.\n\t\t\t\telse if ( !text && startsWithFiller( mutation.target ) ) {\n\t\t\t\t\tmutatedElements.add( domConverter.mapDomToView( mutation.target.parentNode ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Now we build the list of mutations to fire and mark elements. We did not do it earlier to avoid marking the\n\t\t// same node multiple times in case of duplication.\n\n\t\t// List of mutations we will fire.\n\t\tconst viewMutations = [];\n\n\t\tfor ( const mutatedText of mutatedTexts.values() ) {\n\t\t\tthis.renderer.markToSync( 'text', mutatedText.node );\n\t\t\tviewMutations.push( mutatedText );\n\t\t}\n\n\t\tfor ( const viewElement of mutatedElements ) {\n\t\t\tconst domElement = domConverter.mapViewToDom( viewElement );\n\t\t\tconst viewChildren = Array.from( viewElement.getChildren() );\n\t\t\tconst newViewChildren = Array.from( domConverter.domChildrenToView( domElement, { withChildren: false } ) );\n\n\t\t\t// It may happen that as a result of many changes (sth was inserted and then removed),\n\t\t\t// both elements haven't really changed. #1031\n\t\t\tif ( !isEqualWith( viewChildren, newViewChildren, sameNodes ) ) {\n\t\t\t\tthis.renderer.markToSync( 'children', viewElement );\n\n\t\t\t\tviewMutations.push( {\n\t\t\t\t\ttype: 'children',\n\t\t\t\t\toldChildren: viewChildren,\n\t\t\t\t\tnewChildren: newViewChildren,\n\t\t\t\t\tnode: viewElement\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\t// Retrieve `domSelection` using `ownerDocument` of one of mutated nodes.\n\t\t// There should not be simultaneous mutation in multiple documents, so it's fine.\n\t\tconst domSelection = domMutations[ 0 ].target.ownerDocument.getSelection();\n\n\t\tlet viewSelection = null;\n\n\t\tif ( domSelection && domSelection.anchorNode ) {\n\t\t\t// If `domSelection` is inside a dom node that is already bound to a view node from view tree, get\n\t\t\t// corresponding selection in the view and pass it together with `viewMutations`. The `viewSelection` may\n\t\t\t// be used by features handling mutations.\n\t\t\t// Only one range is supported.\n\n\t\t\tconst viewSelectionAnchor = domConverter.domPositionToView( domSelection.anchorNode, domSelection.anchorOffset );\n\t\t\tconst viewSelectionFocus = domConverter.domPositionToView( domSelection.focusNode, domSelection.focusOffset );\n\n\t\t\t// Anchor and focus has to be properly mapped to view.\n\t\t\tif ( viewSelectionAnchor && viewSelectionFocus ) {\n\t\t\t\tviewSelection = new ViewSelection( viewSelectionAnchor );\n\t\t\t\tviewSelection.setFocus( viewSelectionFocus );\n\t\t\t}\n\t\t}\n\n\t\t// In case only non-relevant mutations were recorded it skips the event and force render (#5600).\n\t\tif ( viewMutations.length ) {\n\t\t\tthis.document.fire( 'mutations', viewMutations, viewSelection );\n\n\t\t\t// If nothing changes on `mutations` event, at this point we have \"dirty DOM\" (changed) and de-synched\n\t\t\t// view (which has not been changed). In order to \"reset DOM\" we render the view again.\n\t\t\tthis.view.forceRender();\n\t\t}\n\n\t\tfunction sameNodes( child1, child2 ) {\n\t\t\t// First level of comparison (array of children vs array of children) use the Lodash's default behavior.\n\t\t\tif ( Array.isArray( child1 ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Elements.\n\t\t\tif ( child1 === child2 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// Texts.\n\t\t\telse if ( child1.is( '$text' ) && child2.is( '$text' ) ) {\n\t\t\t\treturn child1.data === child2.data;\n\t\t\t}\n\n\t\t\t// Not matching types.\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Checks if mutation was generated by the browser inserting bogus br on the end of the block element.\n\t * Such mutations are generated while pressing space or performing native spellchecker correction\n\t * on the end of the block element in Firefox browser.\n\t *\n\t * @private\n\t * @param {Object} mutation Native mutation object.\n\t * @returns {Boolean}\n\t */\n\t_isBogusBrMutation( mutation ) {\n\t\tlet addedNode = null;\n\n\t\t// Check if mutation added only one node on the end of its parent.\n\t\tif ( mutation.nextSibling === null && mutation.removedNodes.length === 0 && mutation.addedNodes.length == 1 ) {\n\t\t\taddedNode = this.domConverter.domToView( mutation.addedNodes[ 0 ], {\n\t\t\t\twithChildren: false\n\t\t\t} );\n\t\t}\n\n\t\treturn addedNode && addedNode.is( 'element', 'br' );\n\t}\n}\n\n/**\n * Fired when mutation occurred. If tree view is not changed on this event, DOM will be reverted to the state before\n * mutation, so all changes which should be applied, should be handled on this event.\n *\n * Introduced by {@link module:engine/view/observer/mutationobserver~MutationObserver}.\n *\n * Note that because {@link module:engine/view/observer/mutationobserver~MutationObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/mutationobserver~MutationObserver\n * @event module:engine/view/document~Document#event:mutations\n * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|module:engine/view/observer/mutationobserver~MutatedChildren>}\n * viewMutations Array of mutations.\n * For mutated texts it will be {@link module:engine/view/observer/mutationobserver~MutatedText} and for mutated elements it will be\n * {@link module:engine/view/observer/mutationobserver~MutatedChildren}. You can recognize the type based on the `type` property.\n * @param {module:engine/view/selection~Selection|null} viewSelection View selection that is a result of converting DOM selection to view.\n * Keep in\n * mind that the DOM selection is already \"updated\", meaning that it already acknowledges changes done in mutation.\n */\n\n/**\n * Mutation item for text.\n *\n * @see module:engine/view/document~Document#event:mutations\n * @see module:engine/view/observer/mutationobserver~MutatedChildren\n *\n * @typedef {Object} module:engine/view/observer/mutationobserver~MutatedText\n *\n * @property {String} type For text mutations it is always 'text'.\n * @property {module:engine/view/text~Text} node Mutated text node.\n * @property {String} oldText Old text.\n * @property {String} newText New text.\n */\n\n/**\n * Mutation item for child nodes.\n *\n * @see module:engine/view/document~Document#event:mutations\n * @see module:engine/view/observer/mutationobserver~MutatedText\n *\n * @typedef {Object} module:engine/view/observer/mutationobserver~MutatedChildren\n *\n * @property {String} type For child nodes mutations it is always 'children'.\n * @property {module:engine/view/element~Element} node Parent of the mutated children.\n * @property {Array.<module:engine/view/node~Node>} oldChildren Old child nodes.\n * @property {Array.<module:engine/view/node~Node>} newChildren New child nodes.\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/view/observer/domeventdata\n */\n\nimport { extend } from 'lodash-es';\n\n/**\n * Information about a DOM event in context of the {@link module:engine/view/document~Document}.\n * It wraps the native event, which usually should not be used as the wrapper contains\n * additional data (like key code for keyboard events).\n */\nexport default class DomEventData {\n\t/**\n\t * @param {module:engine/view/view~View} view The instance of the view controller.\n\t * @param {Event} domEvent The DOM event.\n\t * @param {Object} [additionalData] Additional properties that the instance should contain.\n\t */\n\tconstructor( view, domEvent, additionalData ) {\n\t\t/**\n\t\t * Instance of the view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View} module:engine/view/observer/observer~Observer.DomEvent#view\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * The instance of the document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document} module:engine/view/observer/observer~Observer.DomEvent#document\n\t\t */\n\t\tthis.document = view.document;\n\n\t\t/**\n\t\t * The DOM event.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Event} module:engine/view/observer/observer~Observer.DomEvent#domEvent\n\t\t */\n\t\tthis.domEvent = domEvent;\n\n\t\t/**\n\t\t * The DOM target.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement} module:engine/view/observer/observer~Observer.DomEvent#target\n\t\t */\n\t\tthis.domTarget = domEvent.target;\n\n\t\textend( this, additionalData );\n\t}\n\n\t/**\n\t * The tree view element representing the target.\n\t *\n\t * @readonly\n\t * @type module:engine/view/element~Element\n\t */\n\tget target() {\n\t\treturn this.view.domConverter.mapDomToView( this.domTarget );\n\t}\n\n\t/**\n\t * Prevents the native's event default action.\n\t */\n\tpreventDefault() {\n\t\tthis.domEvent.preventDefault();\n\t}\n\n\t/**\n\t * Stops native event propagation.\n\t */\n\tstopPropagation() {\n\t\tthis.domEvent.stopPropagation();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/domeventobserver\n */\n\nimport Observer from './observer';\nimport DomEventData from './domeventdata';\n\n/**\n * Base class for DOM event observers. This class handles\n * {@link module:engine/view/observer/observer~Observer#observe adding} listeners to DOM elements,\n * {@link module:engine/view/observer/observer~Observer#disable disabling} and\n * {@link module:engine/view/observer/observer~Observer#enable re-enabling} events.\n * Child class needs to define\n * {@link module:engine/view/observer/domeventobserver~DomEventObserver#domEventType DOM event type} and\n * {@link module:engine/view/observer/domeventobserver~DomEventObserver#onDomEvent callback}.\n *\n * For instance:\n *\n *\t\tclass ClickObserver extends DomEventObserver {\n *\t\t\t// It can also be defined as a normal property in the constructor.\n *\t\t\tget domEventType() {\n *\t\t\t\treturn 'click';\n *\t\t\t}\n *\n *\t\t\tonDomEvent( domEvent ) {\n *\t\t\t\tthis.fire( 'click', domEvent );\n *\t\t\t}\n *\t\t}\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class DomEventObserver extends Observer {\n\t/**\n\t * Type of the DOM event the observer should listen to. Array of types can be defined\n\t * if the observer should listen to multiple DOM events.\n\t *\n\t * @readonly\n\t * @member {String|Array.<String>} #domEventType\n\t */\n\n\t/**\n\t * Callback which should be called when the DOM event occurred. Note that the callback will not be called if\n\t * observer {@link #isEnabled is not enabled}.\n\t *\n\t * @see #domEventType\n\t * @abstract\n\t * @method #onDomEvent\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * If set to `true` DOM events will be listened on the capturing phase.\n\t\t * Default value is `false`.\n\t\t *\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.useCapture = false;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tconst types = typeof this.domEventType == 'string' ? [ this.domEventType ] : this.domEventType;\n\n\t\ttypes.forEach( type => {\n\t\t\tthis.listenTo( domElement, type, ( eventInfo, domEvent ) => {\n\t\t\t\tif ( this.isEnabled && !this.checkShouldIgnoreEventFromTarget( domEvent.target ) ) {\n\t\t\t\t\tthis.onDomEvent( domEvent );\n\t\t\t\t}\n\t\t\t}, { useCapture: this.useCapture } );\n\t\t} );\n\t}\n\n\t/**\n\t * Calls `Document#fire()` if observer {@link #isEnabled is enabled}.\n\t *\n\t * @see module:utils/emittermixin~EmitterMixin#fire\n\t * @param {String} eventType The event type (name).\n\t * @param {Event} domEvent The DOM event.\n\t * @param {Object} [additionalData] The additional data which should extend the\n\t * {@link module:engine/view/observer/domeventdata~DomEventData event data} object.\n\t */\n\tfire( eventType, domEvent, additionalData ) {\n\t\tif ( this.isEnabled ) {\n\t\t\tthis.document.fire( eventType, new DomEventData( this.view, domEvent, additionalData ) );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/keyobserver\n */\n\nimport DomEventObserver from './domeventobserver';\nimport { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * Observer for events connected with pressing keyboard keys.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class KeyObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'keydown', 'keyup' ];\n\t}\n\n\tonDomEvent( domEvt ) {\n\t\tthis.fire( domEvt.type, domEvt, {\n\t\t\tkeyCode: domEvt.keyCode,\n\n\t\t\taltKey: domEvt.altKey,\n\t\t\tctrlKey: domEvt.ctrlKey,\n\t\t\tshiftKey: domEvt.shiftKey,\n\t\t\tmetaKey: domEvt.metaKey,\n\n\t\t\tget keystroke() {\n\t\t\t\treturn getCode( this );\n\t\t\t}\n\t\t} );\n\t}\n}\n\n/**\n * Fired when a key has been pressed.\n *\n * Introduced by {@link module:engine/view/observer/keyobserver~KeyObserver}.\n *\n * Note that because {@link module:engine/view/observer/keyobserver~KeyObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/keyobserver~KeyObserver\n * @event module:engine/view/document~Document#event:keydown\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEventData\n */\n\n/**\n * Fired when a key has been released.\n *\n * Introduced by {@link module:engine/view/observer/keyobserver~KeyObserver}.\n *\n * Note that because {@link module:engine/view/observer/keyobserver~KeyObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/keyobserver~KeyObserver\n * @event module:engine/view/document~Document#event:keyup\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEventData\n */\n\n/**\n * The value of both events - {@link module:engine/view/document~Document#event:keydown} and\n * {@link module:engine/view/document~Document#event:keyup}.\n *\n * @class module:engine/view/observer/keyobserver~KeyEventData\n * @extends module:engine/view/observer/domeventdata~DomEventData\n * @implements module:utils/keyboard~KeystrokeInfo\n */\n\n/**\n * Code of the whole keystroke. See {@link module:utils/keyboard~getCode}.\n *\n * @readonly\n * @member {Number} module:engine/view/observer/keyobserver~KeyEventData#keystroke\n */\n","import root from './_root.js';\n\n/**\n * Gets the timestamp of the number of milliseconds that have elapsed since\n * the Unix epoch (1 January 1970 00:00:00 UTC).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Date\n * @returns {number} Returns the timestamp.\n * @example\n *\n * _.defer(function(stamp) {\n * console.log(_.now() - stamp);\n * }, _.now());\n * // => Logs the number of milliseconds it took for the deferred invocation.\n */\nvar now = function() {\n return root.Date.now();\n};\n\nexport default now;\n","/** Used to match a single whitespace character. */\nvar reWhitespace = /\\s/;\n\n/**\n * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace\n * character of `string`.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {number} Returns the index of the last non-whitespace character.\n */\nfunction trimmedEndIndex(string) {\n var index = string.length;\n\n while (index-- && reWhitespace.test(string.charAt(index))) {}\n return index;\n}\n\nexport default trimmedEndIndex;\n","import trimmedEndIndex from './_trimmedEndIndex.js';\n\n/** Used to match leading whitespace. */\nvar reTrimStart = /^\\s+/;\n\n/**\n * The base implementation of `_.trim`.\n *\n * @private\n * @param {string} string The string to trim.\n * @returns {string} Returns the trimmed string.\n */\nfunction baseTrim(string) {\n return string\n ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')\n : string;\n}\n\nexport default baseTrim;\n","import baseTrim from './_baseTrim.js';\nimport isObject from './isObject.js';\nimport isSymbol from './isSymbol.js';\n\n/** Used as references for various `Number` constants. */\nvar NAN = 0 / 0;\n\n/** Used to detect bad signed hexadecimal string values. */\nvar reIsBadHex = /^[-+]0x[0-9a-f]+$/i;\n\n/** Used to detect binary string values. */\nvar reIsBinary = /^0b[01]+$/i;\n\n/** Used to detect octal string values. */\nvar reIsOctal = /^0o[0-7]+$/i;\n\n/** Built-in method references without a dependency on `root`. */\nvar freeParseInt = parseInt;\n\n/**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\nfunction toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n}\n\nexport default toNumber;\n","import isObject from './isObject.js';\nimport now from './now.js';\nimport toNumber from './toNumber.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/* Built-in method references for those with the same name as other `lodash` methods. */\nvar nativeMax = Math.max,\n nativeMin = Math.min;\n\n/**\n * Creates a debounced function that delays invoking `func` until after `wait`\n * milliseconds have elapsed since the last time the debounced function was\n * invoked. The debounced function comes with a `cancel` method to cancel\n * delayed `func` invocations and a `flush` method to immediately invoke them.\n * Provide `options` to indicate whether `func` should be invoked on the\n * leading and/or trailing edge of the `wait` timeout. The `func` is invoked\n * with the last arguments provided to the debounced function. Subsequent\n * calls to the debounced function return the result of the last `func`\n * invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the debounced function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.debounce` and `_.throttle`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to debounce.\n * @param {number} [wait=0] The number of milliseconds to delay.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=false]\n * Specify invoking on the leading edge of the timeout.\n * @param {number} [options.maxWait]\n * The maximum time `func` is allowed to be delayed before it's invoked.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new debounced function.\n * @example\n *\n * // Avoid costly calculations while the window size is in flux.\n * jQuery(window).on('resize', _.debounce(calculateLayout, 150));\n *\n * // Invoke `sendMail` when clicked, debouncing subsequent calls.\n * jQuery(element).on('click', _.debounce(sendMail, 300, {\n * 'leading': true,\n * 'trailing': false\n * }));\n *\n * // Ensure `batchLog` is invoked once after 1 second of debounced calls.\n * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });\n * var source = new EventSource('/stream');\n * jQuery(source).on('message', debounced);\n *\n * // Cancel the trailing debounced invocation.\n * jQuery(window).on('popstate', debounced.cancel);\n */\nfunction debounce(func, wait, options) {\n var lastArgs,\n lastThis,\n maxWait,\n result,\n timerId,\n lastCallTime,\n lastInvokeTime = 0,\n leading = false,\n maxing = false,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n wait = toNumber(wait) || 0;\n if (isObject(options)) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n\n function invokeFunc(time) {\n var args = lastArgs,\n thisArg = lastThis;\n\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n\n function leadingEdge(time) {\n // Reset any `maxWait` timer.\n lastInvokeTime = time;\n // Start the timer for the trailing edge.\n timerId = setTimeout(timerExpired, wait);\n // Invoke the leading edge.\n return leading ? invokeFunc(time) : result;\n }\n\n function remainingWait(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime,\n timeWaiting = wait - timeSinceLastCall;\n\n return maxing\n ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n\n function shouldInvoke(time) {\n var timeSinceLastCall = time - lastCallTime,\n timeSinceLastInvoke = time - lastInvokeTime;\n\n // Either this is the first call, activity has stopped and we're at the\n // trailing edge, the system time has gone backwards and we're treating\n // it as the trailing edge, or we've hit the `maxWait` limit.\n return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||\n (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));\n }\n\n function timerExpired() {\n var time = now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n // Restart the timer.\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n\n function trailingEdge(time) {\n timerId = undefined;\n\n // Only invoke if we have `lastArgs` which means `func` has been\n // debounced at least once.\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n\n function flush() {\n return timerId === undefined ? result : trailingEdge(now());\n }\n\n function debounced() {\n var time = now(),\n isInvoking = shouldInvoke(time);\n\n lastArgs = arguments;\n lastThis = this;\n lastCallTime = time;\n\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n // Handle invocations in a tight loop.\n clearTimeout(timerId);\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n\nexport default debounce;\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/view/observer/fakeselectionobserver\n */\n\nimport Observer from './observer';\nimport ViewSelection from '../selection';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport { debounce } from 'lodash-es';\n\n/**\n * Fake selection observer class. If view selection is fake it is placed in dummy DOM container. This observer listens\n * on {@link module:engine/view/document~Document#event:keydown keydown} events and handles moving fake view selection to the correct place\n * if arrow keys are pressed.\n * Fires {@link module:engine/view/document~Document#event:selectionChange selectionChange event} simulating natural behaviour of\n * {@link module:engine/view/observer/selectionobserver~SelectionObserver SelectionObserver}.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class FakeSelectionObserver extends Observer {\n\t/**\n\t * Creates new FakeSelectionObserver instance.\n\t *\n\t * @param {module:engine/view/view~View} view\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} data Selection change data.\n\t\t * @method #_fireSelectionChangeDoneDebounced\n\t\t */\n\t\tthis._fireSelectionChangeDoneDebounced = debounce( data => this.document.fire( 'selectionChangeDone', data ), 200 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'arrowKey', ( eventInfo, data ) => {\n\t\t\tconst selection = document.selection;\n\n\t\t\tif ( selection.isFake && this.isEnabled ) {\n\t\t\t\t// Prevents default key down handling - no selection change will occur.\n\t\t\t\tdata.preventDefault();\n\t\t\t}\n\t\t}, { context: '$capture' } );\n\n\t\tdocument.on( 'arrowKey', ( eventInfo, data ) => {\n\t\t\tconst selection = document.selection;\n\n\t\t\tif ( selection.isFake && this.isEnabled ) {\n\t\t\t\tthis._handleSelectionMove( data.keyCode );\n\t\t\t}\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._fireSelectionChangeDoneDebounced.cancel();\n\t}\n\n\t/**\n\t * Handles collapsing view selection according to given key code. If left or up key is provided - new selection will be\n\t * collapsed to left. If right or down key is pressed - new selection will be collapsed to right.\n\t *\n\t * This method fires {@link module:engine/view/document~Document#event:selectionChange} and\n\t * {@link module:engine/view/document~Document#event:selectionChangeDone} events imitating behaviour of\n\t * {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n\t *\n\t * @private\n\t * @param {Number} keyCode\n\t * @fires module:engine/view/document~Document#event:selectionChange\n\t * @fires module:engine/view/document~Document#event:selectionChangeDone\n\t */\n\t_handleSelectionMove( keyCode ) {\n\t\tconst selection = this.document.selection;\n\t\tconst newSelection = new ViewSelection( selection.getRanges(), { backward: selection.isBackward, fake: false } );\n\n\t\t// Left or up arrow pressed - move selection to start.\n\t\tif ( keyCode == keyCodes.arrowleft || keyCode == keyCodes.arrowup ) {\n\t\t\tnewSelection.setTo( newSelection.getFirstPosition() );\n\t\t}\n\n\t\t// Right or down arrow pressed - move selection to end.\n\t\tif ( keyCode == keyCodes.arrowright || keyCode == keyCodes.arrowdown ) {\n\t\t\tnewSelection.setTo( newSelection.getLastPosition() );\n\t\t}\n\n\t\tconst data = {\n\t\t\toldSelection: selection,\n\t\t\tnewSelection,\n\t\t\tdomSelection: null\n\t\t};\n\n\t\t// Fire dummy selection change event.\n\t\tthis.document.fire( 'selectionChange', data );\n\n\t\t// Call` #_fireSelectionChangeDoneDebounced` every time when `selectionChange` event is fired.\n\t\t// This function is debounced what means that `selectionChangeDone` event will be fired only when\n\t\t// defined int the function time will elapse since the last time the function was called.\n\t\t// So `selectionChangeDone` will be fired when selection will stop changing.\n\t\tthis._fireSelectionChangeDoneDebounced( data );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/selectionobserver\n */\n\n/* global setInterval, clearInterval */\n\nimport Observer from './observer';\nimport MutationObserver from './mutationobserver';\nimport { debounce } from 'lodash-es';\n\n/**\n * Selection observer class observes selection changes in the document. If a selection changes on the document this\n * observer checks if there are any mutations and if the DOM selection is different from the\n * {@link module:engine/view/document~Document#selection view selection}. The selection observer fires\n * {@link module:engine/view/document~Document#event:selectionChange} event only if a selection change was the only change in the document\n * and the DOM selection is different then the view selection.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @see module:engine/view/observer/mutationobserver~MutationObserver\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class SelectionObserver extends Observer {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\t/**\n\t\t * Instance of the mutation observer. Selection observer calls\n\t\t * {@link module:engine/view/observer/mutationobserver~MutationObserver#flush} to ensure that the mutations will be handled\n\t\t * before the {@link module:engine/view/document~Document#event:selectionChange} event is fired.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/observer/mutationobserver~MutationObserver}\n\t\t * module:engine/view/observer/selectionobserver~SelectionObserver#mutationObserver\n\t\t */\n\t\tthis.mutationObserver = view.getObserver( MutationObserver );\n\n\t\t/**\n\t\t * Reference to the view {@link module:engine/view/documentselection~DocumentSelection} object used to compare\n\t\t * new selection with it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/documentselection~DocumentSelection}\n\t\t * module:engine/view/observer/selectionobserver~SelectionObserver#selection\n\t\t */\n\t\tthis.selection = this.document.selection;\n\n\t\t/* eslint-disable max-len */\n\t\t/**\n\t\t * Reference to the {@link module:engine/view/view~View#domConverter}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/domconverter~DomConverter} module:engine/view/observer/selectionobserver~SelectionObserver#domConverter\n\t\t */\n\t\t/* eslint-enable max-len */\n\t\tthis.domConverter = view.domConverter;\n\n\t\t/**\n\t\t * A set of documents which have added `selectionchange` listener to avoid adding a listener twice to the same\n\t\t * document.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakSet.<Document>} module:engine/view/observer/selectionobserver~SelectionObserver#_documents\n\t\t */\n\t\tthis._documents = new WeakSet();\n\n\t\t/**\n\t\t * Fires debounced event `selectionChangeDone`. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} data Selection change data.\n\t\t * @method #_fireSelectionChangeDoneDebounced\n\t\t */\n\t\tthis._fireSelectionChangeDoneDebounced = debounce( data => this.document.fire( 'selectionChangeDone', data ), 200 );\n\n\t\tthis._clearInfiniteLoopInterval = setInterval( () => this._clearInfiniteLoop(), 1000 );\n\n\t\t/**\n\t\t * Private property to check if the code does not enter infinite loop.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} module:engine/view/observer/selectionobserver~SelectionObserver#_loopbackCounter\n\t\t */\n\t\tthis._loopbackCounter = 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domElement ) {\n\t\tconst domDocument = domElement.ownerDocument;\n\n\t\t// Add listener once per each document.\n\t\tif ( this._documents.has( domDocument ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.listenTo( domDocument, 'selectionchange', ( evt, domEvent ) => {\n\t\t\tthis._handleSelectionChange( domEvent, domDocument );\n\t\t} );\n\n\t\tthis._documents.add( domDocument );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tclearInterval( this._clearInfiniteLoopInterval );\n\t\tthis._fireSelectionChangeDoneDebounced.cancel();\n\t}\n\n\t/**\n\t * Selection change listener. {@link module:engine/view/observer/mutationobserver~MutationObserver#flush Flush} mutations, check if\n\t * a selection changes and fires {@link module:engine/view/document~Document#event:selectionChange} event on every change\n\t * and {@link module:engine/view/document~Document#event:selectionChangeDone} when a selection stop changing.\n\t *\n\t * @private\n\t * @param {Event} domEvent DOM event.\n\t * @param {Document} domDocument DOM document.\n\t */\n\t_handleSelectionChange( domEvent, domDocument ) {\n\t\tif ( !this.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domSelection = domDocument.defaultView.getSelection();\n\n\t\tif ( this.checkShouldIgnoreEventFromTarget( domSelection.anchorNode ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ensure the mutation event will be before selection event on all browsers.\n\t\tthis.mutationObserver.flush();\n\n\t\t// If there were mutations then the view will be re-rendered by the mutation observer and the selection\n\t\t// will be updated, so the selections will equal and the event will not be fired, as expected.\n\t\tconst newViewSelection = this.domConverter.domSelectionToView( domSelection );\n\n\t\t// Do not convert selection change if the new view selection has no ranges in it.\n\t\t//\n\t\t// It means that the DOM selection is in some way incorrect. Ranges that were in the DOM selection could not be\n\t\t// converted to the view. This happens when the DOM selection was moved outside of the editable element.\n\t\tif ( newViewSelection.rangeCount == 0 ) {\n\t\t\tthis.view.hasDomSelection = false;\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.view.hasDomSelection = true;\n\n\t\tif ( this.selection.isEqual( newViewSelection ) && this.domConverter.isDomSelectionCorrect( domSelection ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Ensure we are not in the infinite loop (#400).\n\t\t// This counter is reset each second. 60 selection changes in 1 second is enough high number\n\t\t// to be very difficult (impossible) to achieve using just keyboard keys (during normal editor use).\n\t\tif ( ++this._loopbackCounter > 60 ) {\n\t\t\t// Selection change observer detected an infinite rendering loop.\n\t\t\t// Most probably you try to put the selection in the position which is not allowed\n\t\t\t// by the browser and browser fixes it automatically what causes `selectionchange` event on\n\t\t\t// which a loopback through a model tries to re-render the wrong selection and again.\n\t\t\t//\n\t\t\t// @if CK_DEBUG // console.warn( 'Selection change observer detected an infinite rendering loop.' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( this.selection.isSimilar( newViewSelection ) ) {\n\t\t\t// If selection was equal and we are at this point of algorithm, it means that it was incorrect.\n\t\t\t// Just re-render it, no need to fire any events, etc.\n\t\t\tthis.view.forceRender();\n\t\t} else {\n\t\t\tconst data = {\n\t\t\t\toldSelection: this.selection,\n\t\t\t\tnewSelection: newViewSelection,\n\t\t\t\tdomSelection\n\t\t\t};\n\n\t\t\t// Prepare data for new selection and fire appropriate events.\n\t\t\tthis.document.fire( 'selectionChange', data );\n\n\t\t\t// Call `#_fireSelectionChangeDoneDebounced` every time when `selectionChange` event is fired.\n\t\t\t// This function is debounced what means that `selectionChangeDone` event will be fired only when\n\t\t\t// defined int the function time will elapse since the last time the function was called.\n\t\t\t// So `selectionChangeDone` will be fired when selection will stop changing.\n\t\t\tthis._fireSelectionChangeDoneDebounced( data );\n\t\t}\n\t}\n\n\t/**\n\t * Clears `SelectionObserver` internal properties connected with preventing infinite loop.\n\t *\n\t * @protected\n\t */\n\t_clearInfiniteLoop() {\n\t\tthis._loopbackCounter = 0;\n\t}\n}\n\n/**\n * Fired when a selection has changed. This event is fired only when the selection change was the only change that happened\n * in the document, and the old selection is different then the new selection.\n *\n * Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n *\n * Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/selectionobserver~SelectionObserver\n * @event module:engine/view/document~Document#event:selectionChange\n * @param {Object} data\n * @param {module:engine/view/documentselection~DocumentSelection} data.oldSelection Old View selection which is\n * {@link module:engine/view/document~Document#selection}.\n * @param {module:engine/view/selection~Selection} data.newSelection New View selection which is converted DOM selection.\n * @param {Selection} data.domSelection Native DOM selection.\n */\n\n/**\n * Fired when selection stops changing.\n *\n * Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.\n *\n * Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/selectionobserver~SelectionObserver\n * @event module:engine/view/document~Document#event:selectionChangeDone\n * @param {Object} data\n * @param {module:engine/view/documentselection~DocumentSelection} data.oldSelection Old View selection which is\n * {@link module:engine/view/document~Document#selection}.\n * @param {module:engine/view/selection~Selection} data.newSelection New View selection which is converted DOM selection.\n * @param {Selection} data.domSelection Native DOM selection.\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/view/observer/focusobserver\n */\n\n/* globals setTimeout, clearTimeout */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:focus Focus}\n * and {@link module:engine/view/document~Document#event:blur blur} events observer.\n * Focus observer handle also {@link module:engine/view/rooteditableelement~RootEditableElement#isFocused isFocused} property of the\n * {@link module:engine/view/rooteditableelement~RootEditableElement root elements}.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class FocusObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'focus', 'blur' ];\n\t\tthis.useCapture = true;\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'focus', () => {\n\t\t\tdocument.isFocused = true;\n\n\t\t\t// Unfortunately native `selectionchange` event is fired asynchronously.\n\t\t\t// We need to wait until `SelectionObserver` handle the event and then render. Otherwise rendering will\n\t\t\t// overwrite new DOM selection with selection from the view.\n\t\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/795 for more details.\n\t\t\t// Long timeout is needed to solve #676 and https://github.com/ckeditor/ckeditor5-engine/issues/1157 issues.\n\t\t\tthis._renderTimeoutId = setTimeout( () => view.forceRender(), 50 );\n\t\t} );\n\n\t\tdocument.on( 'blur', ( evt, data ) => {\n\t\t\tconst selectedEditable = document.selection.editableElement;\n\n\t\t\tif ( selectedEditable === null || selectedEditable === data.target ) {\n\t\t\t\tdocument.isFocused = false;\n\n\t\t\t\t// Re-render the document to update view elements.\n\t\t\t\tview.forceRender();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Identifier of the timeout currently used by focus listener to delay rendering execution.\n\t\t *\n\t\t * @private\n\t\t * @member {Number} #_renderTimeoutId\n\t\t */\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._renderTimeoutId ) {\n\t\t\tclearTimeout( this._renderTimeoutId );\n\t\t}\n\n\t\tsuper.destroy();\n\t}\n}\n\n/**\n * Fired when one of the editables gets focus.\n *\n * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.\n *\n * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/focusobserver~FocusObserver\n * @event module:engine/view/document~Document#event:focus\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when one of the editables loses focus.\n *\n * Introduced by {@link module:engine/view/observer/focusobserver~FocusObserver}.\n *\n * Note that because {@link module:engine/view/observer/focusobserver~FocusObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/focusobserver~FocusObserver\n * @event module:engine/view/document~Document#event:blur\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\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/view/observer/compositionobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:compositionstart Compositionstart},\n * {@link module:engine/view/document~Document#event:compositionupdate compositionupdate} and\n * {@link module:engine/view/document~Document#event:compositionend compositionend} events observer.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class CompositionObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'compositionstart', 'compositionupdate', 'compositionend' ];\n\t\tconst document = this.document;\n\n\t\tdocument.on( 'compositionstart', () => {\n\t\t\tdocument.isComposing = true;\n\t\t} );\n\n\t\tdocument.on( 'compositionend', () => {\n\t\t\tdocument.isComposing = false;\n\t\t} );\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when composition starts inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionstart\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when composition is updated inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionupdate\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when composition ends inside one of the editables.\n *\n * Introduced by {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * Note that because {@link module:engine/view/observer/compositionobserver~CompositionObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/compositionobserver~CompositionObserver\n * @event module:engine/view/document~Document#event:compositionend\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module engine/view/observer/inputobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * Observer for events connected with data input.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class InputObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'beforeinput' ];\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired before browser inputs (or deletes) some data.\n *\n * This event is available only on browsers which support DOM `beforeinput` event.\n *\n * Introduced by {@link module:engine/view/observer/inputobserver~InputObserver}.\n *\n * Note that because {@link module:engine/view/observer/inputobserver~InputObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @see module:engine/view/observer/inputobserver~InputObserver\n * @event module:engine/view/document~Document#event:beforeinput\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n","import baseGetTag from './_baseGetTag.js';\nimport isArray from './isArray.js';\nimport isObjectLike from './isObjectLike.js';\n\n/** `Object#toString` result references. */\nvar stringTag = '[object String]';\n\n/**\n * Checks if `value` is classified as a `String` primitive or object.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a string, else `false`.\n * @example\n *\n * _.isString('abc');\n * // => true\n *\n * _.isString(1);\n * // => false\n */\nfunction isString(value) {\n return typeof value == 'string' ||\n (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);\n}\n\nexport default isString;\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 utils/dom/createelement\n */\n\nimport isIterable from '../isiterable';\nimport { isString } from 'lodash-es';\n\n/**\n * Creates element with attributes and children.\n *\n *\t\tcreateElement( document, 'p' ); // <p>\n *\t\tcreateElement( document, 'p', { class: 'foo' } ); // <p class=\"foo\">\n *\t\tcreateElement( document, 'p', null, 'foo' ); // <p>foo</p>\n *\t\tcreateElement( document, 'p', null, [ 'foo', createElement( document, 'img' ) ] ); // <p>foo<img></p>\n *\n * @param {Document} doc Document used to create element.\n * @param {String} name Name of the element.\n * @param {Object} [attributes] Object keys will become attributes keys and object values will became attributes values.\n * @param {Node|String|Array.<Node|String>} [children] Child or array of children. Strings will be automatically turned\n * into Text nodes.\n * @returns {Element} Created element.\n */\nexport default function createElement( doc, name, attributes = {}, children = [] ) {\n\tconst namespace = attributes && attributes.xmlns;\n\tconst element = namespace ? doc.createElementNS( namespace, name ) : doc.createElement( name );\n\n\tfor ( const key in attributes ) {\n\t\telement.setAttribute( key, attributes[ key ] );\n\t}\n\n\tif ( isString( children ) || !isIterable( children ) ) {\n\t\tchildren = [ children ];\n\t}\n\n\tfor ( let child of children ) {\n\t\tif ( isString( child ) ) {\n\t\t\tchild = doc.createTextNode( child );\n\t\t}\n\n\t\telement.appendChild( child );\n\t}\n\n\treturn element;\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 utils/dom/isrange\n */\n\n/**\n * Checks if the object is a native DOM Range.\n *\n * @param {*} obj\n * @returns {Boolean}\n */\nexport default function isRange( obj ) {\n\treturn Object.prototype.toString.apply( obj ) == '[object Range]';\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 utils/dom/getborderwidths\n */\n\n/**\n * Returns an object containing CSS border widths of a specified HTML element.\n *\n * @param {HTMLElement} element An element which has CSS borders.\n * @returns {Object} An object containing `top`, `left`, `right` and `bottom` properties\n * with numerical values of the `border-[top,left,right,bottom]-width` CSS styles.\n */\nexport default function getBorderWidths( element ) {\n\t// Call getComputedStyle on the window the element document belongs to.\n\tconst style = element.ownerDocument.defaultView.getComputedStyle( element );\n\n\treturn {\n\t\ttop: parseInt( style.borderTopWidth, 10 ),\n\t\tright: parseInt( style.borderRightWidth, 10 ),\n\t\tbottom: parseInt( style.borderBottomWidth, 10 ),\n\t\tleft: parseInt( style.borderLeftWidth, 10 )\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/rect\n */\n\nimport isRange from './isrange';\nimport isWindow from './iswindow';\nimport getBorderWidths from './getborderwidths';\nimport isText from './istext';\nimport { isElement } from 'lodash-es';\n\nconst rectProperties = [ 'top', 'right', 'bottom', 'left', 'width', 'height' ];\n\n/**\n * A helper class representing a `ClientRect` object, e.g. value returned by\n * the native `object.getBoundingClientRect()` method. Provides a set of methods\n * to manipulate the rect and compare it against other rect instances.\n */\nexport default class Rect {\n\t/**\n\t * Creates an instance of rect.\n\t *\n\t *\t\t// Rect of an HTMLElement.\n\t *\t\tconst rectA = new Rect( document.body );\n\t *\n\t *\t\t// Rect of a DOM Range.\n\t *\t\tconst rectB = new Rect( document.getSelection().getRangeAt( 0 ) );\n\t *\n\t *\t\t// Rect of a window (web browser viewport).\n\t *\t\tconst rectC = new Rect( window );\n\t *\n\t *\t\t// Rect out of an object.\n\t *\t\tconst rectD = new Rect( { top: 0, right: 10, bottom: 10, left: 0, width: 10, height: 10 } );\n\t *\n\t *\t\t// Rect out of another Rect instance.\n\t *\t\tconst rectE = new Rect( rectD );\n\t *\n\t *\t\t// Rect out of a ClientRect.\n\t *\t\tconst rectF = new Rect( document.body.getClientRects().item( 0 ) );\n\t *\n\t * **Note**: By default a rect of an HTML element includes its CSS borders and scrollbars (if any)\n\t * ant the rect of a `window` includes scrollbars too. Use {@link #excludeScrollbarsAndBorders}\n\t * to get the inner part of the rect.\n\t *\n\t * @param {HTMLElement|Range|Window|ClientRect|module:utils/dom/rect~Rect|Object} source A source object to create the rect.\n\t */\n\tconstructor( source ) {\n\t\tconst isSourceRange = isRange( source );\n\n\t\t/**\n\t\t * The object this rect is for.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {HTMLElement|Range|ClientRect|module:utils/dom/rect~Rect|Object} #_source\n\t\t */\n\t\tObject.defineProperty( this, '_source', {\n\t\t\t// If the source is a Rect instance, copy it's #_source.\n\t\t\tvalue: source._source || source,\n\t\t\twritable: true,\n\t\t\tenumerable: false\n\t\t} );\n\n\t\tif ( isElement( source ) || isSourceRange ) {\n\t\t\t// The `Rect` class depends on `getBoundingClientRect` and `getClientRects` DOM methods. If the source\n\t\t\t// of a rect in an HTML element or a DOM range but it does not belong to any rendered DOM tree, these methods\n\t\t\t// will fail to obtain the geometry and the rect instance makes little sense to the features using it.\n\t\t\t// To get rid of this warning make sure the source passed to the constructor is a descendant of `window.document.body`.\n\t\t\t// @if CK_DEBUG // const sourceNode = isSourceRange ? source.startContainer : source;\n\t\t\t// @if CK_DEBUG // if ( !sourceNode.ownerDocument || !sourceNode.ownerDocument.body.contains( sourceNode ) ) {\n\t\t\t// @if CK_DEBUG // \tconsole.warn(\n\t\t\t// @if CK_DEBUG // \t\t'rect-source-not-in-dom: The source of this rect does not belong to any rendered DOM tree.',\n\t\t\t// @if CK_DEBUG // \t\t{ source } );\n\t\t\t// @if CK_DEBUG // }\n\n\t\t\tif ( isSourceRange ) {\n\t\t\t\tconst rangeRects = Rect.getDomRangeRects( source );\n\t\t\t\tcopyRectProperties( this, Rect.getBoundingRect( rangeRects ) );\n\t\t\t} else {\n\t\t\t\tcopyRectProperties( this, source.getBoundingClientRect() );\n\t\t\t}\n\t\t} else if ( isWindow( source ) ) {\n\t\t\tconst { innerWidth, innerHeight } = source;\n\n\t\t\tcopyRectProperties( this, {\n\t\t\t\ttop: 0,\n\t\t\t\tright: innerWidth,\n\t\t\t\tbottom: innerHeight,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: innerWidth,\n\t\t\t\theight: innerHeight\n\t\t\t} );\n\t\t} else {\n\t\t\tcopyRectProperties( this, source );\n\t\t}\n\n\t\t/**\n\t\t * The \"top\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #top\n\t\t */\n\n\t\t/**\n\t\t * The \"right\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #right\n\t\t */\n\n\t\t/**\n\t\t * The \"bottom\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #bottom\n\t\t */\n\n\t\t/**\n\t\t * The \"left\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #left\n\t\t */\n\n\t\t/**\n\t\t * The \"width\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #width\n\t\t */\n\n\t\t/**\n\t\t * The \"height\" value of the rect.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #height\n\t\t */\n\t}\n\n\t/**\n\t * Returns a clone of the rect.\n\t *\n\t * @returns {module:utils/dom/rect~Rect} A cloned rect.\n\t */\n\tclone() {\n\t\treturn new Rect( this );\n\t}\n\n\t/**\n\t * Moves the rect so that its upperleft corner lands in desired `[ x, y ]` location.\n\t *\n\t * @param {Number} x Desired horizontal location.\n\t * @param {Number} y Desired vertical location.\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been moved.\n\t */\n\tmoveTo( x, y ) {\n\t\tthis.top = y;\n\t\tthis.right = x + this.width;\n\t\tthis.bottom = y + this.height;\n\t\tthis.left = x;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves the rect inplace by a dedicated offset.\n\t *\n\t * @param {Number} x A horizontal offset.\n\t * @param {Number} y A vertical offset\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been moved.\n\t */\n\tmoveBy( x, y ) {\n\t\tthis.top += y;\n\t\tthis.right += x;\n\t\tthis.left += x;\n\t\tthis.bottom += y;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns a new rect a a result of intersection with another rect.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect\n\t * @returns {module:utils/dom/rect~Rect}\n\t */\n\tgetIntersection( anotherRect ) {\n\t\tconst rect = {\n\t\t\ttop: Math.max( this.top, anotherRect.top ),\n\t\t\tright: Math.min( this.right, anotherRect.right ),\n\t\t\tbottom: Math.min( this.bottom, anotherRect.bottom ),\n\t\t\tleft: Math.max( this.left, anotherRect.left )\n\t\t};\n\n\t\trect.width = rect.right - rect.left;\n\t\trect.height = rect.bottom - rect.top;\n\n\t\tif ( rect.width < 0 || rect.height < 0 ) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\treturn new Rect( rect );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the area of intersection with another rect.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect [description]\n\t * @returns {Number} Area of intersection.\n\t */\n\tgetIntersectionArea( anotherRect ) {\n\t\tconst rect = this.getIntersection( anotherRect );\n\n\t\tif ( rect ) {\n\t\t\treturn rect.getArea();\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the area of the rect.\n\t *\n\t * @returns {Number}\n\t */\n\tgetArea() {\n\t\treturn this.width * this.height;\n\t}\n\n\t/**\n\t * Returns a new rect, a part of the original rect, which is actually visible to the user,\n\t * e.g. an original rect cropped by parent element rects which have `overflow` set in CSS\n\t * other than `\"visible\"`.\n\t *\n\t * If there's no such visible rect, which is when the rect is limited by one or many of\n\t * the ancestors, `null` is returned.\n\t *\n\t * @returns {module:utils/dom/rect~Rect|null} A visible rect instance or `null`, if there's none.\n\t */\n\tgetVisible() {\n\t\tconst source = this._source;\n\t\tlet visibleRect = this.clone();\n\n\t\t// There's no ancestor to crop <body> with the overflow.\n\t\tif ( !isBody( source ) ) {\n\t\t\tlet parent = source.parentNode || source.commonAncestorContainer;\n\n\t\t\t// Check the ancestors all the way up to the <body>.\n\t\t\twhile ( parent && !isBody( parent ) ) {\n\t\t\t\tconst parentRect = new Rect( parent );\n\t\t\t\tconst intersectionRect = visibleRect.getIntersection( parentRect );\n\n\t\t\t\tif ( intersectionRect ) {\n\t\t\t\t\tif ( intersectionRect.getArea() < visibleRect.getArea() ) {\n\t\t\t\t\t\t// Reduce the visible rect to the intersection.\n\t\t\t\t\t\tvisibleRect = intersectionRect;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// There's no intersection, the rect is completely invisible.\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tparent = parent.parentNode;\n\t\t\t}\n\t\t}\n\n\t\treturn visibleRect;\n\t}\n\n\t/**\n\t * Checks if all property values ({@link #top}, {@link #left}, {@link #right},\n\t * {@link #bottom}, {@link #width} and {@link #height}) are the equal in both rect\n\t * instances.\n\t *\n\t * @param {module:utils/dom/rect~Rect} rect A rect instance to compare with.\n\t * @returns {Boolean} `true` when Rects are equal. `false` otherwise.\n\t */\n\tisEqual( anotherRect ) {\n\t\tfor ( const prop of rectProperties ) {\n\t\t\tif ( this[ prop ] !== anotherRect[ prop ] ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks whether a rect fully contains another rect instance.\n\t *\n\t * @param {module:utils/dom/rect~Rect} anotherRect\n\t * @returns {Boolean} `true` if contains, `false` otherwise.\n\t */\n\tcontains( anotherRect ) {\n\t\tconst intersectRect = this.getIntersection( anotherRect );\n\n\t\treturn !!( intersectRect && intersectRect.isEqual( anotherRect ) );\n\t}\n\n\t/**\n\t * Excludes scrollbars and CSS borders from the rect.\n\t *\n\t * * Borders are removed when {@link #_source} is an HTML element.\n\t * * Scrollbars are excluded from HTML elements and the `window`.\n\t *\n\t * @returns {module:utils/dom/rect~Rect} A rect which has been updated.\n\t */\n\texcludeScrollbarsAndBorders() {\n\t\tconst source = this._source;\n\t\tlet scrollBarWidth, scrollBarHeight, direction;\n\n\t\tif ( isWindow( source ) ) {\n\t\t\tscrollBarWidth = source.innerWidth - source.document.documentElement.clientWidth;\n\t\t\tscrollBarHeight = source.innerHeight - source.document.documentElement.clientHeight;\n\t\t\tdirection = source.getComputedStyle( source.document.documentElement ).direction;\n\t\t} else {\n\t\t\tconst borderWidths = getBorderWidths( this._source );\n\n\t\t\tscrollBarWidth = source.offsetWidth - source.clientWidth - borderWidths.left - borderWidths.right;\n\t\t\tscrollBarHeight = source.offsetHeight - source.clientHeight - borderWidths.top - borderWidths.bottom;\n\t\t\tdirection = source.ownerDocument.defaultView.getComputedStyle( source ).direction;\n\n\t\t\tthis.left += borderWidths.left;\n\t\t\tthis.top += borderWidths.top;\n\t\t\tthis.right -= borderWidths.right;\n\t\t\tthis.bottom -= borderWidths.bottom;\n\t\t\tthis.width = this.right - this.left;\n\t\t\tthis.height = this.bottom - this.top;\n\t\t}\n\n\t\tthis.width -= scrollBarWidth;\n\n\t\tif ( direction === 'ltr' ) {\n\t\t\tthis.right -= scrollBarWidth;\n\t\t} else {\n\t\t\tthis.left += scrollBarWidth;\n\t\t}\n\n\t\tthis.height -= scrollBarHeight;\n\t\tthis.bottom -= scrollBarHeight;\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns an array of rects of the given native DOM Range.\n\t *\n\t * @param {Range} range A native DOM range.\n\t * @returns {Array.<module:utils/dom/rect~Rect>} DOM Range rects.\n\t */\n\tstatic getDomRangeRects( range ) {\n\t\tconst rects = [];\n\t\t// Safari does not iterate over ClientRectList using for...of loop.\n\t\tconst clientRects = Array.from( range.getClientRects() );\n\n\t\tif ( clientRects.length ) {\n\t\t\tfor ( const rect of clientRects ) {\n\t\t\t\trects.push( new Rect( rect ) );\n\t\t\t}\n\t\t}\n\t\t// If there's no client rects for the Range, use parent container's bounding rect\n\t\t// instead and adjust rect's width to simulate the actual geometry of such range.\n\t\t// https://github.com/ckeditor/ckeditor5-utils/issues/153\n\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/317\n\t\telse {\n\t\t\tlet startContainer = range.startContainer;\n\n\t\t\tif ( isText( startContainer ) ) {\n\t\t\t\tstartContainer = startContainer.parentNode;\n\t\t\t}\n\n\t\t\tconst rect = new Rect( startContainer.getBoundingClientRect() );\n\t\t\trect.right = rect.left;\n\t\t\trect.width = 0;\n\n\t\t\trects.push( rect );\n\t\t}\n\n\t\treturn rects;\n\t}\n\n\t/**\n\t * Returns a bounding rectangle that contains all the given `rects`.\n\t *\n\t * @param {Iterable.<module:utils/dom/rect~Rect>} rects A list of rectangles that should be contained in the result rectangle.\n\t * @returns {module:utils/dom/rect~Rect|null} Bounding rectangle or `null` if no `rects` were given.\n\t */\n\tstatic getBoundingRect( rects ) {\n\t\tconst boundingRectData = {\n\t\t\tleft: Number.POSITIVE_INFINITY,\n\t\t\ttop: Number.POSITIVE_INFINITY,\n\t\t\tright: Number.NEGATIVE_INFINITY,\n\t\t\tbottom: Number.NEGATIVE_INFINITY\n\t\t};\n\t\tlet rectangleCount = 0;\n\n\t\tfor ( const rect of rects ) {\n\t\t\trectangleCount++;\n\n\t\t\tboundingRectData.left = Math.min( boundingRectData.left, rect.left );\n\t\t\tboundingRectData.top = Math.min( boundingRectData.top, rect.top );\n\t\t\tboundingRectData.right = Math.max( boundingRectData.right, rect.right );\n\t\t\tboundingRectData.bottom = Math.max( boundingRectData.bottom, rect.bottom );\n\t\t}\n\n\t\tif ( rectangleCount == 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tboundingRectData.width = boundingRectData.right - boundingRectData.left;\n\t\tboundingRectData.height = boundingRectData.bottom - boundingRectData.top;\n\n\t\treturn new Rect( boundingRectData );\n\t}\n}\n\n// Acquires all the rect properties from the passed source.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} rect\n// @param {ClientRect|module:utils/dom/rect~Rect|Object} source\nfunction copyRectProperties( rect, source ) {\n\tfor ( const p of rectProperties ) {\n\t\trect[ p ] = source[ p ];\n\t}\n}\n\n// Checks if provided object is a <body> HTML element.\n//\n// @private\n// @param {HTMLElement|Range} elementOrRange\n// @returns {Boolean}\nfunction isBody( elementOrRange ) {\n\tif ( !isElement( elementOrRange ) ) {\n\t\treturn false;\n\t}\n\n\treturn elementOrRange === elementOrRange.ownerDocument.body;\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 utils/dom/resizeobserver\n */\n\n/* globals setTimeout, clearTimeout */\n\nimport mix from '../mix';\nimport global from './global';\nimport Rect from './rect';\nimport DomEmitterMixin from './emittermixin';\n\nconst RESIZE_CHECK_INTERVAL = 100;\n\n/**\n * A helper class which instances allow performing custom actions when native DOM elements are resized.\n *\n *\t\tconst editableElement = editor.editing.view.getDomRoot();\n *\n *\t\tconst observer = new ResizeObserver( editableElement, entry => {\n *\t\t\tconsole.log( 'The editable element has been resized in DOM.' );\n *\t\t\tconsole.log( entry.target ); // -> editableElement\n *\t\t\tconsole.log( entry.contentRect.width ); // -> e.g. '423px'\n *\t\t} );\n *\n * By default, it uses the [native DOM resize observer](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)\n * under the hood and in browsers that do not support the native API yet, a polyfilled observer is\n * used instead.\n */\nexport default class ResizeObserver {\n\t/**\n\t * Creates an instance of the `ResizeObserver` class.\n\t *\n\t * @param {HTMLElement} element A DOM element that is to be observed for resizing. Note that\n\t * the element must be visible (i.e. not detached from DOM) for the observer to work.\n\t * @param {Function} callback A function called when the observed element was resized. It passes\n\t * the [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)\n\t * object with information about the resize event.\n\t */\n\tconstructor( element, callback ) {\n\t\t// **Note**: For the maximum performance, this class ensures only a single instance of the native\n\t\t// (or polyfilled) observer is used no matter how many instances of this class were created.\n\t\tif ( !ResizeObserver._observerInstance ) {\n\t\t\tResizeObserver._createObserver();\n\t\t}\n\n\t\t/**\n\t\t * The element observer by this observer.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis._element = element;\n\n\t\t/**\n\t\t * The callback executed each time {@link #_element} is resized.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Function}\n\t\t */\n\t\tthis._callback = callback;\n\n\t\tResizeObserver._addElementCallback( element, callback );\n\t\tResizeObserver._observerInstance.observe( element );\n\t}\n\n\t/**\n\t * Destroys the observer which disables the `callback` passed to the {@link #constructor}.\n\t */\n\tdestroy() {\n\t\tResizeObserver._deleteElementCallback( this._element, this._callback );\n\t}\n\n\t/**\n\t * Registers a new resize callback for the DOM element.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @param {Function} callback\n\t */\n\tstatic _addElementCallback( element, callback ) {\n\t\tif ( !ResizeObserver._elementCallbacks ) {\n\t\t\tResizeObserver._elementCallbacks = new Map();\n\t\t}\n\n\t\tlet callbacks = ResizeObserver._elementCallbacks.get( element );\n\n\t\tif ( !callbacks ) {\n\t\t\tcallbacks = new Set();\n\t\t\tResizeObserver._elementCallbacks.set( element, callbacks );\n\t\t}\n\n\t\tcallbacks.add( callback );\n\t}\n\n\t/**\n\t * Removes a resize callback from the DOM element. If no callbacks are left\n\t * for the element, it removes the element from the native observer.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @param {Function} callback\n\t */\n\tstatic _deleteElementCallback( element, callback ) {\n\t\tconst callbacks = ResizeObserver._getElementCallbacks( element );\n\n\t\t// Remove the element callback. Check if exist first in case someone\n\t\t// called destroy() twice.\n\t\tif ( callbacks ) {\n\t\t\tcallbacks.delete( callback );\n\n\t\t\t// If no callbacks left for the element, also remove the element.\n\t\t\tif ( !callbacks.size ) {\n\t\t\t\tResizeObserver._elementCallbacks.delete( element );\n\t\t\t\tResizeObserver._observerInstance.unobserve( element );\n\t\t\t}\n\t\t}\n\n\t\tif ( ResizeObserver._elementCallbacks && !ResizeObserver._elementCallbacks.size ) {\n\t\t\tResizeObserver._observerInstance = null;\n\t\t\tResizeObserver._elementCallbacks = null;\n\t\t}\n\t}\n\n\t/**\n\t * Returns are registered resize callbacks for the DOM element.\n\t *\n\t * @private\n\t * @static\n\t * @param {HTMLElement} element\n\t * @returns {Set.<HTMLElement>|null}\n\t */\n\tstatic _getElementCallbacks( element ) {\n\t\tif ( !ResizeObserver._elementCallbacks ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn ResizeObserver._elementCallbacks.get( element );\n\t}\n\n\t/**\n\t * Creates the single native observer shared across all `ResizeObserver` instances.\n\t * If the browser does not support the native API, it creates a polyfill.\n\t *\n\t * @private\n\t * @static\n\t */\n\tstatic _createObserver() {\n\t\tlet ObserverConstructor;\n\n\t\t// TODO: One day, the `ResizeObserver` API will be supported in all modern web browsers.\n\t\t// When it happens, this module will no longer make sense and should be removed and\n\t\t// the native implementation should be used across the project to save bytes.\n\t\t// Check out https://caniuse.com/#feat=resizeobserver.\n\t\tif ( typeof global.window.ResizeObserver === 'function' ) {\n\t\t\tObserverConstructor = global.window.ResizeObserver;\n\t\t} else {\n\t\t\tObserverConstructor = ResizeObserverPolyfill;\n\t\t}\n\n\t\tResizeObserver._observerInstance = new ObserverConstructor( entries => {\n\t\t\tfor ( const entry of entries ) {\n\t\t\t\tconst callbacks = ResizeObserver._getElementCallbacks( entry.target );\n\n\t\t\t\tif ( callbacks ) {\n\t\t\t\t\tfor ( const callback of callbacks ) {\n\t\t\t\t\t\tcallback( entry );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n/**\n * The single native observer instance (or polyfill in browsers that do not support the API)\n * shared across all {@link module:utils/dom/resizeobserver~ResizeObserver} instances.\n *\n * @static\n * @protected\n * @readonly\n * @property {Object|null} module:utils/dom/resizeobserver~ResizeObserver#_observerInstance\n */\nResizeObserver._observerInstance = null;\n\n/**\n * A mapping of native DOM elements and their callbacks shared across all\n * {@link module:utils/dom/resizeobserver~ResizeObserver} instances.\n *\n * @static\n * @private\n * @readonly\n * @property {Map.<HTMLElement,Set>|null} module:utils/dom/resizeobserver~ResizeObserver#_elementCallbacks\n */\nResizeObserver._elementCallbacks = null;\n\n/**\n * A polyfill class for the native [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).\n *\n * @private\n * @mixes module:utils/domemittermixin~DomEmitterMixin\n */\nclass ResizeObserverPolyfill {\n\t/**\n\t * Creates an instance of the {@link module:utils/dom/resizeobserver~ResizeObserverPolyfill} class.\n\t *\n\t * It synchronously reacts to resize of the window to check if observed elements' geometry changed.\n\t *\n\t * Additionally, the polyfilled observer uses a timeout to check if observed elements' geometry has changed\n\t * in some other way (dynamic layouts, scrollbars showing up, etc.), so its response can also be asynchronous.\n\t *\n\t * @param {Function} callback A function called when any observed element was resized. Refer to the\n\t * native [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver) API to\n\t * learn more.\n\t */\n\tconstructor( callback ) {\n\t\t/**\n\t\t * A function called when any observed {@link #_elements element} was resized.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Function}\n\t\t */\n\t\tthis._callback = callback;\n\n\t\t/**\n\t\t * DOM elements currently observed by the observer instance.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Set}\n\t\t */\n\t\tthis._elements = new Set();\n\n\t\t/**\n\t\t * Cached DOM {@link #_elements elements} bounding rects to compare to upon the next check.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Map.<HTMLElement,module:utils/dom/rect~Rect>}\n\t\t */\n\t\tthis._previousRects = new Map();\n\n\t\t/**\n\t\t * An UID of the current timeout upon which the observed elements rects\n\t\t * will be compared to the {@link #_previousRects previous rects} from the past.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Map.<HTMLElement,module:utils/dom/rect~Rect>}\n\t\t */\n\t\tthis._periodicCheckTimeout = null;\n\t}\n\n\t/**\n\t * Starts observing a DOM element.\n\t *\n\t * Learn more in the\n\t * [native method documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe).\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tobserve( element ) {\n\t\tthis._elements.add( element );\n\n\t\tthis._checkElementRectsAndExecuteCallback();\n\n\t\tif ( this._elements.size === 1 ) {\n\t\t\tthis._startPeriodicCheck();\n\t\t}\n\t}\n\n\t/**\n\t * Stops observing a DOM element.\n\t *\n\t * Learn more in the\n\t * [native method documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/unobserve).\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tunobserve( element ) {\n\t\tthis._elements.delete( element );\n\t\tthis._previousRects.delete( element );\n\n\t\tif ( !this._elements.size ) {\n\t\t\tthis._stopPeriodicCheck();\n\t\t}\n\t}\n\n\t/**\n\t * When called, the observer calls the {@link #_callback resize callback} for all observed\n\t * {@link #_elements elements} but also starts checking periodically for changes in the elements' geometry.\n\t * If some are detected, {@link #_callback resize callback} is called for relevant elements that were resized.\n\t *\n\t * @protected\n\t */\n\t_startPeriodicCheck() {\n\t\tconst periodicCheck = () => {\n\t\t\tthis._checkElementRectsAndExecuteCallback();\n\t\t\tthis._periodicCheckTimeout = setTimeout( periodicCheck, RESIZE_CHECK_INTERVAL );\n\t\t};\n\n\t\tthis.listenTo( global.window, 'resize', () => {\n\t\t\tthis._checkElementRectsAndExecuteCallback();\n\t\t} );\n\n\t\tthis._periodicCheckTimeout = setTimeout( periodicCheck, RESIZE_CHECK_INTERVAL );\n\t}\n\n\t/**\n\t * Stops checking for changes in all observed {@link #_elements elements} geometry.\n\t *\n\t * @protected\n\t */\n\t_stopPeriodicCheck() {\n\t\tclearTimeout( this._periodicCheckTimeout );\n\t\tthis.stopListening();\n\t\tthis._previousRects.clear();\n\t}\n\n\t/**\n\t * Checks if the geometry of any of the {@link #_elements element} has changed. If so, executes\n\t * the {@link #_callback resize callback} with element geometry data.\n\t *\n\t * @protected\n\t */\n\t_checkElementRectsAndExecuteCallback() {\n\t\tconst entries = [];\n\n\t\tfor ( const element of this._elements ) {\n\t\t\tif ( this._hasRectChanged( element ) ) {\n\t\t\t\tentries.push( {\n\t\t\t\t\ttarget: element,\n\t\t\t\t\tcontentRect: this._previousRects.get( element )\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\tif ( entries.length ) {\n\t\t\tthis._callback( entries );\n\t\t}\n\t}\n\n\t/**\n\t * Compares the DOM element geometry to the {@link #_previousRects cached geometry} from the past.\n\t * Returns `true` if geometry has changed or the element is checked for the first time.\n\t *\n\t * @protected\n\t * @param {HTMLElement} element\n\t * @returns {Boolean}\n\t */\n\t_hasRectChanged( element ) {\n\t\tif ( !element.ownerDocument.body.contains( element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst currentRect = new Rect( element );\n\t\tconst previousRect = this._previousRects.get( element );\n\n\t\t// The first check should always yield true despite no Previous rect to compare to.\n\t\t// The native ResizeObserver does that and... that makes sense. Sort of.\n\t\tconst hasChanged = !previousRect || !previousRect.isEqual( currentRect );\n\n\t\tthis._previousRects.set( element, currentRect );\n\n\t\treturn hasChanged;\n\t}\n}\n\nmix( ResizeObserverPolyfill, DomEmitterMixin );\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 utils/dom/setdatainelement\n */\n\n/* globals HTMLTextAreaElement */\n\n/**\n * Sets data in a given element.\n *\n * @param {HTMLElement} el The element in which the data will be set.\n * @param {String} data The data string.\n */\nexport default function setDataInElement( el, data ) {\n\tif ( el instanceof HTMLTextAreaElement ) {\n\t\tel.value = data;\n\t}\n\n\tel.innerHTML = data;\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 utils/dom/tounit\n */\n\n/**\n * Returns a helper function, which adds a desired trailing\n * `unit` to the passed value.\n *\n * @param {String} unit An unit like \"px\" or \"em\".\n * @returns {module:utils/dom/tounit~helper}\n */\nexport default function toUnit( unit ) {\n\t/**\n\t * A function, which adds a predefined trailing `unit`\n\t * to the passed `value`.\n\t *\n\t * @function helper\n \t * @param {*} value A value to be given the unit.\n \t * @returns {String} A value with the trailing unit.\n\t */\n\treturn value => value + unit;\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 utils/first\n */\n\n/**\n * Returns first item of the given `iterable`.\n *\n * @param {Iterable.<*>} iterable\n * @returns {*}\n */\nexport default function first( iterable ) {\n\tconst iteratorItem = iterable.next();\n\n\tif ( iteratorItem.done ) {\n\t\treturn null;\n\t}\n\n\treturn iteratorItem.value;\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/* global setTimeout, clearTimeout */\n\n/**\n * @module utils/focustracker\n */\n\nimport DomEmitterMixin from './dom/emittermixin';\nimport ObservableMixin from './observablemixin';\nimport CKEditorError from './ckeditorerror';\nimport mix from './mix';\n\n/**\n * Allows observing a group of `HTMLElement`s whether at least one of them is focused.\n *\n * Used by the {@link module:core/editor/editor~Editor} in order to track whether the focus is still within the application,\n * or were used outside of its UI.\n *\n * **Note** `focus` and `blur` listeners use event capturing, so it is only needed to register wrapper `HTMLElement`\n * which contain other `focusable` elements. But note that this wrapper element has to be focusable too\n * (have e.g. `tabindex=\"-1\"`).\n *\n * Check out the {@glink framework/guides/deep-dive/ui/focus-tracking \"Deep dive into focus tracking\" guide} to learn more.\n *\n * @mixes module:utils/dom/emittermixin~EmitterMixin\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class FocusTracker {\n\tconstructor() {\n\t\t/**\n\t\t * True when one of the registered elements is focused.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The currently focused element.\n\t\t *\n\t\t * While {@link #isFocused `isFocused`} remains `true`, the focus can\n\t\t * move between different UI elements. This property tracks those\n\t\t * elements and tells which one is currently focused.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {HTMLElement|null} #focusedElement\n\t\t */\n\t\tthis.set( 'focusedElement', null );\n\n\t\t/**\n\t\t * List of registered elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<HTMLElement>}\n\t\t */\n\t\tthis._elements = new Set();\n\n\t\t/**\n\t\t * Event loop timeout.\n\t\t *\n\t\t * @private\n\t\t * @member {Number}\n\t\t */\n\t\tthis._nextEventLoopTimeout = null;\n\t}\n\n\t/**\n\t * Starts tracking the specified element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tadd( element ) {\n\t\tif ( this._elements.has( element ) ) {\n\t\t\t/**\n\t\t\t * This element is already tracked by {@link module:utils/focustracker~FocusTracker}.\n\t\t\t *\n\t\t\t * @error focustracker-add-element-already-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'focustracker-add-element-already-exist', this );\n\t\t}\n\n\t\tthis.listenTo( element, 'focus', () => this._focus( element ), { useCapture: true } );\n\t\tthis.listenTo( element, 'blur', () => this._blur(), { useCapture: true } );\n\t\tthis._elements.add( element );\n\t}\n\n\t/**\n\t * Stops tracking the specified element and stops listening on this element.\n\t *\n\t * @param {HTMLElement} element\n\t */\n\tremove( element ) {\n\t\tif ( element === this.focusedElement ) {\n\t\t\tthis._blur( element );\n\t\t}\n\n\t\tif ( this._elements.has( element ) ) {\n\t\t\tthis.stopListening( element );\n\t\t\tthis._elements.delete( element );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the focus tracker by:\n\t * - Disabling all event listeners attached to tracked elements.\n\t * - Removing all tracked elements that were previously added.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Stores currently focused element and set {#isFocused} as `true`.\n\t *\n\t * @private\n\t * @param {HTMLElement} element Element which has been focused.\n\t */\n\t_focus( element ) {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis.focusedElement = element;\n\t\tthis.isFocused = true;\n\t}\n\n\t/**\n\t * Clears currently focused element and set {@link #isFocused} as `false`.\n\t * This method uses `setTimeout` to change order of fires `blur` and `focus` events.\n\t *\n\t * @private\n\t * @fires blur\n\t */\n\t_blur() {\n\t\tclearTimeout( this._nextEventLoopTimeout );\n\n\t\tthis._nextEventLoopTimeout = setTimeout( () => {\n\t\t\tthis.focusedElement = null;\n\t\t\tthis.isFocused = false;\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * @event focus\n\t */\n\n\t/**\n\t * @event blur\n\t */\n}\n\nmix( FocusTracker, DomEmitterMixin );\nmix( FocusTracker, ObservableMixin );\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 utils/keystrokehandler\n */\n\nimport DomEmitterMixin from './dom/emittermixin';\nimport { getCode, parseKeystroke } from './keyboard';\n\n/**\n * Keystroke handler allows registering callbacks for given keystrokes.\n *\n * The most frequent use of this class is through the {@link module:core/editor/editor~Editor#keystrokes `editor.keystrokes`}\n * property. It allows listening to keystrokes executed in the editing view:\n *\n *\t\teditor.keystrokes.set( 'Ctrl+A', ( keyEvtData, cancel ) => {\n *\t\t\tconsole.log( 'Ctrl+A has been pressed' );\n *\t\t\tcancel();\n *\t\t} );\n *\n * However, this utility class can be used in various part of the UI. For instance, a certain {@link module:ui/view~View}\n * can use it like this:\n *\n *\t\tclass MyView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tthis.keystrokes = new KeystrokeHandler();\n *\n * \t\t\t\tthis.keystrokes.set( 'tab', handleTabKey );\n *\t\t\t}\n *\n *\t\t\trender() {\n *\t\t\t\tsuper.render();\n *\n *\t\t\t\tthis.keystrokes.listenTo( this.element );\n *\t\t\t}\n *\t\t}\n *\n * That keystroke handler will listen to `keydown` events fired in this view's main element.\n *\n */\nexport default class KeystrokeHandler {\n\t/**\n\t * Creates an instance of the keystroke handler.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Listener used to listen to events for easier keystroke handler destruction.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/dom/emittermixin~Emitter}\n\t\t */\n\t\tthis._listener = Object.create( DomEmitterMixin );\n\t}\n\n\t/**\n\t * Starts listening for `keydown` events from a given emitter.\n\t *\n\t * @param {module:utils/emittermixin~Emitter} emitter\n\t */\n\tlistenTo( emitter ) {\n\t\t// The #_listener works here as a kind of dispatcher. It groups the events coming from the same\n\t\t// keystroke so the listeners can be attached to them with different priorities.\n\t\t//\n\t\t// E.g. all the keystrokes with the `keyCode` of 42 coming from the `emitter` are propagated\n\t\t// as a `_keydown:42` event by the `_listener`. If there's a callback created by the `set`\n\t\t// method for this 42 keystroke, it listens to the `_listener#_keydown:42` event only and interacts\n\t\t// only with other listeners of this particular event, thus making it possible to prioritize\n\t\t// the listeners and safely cancel execution, when needed. Instead of duplicating the Emitter logic,\n\t\t// the KeystrokeHandler reuses it to do its job.\n\t\tthis._listener.listenTo( emitter, 'keydown', ( evt, keyEvtData ) => {\n\t\t\tthis._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );\n\t\t} );\n\t}\n\n\t/**\n\t * Registers a handler for the specified keystroke.\n\t *\n\t * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by\n\t * the {@link module:utils/keyboard~parseKeystroke} function.\n\t * @param {Function} callback A function called with the\n\t * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and\n\t * a helper funcion to call both `preventDefault()` and `stopPropagation()` on the underlying event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke\n\t * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority\n\t * are called in the order they were added.\n\t */\n\tset( keystroke, callback, options = {} ) {\n\t\tconst keyCode = parseKeystroke( keystroke );\n\t\tconst priority = options.priority;\n\n\t\t// Execute the passed callback on KeystrokeHandler#_keydown.\n\t\t// TODO: https://github.com/ckeditor/ckeditor5-utils/issues/144\n\t\tthis._listener.listenTo( this._listener, '_keydown:' + keyCode, ( evt, keyEvtData ) => {\n\t\t\tcallback( keyEvtData, () => {\n\t\t\t\t// Stop the event in the DOM: no listener in the web page\n\t\t\t\t// will be triggered by this event.\n\t\t\t\tkeyEvtData.preventDefault();\n\t\t\t\tkeyEvtData.stopPropagation();\n\n\t\t\t\t// Stop the event in the KeystrokeHandler: no more callbacks\n\t\t\t\t// will be executed for this keystroke.\n\t\t\t\tevt.stop();\n\t\t\t} );\n\n\t\t\t// Mark this keystroke as handled by the callback. See: #press.\n\t\t\tevt.return = true;\n\t\t}, { priority } );\n\t}\n\n\t/**\n\t * Triggers a keystroke handler for a specified key combination, if such a keystroke was {@link #set defined}.\n\t *\n\t * @param {module:engine/view/observer/keyobserver~KeyEventData} keyEvtData Key event data.\n\t * @returns {Boolean} Whether the keystroke was handled.\n\t */\n\tpress( keyEvtData ) {\n\t\treturn !!this._listener.fire( '_keydown:' + getCode( keyEvtData ), keyEvtData );\n\t}\n\n\t/**\n\t * Destroys the keystroke handler.\n\t */\n\tdestroy() {\n\t\tthis._listener.stopListening();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/observer/arrowkeysobserver\n */\n\nimport Observer from './observer';\nimport BubblingEventInfo from './bubblingeventinfo';\n\nimport { isArrowKeyCode } from '@ckeditor/ckeditor5-utils';\n\n/**\n * Arrow keys observer introduces the {@link module:engine/view/document~Document#event:arrowKey `Document#arrowKey`} event.\n *\n * Note that this observer is attached by the {@link module:engine/view/view~View} and is available by default.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class ArrowKeysObserver extends Observer {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.document.on( 'keydown', ( event, data ) => {\n\t\t\tif ( this.isEnabled && isArrowKeyCode( data.keyCode ) ) {\n\t\t\t\tconst eventInfo = new BubblingEventInfo( this.document, 'arrowKey', this.document.selection.getFirstRange() );\n\n\t\t\t\tthis.document.fire( eventInfo, data );\n\n\t\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\t\tevent.stop();\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {}\n}\n\n/**\n * Event fired when the user presses an arrow keys.\n *\n * Introduced by {@link module:engine/view/observer/arrowkeysobserver~ArrowKeysObserver}.\n *\n * Note that because {@link module:engine/view/observer/arrowkeysobserver~ArrowKeysObserver} is attached by the\n * {@link module:engine/view/view~View} this event is available by default.\n *\n * @event module:engine/view/document~Document#event:arrowKey\n * @param {module:engine/view/observer/domeventdata~DomEventData} data\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 utils/dom/scroll\n */\n\nimport isRange from './isrange';\nimport Rect from './rect';\nimport isText from './istext';\n\nconst utils = {};\n\n/**\n * Makes any page `HTMLElement` or `Range` (`target`) visible inside the browser viewport.\n * This helper will scroll all `target` ancestors and the web browser viewport to reveal the target to\n * the user. If the `target` is already visible, nothing will happen.\n *\n * @param {HTMLElement|Range} options.target A target, which supposed to become visible to the user.\n * @param {Number} [options.viewportOffset] An offset from the edge of the viewport (in pixels)\n * the `target` will be moved by when the viewport is scrolled. It enhances the user experience\n * by keeping the `target` some distance from the edge of the viewport and thus making it easier to\n * read or edit by the user.\n */\nexport function scrollViewportToShowTarget( { target, viewportOffset = 0 } ) {\n\tconst targetWindow = getWindow( target );\n\tlet currentWindow = targetWindow;\n\tlet currentFrame = null;\n\n\t// Iterate over all windows, starting from target's parent window up to window#top.\n\twhile ( currentWindow ) {\n\t\tlet firstAncestorToScroll;\n\n\t\t// Let's scroll target's ancestors first to reveal it. Then, once the ancestor scrolls\n\t\t// settled down, the algorithm can eventually scroll the viewport of the current window.\n\t\t//\n\t\t// Note: If the current window is target's **original** window (e.g. the first one),\n\t\t// start scrolling the closest parent of the target. If not, scroll the closest parent\n\t\t// of an iframe that resides in the current window.\n\t\tif ( currentWindow == targetWindow ) {\n\t\t\tfirstAncestorToScroll = getParentElement( target );\n\t\t} else {\n\t\t\tfirstAncestorToScroll = getParentElement( currentFrame );\n\t\t}\n\n\t\t// Scroll the target's ancestors first. Once done, scrolling the viewport is easy.\n\t\tscrollAncestorsToShowRect( firstAncestorToScroll, () => {\n\t\t\t// Note: If the target does not belong to the current window **directly**,\n\t\t\t// i.e. it resides in an iframe belonging to the window, obtain the target's rect\n\t\t\t// in the coordinates of the current window. By default, a Rect returns geometry\n\t\t\t// relative to the current window's viewport. To make it work in a parent window,\n\t\t\t// it must be shifted.\n\t\t\treturn getRectRelativeToWindow( target, currentWindow );\n\t\t} );\n\n\t\t// Obtain the rect of the target after it has been scrolled within its ancestors.\n\t\t// It's time to scroll the viewport.\n\t\tconst targetRect = getRectRelativeToWindow( target, currentWindow );\n\n\t\tscrollWindowToShowRect( currentWindow, targetRect, viewportOffset );\n\n\t\tif ( currentWindow.parent != currentWindow ) {\n\t\t\t// Keep the reference to the <iframe> element the \"previous current window\" was\n\t\t\t// rendered within. It will be useful to recalculate the rect of the target\n\t\t\t// in the parent window's relative geometry. The target's rect must be shifted\n\t\t\t// by it's iframe's position.\n\t\t\tcurrentFrame = currentWindow.frameElement;\n\t\t\tcurrentWindow = currentWindow.parent;\n\n\t\t\t// If the current window has some parent but frameElement is inaccessible, then they have\n\t\t\t// different domains/ports and, due to security reasons, accessing and scrolling\n\t\t\t// the parent window won't be possible.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/930.\n\t\t\tif ( !currentFrame ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t} else {\n\t\t\tcurrentWindow = null;\n\t\t}\n\t}\n}\n\n/**\n * Makes any page `HTMLElement` or `Range` (target) visible within its scrollable ancestors,\n * e.g. if they have `overflow: scroll` CSS style.\n *\n * @param {HTMLElement|Range} target A target, which supposed to become visible to the user.\n */\nexport function scrollAncestorsToShowTarget( target ) {\n\tconst targetParent = getParentElement( target );\n\n\tscrollAncestorsToShowRect( targetParent, () => {\n\t\treturn new Rect( target );\n\t} );\n}\n\n// TODO: Using a property value shorthand in the top of the file\n// causes JSDoc to throw errors. See https://github.com/cksource/docs-builder/issues/75.\nObject.assign( utils, {\n\tscrollViewportToShowTarget,\n\tscrollAncestorsToShowTarget\n} );\n\n// Makes a given rect visible within its parent window.\n//\n// Note: Avoid the situation where the caret is still in the viewport, but totally\n// at the edge of it. In such situation, if it moved beyond the viewport in the next\n// action e.g. after paste, the scrolling would move it to the viewportOffset level\n// and it all would look like the caret visually moved up/down:\n//\n// 1.\n//\t\t| foo[]\n//\t\t| <--- N px of space below the caret\n//\t\t+---------------------------------...\n//\n// 2. *paste*\n// 3.\n//\t\t|\n//\t\t|\n//\t\t+-foo-----------------------------...\n//\t\t bar[] <--- caret below viewport, scrolling...\n//\n// 4. *scrolling*\n// 5.\n//\t\t|\n//\t\t| foo\n//\t\t| bar[] <--- caret precisely at the edge\n//\t\t+---------------------------------...\n//\n// To prevent this, this method checks the rects moved by the viewportOffset to cover\n// the upper/lower edge of the viewport. It makes sure if the action repeats, there's\n// no twitching it's a purely visual improvement:\n//\n// 5. (after fix)\n//\t\t|\n//\t\t| foo\n//\t\t| bar[]\n//\t\t| <--- N px of space below the caret\n//\t\t+---------------------------------...\n//\n// @private\n// @param {Window} window A window which is scrolled to reveal the rect.\n// @param {module:utils/dom/rect~Rect} rect A rect which is to be revealed.\n// @param {Number} viewportOffset See scrollViewportToShowTarget.\nfunction scrollWindowToShowRect( window, rect, viewportOffset ) {\n\tconst targetShiftedDownRect = rect.clone().moveBy( 0, viewportOffset );\n\tconst targetShiftedUpRect = rect.clone().moveBy( 0, -viewportOffset );\n\tconst viewportRect = new Rect( window ).excludeScrollbarsAndBorders();\n\n\tconst rects = [ targetShiftedUpRect, targetShiftedDownRect ];\n\n\tif ( !rects.every( rect => viewportRect.contains( rect ) ) ) {\n\t\tlet { scrollX, scrollY } = window;\n\n\t\tif ( isAbove( targetShiftedUpRect, viewportRect ) ) {\n\t\t\tscrollY -= viewportRect.top - rect.top + viewportOffset;\n\t\t} else if ( isBelow( targetShiftedDownRect, viewportRect ) ) {\n\t\t\tscrollY += rect.bottom - viewportRect.bottom + viewportOffset;\n\t\t}\n\n\t\t// TODO: Web browsers scroll natively to place the target in the middle\n\t\t// of the viewport. It's not a very popular case, though.\n\t\tif ( isLeftOf( rect, viewportRect ) ) {\n\t\t\tscrollX -= viewportRect.left - rect.left + viewportOffset;\n\t\t} else if ( isRightOf( rect, viewportRect ) ) {\n\t\t\tscrollX += rect.right - viewportRect.right + viewportOffset;\n\t\t}\n\n\t\twindow.scrollTo( scrollX, scrollY );\n\t}\n}\n\n// Recursively scrolls element ancestors to visually reveal a rect.\n//\n// @private\n// @param {HTMLElement} A parent The first ancestors to start scrolling.\n// @param {Function} getRect A function which returns the Rect, which is to be revealed.\nfunction scrollAncestorsToShowRect( parent, getRect ) {\n\tconst parentWindow = getWindow( parent );\n\tlet parentRect, targetRect;\n\n\twhile ( parent != parentWindow.document.body ) {\n\t\ttargetRect = getRect();\n\t\tparentRect = new Rect( parent ).excludeScrollbarsAndBorders();\n\n\t\tif ( !parentRect.contains( targetRect ) ) {\n\t\t\tif ( isAbove( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollTop -= parentRect.top - targetRect.top;\n\t\t\t} else if ( isBelow( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollTop += targetRect.bottom - parentRect.bottom;\n\t\t\t}\n\n\t\t\tif ( isLeftOf( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollLeft -= parentRect.left - targetRect.left;\n\t\t\t} else if ( isRightOf( targetRect, parentRect ) ) {\n\t\t\t\tparent.scrollLeft += targetRect.right - parentRect.right;\n\t\t\t}\n\t\t}\n\n\t\tparent = parent.parentNode;\n\t}\n}\n\n// Determines if a given `Rect` extends beyond the bottom edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isBelow( firstRect, secondRect ) {\n\treturn firstRect.bottom > secondRect.bottom;\n}\n\n// Determines if a given `Rect` extends beyond the top edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isAbove( firstRect, secondRect ) {\n\treturn firstRect.top < secondRect.top;\n}\n\n// Determines if a given `Rect` extends beyond the left edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isLeftOf( firstRect, secondRect ) {\n\treturn firstRect.left < secondRect.left;\n}\n\n// Determines if a given `Rect` extends beyond the right edge of the second `Rect`.\n//\n// @private\n// @param {module:utils/dom/rect~Rect} firstRect\n// @param {module:utils/dom/rect~Rect} secondRect\nfunction isRightOf( firstRect, secondRect ) {\n\treturn firstRect.right > secondRect.right;\n}\n\n// Returns the closest window of an element or range.\n//\n// @private\n// @param {HTMLElement|Range} firstRect\n// @returns {Window}\nfunction getWindow( elementOrRange ) {\n\tif ( isRange( elementOrRange ) ) {\n\t\treturn elementOrRange.startContainer.ownerDocument.defaultView;\n\t} else {\n\t\treturn elementOrRange.ownerDocument.defaultView;\n\t}\n}\n\n// Returns the closest parent of an element or DOM range.\n//\n// @private\n// @param {HTMLElement|Range} firstRect\n// @returns {HTMLelement}\nfunction getParentElement( elementOrRange ) {\n\tif ( isRange( elementOrRange ) ) {\n\t\tlet parent = elementOrRange.commonAncestorContainer;\n\n\t\t// If a Range is attached to the Text, use the closest element ancestor.\n\t\tif ( isText( parent ) ) {\n\t\t\tparent = parent.parentNode;\n\t\t}\n\n\t\treturn parent;\n\t} else {\n\t\treturn elementOrRange.parentNode;\n\t}\n}\n\n// Returns the rect of an element or range residing in an iframe.\n// The result rect is relative to the geometry of the passed window instance.\n//\n// @private\n// @param {HTMLElement|Range} target Element or range which rect should be returned.\n// @param {Window} relativeWindow A window the rect should be relative to.\n// @returns {module:utils/dom/rect~Rect}\nfunction getRectRelativeToWindow( target, relativeWindow ) {\n\tconst targetWindow = getWindow( target );\n\tconst rect = new Rect( target );\n\n\tif ( targetWindow === relativeWindow ) {\n\t\treturn rect;\n\t} else {\n\t\tlet currentWindow = targetWindow;\n\n\t\twhile ( currentWindow != relativeWindow ) {\n\t\t\tconst frame = currentWindow.frameElement;\n\t\t\tconst frameRect = new Rect( frame ).excludeScrollbarsAndBorders();\n\n\t\t\trect.moveBy( frameRect.left, frameRect.top );\n\n\t\t\tcurrentWindow = currentWindow.parent;\n\t\t}\n\t}\n\n\treturn rect;\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/view/view\n */\n\nimport Document from './document';\nimport DowncastWriter from './downcastwriter';\nimport Renderer from './renderer';\nimport DomConverter from './domconverter';\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\n\nimport MutationObserver from './observer/mutationobserver';\nimport KeyObserver from './observer/keyobserver';\nimport FakeSelectionObserver from './observer/fakeselectionobserver';\nimport SelectionObserver from './observer/selectionobserver';\nimport FocusObserver from './observer/focusobserver';\nimport CompositionObserver from './observer/compositionobserver';\nimport InputObserver from './observer/inputobserver';\nimport ArrowKeysObserver from './observer/arrowkeysobserver';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { scrollViewportToShowTarget } from '@ckeditor/ckeditor5-utils/src/dom/scroll';\nimport { injectUiElementHandling } from './uielement';\nimport { injectQuirksHandling } from './filler';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Editor's view controller class. Its main responsibility is DOM - View management for editing purposes, to provide\n * abstraction over the DOM structure and events and hide all browsers quirks.\n *\n * View controller renders view document to DOM whenever view structure changes. To determine when view can be rendered,\n * all changes need to be done using the {@link module:engine/view/view~View#change} method, using\n * {@link module:engine/view/downcastwriter~DowncastWriter}:\n *\n *\t\tview.change( writer => {\n *\t\t\twriter.insert( position, writer.createText( 'foo' ) );\n *\t\t} );\n *\n * View controller also register {@link module:engine/view/observer/observer~Observer observers} which observes changes\n * on DOM and fire events on the {@link module:engine/view/document~Document Document}.\n * Note that the following observers are added by the class constructor and are always available:\n *\n * * {@link module:engine/view/observer/mutationobserver~MutationObserver},\n * * {@link module:engine/view/observer/selectionobserver~SelectionObserver},\n * * {@link module:engine/view/observer/focusobserver~FocusObserver},\n * * {@link module:engine/view/observer/keyobserver~KeyObserver},\n * * {@link module:engine/view/observer/fakeselectionobserver~FakeSelectionObserver}.\n * * {@link module:engine/view/observer/compositionobserver~CompositionObserver}.\n *\n * This class also {@link module:engine/view/view~View#attachDomRoot binds the DOM and the view elements}.\n *\n * If you do not need full a DOM - view management, and only want to transform a tree of view elements to a tree of DOM\n * elements you do not need this controller. You can use the {@link module:engine/view/domconverter~DomConverter DomConverter} instead.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class View {\n\t/**\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( stylesProcessor ) {\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/document~Document} associated with this view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = new Document( stylesProcessor );\n\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/domconverter~DomConverter domConverter} used by\n\t\t * {@link module:engine/view/view~View#_renderer renderer}\n\t\t * and {@link module:engine/view/observer/observer~Observer observers}.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis.domConverter = new DomConverter( this.document );\n\n\t\t/**\n\t\t * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Map.<String, HTMLElement>}\n\t\t */\n\t\tthis.domRoots = new Map();\n\n\t\t/**\n\t\t * Used to prevent calling {@link #forceRender} and {@link #change} during rendering view to the DOM.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isRenderingInProgress\n\t\t */\n\t\tthis.set( 'isRenderingInProgress', false );\n\n\t\t/**\n\t\t * Informs whether the DOM selection is inside any of the DOM roots managed by the view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #hasDomSelection\n\t\t */\n\t\tthis.set( 'hasDomSelection', false );\n\n\t\t/**\n\t\t * Instance of the {@link module:engine/view/renderer~Renderer renderer}.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:engine/view/renderer~Renderer}\n\t\t */\n\t\tthis._renderer = new Renderer( this.domConverter, this.document.selection );\n\t\tthis._renderer.bind( 'isFocused' ).to( this.document );\n\n\t\t/**\n\t\t * A DOM root attributes cache. It saves the initial values of DOM root attributes before the DOM element\n\t\t * is {@link module:engine/view/view~View#attachDomRoot attached} to the view so later on, when\n\t\t * the view is destroyed ({@link module:engine/view/view~View#detachDomRoot}), they can be easily restored.\n\t\t * This way, the DOM element can go back to the (clean) state as if the editing view never used it.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap.<HTMLElement,Object>}\n\t\t */\n\t\tthis._initialDomRootAttributes = new WeakMap();\n\n\t\t/**\n\t\t * Map of registered {@link module:engine/view/observer/observer~Observer observers}.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<Function, module:engine/view/observer/observer~Observer>}\n\t\t */\n\t\tthis._observers = new Map();\n\n\t\t/**\n\t\t * Is set to `true` when {@link #change view changes} are currently in progress.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._ongoingChange = false;\n\n\t\t/**\n\t\t * Used to prevent calling {@link #forceRender} and {@link #change} during rendering view to the DOM.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._postFixersInProgress = false;\n\n\t\t/**\n\t\t * Internal flag to temporary disable rendering. See the usage in the {@link #_disableRendering}.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._renderingDisabled = false;\n\n\t\t/**\n\t\t * Internal flag that disables rendering when there are no changes since the last rendering.\n\t\t * It stores information about changed selection and changed elements from attached document roots.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasChangedSinceTheLastRendering = false;\n\n\t\t/**\n\t\t * DowncastWriter instance used in {@link #change change method} callbacks.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/downcastwriter~DowncastWriter}\n\t\t */\n\t\tthis._writer = new DowncastWriter( this.document );\n\n\t\t// Add default observers.\n\t\tthis.addObserver( MutationObserver );\n\t\tthis.addObserver( SelectionObserver );\n\t\tthis.addObserver( FocusObserver );\n\t\tthis.addObserver( KeyObserver );\n\t\tthis.addObserver( FakeSelectionObserver );\n\t\tthis.addObserver( CompositionObserver );\n\t\tthis.addObserver( ArrowKeysObserver );\n\n\t\tif ( env.isAndroid ) {\n\t\t\tthis.addObserver( InputObserver );\n\t\t}\n\n\t\t// Inject quirks handlers.\n\t\tinjectQuirksHandling( this );\n\t\tinjectUiElementHandling( this );\n\n\t\t// Use 'normal' priority so that rendering is performed as first when using that priority.\n\t\tthis.on( 'render', () => {\n\t\t\tthis._render();\n\n\t\t\t// Informs that layout has changed after render.\n\t\t\tthis.document.fire( 'layoutChanged' );\n\n\t\t\t// Reset the `_hasChangedSinceTheLastRendering` flag after rendering.\n\t\t\tthis._hasChangedSinceTheLastRendering = false;\n\t\t} );\n\n\t\t// Listen to the document selection changes directly.\n\t\tthis.listenTo( this.document.selection, 'change', () => {\n\t\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\t} );\n\t}\n\n\t/**\n\t * Attaches a DOM root element to the view element and enable all observers on that element.\n\t * Also {@link module:engine/view/renderer~Renderer#markToSync mark element} to be synchronized\n\t * with the view what means that all child nodes will be removed and replaced with content of the view root.\n\t *\n\t * This method also will change view element name as the same as tag name of given dom root.\n\t * Name is always transformed to lower case.\n\t *\n\t * **Note:** Use {@link #detachDomRoot `detachDomRoot()`} to revert this action.\n\t *\n\t * @param {Element} domRoot DOM root element.\n\t * @param {String} [name='main'] Name of the root.\n\t */\n\tattachDomRoot( domRoot, name = 'main' ) {\n\t\tconst viewRoot = this.document.getRoot( name );\n\n\t\t// Set view root name the same as DOM root tag name.\n\t\tviewRoot._name = domRoot.tagName.toLowerCase();\n\n\t\tconst initialDomRootAttributes = {};\n\n\t\t// 1. Copy and cache the attributes to remember the state of the element before attaching.\n\t\t// The cached attributes will be restored in detachDomRoot() so the element goes to the\n\t\t// clean state as if the editing view never used it.\n\t\t// 2. Apply the attributes using the view writer, so they all go under the control of the engine.\n\t\t// The editing view takes over the attribute management completely because various\n\t\t// features (e.g. addPlaceholder()) require dynamic changes of those attributes and they\n\t\t// cannot be managed by the engine and the UI library at the same time.\n\t\tfor ( const { name, value } of Array.from( domRoot.attributes ) ) {\n\t\t\tinitialDomRootAttributes[ name ] = value;\n\n\t\t\t// Do not use writer.setAttribute() for the class attribute. The EditableUIView class\n\t\t\t// and its descendants could have already set some using the writer.addClass() on the view\n\t\t\t// document root. They haven't been rendered yet so they are not present in the DOM root.\n\t\t\t// Using writer.setAttribute( 'class', ... ) would override them completely.\n\t\t\tif ( name === 'class' ) {\n\t\t\t\tthis._writer.addClass( value.split( ' ' ), viewRoot );\n\t\t\t} else {\n\t\t\t\tthis._writer.setAttribute( name, value, viewRoot );\n\t\t\t}\n\t\t}\n\n\t\tthis._initialDomRootAttributes.set( domRoot, initialDomRootAttributes );\n\n\t\tconst updateContenteditableAttribute = () => {\n\t\t\tthis._writer.setAttribute( 'contenteditable', !viewRoot.isReadOnly, viewRoot );\n\n\t\t\tif ( viewRoot.isReadOnly ) {\n\t\t\t\tthis._writer.addClass( 'ck-read-only', viewRoot );\n\t\t\t} else {\n\t\t\t\tthis._writer.removeClass( 'ck-read-only', viewRoot );\n\t\t\t}\n\t\t};\n\n\t\t// Set initial value.\n\t\tupdateContenteditableAttribute();\n\n\t\tthis.domRoots.set( name, domRoot );\n\t\tthis.domConverter.bindElements( domRoot, viewRoot );\n\t\tthis._renderer.markToSync( 'children', viewRoot );\n\t\tthis._renderer.markToSync( 'attributes', viewRoot );\n\t\tthis._renderer.domDocuments.add( domRoot.ownerDocument );\n\n\t\tviewRoot.on( 'change:children', ( evt, node ) => this._renderer.markToSync( 'children', node ) );\n\t\tviewRoot.on( 'change:attributes', ( evt, node ) => this._renderer.markToSync( 'attributes', node ) );\n\t\tviewRoot.on( 'change:text', ( evt, node ) => this._renderer.markToSync( 'text', node ) );\n\t\tviewRoot.on( 'change:isReadOnly', () => this.change( updateContenteditableAttribute ) );\n\n\t\tviewRoot.on( 'change', () => {\n\t\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\t} );\n\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.observe( domRoot, name );\n\t\t}\n\t}\n\n\t/**\n\t * Detaches a DOM root element from the view element and restores its attributes to the state before\n\t * {@link #attachDomRoot `attachDomRoot()`}.\n\t *\n\t * @param {String} name Name of the root to detach.\n\t */\n\tdetachDomRoot( name ) {\n\t\tconst domRoot = this.domRoots.get( name );\n\n\t\t// Remove all root attributes so the DOM element is \"bare\".\n\t\tArray.from( domRoot.attributes ).forEach( ( { name } ) => domRoot.removeAttribute( name ) );\n\n\t\tconst initialDomRootAttributes = this._initialDomRootAttributes.get( domRoot );\n\n\t\t// Revert all view root attributes back to the state before attachDomRoot was called.\n\t\tfor ( const attribute in initialDomRootAttributes ) {\n\t\t\tdomRoot.setAttribute( attribute, initialDomRootAttributes[ attribute ] );\n\t\t}\n\n\t\tthis.domRoots.delete( name );\n\t\tthis.domConverter.unbindDomElement( domRoot );\n\t}\n\n\t/**\n\t * Gets DOM root element.\n\t *\n\t * @param {String} [name='main'] Name of the root.\n\t * @returns {Element} DOM root element instance.\n\t */\n\tgetDomRoot( name = 'main' ) {\n\t\treturn this.domRoots.get( name );\n\t}\n\n\t/**\n\t * Creates observer of the given type if not yet created, {@link module:engine/view/observer/observer~Observer#enable enables} it\n\t * and {@link module:engine/view/observer/observer~Observer#observe attaches} to all existing and future\n\t * {@link #domRoots DOM roots}.\n\t *\n\t * Note: Observers are recognized by their constructor (classes). A single observer will be instantiated and used only\n\t * when registered for the first time. This means that features and other components can register a single observer\n\t * multiple times without caring whether it has been already added or not.\n\t *\n\t * @param {Function} Observer The constructor of an observer to add.\n\t * Should create an instance inheriting from {@link module:engine/view/observer/observer~Observer}.\n\t * @returns {module:engine/view/observer/observer~Observer} Added observer instance.\n\t */\n\taddObserver( Observer ) {\n\t\tlet observer = this._observers.get( Observer );\n\n\t\tif ( observer ) {\n\t\t\treturn observer;\n\t\t}\n\n\t\tobserver = new Observer( this );\n\n\t\tthis._observers.set( Observer, observer );\n\n\t\tfor ( const [ name, domElement ] of this.domRoots ) {\n\t\t\tobserver.observe( domElement, name );\n\t\t}\n\n\t\tobserver.enable();\n\n\t\treturn observer;\n\t}\n\n\t/**\n\t * Returns observer of the given type or `undefined` if such observer has not been added yet.\n\t *\n\t * @param {Function} Observer The constructor of an observer to get.\n\t * @returns {module:engine/view/observer/observer~Observer|undefined} Observer instance or undefined.\n\t */\n\tgetObserver( Observer ) {\n\t\treturn this._observers.get( Observer );\n\t}\n\n\t/**\n\t * Disables all added observers.\n\t */\n\tdisableObservers() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.disable();\n\t\t}\n\t}\n\n\t/**\n\t * Enables all added observers.\n\t */\n\tenableObservers() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.enable();\n\t\t}\n\t}\n\n\t/**\n\t * Scrolls the page viewport and {@link #domRoots} with their ancestors to reveal the\n\t * caret, if not already visible to the user.\n\t */\n\tscrollToTheSelection() {\n\t\tconst range = this.document.selection.getFirstRange();\n\n\t\tif ( range ) {\n\t\t\tscrollViewportToShowTarget( {\n\t\t\t\ttarget: this.domConverter.viewRangeToDom( range ),\n\t\t\t\tviewportOffset: 20\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * It will focus DOM element representing {@link module:engine/view/editableelement~EditableElement EditableElement}\n\t * that is currently having selection inside.\n\t */\n\tfocus() {\n\t\tif ( !this.document.isFocused ) {\n\t\t\tconst editable = this.document.selection.editableElement;\n\n\t\t\tif ( editable ) {\n\t\t\t\tthis.domConverter.focus( editable );\n\t\t\t\tthis.forceRender();\n\t\t\t} else {\n\t\t\t\t// Before focusing view document, selection should be placed inside one of the view's editables.\n\t\t\t\t// Normally its selection will be converted from model document (which have default selection), but\n\t\t\t\t// when using view document on its own, we need to manually place selection before focusing it.\n\t\t\t\t//\n\t\t\t\t// @if CK_DEBUG // console.warn( 'There is no selection in any editable to focus.' );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * The `change()` method is the primary way of changing the view. You should use it to modify any node in the view tree.\n\t * It makes sure that after all changes are made the view is rendered to the DOM (assuming that the view will be changed\n\t * inside the callback). It prevents situations when the DOM is updated when the view state is not yet correct. It allows\n\t * to nest calls one inside another and still performs a single rendering after all those changes are made.\n\t * It also returns the return value of its callback.\n\t *\n\t *\t\tconst text = view.change( writer => {\n\t *\t\t\tconst newText = writer.createText( 'foo' );\n\t *\t\t\twriter.insert( position1, newText );\n\t *\n\t *\t\t\tview.change( writer => {\n\t *\t\t\t\twriter.insert( position2, writer.createText( 'bar' ) );\n\t *\t\t\t} );\n\t *\n\t * \t\t\twriter.remove( range );\n\t *\n\t * \t\t\treturn newText;\n\t *\t\t} );\n\t *\n\t * When the outermost change block is done and rendering to the DOM is over the\n\t * {@link module:engine/view/view~View#event:render `View#render`} event is fired.\n\t *\n\t * This method throws a `applying-view-changes-on-rendering` error when\n\t * the change block is used after rendering to the DOM has started.\n\t *\n\t * @param {Function} callback Callback function which may modify the view.\n\t * @returns {*} Value returned by the callback.\n\t */\n\tchange( callback ) {\n\t\tif ( this.isRenderingInProgress || this._postFixersInProgress ) {\n\t\t\t/**\n\t\t\t * Thrown when there is an attempt to make changes to the view tree when it is in incorrect state. This may\n\t\t\t * cause some unexpected behaviour and inconsistency between the DOM and the view.\n\t\t\t * This may be caused by:\n\t\t\t *\n\t\t\t * * calling {@link #change} or {@link #forceRender} during rendering process,\n\t\t\t * * calling {@link #change} or {@link #forceRender} inside of\n\t\t\t * {@link module:engine/view/document~Document#registerPostFixer post-fixer function}.\n\t\t\t *\n\t\t\t * @error cannot-change-view-tree\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'cannot-change-view-tree',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\t// Recursive call to view.change() method - execute listener immediately.\n\t\t\tif ( this._ongoingChange ) {\n\t\t\t\treturn callback( this._writer );\n\t\t\t}\n\n\t\t\t// This lock will assure that all recursive calls to view.change() will end up in same block - one \"render\"\n\t\t\t// event for all nested calls.\n\t\t\tthis._ongoingChange = true;\n\t\t\tconst callbackResult = callback( this._writer );\n\t\t\tthis._ongoingChange = false;\n\n\t\t\t// This lock is used by editing controller to render changes from outer most model.change() once. As plugins might call\n\t\t\t// view.change() inside model.change() block - this will ensures that postfixers and rendering are called once after all\n\t\t\t// changes. Also, we don't need to render anything if there're no changes since last rendering.\n\t\t\tif ( !this._renderingDisabled && this._hasChangedSinceTheLastRendering ) {\n\t\t\t\tthis._postFixersInProgress = true;\n\t\t\t\tthis.document._callPostFixers( this._writer );\n\t\t\t\tthis._postFixersInProgress = false;\n\n\t\t\t\tthis.fire( 'render' );\n\t\t\t}\n\n\t\t\treturn callbackResult;\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * Forces rendering {@link module:engine/view/document~Document view document} to DOM. If any view changes are\n\t * currently in progress, rendering will start after all {@link #change change blocks} are processed.\n\t *\n\t * Note that this method is dedicated for special cases. All view changes should be wrapped in the {@link #change}\n\t * block and the view will automatically check whether it needs to render DOM or not.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `applying-view-changes-on-rendering` when\n\t * trying to re-render when rendering to DOM has already started.\n\t */\n\tforceRender() {\n\t\tthis._hasChangedSinceTheLastRendering = true;\n\t\tthis.change( () => {} );\n\t}\n\n\t/**\n\t * Destroys this instance. Makes sure that all observers are destroyed and listeners removed.\n\t */\n\tdestroy() {\n\t\tfor ( const observer of this._observers.values() ) {\n\t\t\tobserver.destroy();\n\t\t}\n\n\t\tthis.document.destroy();\n\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/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/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/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 * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t Creates new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = view.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = view.createRange( start, end );\n\t *\t\tconst selection = view.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ view.createRange( start1, end2 ), view.createRange( star2, end2 ) ];\n\t *\t\tconst selection = view.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = view.createSelection();\n\t *\t\tconst selection = view.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = view.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = view.createPositionFromPath( root, path );\n\t *\t\tconst selection = view.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = view.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = view.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = view.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = view.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s factory method allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = view.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = view.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Disables or enables rendering. If the flag is set to `true` then the rendering will be disabled.\n\t * If the flag is set to `false` and if there was some change in the meantime, then the rendering action will be performed.\n\t *\n\t * @protected\n\t * @param {Boolean} flag A flag indicates whether the rendering should be disabled.\n\t */\n\t_disableRendering( flag ) {\n\t\tthis._renderingDisabled = flag;\n\n\t\tif ( flag == false ) {\n\t\t\t// Render when you stop blocking rendering.\n\t\t\tthis.change( () => {} );\n\t\t}\n\t}\n\n\t/**\n\t * Renders all changes. In order to avoid triggering the observers (e.g. mutations) all observers are disabled\n\t * before rendering and re-enabled after that.\n\t *\n\t * @private\n\t */\n\t_render() {\n\t\tthis.isRenderingInProgress = true;\n\t\tthis.disableObservers();\n\t\tthis._renderer.render();\n\t\tthis.enableObservers();\n\t\tthis.isRenderingInProgress = false;\n\t}\n\n\t/**\n\t * Fired after a topmost {@link module:engine/view/view~View#change change block} and all\n\t * {@link module:engine/view/document~Document#registerPostFixer post-fixers} are executed.\n\t *\n\t * Actual rendering is performed as a first listener on 'normal' priority.\n\t *\n\t *\t\tview.on( 'render', () => {\n\t *\t\t\t// Rendering to the DOM is complete.\n\t *\t\t} );\n\t *\n\t * This event is useful when you want to update interface elements after the rendering, e.g. position of the\n\t * balloon panel. If you wants to change view structure use\n\t * {@link module:engine/view/document~Document#registerPostFixer post-fixers}.\n\t *\n\t * @event module:engine/view/view~View#event:render\n\t */\n}\n\nmix( View, ObservableMixin );\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/node\n */\n\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Model node. Most basic structure of model tree.\n *\n * This is an abstract class that is a base for other classes representing different nodes in model.\n *\n * **Note:** If a node is detached from the model tree, you can manipulate it using it's API.\n * However, it is **very important** that nodes already attached to model tree should be only changed through\n * {@link module:engine/model/writer~Writer Writer API}.\n *\n * Changes done by `Node` methods, like {@link module:engine/model/element~Element#_insertChild _insertChild} or\n * {@link module:engine/model/node~Node#_setAttribute _setAttribute}\n * do not generate {@link module:engine/model/operation/operation~Operation operations}\n * which are essential for correct editor work if you modify nodes in {@link module:engine/model/document~Document document} root.\n *\n * The flow of working on `Node` (and classes that inherits from it) is as such:\n * 1. You can create a `Node` instance, modify it using it's API.\n * 2. Add `Node` to the model using `Batch` API.\n * 3. Change `Node` that was already added to the model using `Batch` API.\n *\n * Similarly, you cannot use `Batch` API on a node that has not been added to the model tree, with the exception\n * of {@link module:engine/model/writer~Writer#insert inserting} that node to the model tree.\n *\n * Be aware that using {@link module:engine/model/writer~Writer#remove remove from Batch API} does not allow to use `Node` API because\n * the information about `Node` is still kept in model document.\n *\n * In case of {@link module:engine/model/element~Element element node}, adding and removing children also counts as changing a node and\n * follows same rules.\n */\nexport default class Node {\n\t/**\n\t * Creates a model node.\n\t *\n\t * This is an abstract class, so this constructor should not be used directly.\n\t *\n\t * @abstract\n\t * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\tconstructor( attrs ) {\n\t\t/**\n\t\t * Parent of this node. It could be {@link module:engine/model/element~Element}\n\t\t * or {@link module:engine/model/documentfragment~DocumentFragment}.\n\t\t * Equals to `null` if the node has no parent.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t\t */\n\t\tthis.parent = null;\n\n\t\t/**\n\t\t * Attributes set on this node.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/model/node~Node#_attrs\n\t\t */\n\t\tthis._attrs = toMap( attrs );\n\t}\n\n\t/**\n\t * Index of this node in it's parent or `null` if the node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that model tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget index() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( ( pos = this.parent.getChildIndex( this ) ) === null ) {\n\t\t\tthrow new CKEditorError( 'model-node-not-found-in-parent', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Offset at which this node starts in it's parent. It is equal to the sum of {@link #offsetSize offsetSize}\n\t * of all it's previous siblings. Equals to `null` if node has no parent.\n\t *\n\t * Accessing this property throws an error if this node's parent element does not contain it.\n\t * This means that model tree got broken.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget startOffset() {\n\t\tlet pos;\n\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( ( pos = this.parent.getChildStartOffset( this ) ) === null ) {\n\t\t\tthrow new CKEditorError( 'model-node-not-found-in-parent', this );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Offset size of this node. Represents how much \"offset space\" is occupied by the node in it's parent.\n\t * It is important for {@link module:engine/model/position~Position position}. When node has `offsetSize` greater than `1`, position\n\t * can be placed between that node start and end. `offsetSize` greater than `1` is for nodes that represents more\n\t * than one entity, i.e. {@link module:engine/model/text~Text text node}.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn 1;\n\t}\n\n\t/**\n\t * Offset at which this node ends in it's parent. It is equal to the sum of this node's\n\t * {@link module:engine/model/node~Node#startOffset start offset} and {@link #offsetSize offset size}.\n\t * Equals to `null` if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget endOffset() {\n\t\tif ( !this.parent ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.startOffset + this.offsetSize;\n\t}\n\n\t/**\n\t * Node's next sibling or `null` if the node is a last child of it's parent or if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nextSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index + 1 ) ) || null;\n\t}\n\n\t/**\n\t * Node's previous sibling or `null` if the node is a first child of it's parent or if the node has no parent.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget previousSibling() {\n\t\tconst index = this.index;\n\n\t\treturn ( index !== null && this.parent.getChild( index - 1 ) ) || null;\n\t}\n\n\t/**\n\t * The top-most ancestor of the node. If node has no parent it is the root itself. If the node is a part\n\t * of {@link module:engine/model/documentfragment~DocumentFragment}, it's `root` is equal to that `DocumentFragment`.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\tlet root = this; // eslint-disable-line consistent-this\n\n\t\twhile ( root.parent ) {\n\t\t\troot = root.parent;\n\t\t}\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Returns true if the node is in a tree rooted in the document (is a descendant of one of its roots).\n\t *\n\t * @returns {Boolean}\n\t */\n\tisAttached() {\n\t\treturn this.root.is( 'rootElement' );\n\t}\n\n\t/**\n\t * Gets path to the node. The path is an array containing starting offsets of consecutive ancestors of this node,\n\t * beginning from {@link module:engine/model/node~Node#root root}, down to this node's starting offset. The path can be used to\n\t * create {@link module:engine/model/position~Position Position} instance.\n\t *\n\t *\t\tconst abc = new Text( 'abc' );\n\t *\t\tconst foo = new Text( 'foo' );\n\t *\t\tconst h1 = new Element( 'h1', null, new Text( 'header' ) );\n\t *\t\tconst p = new Element( 'p', null, [ abc, foo ] );\n\t *\t\tconst div = new Element( 'div', null, [ h1, p ] );\n\t *\t\tfoo.getPath(); // Returns [ 1, 3 ]. `foo` is in `p` which is in `div`. `p` starts at offset 1, while `foo` at 3.\n\t *\t\th1.getPath(); // Returns [ 0 ].\n\t *\t\tdiv.getPath(); // Returns [].\n\t *\n\t * @returns {Array.<Number>} The path.\n\t */\n\tgetPath() {\n\t\tconst path = [];\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\twhile ( node.parent ) {\n\t\t\tpath.unshift( node.startOffset );\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this node.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from node's parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Returns a {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both nodes.\n\t *\n\t * @param {module:engine/model/node~Node} node The second node.\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` both nodes will be considered \"ancestors\" too.\n\t * Which means that if e.g. node A is inside B, then their common ancestor will be B.\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( node, options = {} ) {\n\t\tconst ancestorsA = this.getAncestors( options );\n\t\tconst ancestorsB = node.getAncestors( options );\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns whether this node is before given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/model/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/model/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisBefore( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisPath = this.getPath();\n\t\tconst nodePath = node.getPath();\n\n\t\tconst result = compareArrays( thisPath, nodePath );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'prefix':\n\t\t\t\treturn true;\n\n\t\t\tcase 'extension':\n\t\t\t\treturn false;\n\n\t\t\tdefault:\n\t\t\t\treturn thisPath[ result ] < nodePath[ result ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns whether this node is after given node. `false` is returned if nodes are in different trees (for example,\n\t * in different {@link module:engine/model/documentfragment~DocumentFragment}s).\n\t *\n\t * @param {module:engine/model/node~Node} node Node to compare with.\n\t * @returns {Boolean}\n\t */\n\tisAfter( node ) {\n\t\t// Given node is not before this node if they are same.\n\t\tif ( this == node ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Return `false` if it is impossible to compare nodes.\n\t\tif ( this.root !== node.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// In other cases, just check if the `node` is before, and return the opposite.\n\t\treturn !this.isBefore( node );\n\t}\n\n\t/**\n\t * Checks if the node has an attribute with given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on node, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on node.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._attrs.entries();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._attrs.keys();\n\t}\n\n\t/**\n\t * Converts `Node` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = {};\n\n\t\t// Serializes attributes to the object.\n\t\t// attributes = { a: 'foo', b: 1, c: true }.\n\t\tif ( this._attrs.size ) {\n\t\t\tjson.attributes = Array.from( this._attrs ).reduce( ( result, attr ) => {\n\t\t\t\tresult[ attr[ 0 ] ] = attr[ 1 ];\n\n\t\t\t\treturn result;\n\t\t\t}, {} );\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t * This method is useful when processing model objects that are of unknown type. For example, a function\n\t * may return a {@link module:engine/model/documentfragment~DocumentFragment} or a {@link module:engine/model/node~Node}\n\t * that can be either a text node or an element. This method can be used to check what kind of object is returned.\n\t *\n\t *\t\tsomeObject.is( 'element' ); // -> true if this is an element\n\t *\t\tsomeObject.is( 'node' ); // -> true if this is a node (a text node or an element)\n\t *\t\tsomeObject.is( 'documentFragment' ); // -> true if this is a document fragment\n\t *\n\t * Since this method is also available on a range of view objects, you can prefix the type of the object with\n\t * `model:` or `view:` to check, for example, if this is the model's or view's element:\n\t *\n\t *\t\tmodelElement.is( 'model:element' ); // -> true\n\t *\t\tmodelElement.is( 'view:element' ); // -> false\n\t *\n\t * By using this method it is also possible to check a name of an element:\n\t *\n\t *\t\timageElement.is( 'element', 'image' ); // -> true\n\t *\t\timageElement.is( 'element', 'image' ); // -> same as above\n\t *\t\timageElement.is( 'model:element', 'image' ); // -> same as above, but more precise\n\t *\n\t * The list of model objects which implement the `is()` method:\n\t *\n\t * * {@link module:engine/model/node~Node#is `Node#is()`}\n\t * * {@link module:engine/model/text~Text#is `Text#is()`}\n\t * * {@link module:engine/model/element~Element#is `Element#is()`}\n\t * * {@link module:engine/model/rootelement~RootElement#is `RootElement#is()`}\n\t * * {@link module:engine/model/position~Position#is `Position#is()`}\n\t * * {@link module:engine/model/liveposition~LivePosition#is `LivePosition#is()`}\n\t * * {@link module:engine/model/range~Range#is `Range#is()`}\n\t * * {@link module:engine/model/liverange~LiveRange#is `LiveRange#is()`}\n\t * * {@link module:engine/model/documentfragment~DocumentFragment#is `DocumentFragment#is()`}\n\t * * {@link module:engine/model/selection~Selection#is `Selection#is()`}\n\t * * {@link module:engine/model/documentselection~DocumentSelection#is `DocumentSelection#is()`}\n\t * * {@link module:engine/model/markercollection~Marker#is `Marker#is()`}\n\t * * {@link module:engine/model/textproxy~TextProxy#is `TextProxy#is()`}\n\t *\n\t * @method #is\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'node' || type === 'model:node';\n\t}\n\n\t/**\n\t * Creates a copy of this node, that is a node with exactly same attributes, and returns it.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/node~Node} Node with same attributes as this node.\n\t */\n\t_clone() {\n\t\treturn new Node( this._attrs );\n\t}\n\n\t/**\n\t * Removes this node from it's parent.\n\t *\n\t * @see module:engine/model/writer~Writer#remove\n\t * @protected\n\t */\n\t_remove() {\n\t\tthis.parent._removeChildren( this.index );\n\t}\n\n\t/**\n\t * Sets attribute on the node. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * @see module:engine/model/writer~Writer#setAttribute\n\t * @protected\n\t * @param {String} key Key of attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\t_setAttribute( key, value ) {\n\t\tthis._attrs.set( key, value );\n\t}\n\n\t/**\n\t * Removes all attributes from the node and sets given attributes.\n\t *\n\t * @see module:engine/model/writer~Writer#setAttributes\n\t * @protected\n\t * @param {Object} [attrs] Attributes to set. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\t_setAttributesTo( attrs ) {\n\t\tthis._attrs = toMap( attrs );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the node.\n\t *\n\t * @see module:engine/model/writer~Writer#removeAttribute\n\t * @protected\n\t * @param {String} key Key of attribute to remove.\n\t * @returns {Boolean} `true` if the attribute was set on the element, `false` otherwise.\n\t */\n\t_removeAttribute( key ) {\n\t\treturn this._attrs.delete( key );\n\t}\n\n\t/**\n\t * Removes all attributes from the node.\n\t *\n\t * @see module:engine/model/writer~Writer#clearAttributes\n\t * @protected\n\t */\n\t_clearAttributes() {\n\t\tthis._attrs.clear();\n\t}\n}\n\n/**\n * The node's parent does not contain this node.\n *\n * @error model-node-not-found-in-parent\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/text\n */\n\nimport Node from './node';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * Model text node. Type of {@link module:engine/model/node~Node node} that contains {@link module:engine/model/text~Text#data text data}.\n *\n * **Important:** see {@link module:engine/model/node~Node} to read about restrictions using `Text` and `Node` API.\n *\n * **Note:** keep in mind that `Text` instances might indirectly got removed from model tree when model is changed.\n * This happens when {@link module:engine/model/writer~Writer model writer} is used to change model and the text node is merged with\n * another text node. Then, both text nodes are removed and a new text node is inserted into the model. Because of\n * this behavior, keeping references to `Text` is not recommended. Instead, consider creating\n * {@link module:engine/model/liveposition~LivePosition live position} placed before the text node.\n *\n * @extends module:engine/model/node~Node\n */\nexport default class Text extends Node {\n\t/**\n\t * Creates a text node.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createText} method instead.\n\t *\n\t * @protected\n\t * @param {String} data Node's text.\n\t * @param {Object} [attrs] Node's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t */\n\tconstructor( data, attrs ) {\n\t\tsuper( attrs );\n\n\t\t/**\n\t\t * Text data contained in this text node.\n\t\t *\n\t\t * @protected\n\t\t * @type {String}\n\t\t */\n\t\tthis._data = data || '';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Returns a text data contained in the node.\n\t *\n\t * @readonly\n\t * @type {String}\n\t */\n\tget data() {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttext.is( '$text' ); // -> true\n\t *\t\ttext.is( 'node' ); // -> true\n\t *\t\ttext.is( 'model:$text' ); // -> true\n\t *\t\ttext.is( 'model:node' ); // -> true\n\t *\n\t *\t\ttext.is( 'view:$text' ); // -> false\n\t *\t\ttext.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$text'` type. The legacy `'text'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$text' || type === 'model:$text' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'text' || type === 'model:text' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'node' || type === 'model:node';\n\t}\n\n\t/**\n\t * Converts `Text` instance to plain object and returns it.\n\t *\n\t * @returns {Object} `Text` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.data = this.data;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a copy of this text node and returns it. Created text node has same text data and attributes as original text node.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\t_clone() {\n\t\treturn new Text( this.data, this.getAttributes() );\n\t}\n\n\t/**\n\t * Creates a `Text` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Text`.\n\t * @returns {module:engine/model/text~Text} `Text` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new Text( json.data, json.attributes );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelText: ${ this }, attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelText: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/textproxy\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const { convertMapToStringifiedObject } = require( '../dev-utils/utils' );\n\n/**\n * `TextProxy` represents a part of {@link module:engine/model/text~Text text node}.\n *\n * Since {@link module:engine/model/position~Position positions} can be placed between characters of a text node,\n * {@link module:engine/model/range~Range ranges} may contain only parts of text nodes. When {@link module:engine/model/range~Range#getItems\n * getting items}\n * contained in such range, we need to represent a part of that text node, since returning the whole text node would be incorrect.\n * `TextProxy` solves this issue.\n *\n * `TextProxy` has an API similar to {@link module:engine/model/text~Text Text} and allows to do most of the common tasks performed\n * on model nodes.\n *\n * **Note:** Some `TextProxy` instances may represent whole text node, not just a part of it.\n * See {@link module:engine/model/textproxy~TextProxy#isPartial}.\n *\n * **Note:** `TextProxy` is not an instance of {@link module:engine/model/node~Node node}. Keep this in mind when using it as a\n * parameter of methods.\n *\n * **Note:** `TextProxy` is a readonly interface. If you want to perform changes on model data represented by a `TextProxy`\n * use {@link module:engine/model/writer~Writer model writer API}.\n *\n * **Note:** `TextProxy` instances are created on the fly, basing on the current state of model. Because of this, it is\n * highly unrecommended to store references to `TextProxy` instances. `TextProxy` instances are not refreshed when\n * model changes, so they might get invalidated. Instead, consider creating {@link module:engine/model/liveposition~LivePosition live\n * position}.\n *\n * `TextProxy` instances are created by {@link module:engine/model/treewalker~TreeWalker model tree walker}. You should not need to create\n * an instance of this class by your own.\n */\nexport default class TextProxy {\n\t/**\n\t * Creates a text proxy.\n\t *\n\t * @protected\n\t * @param {module:engine/model/text~Text} textNode Text node which part is represented by this text proxy.\n\t * @param {Number} offsetInText Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy\n\t * starts.\n\t * @param {Number} length Text proxy length, that is how many text node's characters, starting from `offsetInText` it represents.\n\t * @constructor\n\t */\n\tconstructor( textNode, offsetInText, length ) {\n\t\t/**\n\t\t * Text node which part is represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/text~Text}\n\t\t */\n\t\tthis.textNode = textNode;\n\n\t\tif ( offsetInText < 0 || offsetInText > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `offsetInText` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-offsetintext\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-offsetintext', this );\n\t\t}\n\n\t\tif ( length < 0 || offsetInText + length > textNode.offsetSize ) {\n\t\t\t/**\n\t\t\t * Given `length` value is incorrect.\n\t\t\t *\n\t\t\t * @error model-textproxy-wrong-length\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-textproxy-wrong-length', this );\n\t\t}\n\n\t\t/**\n\t\t * Text data represented by this text proxy.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.data = textNode.data.substring( offsetInText, offsetInText + length );\n\n\t\t/**\n\t\t * Offset in {@link module:engine/model/textproxy~TextProxy#textNode text node} from which the text proxy starts.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.offsetInText = offsetInText;\n\t}\n\n\t/**\n\t * Offset at which this text proxy starts in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#startOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget startOffset() {\n\t\treturn this.textNode.startOffset !== null ? this.textNode.startOffset + this.offsetInText : null;\n\t}\n\n\t/**\n\t * Offset size of this text proxy. Equal to the number of characters represented by the text proxy.\n\t *\n\t * @see module:engine/model/node~Node#offsetSize\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget offsetSize() {\n\t\treturn this.data.length;\n\t}\n\n\t/**\n\t * Offset at which this text proxy ends in it's parent.\n\t *\n\t * @see module:engine/model/node~Node#endOffset\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget endOffset() {\n\t\treturn this.startOffset !== null ? this.startOffset + this.offsetSize : null;\n\t}\n\n\t/**\n\t * Flag indicating whether `TextProxy` instance covers only part of the original {@link module:engine/model/text~Text text node}\n\t * (`true`) or the whole text node (`false`).\n\t *\n\t * This is `false` when text proxy starts at the very beginning of {@link module:engine/model/textproxy~TextProxy#textNode textNode}\n\t * ({@link module:engine/model/textproxy~TextProxy#offsetInText offsetInText} equals `0`) and text proxy sizes is equal to\n\t * text node size.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isPartial() {\n\t\treturn this.offsetSize !== this.textNode.offsetSize;\n\t}\n\n\t/**\n\t * Parent of this text proxy, which is same as parent of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tget parent() {\n\t\treturn this.textNode.parent;\n\t}\n\n\t/**\n\t * Root of this text proxy, which is same as root of text node represented by this text proxy.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.textNode.root;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\ttextProxy.is( '$textProxy' ); // -> true\n\t *\t\ttextProxy.is( 'model:$textProxy' ); // -> true\n\t *\n\t *\t\ttextProxy.is( 'view:$textProxy' ); // -> false\n\t *\t\ttextProxy.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * **Note:** Until version 20.0.0 this method wasn't accepting `'$textProxy'` type. The legacy `'textProxt'` type is still\n\t * accepted for backward compatibility.\n\t *\n\t * @param {String} type Type to check.\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === '$textProxy' || type === 'model:$textProxy' ||\n\t\t\t// This are legacy values kept for backward compatibility.\n\t\t\ttype === 'textProxy' || type === 'model:textProxy';\n\t}\n\n\t/**\n\t * Gets path to this text proxy.\n\t *\n\t * @see module:engine/model/node~Node#getPath\n\t * @returns {Array.<Number>}\n\t */\n\tgetPath() {\n\t\tconst path = this.textNode.getPath();\n\n\t\tif ( path.length > 0 ) {\n\t\t\tpath[ path.length - 1 ] += this.offsetInText;\n\t\t}\n\n\t\treturn path;\n\t}\n\n\t/**\n\t * Returns ancestors array of this text proxy.\n\t *\n\t * @param {Object} options Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this text proxy will be also included in parent's array.\n\t * @param {Boolean} [options.parentFirst=false] When set to `true`, array will be sorted from text proxy parent to root element,\n\t * otherwise root element will be the first item in the array.\n\t * @returns {Array} Array with ancestors.\n\t */\n\tgetAncestors( options = { includeSelf: false, parentFirst: false } ) {\n\t\tconst ancestors = [];\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tancestors[ options.parentFirst ? 'push' : 'unshift' ]( parent );\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn ancestors;\n\t}\n\n\t/**\n\t * Checks if this text proxy has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on text proxy, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this.textNode.hasAttribute( key );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on text proxy.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this.textNode.getAttribute( key );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attributes. Attributes are returned as arrays containing two\n\t * items. First one is attribute key and second is attribute value.\n\t *\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this.textNode.getAttributes();\n\t}\n\n\t/**\n\t * Returns iterator that iterates over this node's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this.textNode.getAttributeKeys();\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `#${ this.data }`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelTextProxy: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelTextProxy: ${ this }, ` +\n\t// @if CK_DEBUG_ENGINE // \t\t`attrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/nodelist\n */\n\nimport Node from './node';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Provides an interface to operate on a list of {@link module:engine/model/node~Node nodes}. `NodeList` is used internally\n * in classes like {@link module:engine/model/element~Element Element}\n * or {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment}.\n */\nexport default class NodeList {\n\t/**\n\t * Creates an empty node list.\n\t *\n\t * @protected\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes contained in this node list.\n\t */\n\tconstructor( nodes ) {\n\t\t/**\n\t\t * Nodes contained in this node list.\n\t\t *\n\t\t * @private\n\t\t * @member {Array.<module:engine/model/node~Node>}\n\t\t */\n\t\tthis._nodes = [];\n\n\t\tif ( nodes ) {\n\t\t\tthis._insertNodes( 0, nodes );\n\t\t}\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all nodes contained inside this node list.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._nodes[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Number of nodes contained inside this node list.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._nodes.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes contained inside this node list.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\t}\n\n\t/**\n\t * Gets the node at the given index. Returns `null` if incorrect index was passed.\n\t *\n\t * @param {Number} index Index of node.\n\t * @returns {module:engine/model/node~Node|null} Node at given index.\n\t */\n\tgetNode( index ) {\n\t\treturn this._nodes[ index ] || null;\n\t}\n\n\t/**\n\t * Returns an index of the given node. Returns `null` if given node is not inside this node list.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's index.\n\t */\n\tgetNodeIndex( node ) {\n\t\tconst index = this._nodes.indexOf( node );\n\n\t\treturn index == -1 ? null : index;\n\t}\n\n\t/**\n\t * Returns the starting offset of given node. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all nodes that are before this node in this node list.\n\t *\n\t * @param {module:engine/model/node~Node} node Node to look for.\n\t * @returns {Number|null} Node's starting offset.\n\t */\n\tgetNodeStartOffset( node ) {\n\t\tconst index = this.getNodeIndex( node );\n\n\t\treturn index === null ? null : this._nodes.slice( 0, index ).reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\t}\n\n\t/**\n\t * Converts index to offset in node list.\n\t *\n\t * Returns starting offset of a node that is at given index. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * `model-nodelist-index-out-of-bounds` if given index is less than `0` or more than {@link #length}.\n\t *\n\t * @param {Number} index Node's index.\n\t * @returns {Number} Node's starting offset.\n\t */\n\tindexToOffset( index ) {\n\t\tif ( index == this._nodes.length ) {\n\t\t\treturn this.maxOffset;\n\t\t}\n\n\t\tconst node = this._nodes[ index ];\n\n\t\tif ( !node ) {\n\t\t\t/**\n\t\t\t * Given index cannot be found in the node list.\n\t\t\t *\n\t\t\t * @error model-nodelist-index-out-of-bounds\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-nodelist-index-out-of-bounds', this );\n\t\t}\n\n\t\treturn this.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Converts offset in node list to index.\n\t *\n\t * Returns index of a node that occupies given offset. Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError}\n\t * `model-nodelist-offset-out-of-bounds` if given offset is less than `0` or more than {@link #maxOffset}.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number} Index of a node that occupies given offset.\n\t */\n\toffsetToIndex( offset ) {\n\t\tlet totalOffset = 0;\n\n\t\tfor ( const node of this._nodes ) {\n\t\t\tif ( offset >= totalOffset && offset < totalOffset + node.offsetSize ) {\n\t\t\t\treturn this.getNodeIndex( node );\n\t\t\t}\n\n\t\t\ttotalOffset += node.offsetSize;\n\t\t}\n\n\t\tif ( totalOffset != offset ) {\n\t\t\t/**\n\t\t\t * Given offset cannot be found in the node list.\n\t\t\t *\n\t\t\t * @error model-nodelist-offset-out-of-bounds\n\t\t\t * @param {Number} offset\n\t\t\t * @param {module:engine/model/nodelist~NodeList} nodeList Stringified node list.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-nodelist-offset-out-of-bounds',\n\t\t\t\tthis,\n\t\t\t\t{\n\t\t\t\t\toffset,\n\t\t\t\t\tnodeList: this\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn this.length;\n\t}\n\n\t/**\n\t * Inserts given nodes at given index.\n\t *\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes to be inserted.\n\t */\n\t_insertNodes( index, nodes ) {\n\t\t// Validation.\n\t\tfor ( const node of nodes ) {\n\t\t\tif ( !( node instanceof Node ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to insert an object which is not a Node instance.\n\t\t\t\t *\n\t\t\t\t * @error model-nodelist-insertnodes-not-node\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-nodelist-insertnodes-not-node', this );\n\t\t\t}\n\t\t}\n\n\t\tthis._nodes.splice( index, 0, ...nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index.\n\t *\n\t * @protected\n\t * @param {Number} indexStart Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeNodes( indexStart, howMany = 1 ) {\n\t\treturn this._nodes.splice( indexStart, howMany );\n\t}\n\n\t/**\n\t * Converts `NodeList` instance to an array containing nodes that were inserted in the node list. Nodes\n\t * are also converted to their plain object representation.\n\t *\n\t * @returns {Array.<module:engine/model/node~Node>} `NodeList` instance converted to `Array`.\n\t */\n\ttoJSON() {\n\t\treturn this._nodes.map( node => node.toJSON() );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/element\n */\n\nimport Node from './node';\nimport NodeList from './nodelist';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n// @if CK_DEBUG_ENGINE // const { stringifyMap, convertMapToStringifiedObject, convertMapToTags } = require( '../dev-utils/utils' );\n\n/**\n * Model element. Type of {@link module:engine/model/node~Node node} that has a {@link module:engine/model/element~Element#name name} and\n * {@link module:engine/model/element~Element#getChildren child nodes}.\n *\n * **Important**: see {@link module:engine/model/node~Node} to read about restrictions using `Element` and `Node` API.\n *\n * @extends module:engine/model/node~Node\n */\nexport default class Element extends Node {\n\t/**\n\t * Creates a model element.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createElement} method instead.\n\t *\n\t * @protected\n\t * @param {String} name Element's name.\n\t * @param {Object} [attrs] Element's attributes. See {@link module:utils/tomap~toMap} for a list of accepted values.\n\t * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]\n\t * One or more nodes to be inserted as children of created element.\n\t */\n\tconstructor( name, attrs, children ) {\n\t\tsuper( attrs );\n\n\t\t/**\n\t\t * Element name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:engine/model/element~Element#name\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * List of children nodes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/element~Element#_children\n\t\t */\n\t\tthis._children = new NodeList();\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Number of this element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this element's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._children.maxOffset;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this element, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\telement.is( 'element' ); // -> true\n\t *\t\telement.is( 'node' ); // -> true\n\t *\t\telement.is( 'model:element' ); // -> true\n\t *\t\telement.is( 'model:node' ); // -> true\n\t *\n\t *\t\telement.is( 'view:element' ); // -> false\n\t *\t\telement.is( 'documentSelection' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/model/element~Element#name name}:\n\t *\n\t *\t\telement.is( 'element', 'image' ); // -> true if this is an <image> element\n\t *\t\telement.is( 'element', 'image' ); // -> same as above\n\t *\t\ttext.is( 'element', 'image' ); -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name = null ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'element' || type === 'model:element' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'node' || type === 'model:node';\n\t\t}\n\n\t\treturn name === this.name && ( type === 'element' || type === 'model:element' );\n\t}\n\n\t/**\n\t * Gets the child at the given index.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/model/node~Node} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children.getNode( index );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all of this element's children.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an index of the given child node. Returns `null` if given node is not a child of this element.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number} Child node's index in this element.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.getNodeIndex( node );\n\t}\n\n\t/**\n\t * Returns the starting offset of given child. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if\n\t * given node is not a child of this element.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number} Child node's starting offset.\n\t */\n\tgetChildStartOffset( node ) {\n\t\treturn this._children.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is\n\t * too high, returns {@link module:engine/model/element~Element#getChildIndex index after last child}.\n\t *\n\t *\t\tconst textNode = new Text( 'foo' );\n\t *\t\tconst pElement = new Element( 'p' );\n\t *\t\tconst divElement = new Element( [ textNode, pElement ] );\n\t *\t\tdivElement.offsetToIndex( -1 ); // Returns 0, because offset is too low.\n\t *\t\tdivElement.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.\n\t *\t\tdivElement.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.\n\t *\t\tdivElement.offsetToIndex( 2 ); // Returns 0.\n\t *\t\tdivElement.offsetToIndex( 3 ); // Returns 1.\n\t *\t\tdivElement.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number}\n\t */\n\toffsetToIndex( offset ) {\n\t\treturn this._children.offsetToIndex( offset );\n\t}\n\n\t/**\n\t * Returns a descendant node by its path relative to this element.\n\t *\n\t *\t\t// <this>a<b>c</b></this>\n\t *\t\tthis.getNodeByPath( [ 0 ] ); // -> \"a\"\n\t *\t\tthis.getNodeByPath( [ 1 ] ); // -> <b>\n\t *\t\tthis.getNodeByPath( [ 1, 0 ] ); // -> \"c\"\n\t *\n\t * @param {Array.<Number>} relativePath Path of the node to find, relative to this element.\n\t * @returns {module:engine/model/node~Node}\n\t */\n\tgetNodeByPath( relativePath ) {\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\tfor ( const index of relativePath ) {\n\t\t\tnode = node.getChild( node.offsetToIndex( index ) );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Returns the parent element of the given name. Returns null if the element is not inside the desired parent.\n\t *\n\t * @param {String} parentName The name of the parent element to find.\n\t * @param {Object} [options] Options object.\n\t * @param {Boolean} [options.includeSelf=false] When set to `true` this node will be also included while searching.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tfindAncestor( parentName, options = { includeSelf: false } ) {\n\t\tlet parent = options.includeSelf ? this : this.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( parent.name === parentName ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts `Element` instance to plain object and returns it. Takes care of converting all of this element's children.\n\t *\n\t * @returns {Object} `Element` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.name = this.name;\n\n\t\tif ( this._children.length > 0 ) {\n\t\t\tjson.children = [];\n\n\t\t\tfor ( const node of this._children ) {\n\t\t\t\tjson.children.push( node.toJSON() );\n\t\t\t}\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a copy of this 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 * @protected\n\t * @param {Boolean} [deep=false] 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\t_clone( deep = false ) {\n\t\tconst children = deep ? Array.from( this._children ).map( node => node._clone( true ) ) : null;\n\n\t\treturn new Element( this.name, this.getAttributes(), children );\n\t}\n\n\t/**\n\t * {@link module:engine/model/element~Element#_insertChild Inserts} one or more nodes at the end of this element.\n\t *\n\t * @see module:engine/model/writer~Writer#append\n\t * @protected\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} nodes Nodes to be inserted.\n\t */\n\t_appendChild( nodes ) {\n\t\tthis._insertChild( this.childCount, nodes );\n\t}\n\n\t/**\n\t * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes\n\t * to this element.\n\t *\n\t * @see module:engine/model/writer~Writer#insert\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_insertChild( index, items ) {\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t}\n\n\t\tthis._children._insertNodes( index, nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index and sets\n\t * {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.\n\t *\n\t * @see module:engine/model/writer~Writer#remove\n\t * @protected\n\t * @param {Number} index Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tconst nodes = this._children._removeNodes( index, howMany );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tnode.parent = null;\n\t\t}\n\n\t\treturn nodes;\n\t}\n\n\t/**\n\t * Creates an `Element` instance from given plain object (i.e. parsed JSON string).\n\t * Converts `Element` children to proper nodes.\n\t *\n\t * @param {Object} json Plain object to be converted to `Element`.\n\t * @returns {module:engine/model/element~Element} `Element` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\tlet children = null;\n\n\t\tif ( json.children ) {\n\t\t\tchildren = [];\n\n\t\t\tfor ( const child of json.children ) {\n\t\t\t\tif ( child.name ) {\n\t\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Element( json.name, json.attributes, children );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `<${ this.rootName || this.name }>`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelElement: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logExtended() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( `ModelElement: ${ this }, ${ this.childCount } children,\n\t// @if CK_DEBUG_ENGINE //\t\tattrs: ${ convertMapToStringifiedObject( this.getAttributes() ) }` );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logAll() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( '--------------------' );\n\t// @if CK_DEBUG_ENGINE //\n\t// @if CK_DEBUG_ENGINE // \tthis.logExtended();\n\t// @if CK_DEBUG_ENGINE //\tconsole.log( 'List of children:' );\n\t// @if CK_DEBUG_ENGINE //\n\t// @if CK_DEBUG_ENGINE // \tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE // \t\tchild.log();\n\t// @if CK_DEBUG_ENGINE // \t}\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // printTree( level = 0) {\n\t// @if CK_DEBUG_ENGINE // \tlet string = '';\n\n\t// @if CK_DEBUG_ENGINE // \tstring += '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE // \tstring += `<${ this.rootName || this.name }${ convertMapToTags( this.getAttributes() ) }>`;\n\n\t// @if CK_DEBUG_ENGINE // \tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE // \t\tstring += '\\n';\n\n\t// @if CK_DEBUG_ENGINE // \t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE // \t\t\tconst textAttrs = convertMapToTags( child._attrs );\n\n\t// @if CK_DEBUG_ENGINE // \t\t\tstring += '\\t'.repeat( level + 1 );\n\n\t// @if CK_DEBUG_ENGINE // \t\t\tif ( textAttrs !== '' ) {\n\t// @if CK_DEBUG_ENGINE // \t\t\t\tstring += `<$text${ textAttrs }>` + child.data + '</$text>';\n\t// @if CK_DEBUG_ENGINE // \t\t\t} else {\n\t// @if CK_DEBUG_ENGINE // \t\t\t\tstring += child.data;\n\t// @if CK_DEBUG_ENGINE // \t\t\t}\n\t// @if CK_DEBUG_ENGINE // \t\t} else {\n\t// @if CK_DEBUG_ENGINE // \t\t\tstring += child.printTree( level + 1 );\n\t// @if CK_DEBUG_ENGINE // \t\t}\n\t// @if CK_DEBUG_ENGINE // \t}\n\n\t// @if CK_DEBUG_ENGINE // \tif ( this.childCount ) {\n\t// @if CK_DEBUG_ENGINE // \t\tstring += '\\n' + '\\t'.repeat( level );\n\t// @if CK_DEBUG_ENGINE // \t}\n\n\t// @if CK_DEBUG_ENGINE // \tstring += `</${ this.rootName || this.name }>`;\n\n\t// @if CK_DEBUG_ENGINE // \treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/model/item~Item|Iterable.<String|module:engine/model/item~Item>}\n// @returns {Iterable.<module:engine/model/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data, node.getAttributes() );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/treewalker\n */\n\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport Element from './element';\nimport {\n\tdefault as Position,\n\tgetTextNodeAtPosition,\n\tgetNodeAfterPosition,\n\tgetNodeBeforePosition\n} from './position';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Position iterator class. It allows to iterate forward and backward over the document.\n */\nexport default class TreeWalker {\n\t/**\n\t * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.\n\t *\n\t * @constructor\n\t * @param {Object} [options={}] Object with configuration.\n\t * @param {'forward'|'backward'} [options.direction='forward'] Walking direction.\n\t * @param {module:engine/model/range~Range} [options.boundaries=null] Range to define boundaries of the iterator.\n\t * @param {module:engine/model/position~Position} [options.startPosition] Starting position.\n\t * @param {Boolean} [options.singleCharacters=false] Flag indicating whether all consecutive characters with the same attributes\n\t * should be returned one by one as multiple {@link module:engine/model/textproxy~TextProxy} (`true`) objects or as one\n\t * {@link module:engine/model/textproxy~TextProxy} (`false`).\n\t * @param {Boolean} [options.shallow=false] Flag indicating whether iterator should enter elements or not. If the\n\t * iterator is shallow child nodes of any iterated node will not be returned along with `elementEnd` tag.\n\t * @param {Boolean} [options.ignoreElementEnd=false] Flag indicating whether iterator should ignore `elementEnd`\n\t * tags. If the option is true walker will not return a parent node of start position. If this option is `true`\n\t * each {@link module:engine/model/element~Element} will be returned once, while if the option is `false` they might be returned\n\t * twice: for `'elementStart'` and `'elementEnd'`.\n\t */\n\tconstructor( options = {} ) {\n\t\tif ( !options.boundaries && !options.startPosition ) {\n\t\t\t/**\n\t\t\t * Neither boundaries nor starting position of a `TreeWalker` have been defined.\n\t\t\t *\n\t\t\t * @error model-tree-walker-no-start-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-tree-walker-no-start-position',\n\t\t\t\tnull\n\t\t\t);\n\t\t}\n\n\t\tconst direction = options.direction || 'forward';\n\n\t\tif ( direction != 'forward' && direction != 'backward' ) {\n\t\t\t/**\n\t\t\t * Only `backward` and `forward` direction allowed.\n\t\t\t *\n\t\t\t * @error model-tree-walker-unknown-direction\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-tree-walker-unknown-direction', options, { direction } );\n\t\t}\n\n\t\t/**\n\t\t * Walking direction. Defaults `'forward'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'backward'|'forward'} module:engine/model/treewalker~TreeWalker#direction\n\t\t */\n\t\tthis.direction = direction;\n\n\t\t/**\n\t\t * Iterator boundaries.\n\t\t *\n\t\t * When the iterator is walking `'forward'` on the end of boundary or is walking `'backward'`\n\t\t * on the start of boundary, then `{ done: true }` is returned.\n\t\t *\n\t\t * If boundaries are not defined they are set before first and after last child of the root node.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range} module:engine/model/treewalker~TreeWalker#boundaries\n\t\t */\n\t\tthis.boundaries = options.boundaries || null;\n\n\t\t/**\n\t\t * Iterator position. This is always static position, even if the initial position was a\n\t\t * {@link module:engine/model/liveposition~LivePosition live position}. If start position is not defined then position depends\n\t\t * on {@link #direction}. If direction is `'forward'` position starts form the beginning, when direction\n\t\t * is `'backward'` position starts from the end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/treewalker~TreeWalker#position\n\t\t */\n\t\tif ( options.startPosition ) {\n\t\t\tthis.position = options.startPosition.clone();\n\t\t} else {\n\t\t\tthis.position = Position._createAt( this.boundaries[ this.direction == 'backward' ? 'end' : 'start' ] );\n\t\t}\n\n\t\t// Reset position stickiness in case it was set to other value, as the stickiness is kept after cloning.\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * Flag indicating whether all consecutive characters with the same attributes should be\n\t\t * returned as one {@link module:engine/model/textproxy~TextProxy} (`true`) or one by one (`false`).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#singleCharacters\n\t\t */\n\t\tthis.singleCharacters = !!options.singleCharacters;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should enter elements or not. If the iterator is shallow child nodes of any\n\t\t * iterated node will not be returned along with `elementEnd` tag.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#shallow\n\t\t */\n\t\tthis.shallow = !!options.shallow;\n\n\t\t/**\n\t\t * Flag indicating whether iterator should ignore `elementEnd` tags. If the option is true walker will not\n\t\t * return a parent node of the start position. If this option is `true` each {@link module:engine/model/element~Element} will\n\t\t * be returned once, while if the option is `false` they might be returned twice:\n\t\t * for `'elementStart'` and `'elementEnd'`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:engine/model/treewalker~TreeWalker#ignoreElementEnd\n\t\t */\n\t\tthis.ignoreElementEnd = !!options.ignoreElementEnd;\n\n\t\t/**\n\t\t * Start boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryStartParent\n\t\t */\n\t\tthis._boundaryStartParent = this.boundaries ? this.boundaries.start.parent : null;\n\n\t\t/**\n\t\t * End boundary cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element} module:engine/model/treewalker~TreeWalker#_boundaryEndParent\n\t\t */\n\t\tthis._boundaryEndParent = this.boundaries ? this.boundaries.end.parent : null;\n\n\t\t/**\n\t\t * Parent of the most recently visited node. Cached for optimization purposes.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t\t * module:engine/model/treewalker~TreeWalker#_visitedParent\n\t\t */\n\t\tthis._visitedParent = this.position.parent;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:engine/model/treewalker~TreeWalkerValue>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Moves {@link #position} in the {@link #direction} skipping values as long as the callback function returns `true`.\n\t *\n\t * For example:\n\t *\n\t * \t\twalker.skip( value => value.type == 'text' ); // <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>\n\t * \t\twalker.skip( () => true ); // Move the position to the end: <paragraph>[]foo</paragraph> -> <paragraph>foo</paragraph>[]\n\t * \t\twalker.skip( () => false ); // Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t */\n\tskip( skip ) {\n\t\tlet done, value, prevPosition, prevVisitedParent;\n\n\t\tdo {\n\t\t\tprevPosition = this.position;\n\t\t\tprevVisitedParent = this._visitedParent;\n\n\t\t\t( { done, value } = this.next() );\n\t\t} while ( !done && skip( value ) );\n\n\t\tif ( !done ) {\n\t\t\tthis.position = prevPosition;\n\t\t\tthis._visitedParent = prevVisitedParent;\n\t\t}\n\t}\n\n\t/**\n\t * Gets the next tree walker's value.\n\t *\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} Next tree walker's value.\n\t */\n\tnext() {\n\t\tif ( this.direction == 'forward' ) {\n\t\t\treturn this._next();\n\t\t} else {\n\t\t\treturn this._previous();\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step forward in model. Moves the {@link #position} to the next position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_next() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the end of the root.\n\t\tif ( parent.parent === null && position.offset === parent.maxOffset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent === this._boundaryEndParent && position.offset == this.boundaries.end.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just after the current position.\n\t\t// Use a highly optimized version instead of checking the text node first and then getting the node after. See #6582.\n\t\tconst positionParent = position.parent;\n\t\tconst textNodeAtPosition = getTextNodeAtPosition( position, positionParent );\n\t\tconst node = textNodeAtPosition ? textNodeAtPosition : getNodeAfterPosition( position, positionParent, textNodeAtPosition );\n\n\t\tif ( node instanceof Element ) {\n\t\t\tif ( !this.shallow ) {\n\t\t\t\t// Manual operations on path internals for optimization purposes. Here and in the rest of the method.\n\t\t\t\tposition.path.push( 0 );\n\t\t\t\tthis._visitedParent = node;\n\t\t\t} else {\n\t\t\t\tposition.offset++;\n\t\t\t}\n\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.endOffset;\n\n\t\t\t\tif ( this._boundaryEndParent == parent && this.boundaries.end.offset < offset ) {\n\t\t\t\t\toffset = this.boundaries.end.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = offset - position.offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode, charactersCount );\n\n\t\t\tposition.offset += charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the end of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tposition.offset++;\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\treturn this._next();\n\t\t\t} else {\n\t\t\t\treturn formatReturnValue( 'elementEnd', parent, previousPosition, position );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Makes a step backward in model. Moves the {@link #position} to the previous position and returns the encountered value.\n\t *\n\t * @private\n\t * @returns {Object}\n\t * @returns {Boolean} return.done True if iterator is done.\n\t * @returns {module:engine/model/treewalker~TreeWalkerValue} return.value Information about taken step.\n\t */\n\t_previous() {\n\t\tconst previousPosition = this.position;\n\t\tconst position = this.position.clone();\n\t\tconst parent = this._visitedParent;\n\n\t\t// We are at the beginning of the root.\n\t\tif ( parent.parent === null && position.offset === 0 ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// We reached the walker boundary.\n\t\tif ( parent == this._boundaryStartParent && position.offset == this.boundaries.start.offset ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\t// Get node just before the current position.\n\t\t// Use a highly optimized version instead of checking the text node first and then getting the node before. See #6582.\n\t\tconst positionParent = position.parent;\n\t\tconst textNodeAtPosition = getTextNodeAtPosition( position, positionParent );\n\t\tconst node = textNodeAtPosition ? textNodeAtPosition : getNodeBeforePosition( position, positionParent, textNodeAtPosition );\n\n\t\tif ( node instanceof Element ) {\n\t\t\tposition.offset--;\n\n\t\t\tif ( !this.shallow ) {\n\t\t\t\tposition.path.push( node.maxOffset );\n\t\t\t\tthis.position = position;\n\t\t\t\tthis._visitedParent = node;\n\n\t\t\t\tif ( this.ignoreElementEnd ) {\n\t\t\t\t\treturn this._previous();\n\t\t\t\t} else {\n\t\t\t\t\treturn formatReturnValue( 'elementEnd', node, previousPosition, position );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.position = position;\n\n\t\t\t\treturn formatReturnValue( 'elementStart', node, previousPosition, position, 1 );\n\t\t\t}\n\t\t} else if ( node instanceof Text ) {\n\t\t\tlet charactersCount;\n\n\t\t\tif ( this.singleCharacters ) {\n\t\t\t\tcharactersCount = 1;\n\t\t\t} else {\n\t\t\t\tlet offset = node.startOffset;\n\n\t\t\t\tif ( this._boundaryStartParent == parent && this.boundaries.start.offset > offset ) {\n\t\t\t\t\toffset = this.boundaries.start.offset;\n\t\t\t\t}\n\n\t\t\t\tcharactersCount = position.offset - offset;\n\t\t\t}\n\n\t\t\tconst offsetInTextNode = position.offset - node.startOffset;\n\t\t\tconst item = new TextProxy( node, offsetInTextNode - charactersCount, charactersCount );\n\n\t\t\tposition.offset -= charactersCount;\n\t\t\tthis.position = position;\n\n\t\t\treturn formatReturnValue( 'text', item, previousPosition, position, charactersCount );\n\t\t} else {\n\t\t\t// `node` is not set, we reached the beginning of current `parent`.\n\t\t\tposition.path.pop();\n\t\t\tthis.position = position;\n\t\t\tthis._visitedParent = parent.parent;\n\n\t\t\treturn formatReturnValue( 'elementStart', parent, previousPosition, position, 1 );\n\t\t}\n\t}\n}\n\nfunction formatReturnValue( type, item, previousPosition, nextPosition, length ) {\n\treturn {\n\t\tdone: false,\n\t\tvalue: {\n\t\t\ttype,\n\t\t\titem,\n\t\t\tpreviousPosition,\n\t\t\tnextPosition,\n\t\t\tlength\n\t\t}\n\t};\n}\n\n/**\n * Type of the step made by {@link module:engine/model/treewalker~TreeWalker}.\n * Possible values: `'elementStart'` if walker is at the beginning of a node, `'elementEnd'` if walker is at the end of node,\n * `'character'` if walker traversed over a character, or `'text'` if walker traversed over multiple characters (available in\n * character merging mode, see {@link module:engine/model/treewalker~TreeWalker#constructor}).\n *\n * @typedef {'elementStart'|'elementEnd'|'character'|'text'} module:engine/model/treewalker~TreeWalkerValueType\n */\n\n/**\n * Object returned by {@link module:engine/model/treewalker~TreeWalker} when traversing tree model.\n *\n * @typedef {Object} module:engine/model/treewalker~TreeWalkerValue\n * @property {module:engine/model/treewalker~TreeWalkerValueType} type\n * @property {module:engine/model/item~Item} item Item between old and new positions of {@link module:engine/model/treewalker~TreeWalker}.\n * @property {module:engine/model/position~Position} previousPosition Previous position of the iterator.\n * * Forward iteration: For `'elementEnd'` it is the last position inside the element. For all other types it is the\n * position before the item.\n * * Backward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after item.\n * @property {module:engine/model/position~Position} nextPosition Next position of the iterator.\n * * Forward iteration: For `'elementStart'` it is the first position inside the element. For all other types it is\n * the position after the item.\n * * Backward iteration: For `'elementEnd'` it is last position inside element. For all other types it is the position\n * before the item.\n * @property {Number} [length] Length of the item. For `'elementStart'` and `'character'` it is 1. For `'text'` it is\n * the length of the text. For `'elementEnd'` it is `undefined`.\n */\n\n/**\n * Tree walking directions.\n *\n * @typedef {'forward'|'backward'} module:engine/model/treewalker~TreeWalkerDirection\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/position\n */\n\nimport TreeWalker from './treewalker';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// To check if component is loaded more than once.\nimport '@ckeditor/ckeditor5-utils/src/version';\n\n/**\n * Represents a position in the model tree.\n *\n * A position is represented by its {@link module:engine/model/position~Position#root} and\n * a {@link module:engine/model/position~Position#path} in that root.\n *\n * You can create position instances via its constructor or the `createPosition*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n *\n * **Note:** Position is based on offsets, not indexes. This means that a position between two text nodes\n * `foo` and `bar` has offset `3`, not `1`. See {@link module:engine/model/position~Position#path} for more information.\n *\n * Since a position in the model is represented by a {@link module:engine/model/position~Position#root position root} and\n * {@link module:engine/model/position~Position#path position path} it is possible to create positions placed in non-existing places.\n * This requirement is important for operational transformation algorithms.\n *\n * Also, {@link module:engine/model/operation/operation~Operation operations}\n * kept in the {@link module:engine/model/document~Document#history document history}\n * are storing positions (and ranges) which were correct when those operations were applied, but may not be correct\n * after the document has changed.\n *\n * When changes are applied to the model, it may also happen that {@link module:engine/model/position~Position#parent position parent}\n * will change even if position path has not changed. Keep in mind, that if a position leads to non-existing element,\n * {@link module:engine/model/position~Position#parent} and some other properties and methods will throw errors.\n *\n * In most cases, position with wrong path is caused by an error in code, but it is sometimes needed, as described above.\n */\nexport default class Position {\n\t/**\n\t * Creates a position.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} root Root of the position.\n\t * @param {Array.<Number>} 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 */\n\tconstructor( root, path, stickiness = 'toNone' ) {\n\t\tif ( !root.is( 'element' ) && !root.is( 'documentFragment' ) ) {\n\t\t\t/**\n\t\t\t * Position root is invalid.\n\t\t\t *\n\t\t\t * Positions can only be anchored in elements or document fragments.\n\t\t\t *\n\t\t\t * @error model-position-root-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-root-invalid',\n\t\t\t\troot\n\t\t\t);\n\t\t}\n\n\t\tif ( !( path instanceof Array ) || path.length === 0 ) {\n\t\t\t/**\n\t\t\t * Position path must be an array with at least one item.\n\t\t\t *\n\t\t\t * @error model-position-path-incorrect-format\n\t\t\t * @param path\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-path-incorrect-format',\n\t\t\t\troot,\n\t\t\t\t{ path }\n\t\t\t);\n\t\t}\n\n\t\t// Normalize the root and path when element (not root) is passed.\n\t\tif ( root.is( 'rootElement' ) ) {\n\t\t\tpath = path.slice();\n\t\t} else {\n\t\t\tpath = [ ...root.getPath(), ...path ];\n\t\t\troot = root.root;\n\t\t}\n\n\t\t/**\n\t\t * Root of the position path.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t\t * module:engine/model/position~Position#root\n\t\t */\n\t\tthis.root = root;\n\n\t\t/**\n\t\t * Position of the node in the tree. **Path contains offsets, not indexes.**\n\t\t *\n\t\t * Position can be placed before, after or in a {@link module:engine/model/node~Node node} if that node has\n\t\t * {@link module:engine/model/node~Node#offsetSize} greater than `1`. Items in position path are\n\t\t * {@link module:engine/model/node~Node#startOffset starting offsets} of position ancestors, starting from direct root children,\n\t\t * down to the position offset in it's parent.\n\t\t *\n\t\t *\t\t ROOT\n\t\t *\t\t |- P before: [ 0 ] after: [ 1 ]\n\t\t *\t\t |- UL before: [ 1 ] after: [ 2 ]\n\t\t *\t\t |- LI before: [ 1, 0 ] after: [ 1, 1 ]\n\t\t *\t\t | |- foo before: [ 1, 0, 0 ] after: [ 1, 0, 3 ]\n\t\t *\t\t |- LI before: [ 1, 1 ] after: [ 1, 2 ]\n\t\t *\t\t |- bar before: [ 1, 1, 0 ] after: [ 1, 1, 3 ]\n\t\t *\n\t\t * `foo` and `bar` are representing {@link module:engine/model/text~Text text nodes}. Since text nodes has offset size\n\t\t * greater than `1` you can place position offset between their start and end:\n\t\t *\n\t\t *\t\t ROOT\n\t\t *\t\t |- P\n\t\t *\t\t |- UL\n\t\t *\t\t |- LI\n\t\t *\t\t | |- f^o|o ^ has path: [ 1, 0, 1 ] | has path: [ 1, 0, 2 ]\n\t\t *\t\t |- LI\n\t\t *\t\t |- b^a|r ^ has path: [ 1, 1, 1 ] | has path: [ 1, 1, 2 ]\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<Number>} module:engine/model/position~Position#path\n\t\t */\n\t\tthis.path = path;\n\n\t\t/**\n\t\t * Position stickiness. See {@link module:engine/model/position~PositionStickiness}.\n\t\t *\n\t\t * @member {module:engine/model/position~PositionStickiness} module:engine/model/position~Position#stickiness\n\t\t */\n\t\tthis.stickiness = stickiness;\n\t}\n\n\t/**\n\t * Offset at which this position is located in its {@link module:engine/model/position~Position#parent parent}. It is equal\n\t * to the last item in position {@link module:engine/model/position~Position#path path}.\n\t *\n\t * @type {Number}\n\t */\n\tget offset() {\n\t\treturn this.path[ this.path.length - 1 ];\n\t}\n\n\tset offset( newOffset ) {\n\t\tthis.path[ this.path.length - 1 ] = newOffset;\n\t}\n\n\t/**\n\t * Parent element of this position.\n\t *\n\t * Keep in mind that `parent` value is calculated when the property is accessed.\n\t * If {@link module:engine/model/position~Position#path position path}\n\t * leads to a non-existing element, `parent` property will throw error.\n\t *\n\t * Also it is a good idea to cache `parent` property if it is used frequently in an algorithm (i.e. in a long loop).\n\t *\n\t * @readonly\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget parent() {\n\t\tlet parent = this.root;\n\n\t\tfor ( let i = 0; i < this.path.length - 1; i++ ) {\n\t\t\tparent = parent.getChild( parent.offsetToIndex( this.path[ i ] ) );\n\n\t\t\tif ( !parent ) {\n\t\t\t\t/**\n\t\t\t\t * The position's path is incorrect. This means that a position does not point to\n\t\t\t\t * a correct place in the tree and hence, some of its methods and getters cannot work correctly.\n\t\t\t\t *\n\t\t\t\t * **Note**: Unlike DOM and view positions, in the model, the\n\t\t\t\t * {@link module:engine/model/position~Position#parent position's parent} is always an element or a document fragment.\n\t\t\t\t * The last offset in the {@link module:engine/model/position~Position#path position's path} is the point in this element\n\t\t\t\t * where this position points.\n\t\t\t\t *\n\t\t\t\t * Read more about model positions and offsets in\n\t\t\t\t * the {@glink framework/guides/architecture/editing-engine#indexes-and-offsets Editing engine architecture guide}.\n\t\t\t\t *\n\t\t\t\t * @error model-position-path-incorrect\n\t\t\t\t * @param {module:engine/model/position~Position} position The incorrect position.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-position-path-incorrect', this, { position: this } );\n\t\t\t}\n\t\t}\n\n\t\tif ( parent.is( '$text' ) ) {\n\t\t\tthrow new CKEditorError( 'model-position-path-incorrect', this, { position: this } );\n\t\t}\n\n\t\treturn parent;\n\t}\n\n\t/**\n\t * Position {@link module:engine/model/position~Position#offset offset} converted to an index in position's parent node. It is\n\t * equal to the {@link module:engine/model/node~Node#index index} of a node after this position. If position is placed\n\t * in text node, position index is equal to the index of that text node.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget index() {\n\t\treturn this.parent.offsetToIndex( this.offset );\n\t}\n\n\t/**\n\t * Returns {@link module:engine/model/text~Text text node} instance in which this position is placed or `null` if this\n\t * position is not in a text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/text~Text|null}\n\t */\n\tget textNode() {\n\t\treturn getTextNodeAtPosition( this, this.parent );\n\t}\n\n\t/**\n\t * Node directly after this position or `null` if this position is in text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nodeAfter() {\n\t\t// Cache the parent and reuse for performance reasons. See #6579 and #6582.\n\t\tconst parent = this.parent;\n\n\t\treturn getNodeAfterPosition( this, parent, getTextNodeAtPosition( this, parent ) );\n\t}\n\n\t/**\n\t * Node directly before this position or `null` if this position is in text node.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/node~Node|null}\n\t */\n\tget nodeBefore() {\n\t\t// Cache the parent and reuse for performance reasons. See #6579 and #6582.\n\t\tconst parent = this.parent;\n\n\t\treturn getNodeBeforePosition( this, parent, getTextNodeAtPosition( this, parent ) );\n\t}\n\n\t/**\n\t * Is `true` if position is at the beginning of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtStart() {\n\t\treturn this.offset === 0;\n\t}\n\n\t/**\n\t * Is `true` if position is at the end of its {@link module:engine/model/position~Position#parent parent}, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isAtEnd() {\n\t\treturn this.offset == this.parent.maxOffset;\n\t}\n\n\t/**\n\t * Checks whether this position is before or after given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {module:engine/model/position~PositionRelation}\n\t */\n\tcompareWith( otherPosition ) {\n\t\tif ( this.root != otherPosition.root ) {\n\t\t\treturn 'different';\n\t\t}\n\n\t\tconst result = compareArrays( this.path, otherPosition.path );\n\n\t\tswitch ( result ) {\n\t\t\tcase 'same':\n\t\t\t\treturn 'same';\n\n\t\t\tcase 'prefix':\n\t\t\t\treturn 'before';\n\n\t\t\tcase 'extension':\n\t\t\t\treturn 'after';\n\n\t\t\tdefault:\n\t\t\t\treturn this.path[ result ] < otherPosition.path[ result ] ? 'before' : 'after';\n\t\t}\n\t}\n\n\t/**\n\t * Gets the farthest position which matches the callback using\n\t * {@link module:engine/model/treewalker~TreeWalker TreeWalker}.\n\t *\n\t * For example:\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text' );\n\t * \t\t// <paragraph>[]foo</paragraph> -> <paragraph>foo[]</paragraph>\n\t *\n\t * \t\tgetLastMatchingPosition( value => value.type == 'text', { direction: 'backward' } );\n\t * \t\t// <paragraph>foo[]</paragraph> -> <paragraph>[]foo</paragraph>\n\t *\n\t * \t\tgetLastMatchingPosition( value => false );\n\t * \t\t// Do not move the position.\n\t *\n\t * @param {Function} skip Callback function. Gets {@link module:engine/model/treewalker~TreeWalkerValue} and should\n\t * return `true` if the value should be skipped or `false` if not.\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t *\n\t * @returns {module:engine/model/position~Position} The position after the last item which matches the `skip` callback test.\n\t */\n\tgetLastMatchingPosition( skip, options = {} ) {\n\t\toptions.startPosition = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\t\ttreeWalker.skip( skip );\n\n\t\treturn treeWalker.position;\n\t}\n\n\t/**\n\t * Returns a path to this position's parent. Parent path is equal to position {@link module:engine/model/position~Position#path path}\n\t * but without the last item.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @returns {Array.<Number>} Path to the parent.\n\t */\n\tgetParentPath() {\n\t\treturn this.path.slice( 0, -1 );\n\t}\n\n\t/**\n\t * Returns ancestors array of this position, that is this position's parent and its ancestors.\n\t *\n\t * @returns {Array.<module:engine/model/item~Item>} Array with ancestors.\n\t */\n\tgetAncestors() {\n\t\tconst parent = this.parent;\n\n\t\tif ( parent.is( 'documentFragment' ) ) {\n\t\t\treturn [ parent ];\n\t\t} else {\n\t\t\treturn parent.getAncestors( { includeSelf: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the parent element of the given name. Returns null if the position is not inside the desired parent.\n\t *\n\t * @param {String} parentName The name of the parent element to find.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tfindAncestor( parentName ) {\n\t\tconst parent = this.parent;\n\n\t\tif ( parent.is( 'element' ) ) {\n\t\t\treturn parent.findAncestor( parentName, { includeSelf: true } );\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the slice of two position {@link #path paths} which is identical. The {@link #root roots}\n\t * of these two paths must be identical.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} position The second position.\n\t * @returns {Array.<Number>} The common path.\n\t */\n\tgetCommonPath( position ) {\n\t\tif ( this.root != position.root ) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// We find on which tree-level start and end have the lowest common ancestor\n\t\tconst cmp = compareArrays( this.path, position.path );\n\t\t// If comparison returned string it means that arrays are same.\n\t\tconst diffAt = ( typeof cmp == 'string' ) ? Math.min( this.path.length, position.path.length ) : cmp;\n\n\t\treturn this.path.slice( 0, diffAt );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of both positions. The {@link #root roots} of these two positions must be identical.\n\t *\n\t * @param {module:engine/model/position~Position} position The second position.\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor( position ) {\n\t\tconst ancestorsA = this.getAncestors();\n\t\tconst ancestorsB = position.getAncestors();\n\n\t\tlet i = 0;\n\n\t\twhile ( ancestorsA[ i ] == ancestorsB[ i ] && ancestorsA[ i ] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i === 0 ? null : ancestorsA[ i - 1 ];\n\t}\n\n\t/**\n\t * Returns a new instance of `Position`, that has same {@link #parent parent} but it's offset\n\t * is shifted by `shift` value (can be a negative value).\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {Number} shift Offset shift. Can be a negative value.\n\t * @returns {module:engine/model/position~Position} Shifted position.\n\t */\n\tgetShiftedBy( shift ) {\n\t\tconst shifted = this.clone();\n\n\t\tconst offset = shifted.offset + shift;\n\t\tshifted.offset = offset < 0 ? 0 : offset;\n\n\t\treturn shifted;\n\t}\n\n\t/**\n\t * Checks whether this position is after given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @see module:engine/model/position~Position#isBefore\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if this position is after given position.\n\t */\n\tisAfter( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'after';\n\t}\n\n\t/**\n\t * Checks whether this position is before given position.\n\t *\n\t * **Note:** watch out when using negation of the value returned by this method, because the negation will also\n\t * be `true` if positions are in different roots and you might not expect this. You should probably use\n\t * `a.isAfter( b ) || a.isEqual( b )` or `!a.isBefore( p ) && a.root == b.root` in most scenarios. If your\n\t * condition uses multiple `isAfter` and `isBefore` checks, build them so they do not use negated values, i.e.:\n\t *\n\t *\t\tif ( a.isBefore( b ) && c.isAfter( d ) ) {\n\t *\t\t\t// do A.\n\t *\t\t} else {\n\t *\t\t\t// do B.\n\t *\t\t}\n\t *\n\t * or, if you have only one if-branch:\n\t *\n\t *\t\tif ( !( a.isBefore( b ) && c.isAfter( d ) ) {\n\t *\t\t\t// do B.\n\t *\t\t}\n\t *\n\t * rather than:\n\t *\n\t *\t\tif ( !a.isBefore( b ) || && !c.isAfter( d ) ) {\n\t *\t\t\t// do B.\n\t *\t\t} else {\n\t *\t\t\t// do A.\n\t *\t\t}\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if this position is before given position.\n\t */\n\tisBefore( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'before';\n\t}\n\n\t/**\n\t * Checks whether this position is equal to given position.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions are same.\n\t */\n\tisEqual( otherPosition ) {\n\t\treturn this.compareWith( otherPosition ) == 'same';\n\t}\n\n\t/**\n\t * Checks whether this position is touching given position. Positions touch when there are no text nodes\n\t * or empty nodes in a range between them. Technically, those positions are not equal but in many cases\n\t * they are very similar or even indistinguishable.\n\t *\n\t * @param {module:engine/model/position~Position} otherPosition Position to compare with.\n\t * @returns {Boolean} True if positions touch.\n\t */\n\tisTouching( otherPosition ) {\n\t\tlet left = null;\n\t\tlet right = null;\n\t\tconst compare = this.compareWith( otherPosition );\n\n\t\tswitch ( compare ) {\n\t\t\tcase 'same':\n\t\t\t\treturn true;\n\n\t\t\tcase 'before':\n\t\t\t\tleft = Position._createAt( this );\n\t\t\t\tright = Position._createAt( otherPosition );\n\t\t\t\tbreak;\n\n\t\t\tcase 'after':\n\t\t\t\tleft = Position._createAt( otherPosition );\n\t\t\t\tright = Position._createAt( this );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\n\t\t// Cached for optimization purposes.\n\t\tlet leftParent = left.parent;\n\n\t\twhile ( left.path.length + right.path.length ) {\n\t\t\tif ( left.isEqual( right ) ) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif ( left.path.length > right.path.length ) {\n\t\t\t\tif ( left.offset !== leftParent.maxOffset ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tleft.path = left.path.slice( 0, -1 );\n\t\t\t\tleftParent = leftParent.parent;\n\t\t\t\tleft.offset++;\n\t\t\t} else {\n\t\t\t\tif ( right.offset !== 0 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tright.path = right.path.slice( 0, -1 );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tposition.is( 'position' ); // -> true\n\t *\t\tposition.is( 'model:position' ); // -> true\n\t *\n\t *\t\tposition.is( 'view:position' ); // -> false\n\t *\t\tposition.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'position' || type === 'model:position';\n\t}\n\n\t/**\n\t * Checks if two positions are in the same parent.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/position~Position} position Position to compare with.\n\t * @returns {Boolean} `true` if positions have the same parent, `false` otherwise.\n\t */\n\thasSameParentAs( position ) {\n\t\tif ( this.root !== position.root ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst thisParentPath = this.getParentPath();\n\t\tconst posParentPath = position.getParentPath();\n\n\t\treturn compareArrays( thisParentPath, posParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Returns a copy of this position that is transformed by given `operation`.\n\t *\n\t * The new position's parameters are updated accordingly to the effect of the `operation`.\n\t *\n\t * For example, if `n` nodes are inserted before the position, the returned position {@link ~Position#offset} will be\n\t * increased by `n`. If the position was in a merged element, it will be accordingly moved to the new element, etc.\n\t *\n\t * This method is safe to use it on non-existing positions (for example during operational transformation).\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform by.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tlet result;\n\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\tresult = this._getTransformedByInsertOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\tresult = this._getTransformedByMoveOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'split':\n\t\t\t\tresult = this._getTransformedBySplitOperation( operation );\n\t\t\t\tbreak;\n\t\t\tcase 'merge':\n\t\t\t\tresult = this._getTransformedByMergeOperation( operation );\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tresult = Position._createAt( this );\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by an insert operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByInsertOperation( operation ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany );\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by a move operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByMoveOperation( operation ) {\n\t\treturn this._getTransformedByMove( operation.sourcePosition, operation.targetPosition, operation.howMany );\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by a split operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst movedRange = operation.movedRange;\n\n\t\tconst isContained = movedRange.containsPosition( this ) ||\n\t\t\t( movedRange.start.isEqual( this ) && this.stickiness == 'toNext' );\n\n\t\tif ( isContained ) {\n\t\t\treturn this._getCombined( operation.splitPosition, operation.moveTargetPosition );\n\t\t} else {\n\t\t\tif ( operation.graveyardPosition ) {\n\t\t\t\treturn this._getTransformedByMove( operation.graveyardPosition, operation.insertionPosition, 1 );\n\t\t\t} else {\n\t\t\t\treturn this._getTransformedByInsertion( operation.insertionPosition, 1 );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns a copy of this position transformed by merge operation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/position~Position}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\tconst movedRange = operation.movedRange;\n\t\tconst isContained = movedRange.containsPosition( this ) || movedRange.start.isEqual( this );\n\n\t\tlet pos;\n\n\t\tif ( isContained ) {\n\t\t\tpos = this._getCombined( operation.sourcePosition, operation.targetPosition );\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Above happens during OT when the merged element is moved before the merged-to element.\n\t\t\t\tpos = pos._getTransformedByDeletion( operation.deletionPosition, 1 );\n\t\t\t}\n\t\t} else if ( this.isEqual( operation.deletionPosition ) ) {\n\t\t\tpos = Position._createAt( operation.deletionPosition );\n\t\t} else {\n\t\t\tpos = this._getTransformedByMove( operation.deletionPosition, operation.graveyardPosition, 1 );\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by removing `howMany` nodes starting from `deletePosition`.\n\t * It may happen that this position is in a removed node. If that is the case, `null` is returned instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletePosition Position before the first removed node.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/position~Position|null} Transformed position or `null`.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tconst transformed = Position._createAt( this );\n\n\t\t// This position can't be affected if deletion was in a different root.\n\t\tif ( this.root != deletePosition.root ) {\n\t\t\treturn transformed;\n\t\t}\n\n\t\tif ( compareArrays( deletePosition.getParentPath(), this.getParentPath() ) == 'same' ) {\n\t\t\t// If nodes are removed from the node that is pointed by this position...\n\t\t\tif ( deletePosition.offset < this.offset ) {\n\t\t\t\t// And are removed from before an offset of that position...\n\t\t\t\tif ( deletePosition.offset + howMany > this.offset ) {\n\t\t\t\t\t// Position is in removed range, it's no longer in the tree.\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\t// Decrement the offset accordingly.\n\t\t\t\t\ttransformed.offset -= howMany;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ( compareArrays( deletePosition.getParentPath(), this.getParentPath() ) == 'prefix' ) {\n\t\t\t// If nodes are removed from a node that is on a path to this position...\n\t\t\tconst i = deletePosition.path.length - 1;\n\n\t\t\tif ( deletePosition.offset <= this.path[ i ] ) {\n\t\t\t\t// And are removed from before next node of that path...\n\t\t\t\tif ( deletePosition.offset + howMany > this.path[ i ] ) {\n\t\t\t\t\t// If the next node of that path is removed return null\n\t\t\t\t\t// because the node containing this position got removed.\n\t\t\t\t\treturn null;\n\t\t\t\t} else {\n\t\t\t\t\t// Otherwise, decrement index on that path.\n\t\t\t\t\ttransformed.path[ i ] -= howMany;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn transformed;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by inserting `howMany` nodes at `insertPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany ) {\n\t\tconst transformed = Position._createAt( this );\n\n\t\t// This position can't be affected if insertion was in a different root.\n\t\tif ( this.root != insertPosition.root ) {\n\t\t\treturn transformed;\n\t\t}\n\n\t\tif ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'same' ) {\n\t\t\t// If nodes are inserted in the node that is pointed by this position...\n\t\t\tif ( insertPosition.offset < this.offset || ( insertPosition.offset == this.offset && this.stickiness != 'toPrevious' ) ) {\n\t\t\t\t// And are inserted before an offset of that position...\n\t\t\t\t// \"Push\" this positions offset.\n\t\t\t\ttransformed.offset += howMany;\n\t\t\t}\n\t\t} else if ( compareArrays( insertPosition.getParentPath(), this.getParentPath() ) == 'prefix' ) {\n\t\t\t// If nodes are inserted in a node that is on a path to this position...\n\t\t\tconst i = insertPosition.path.length - 1;\n\n\t\t\tif ( insertPosition.offset <= this.path[ i ] ) {\n\t\t\t\t// And are inserted before next node of that path...\n\t\t\t\t// \"Push\" the index on that path.\n\t\t\t\ttransformed.path[ i ] += howMany;\n\t\t\t}\n\t\t}\n\n\t\treturn transformed;\n\t}\n\n\t/**\n\t * Returns a copy of this position that is updated by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position before the first element to move.\n\t * @param {module:engine/model/position~Position} targetPosition Position where moved elements will be inserted.\n\t * @param {Number} howMany How many consecutive nodes to move, starting from `sourcePosition`.\n\t * @returns {module:engine/model/position~Position} Transformed position.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany ) {\n\t\t// Update target position, as it could be affected by nodes removal.\n\t\ttargetPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( sourcePosition.isEqual( targetPosition ) ) {\n\t\t\t// If `targetPosition` is equal to `sourcePosition` this isn't really any move. Just return position as it is.\n\t\t\treturn Position._createAt( this );\n\t\t}\n\n\t\t// Moving a range removes nodes from their original position. We acknowledge this by proper transformation.\n\t\tconst transformed = this._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tconst isMoved = transformed === null ||\n\t\t\t( sourcePosition.isEqual( this ) && this.stickiness == 'toNext' ) ||\n\t\t\t( sourcePosition.getShiftedBy( howMany ).isEqual( this ) && this.stickiness == 'toPrevious' );\n\n\t\tif ( isMoved ) {\n\t\t\t// This position is inside moved range (or sticks to it).\n\t\t\t// In this case, we calculate a combination of this position, move source position and target position.\n\t\t\treturn this._getCombined( sourcePosition, targetPosition );\n\t\t} else {\n\t\t\t// This position is not inside a removed range.\n\t\t\t//\n\t\t\t// In next step, we simply reflect inserting `howMany` nodes, which might further affect the position.\n\t\t\treturn transformed._getTransformedByInsertion( targetPosition, howMany );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a new position that is a combination of this position and given positions.\n\t *\n\t * The combined position is a copy of this position transformed by moving a range starting at `source` position\n\t * to the `target` position. It is expected that this position is inside the moved range.\n\t *\n\t * Example:\n\t *\n\t *\t\tlet original = model.createPositionFromPath( root, [ 2, 3, 1 ] );\n\t *\t\tlet source = model.createPositionFromPath( root, [ 2, 2 ] );\n\t *\t\tlet target = model.createPositionFromPath( otherRoot, [ 1, 1, 3 ] );\n\t *\t\toriginal._getCombined( source, target ); // path is [ 1, 1, 4, 1 ], root is `otherRoot`\n\t *\n\t * Explanation:\n\t *\n\t * We have a position `[ 2, 3, 1 ]` and move some nodes from `[ 2, 2 ]` to `[ 1, 1, 3 ]`. The original position\n\t * was inside moved nodes and now should point to the new place. The moved nodes will be after\n\t * positions `[ 1, 1, 3 ]`, `[ 1, 1, 4 ]`, `[ 1, 1, 5 ]`. Since our position was in the second moved node,\n\t * the transformed position will be in a sub-tree of a node at `[ 1, 1, 4 ]`. Looking at original path, we\n\t * took care of `[ 2, 3 ]` part of it. Now we have to add the rest of the original path to the transformed path.\n\t * Finally, the transformed position will point to `[ 1, 1, 4, 1 ]`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} source Beginning of the moved range.\n\t * @param {module:engine/model/position~Position} target Position where the range is moved.\n\t * @returns {module:engine/model/position~Position} Combined position.\n\t */\n\t_getCombined( source, target ) {\n\t\tconst i = source.path.length - 1;\n\n\t\t// The first part of a path to combined position is a path to the place where nodes were moved.\n\t\tconst combined = Position._createAt( target );\n\t\tcombined.stickiness = this.stickiness;\n\n\t\t// Then we have to update the rest of the path.\n\n\t\t// Fix the offset because this position might be after `from` position and we have to reflect that.\n\t\tcombined.offset = combined.offset + this.path[ i ] - source.offset;\n\n\t\t// Then, add the rest of the path.\n\t\t// If this position is at the same level as `from` position nothing will get added.\n\t\tcombined.path = [ ...combined.path, ...this.path.slice( i + 1 ) ];\n\n\t\treturn combined;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\troot: this.root.toJSON(),\n\t\t\tpath: Array.from( this.path ),\n\t\t\tstickiness: this.stickiness\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new position that is equal to current position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.root, this.path, this.stickiness );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/model/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/model/item~Item model item} and `'before'` or `'after'` (sets position before or after given model item).\n\t *\n\t * This method is a shortcut to other factory methods such as:\n\t *\n\t * * {@link module:engine/model/position~Position._createBefore},\n\t * * {@link module:engine/model/position~Position._createAfter}.\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 the\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness. Used only when the\n\t * first parameter is a {@link module:engine/model/item~Item model item}.\n\t * @protected\n\t */\n\tstatic _createAt( itemOrPosition, offset, stickiness = 'toNone' ) {\n\t\tif ( itemOrPosition instanceof Position ) {\n\t\t\treturn new Position( itemOrPosition.root, itemOrPosition.path, itemOrPosition.stickiness );\n\t\t} else {\n\t\t\tconst node = itemOrPosition;\n\n\t\t\tif ( offset == 'end' ) {\n\t\t\t\toffset = node.maxOffset;\n\t\t\t} else if ( offset == 'before' ) {\n\t\t\t\treturn this._createBefore( node, stickiness );\n\t\t\t} else if ( offset == 'after' ) {\n\t\t\t\treturn this._createAfter( node, stickiness );\n\t\t\t} else if ( offset !== 0 && !offset ) {\n\t\t\t\t/**\n\t\t\t\t * {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}\n\t\t\t\t * requires the offset to be specified when the first parameter is a model item.\n\t\t\t\t *\n\t\t\t\t * @error model-createpositionat-offset-required\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-createpositionat-offset-required', [ this, itemOrPosition ] );\n\t\t\t}\n\n\t\t\tif ( !node.is( 'element' ) && !node.is( 'documentFragment' ) ) {\n\t\t\t\t/**\n\t\t\t\t * Position parent have to be a model element or model document fragment.\n\t\t\t\t *\n\t\t\t\t * @error model-position-parent-incorrect\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-position-parent-incorrect',\n\t\t\t\t\t[ this, itemOrPosition ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst path = node.getPath();\n\n\t\t\tpath.push( offset );\n\n\t\t\treturn new this( node.root, path, stickiness );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a new position, after given {@link module:engine/model/item~Item model item}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item after which the position should be placed.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * @returns {module:engine/model/position~Position}\n\t * @protected\n\t */\n\tstatic _createAfter( item, stickiness ) {\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position after a root element.\n\t\t\t *\n\t\t\t * @error model-position-after-root\n\t\t\t * @param {module:engine/model/item~Item} root\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-after-root',\n\t\t\t\t[ this, item ],\n\t\t\t\t{ root: item }\n\t\t\t);\n\t\t}\n\n\t\treturn this._createAt( item.parent, item.endOffset, stickiness );\n\t}\n\n\t/**\n\t * Creates a new position, before the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item before which the position should be placed.\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone'] Position stickiness.\n\t * @returns {module:engine/model/position~Position}\n\t * @protected\n\t */\n\tstatic _createBefore( item, stickiness ) {\n\t\tif ( !item.parent ) {\n\t\t\t/**\n\t\t\t * You can not make a position before a root element.\n\t\t\t *\n\t\t\t * @error model-position-before-root\n\t\t\t * @param {module:engine/model/item~Item} root\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-before-root',\n\t\t\t\titem,\n\t\t\t\t{ root: item }\n\t\t\t);\n\t\t}\n\n\t\treturn this._createAt( item.parent, item.startOffset, stickiness );\n\t}\n\n\t/**\n\t * Creates a `Position` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Position`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be position owner.\n\t * @returns {module:engine/model/position~Position} `Position` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\tif ( json.root === '$graveyard' ) {\n\t\t\tconst pos = new Position( doc.graveyard, json.path );\n\t\t\tpos.stickiness = json.stickiness;\n\n\t\t\treturn pos;\n\t\t}\n\n\t\tif ( !doc.getRoot( json.root ) ) {\n\t\t\t/**\n\t\t\t * Cannot create position for document. Root with specified name does not exist.\n\t\t\t *\n\t\t\t * @error model-position-fromjson-no-root\n\t\t\t * @param {String} rootName\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'model-position-fromjson-no-root',\n\t\t\t\tdoc,\n\t\t\t\t{ rootName: json.root }\n\t\t\t);\n\t\t}\n\n\t\treturn new Position( doc.getRoot( json.root ), json.path, json.stickiness );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n/**\n * A flag indicating whether this position is `'before'` or `'after'` or `'same'` as given position.\n * If positions are in different roots `'different'` flag is returned.\n *\n * @typedef {String} module:engine/model/position~PositionRelation\n */\n\n/**\n * Represents how position is \"sticking\" with neighbour nodes. Used to define how position should be transformed (moved)\n * in edge cases. Possible values: `'toNone'`, `'toNext'`, `'toPrevious'`.\n *\n * Examples:\n *\n *\t\tInsert. Position is at | and nodes are inserted at the same position, marked as ^:\n *\n *\t\t- sticks to none: <p>f^|oo</p> -> <p>fbar|oo</p>\n *\t\t- sticks to next node: <p>f^|oo</p> -> <p>fbar|oo</p>\n *\t\t- sticks to previous node: <p>f|^oo</p> -> <p>f|baroo</p>\n *\n *\n *\t\tMove. Position is at | and range [oo] is moved to position ^:\n *\n *\t\t- sticks to none: <p>f|[oo]</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\t\t- sticks to none: <p>f[oo]|</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\n *\t\t- sticks to next node: <p>f|[oo]</p><p>b^ar</p> -> <p>f</p><p>b|ooar</p>\n *\t\t- sticks to next node: <p>f[oo]|</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\n *\t\t- sticks to previous node: <p>f|[oo]</p><p>b^ar</p> -> <p>f|</p><p>booar</p>\n *\t\t- sticks to previous node: <p>f[oo]|</p><p>b^ar</p> -> <p>f</p><p>boo|ar</p>\n *\n * @typedef {String} module:engine/model/position~PositionStickiness\n */\n\n/**\n * Returns a text node at the given position.\n *\n * This is a helper function optimized to reuse the position parent instance for performance reasons.\n *\n * Normally, you should use {@link module:engine/model/position~Position#textNode `Position#textNode`}.\n * If you start hitting performance issues with {@link module:engine/model/position~Position#parent `Position#parent`}\n * check if your algorithm does not access it multiple times (which can happen directly or indirectly via other position properties).\n *\n * See https://github.com/ckeditor/ckeditor5/issues/6579.\n *\n * See also:\n *\n * * {@link module:engine/model/position~getNodeAfterPosition}\n * * {@link module:engine/model/position~getNodeBeforePosition}\n *\n * @param {module:engine/model/position~Position} position\n * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} positionParent The parent of the\n * given position.\n * @returns {module:engine/model/text~Text|null}\n */\nexport function getTextNodeAtPosition( position, positionParent ) {\n\tconst node = positionParent.getChild( positionParent.offsetToIndex( position.offset ) );\n\n\tif ( node && node.is( '$text' ) && node.startOffset < position.offset ) {\n\t\treturn node;\n\t}\n\n\treturn null;\n}\n\n/**\n * Returns the node after the given position.\n *\n * This is a helper function optimized to reuse the position parent instance and the calculation of the text node at the\n * specific position for performance reasons.\n *\n * Normally, you should use {@link module:engine/model/position~Position#nodeAfter `Position#nodeAfter`}.\n * If you start hitting performance issues with {@link module:engine/model/position~Position#parent `Position#parent`} and/or\n * {@link module:engine/model/position~Position#textNode `Position#textNode`}\n * check if your algorithm does not access those properties multiple times\n * (which can happen directly or indirectly via other position properties).\n *\n * See https://github.com/ckeditor/ckeditor5/issues/6579 and https://github.com/ckeditor/ckeditor5/issues/6582.\n *\n * See also:\n *\n * * {@link module:engine/model/position~getTextNodeAtPosition}\n * * {@link module:engine/model/position~getNodeBeforePosition}\n *\n * @param {module:engine/model/position~Position} position\n * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} positionParent The parent of the\n * given position.\n * @param {module:engine/model/text~Text|null} textNode Text node at the given position.\n * @returns {module:engine/model/node~Node|null}\n */\nexport function getNodeAfterPosition( position, positionParent, textNode ) {\n\tif ( textNode !== null ) {\n\t\treturn null;\n\t}\n\n\treturn positionParent.getChild( positionParent.offsetToIndex( position.offset ) );\n}\n\n/**\n * Returns the node before the given position.\n *\n * Refer to {@link module:engine/model/position~getNodeBeforePosition} for documentation on when to use this util method.\n *\n * See also:\n *\n * * {@link module:engine/model/position~getTextNodeAtPosition}\n * * {@link module:engine/model/position~getNodeAfterPosition}\n *\n * @param {module:engine/model/position~Position} position\n * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} positionParent The parent of the\n * given position.\n * @param {module:engine/model/text~Text|null} textNode Text node at the given position.\n * @returns {module:engine/model/node~Node|null}\n */\nexport function getNodeBeforePosition( position, positionParent, textNode ) {\n\tif ( textNode !== null ) {\n\t\treturn null;\n\t}\n\n\treturn positionParent.getChild( positionParent.offsetToIndex( position.offset ) - 1 );\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/range\n */\n\nimport Position from './position';\nimport TreeWalker from './treewalker';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\n/**\n * Represents a range in the model tree.\n *\n * A range is defined by its {@link module:engine/model/range~Range#start} and {@link module:engine/model/range~Range#end}\n * positions.\n *\n * You can create range instances via its constructor or the `createRange*()` factory methods of\n * {@link module:engine/model/model~Model} and {@link module:engine/model/writer~Writer}.\n */\nexport default class Range {\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * @param {module:engine/model/position~Position} start 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 */\n\tconstructor( start, end = null ) {\n\t\t/**\n\t\t * Start position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.start = Position._createAt( start );\n\n\t\t/**\n\t\t * End position.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position}\n\t\t */\n\t\tthis.end = end ? Position._createAt( end ) : Position._createAt( start );\n\n\t\t// If the range is collapsed, treat in a similar way as a position and set its boundaries stickiness to 'toNone'.\n\t\t// In other case, make the boundaries stick to the \"inside\" of the range.\n\t\tthis.start.stickiness = this.isCollapsed ? 'toNone' : 'toNext';\n\t\tthis.end.stickiness = this.isCollapsed ? 'toNone' : 'toPrevious';\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them together with additional information like length or {@link module:engine/model/position~Position positions},\n\t * grouped as {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t * It iterates over all {@link module:engine/model/textproxy~TextProxy text contents} that are inside the range\n\t * and all the {@link module:engine/model/element~Element}s that are entered into when iterating over this range.\n\t *\n\t * This iterator uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range\n\t * and `ignoreElementEnd` option set to `true`.\n\t *\n\t * @returns {Iterable.<module:engine/model/treewalker~TreeWalkerValue>}\n\t */\n\t* [ Symbol.iterator ]() {\n\t\tyield* new TreeWalker( { boundaries: this, ignoreElementEnd: true } );\n\t}\n\n\t/**\n\t * Returns whether the range is collapsed, that is if {@link #start} and\n\t * {@link #end} positions are equal.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this.start.isEqual( this.end );\n\t}\n\n\t/**\n\t * Returns whether this range is flat, that is if {@link #start} position and\n\t * {@link #end} position are in the same {@link module:engine/model/position~Position#parent}.\n\t *\n\t * @type {Boolean}\n\t */\n\tget isFlat() {\n\t\tconst startParentPath = this.start.getParentPath();\n\t\tconst endParentPath = this.end.getParentPath();\n\n\t\treturn compareArrays( startParentPath, endParentPath ) == 'same';\n\t}\n\n\t/**\n\t * Range root element.\n\t *\n\t * @type {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this.start.root;\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position Position to check.\n\t * @returns {Boolean} `true` if given {@link module:engine/model/position~Position position} is contained\n\t * in this range,`false` otherwise.\n\t */\n\tcontainsPosition( position ) {\n\t\treturn position.isAfter( this.start ) && position.isBefore( this.end );\n\t}\n\n\t/**\n\t * Checks whether this range contains given {@link ~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check.\n\t * @param {Boolean} [loose=false] Whether the check is loose or strict. If the check is strict (`false`), compared range cannot\n\t * start or end at the same position as this range boundaries. If the check is loose (`true`), compared range can start, end or\n\t * even be equal to this range. Note that collapsed ranges are always compared in strict mode.\n\t * @returns {Boolean} `true` if given {@link ~Range range} boundaries are contained by this range, `false` otherwise.\n\t */\n\tcontainsRange( otherRange, loose = false ) {\n\t\tif ( otherRange.isCollapsed ) {\n\t\t\tloose = false;\n\t\t}\n\n\t\tconst containsStart = this.containsPosition( otherRange.start ) || ( loose && this.start.isEqual( otherRange.start ) );\n\t\tconst containsEnd = this.containsPosition( otherRange.end ) || ( loose && this.end.isEqual( otherRange.end ) );\n\n\t\treturn containsStart && containsEnd;\n\t}\n\n\t/**\n\t * Checks whether given {@link module:engine/model/item~Item} is inside this range.\n\t *\n\t * @param {module:engine/model/item~Item} item Model item to check.\n\t */\n\tcontainsItem( item ) {\n\t\tconst pos = Position._createBefore( item );\n\n\t\treturn this.containsPosition( pos ) || this.start.isEqual( pos );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trange.is( 'range' ); // -> true\n\t *\t\trange.is( 'model:range' ); // -> true\n\t *\n\t *\t\trange.is( 'view:range' ); // -> false\n\t *\t\trange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'range' || type === 'model:range';\n\t}\n\n\t/**\n\t * Two ranges are equal if their {@link #start} and {@link #end} positions are equal.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges are equal, `false` otherwise.\n\t */\n\tisEqual( otherRange ) {\n\t\treturn this.start.isEqual( otherRange.start ) && this.end.isEqual( otherRange.end );\n\t}\n\n\t/**\n\t * Checks and returns whether this range intersects with given range.\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to compare with.\n\t * @returns {Boolean} `true` if ranges intersect, `false` otherwise.\n\t */\n\tisIntersecting( otherRange ) {\n\t\treturn this.start.isBefore( otherRange.end ) && this.end.isAfter( otherRange.start );\n\t}\n\n\t/**\n\t * Computes which part(s) of this {@link ~Range range} is not a part of given {@link ~Range range}.\n\t * Returned array contains zero, one or two {@link ~Range ranges}.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\tlet transformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has no ranges because `otherRange` contains `range`\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 3 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has one range: from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 4 ] ) );\n\t *\t\ttransformed = range.getDifference( otherRange );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3 ] and from [ 4 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to differentiate against.\n\t * @returns {Array.<module:engine/model/range~Range>} The difference between ranges.\n\t */\n\tgetDifference( otherRange ) {\n\t\tconst ranges = [];\n\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect.\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the start to the middle of this range.\n\t\t\t\tranges.push( new Range( this.start, otherRange.start ) );\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// add shrunken range - from the middle of this range to the end.\n\t\t\t\tranges.push( new Range( otherRange.end, this.end ) );\n\t\t\t}\n\t\t} else {\n\t\t\t// Ranges do not intersect, return the original range.\n\t\t\tranges.push( new Range( this.start, this.end ) );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an intersection of this {@link ~Range range} and given {@link ~Range range}.\n\t * Intersection is a common part of both of those ranges. If ranges has no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange( model.createPositionFromPath( root, [ 1 ] ), model.createPositionFromPath( root, [ 2 ] ) );\n\t *\t\tlet transformed = range.getIntersection( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange( model.createPositionFromPath( root, [ 3 ] ), model.createPositionFromPath( root, [ 5 ] ) );\n\t *\t\ttransformed = range.getIntersection( otherRange ); // range from [ 3 ] to [ 4, 0, 1 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to check for intersection.\n\t * @returns {module:engine/model/range~Range|null} A common part of given ranges or `null` if ranges have no common part.\n\t */\n\tgetIntersection( otherRange ) {\n\t\tif ( this.isIntersecting( otherRange ) ) {\n\t\t\t// Ranges intersect, so a common range will be returned.\n\t\t\t// At most, it will be same as this range.\n\t\t\tlet commonRangeStart = this.start;\n\t\t\tlet commonRangeEnd = this.end;\n\n\t\t\tif ( this.containsPosition( otherRange.start ) ) {\n\t\t\t\t// Given range start is inside this range. This means thaNt we have to\n\t\t\t\t// shrink common range to the given range start.\n\t\t\t\tcommonRangeStart = otherRange.start;\n\t\t\t}\n\n\t\t\tif ( this.containsPosition( otherRange.end ) ) {\n\t\t\t\t// Given range end is inside this range. This means that we have to\n\t\t\t\t// shrink common range to the given range end.\n\t\t\t\tcommonRangeEnd = otherRange.end;\n\t\t\t}\n\n\t\t\treturn new Range( commonRangeStart, commonRangeEnd );\n\t\t}\n\n\t\t// Ranges do not intersect, so they do not have common part.\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns a range created by joining this {@link ~Range range} with the given {@link ~Range range}.\n\t * If ranges have no common part, returns `null`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet otherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 1 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2 ] )\n \t *\t\t);\n\t *\t\tlet transformed = range.getJoined( otherRange ); // null - ranges have no common part\n\t *\n\t *\t\totherRange = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 3 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 5 ] )\n\t *\t\t);\n\t *\t\ttransformed = range.getJoined( otherRange ); // range from [ 2, 7 ] to [ 5 ]\n\t *\n\t * @param {module:engine/model/range~Range} otherRange Range to be joined.\n\t * @param {Boolean} [loose=false] Whether the intersection check is loose or strict. If the check is strict (`false`),\n\t * ranges are tested for intersection or whether start/end positions are equal. If the check is loose (`true`),\n\t * compared range is also checked if it's {@link module:engine/model/position~Position#isTouching touching} current range.\n\t * @returns {module:engine/model/range~Range|null} A sum of given ranges or `null` if ranges have no common part.\n\t */\n\tgetJoined( otherRange, loose = false ) {\n\t\tlet shouldJoin = this.isIntersecting( otherRange );\n\n\t\tif ( !shouldJoin ) {\n\t\t\tif ( this.start.isBefore( otherRange.start ) ) {\n\t\t\t\tshouldJoin = loose ? this.end.isTouching( otherRange.start ) : this.end.isEqual( otherRange.start );\n\t\t\t} else {\n\t\t\t\tshouldJoin = loose ? otherRange.end.isTouching( this.start ) : otherRange.end.isEqual( this.start );\n\t\t\t}\n\t\t}\n\n\t\tif ( !shouldJoin ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet startPosition = this.start;\n\t\tlet endPosition = this.end;\n\n\t\tif ( otherRange.start.isBefore( startPosition ) ) {\n\t\t\tstartPosition = otherRange.start;\n\t\t}\n\n\t\tif ( otherRange.end.isAfter( endPosition ) ) {\n\t\t\tendPosition = otherRange.end;\n\t\t}\n\n\t\treturn new Range( startPosition, endPosition );\n\t}\n\n\t/**\n\t * Computes and returns the smallest set of {@link #isFlat flat} ranges, that covers this range in whole.\n\t *\n\t * See an example of a model structure (`[` and `]` are range boundaries):\n\t *\n\t *\t\troot root\n\t *\t\t |- element DIV DIV P2 P3 DIV\n\t *\t\t | |- element H H P1 f o o b a r H P4\n\t *\t\t | | |- \"fir[st\" fir[st lorem se]cond ipsum\n\t *\t\t | |- element P1\n\t *\t\t | | |- \"lorem\" ||\n\t *\t\t |- element P2 ||\n\t *\t\t | |- \"foo\" VV\n\t *\t\t |- element P3\n\t *\t\t | |- \"bar\" root\n\t *\t\t |- element DIV DIV [P2 P3] DIV\n\t *\t\t | |- element H H [P1] f o o b a r H P4\n\t *\t\t | | |- \"se]cond\" fir[st] lorem [se]cond ipsum\n\t *\t\t | |- element P4\n\t *\t\t | | |- \"ipsum\"\n\t *\n\t * As it can be seen, letters contained in the range are: `stloremfoobarse`, spread across different parents.\n\t * We are looking for minimal set of flat ranges that contains the same nodes.\n\t *\n\t * Minimal flat ranges for above range `( [ 0, 0, 3 ], [ 3, 0, 2 ] )` will be:\n\t *\n\t *\t\t( [ 0, 0, 3 ], [ 0, 0, 5 ] ) = \"st\"\n\t *\t\t( [ 0, 1 ], [ 0, 2 ] ) = element P1 (\"lorem\")\n\t *\t\t( [ 1 ], [ 3 ] ) = element P2, element P3 (\"foobar\")\n\t *\t\t( [ 3, 0, 0 ], [ 3, 0, 2 ] ) = \"se\"\n\t *\n\t * **Note:** if an {@link module:engine/model/element~Element element} is not wholly contained in this range, it won't be returned\n\t * in any of the returned flat ranges. See in the example how `H` elements at the beginning and at the end of the range\n\t * were omitted. Only their parts that were wholly in the range were returned.\n\t *\n\t * **Note:** this method is not returning flat ranges that contain no nodes.\n\t *\n\t * @returns {Array.<module:engine/model/range~Range>} Array of flat ranges covering this range.\n\t */\n\tgetMinimalFlatRanges() {\n\t\tconst ranges = [];\n\t\tconst diffAt = this.start.getCommonPath( this.end ).length;\n\n\t\tconst pos = Position._createAt( this.start );\n\t\tlet posParent = pos.parent;\n\n\t\t// Go up.\n\t\twhile ( pos.path.length > diffAt + 1 ) {\n\t\t\tconst howMany = posParent.maxOffset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.path = pos.path.slice( 0, -1 );\n\t\t\tpos.offset++;\n\t\t\tposParent = posParent.parent;\n\t\t}\n\n\t\t// Go down.\n\t\twhile ( pos.path.length <= this.end.path.length ) {\n\t\t\tconst offset = this.end.path[ pos.path.length - 1 ];\n\t\t\tconst howMany = offset - pos.offset;\n\n\t\t\tif ( howMany !== 0 ) {\n\t\t\t\tranges.push( new Range( pos, pos.getShiftedBy( howMany ) ) );\n\t\t\t}\n\n\t\t\tpos.offset = offset;\n\t\t\tpos.path.push( 0 );\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/treewalker~TreeWalker TreeWalker} instance with this range as a boundary.\n\t *\n\t * For example, to iterate over all items in the entire document root:\n\t *\n\t *\t\t// Create a range spanning over the entire root content:\n\t *\t\tconst range = editor.model.createRangeIn( editor.model.document.getRoot() );\n\t *\n\t *\t\t// Iterate over all items in this range:\n\t *\t\tfor ( const value of range.getWalker() ) {\n\t *\t\t\tconsole.log( value.item );\n\t *\t\t}\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @param {module:engine/model/position~Position} [options.startPosition]\n\t * @param {Boolean} [options.singleCharacters=false]\n\t * @param {Boolean} [options.shallow=false]\n\t * @param {Boolean} [options.ignoreElementEnd=false]\n\t */\n\tgetWalker( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\treturn new TreeWalker( options );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/item~Item items} that are in this range and returns\n\t * them.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range and `ignoreElementEnd` option\n\t * set to `true`. However it returns only {@link module:engine/model/item~Item model items},\n\t * not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/model/item~Item>}\n\t */\n\t* getItems( options = {} ) {\n\t\toptions.boundaries = this;\n\t\toptions.ignoreElementEnd = true;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.item;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all {@link module:engine/model/position~Position positions} that are boundaries or\n\t * contained in this range.\n\t *\n\t * This method uses {@link module:engine/model/treewalker~TreeWalker} with `boundaries` set to this range. However it returns only\n\t * {@link module:engine/model/position~Position positions}, not {@link module:engine/model/treewalker~TreeWalkerValue}.\n\t *\n\t * You may specify additional options for the tree walker. See {@link module:engine/model/treewalker~TreeWalker} for\n\t * a full list of available options.\n\t *\n\t * @param {Object} options Object with configuration options. See {@link module:engine/model/treewalker~TreeWalker}.\n\t * @returns {Iterable.<module:engine/model/position~Position>}\n\t */\n\t* getPositions( options = {} ) {\n\t\toptions.boundaries = this;\n\n\t\tconst treeWalker = new TreeWalker( options );\n\n\t\tyield treeWalker.position;\n\n\t\tfor ( const value of treeWalker ) {\n\t\t\tyield value.nextPosition;\n\t\t}\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by given `operation`.\n\t *\n\t * **Note:** transformation may break one range into multiple ranges (for example, when a part of the range is\n\t * moved to a different part of document tree). For this reason, an array is returned by this method and it\n\t * may contain one or more `Range` instances.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to transform range by.\n\t * @returns {Array.<module:engine/model/range~Range>} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperation( operation ) {\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert':\n\t\t\t\treturn this._getTransformedByInsertOperation( operation );\n\t\t\tcase 'move':\n\t\t\tcase 'remove':\n\t\t\tcase 'reinsert':\n\t\t\t\treturn this._getTransformedByMoveOperation( operation );\n\t\t\tcase 'split':\n\t\t\t\treturn [ this._getTransformedBySplitOperation( operation ) ];\n\t\t\tcase 'merge':\n\t\t\t\treturn [ this._getTransformedByMergeOperation( operation ) ];\n\t\t}\n\n\t\treturn [ new Range( this.start, this.end ) ];\n\t}\n\n\t/**\n\t * Returns a range that is a result of transforming this range by multiple `operations`.\n\t *\n\t * @see ~Range#getTransformedByOperation\n\t * @param {Iterable.<module:engine/model/operation/operation~Operation>} operations Operations to transform the range by.\n\t * @returns {Array.<module:engine/model/range~Range>} Range which is the result of transformation.\n\t */\n\tgetTransformedByOperations( operations ) {\n\t\tconst ranges = [ new Range( this.start, this.end ) ];\n\n\t\tfor ( const operation of operations ) {\n\t\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\t\tconst result = ranges[ i ].getTransformedByOperation( operation );\n\n\t\t\t\tranges.splice( i, 1, ...result );\n\t\t\t\ti += result.length - 1;\n\t\t\t}\n\t\t}\n\n\t\t// It may happen that a range is split into two, and then the part of second \"piece\" is moved into first\n\t\t// \"piece\". In this case we will have incorrect third range, which should not be included in the result --\n\t\t// because it is already included in the first \"piece\". In this loop we are looking for all such ranges that\n\t\t// are inside other ranges and we simply remove them.\n\t\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t\tconst range = ranges[ i ];\n\n\t\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t\tconst next = ranges[ j ];\n\n\t\t\t\tif ( range.containsRange( next ) || next.containsRange( range ) || range.isEqual( next ) ) {\n\t\t\t\t\tranges.splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn ranges;\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element} or {@link module:engine/model/documentfragment~DocumentFragment}\n\t * which is a common ancestor of the range's both ends (in which the entire range is contained).\n\t *\n\t * @returns {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetCommonAncestor() {\n\t\treturn this.start.getCommonAncestor( this.end );\n\t}\n\n\t/**\n\t * Returns an {@link module:engine/model/element~Element Element} contained by the range.\n\t * The element will be returned when it is the **only** node within the range and **fullycontained**\n\t * at the same time.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetContainedElement() {\n\t\tif ( this.isCollapsed ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst nodeAfterStart = this.start.nodeAfter;\n\t\tconst nodeBeforeEnd = this.end.nodeBefore;\n\n\t\tif ( nodeAfterStart && nodeAfterStart.is( 'element' ) && nodeAfterStart === nodeBeforeEnd ) {\n\t\t\treturn nodeAfterStart;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Converts `Range` to plain object and returns it.\n\t *\n\t * @returns {Object} `Node` converted to plain object.\n\t */\n\ttoJSON() {\n\t\treturn {\n\t\t\tstart: this.start.toJSON(),\n\t\t\tend: this.end.toJSON()\n\t\t};\n\t}\n\n\t/**\n\t * Returns a new range that is equal to current range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.start, this.end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by insert operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/insertoperation~InsertOperation} operation\n\t * @returns {Array.<module:engine/model/range~Range>}\n\t */\n\t_getTransformedByInsertOperation( operation, spread = false ) {\n\t\treturn this._getTransformedByInsertion( operation.position, operation.howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by move operation.\n\t *\n\t * One or more ranges may be returned as a result of this transformation.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/moveoperation~MoveOperation} operation\n\t * @returns {Array.<module:engine/model/range~Range>}\n\t */\n\t_getTransformedByMoveOperation( operation, spread = false ) {\n\t\tconst sourcePosition = operation.sourcePosition;\n\t\tconst howMany = operation.howMany;\n\t\tconst targetPosition = operation.targetPosition;\n\n\t\treturn this._getTransformedByMove( sourcePosition, targetPosition, howMany, spread );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by split operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/splitoperation~SplitOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedBySplitOperation( operation ) {\n\t\tconst start = this.start._getTransformedBySplitOperation( operation );\n\t\tlet end = this.end._getTransformedBySplitOperation( operation );\n\n\t\tif ( this.end.isEqual( operation.insertionPosition ) ) {\n\t\t\tend = this.end.getShiftedBy( 1 );\n\t\t}\n\n\t\t// Below may happen when range contains graveyard element used by split operation.\n\t\tif ( start.root != end.root ) {\n\t\t\t// End position was next to the moved graveyard element and was moved with it.\n\t\t\t// Fix it by using old `end` which has proper `root`.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns a result of transforming a copy of this range by merge operation.\n\t *\n\t * Always one range is returned. The transformation is done in a way to not break the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/operation/mergeoperation~MergeOperation} operation\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getTransformedByMergeOperation( operation ) {\n\t\t// Special case when the marker is set on \"the closing tag\" of an element. Marker can be set like that during\n\t\t// transformations, especially when a content of a few block elements were removed. For example:\n\t\t//\n\t\t// {} is the transformed range, [] is the removed range.\n\t\t// <p>F[o{o</p><p>B}ar</p><p>Xy]z</p>\n\t\t//\n\t\t// <p>Fo{o</p><p>B}ar</p><p>z</p>\n\t\t// <p>F{</p><p>B}ar</p><p>z</p>\n\t\t// <p>F{</p>}<p>z</p>\n\t\t// <p>F{}z</p>\n\t\t//\n\t\tif ( this.start.isEqual( operation.targetPosition ) && this.end.isEqual( operation.deletionPosition ) ) {\n\t\t\treturn new Range( this.start );\n\t\t}\n\n\t\tlet start = this.start._getTransformedByMergeOperation( operation );\n\t\tlet end = this.end._getTransformedByMergeOperation( operation );\n\n\t\tif ( start.root != end.root ) {\n\t\t\t// This happens when the end position was next to the merged (deleted) element.\n\t\t\t// Then, the end position was moved to the graveyard root. In this case we need to fix\n\t\t\t// the range cause its boundaries would be in different roots.\n\t\t\tend = this.end.getShiftedBy( -1 );\n\t\t}\n\n\t\tif ( start.isAfter( end ) ) {\n\t\t\t// This happens in three following cases:\n\t\t\t//\n\t\t\t// Case 1: Merge operation source position is before the target position (due to some transformations, OT, etc.)\n\t\t\t// This means that start can be moved before the end of the range.\n\t\t\t//\n\t\t\t// Before: <p>a{a</p><p>b}b</p><p>cc</p>\n\t\t\t// Merge: <p>b}b</p><p>cca{a</p>\n\t\t\t// Fix: <p>{b}b</p><p>ccaa</p>\n\t\t\t//\n\t\t\t// Case 2: Range start is before merged node but not directly.\n\t\t\t// Result should include all nodes that were in the original range.\n\t\t\t//\n\t\t\t// Before: <p>aa</p>{<p>cc</p><p>b}b</p>\n\t\t\t// Merge: <p>aab}b</p>{<p>cc</p>\n\t\t\t// Fix: <p>aa{bb</p><p>cc</p>}\n\t\t\t//\n\t\t\t// The range is expanded by an additional `b` letter but it is better than dropping the whole `cc` paragraph.\n\t\t\t//\n\t\t\t// Case 3: Range start is directly before merged node.\n\t\t\t// Resulting range should include only nodes from the merged element:\n\t\t\t//\n\t\t\t// Before: <p>aa</p>{<p>b}b</p><p>cc</p>\n\t\t\t// Merge: <p>aab}b</p>{<p>cc</p>\n\t\t\t// Fix: <p>aa{b}b</p><p>cc</p>\n\t\t\t//\n\n\t\t\tif ( operation.sourcePosition.isBefore( operation.targetPosition ) ) {\n\t\t\t\t// Case 1.\n\t\t\t\tstart = Position._createAt( end );\n\t\t\t\tstart.offset = 0;\n\t\t\t} else {\n\t\t\t\tif ( !operation.deletionPosition.isEqual( start ) ) {\n\t\t\t\t\t// Case 2.\n\t\t\t\t\tend = operation.deletionPosition;\n\t\t\t\t}\n\n\t\t\t\t// In both case 2 and 3 start is at the end of the merge-to element.\n\t\t\t\tstart = operation.targetPosition;\n\t\t\t}\n\n\t\t\treturn new Range( start, end );\n\t\t}\n\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Returns an array containing one or two {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by inserting `howMany` nodes at `insertPosition`. Two {@link ~Range ranges} are\n\t * returned if the insertion was inside this {@link ~Range range} and `spread` is set to `true`.\n\t *\n\t * Examples:\n\t *\n\t *\t\tlet range = model.createRange(\n\t *\t\t\tmodel.createPositionFromPath( root, [ 2, 7 ] ),\n\t *\t\t\tmodel.createPositionFromPath( root, [ 4, 0, 1 ] )\n\t *\t\t);\n\t *\t\tlet transformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 1 ] ), 2 );\n\t *\t\t// transformed array has one range from [ 4, 7 ] to [ 6, 0, 1 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 4, 0, 0 ] ), 4 );\n\t *\t\t// transformed array has one range from [ 2, 7 ] to [ 4, 0, 5 ]\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4 );\n\t *\t\t// transformed array has one range, which is equal to original range\n\t *\n\t *\t\ttransformed = range._getTransformedByInsertion( model.createPositionFromPath( root, [ 3, 2 ] ), 4, true );\n\t *\t\t// transformed array has two ranges: from [ 2, 7 ] to [ 3, 2 ] and from [ 3, 6 ] to [ 4, 0, 1 ]\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} insertPosition Position where nodes are inserted.\n\t * @param {Number} howMany How many nodes are inserted.\n\t * @param {Boolean} [spread] Flag indicating whether this {~Range range} should be spread if insertion\n\t * was inside the range. Defaults to `false`.\n\t * @returns {Array.<module:engine/model/range~Range>} Result of the transformation.\n\t */\n\t_getTransformedByInsertion( insertPosition, howMany, spread = false ) {\n\t\tif ( spread && this.containsPosition( insertPosition ) ) {\n\t\t\t// Range has to be spread. The first part is from original start to the spread point.\n\t\t\t// The other part is from spread point to the original end, but transformed by\n\t\t\t// insertion to reflect insertion changes.\n\n\t\t\treturn [\n\t\t\t\tnew Range( this.start, insertPosition ),\n\t\t\t\tnew Range(\n\t\t\t\t\tinsertPosition.getShiftedBy( howMany ),\n\t\t\t\t\tthis.end._getTransformedByInsertion( insertPosition, howMany )\n\t\t\t\t)\n\t\t\t];\n\t\t} else {\n\t\t\tconst range = new Range( this.start, this.end );\n\n\t\t\trange.start = range.start._getTransformedByInsertion( insertPosition, howMany );\n\t\t\trange.end = range.end._getTransformedByInsertion( insertPosition, howMany );\n\n\t\t\treturn [ range ];\n\t\t}\n\t}\n\n\t/**\n\t * Returns an array containing {@link ~Range ranges} that are a result of transforming this\n\t * {@link ~Range range} by moving `howMany` nodes from `sourcePosition` to `targetPosition`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} sourcePosition Position from which nodes are moved.\n\t * @param {module:engine/model/position~Position} targetPosition Position to where nodes are moved.\n\t * @param {Number} howMany How many nodes are moved.\n\t * @param {Boolean} [spread=false] Whether the range should be spread if the move points inside the range.\n\t * @returns {Array.<module:engine/model/range~Range>} Result of the transformation.\n\t */\n\t_getTransformedByMove( sourcePosition, targetPosition, howMany, spread = false ) {\n\t\t// Special case for transforming a collapsed range. Just transform it like a position.\n\t\tif ( this.isCollapsed ) {\n\t\t\tconst newPos = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\treturn [ new Range( newPos ) ];\n\t\t}\n\n\t\t// Special case for transformation when a part of the range is moved towards the range.\n\t\t//\n\t\t// Examples:\n\t\t//\n\t\t// <div><p>ab</p><p>c[d</p></div><p>e]f</p> --> <div><p>ab</p></div><p>c[d</p><p>e]f</p>\n\t\t// <p>e[f</p><div><p>a]b</p><p>cd</p></div> --> <p>e[f</p><p>a]b</p><div><p>cd</p></div>\n\t\t//\n\t\t// Without this special condition, the default algorithm leaves an \"artifact\" range from one of `differenceSet` parts:\n\t\t//\n\t\t// <div><p>ab</p><p>c[d</p></div><p>e]f</p> --> <div><p>ab</p>{</div>}<p>c[d</p><p>e]f</p>\n\t\t//\n\t\t// This special case is applied only if the range is to be kept together (not spread).\n\t\tconst moveRange = Range._createFromPositionAndShift( sourcePosition, howMany );\n\t\tconst insertPosition = targetPosition._getTransformedByDeletion( sourcePosition, howMany );\n\n\t\tif ( this.containsPosition( targetPosition ) && !spread ) {\n\t\t\tif ( moveRange.containsPosition( this.start ) || moveRange.containsPosition( this.end ) ) {\n\t\t\t\tconst start = this.start._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\t\t\t\tconst end = this.end._getTransformedByMove( sourcePosition, targetPosition, howMany );\n\n\t\t\t\treturn [ new Range( start, end ) ];\n\t\t\t}\n\t\t}\n\n\t\t// Default algorithm.\n\t\tlet result;\n\n\t\tconst differenceSet = this.getDifference( moveRange );\n\t\tlet difference = null;\n\n\t\tconst common = this.getIntersection( moveRange );\n\n\t\tif ( differenceSet.length == 1 ) {\n\t\t\t// `moveRange` and this range may intersect but may be separate.\n\t\t\tdifference = new Range(\n\t\t\t\tdifferenceSet[ 0 ].start._getTransformedByDeletion( sourcePosition, howMany ),\n\t\t\t\tdifferenceSet[ 0 ].end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} else if ( differenceSet.length == 2 ) {\n\t\t\t// `moveRange` is inside this range.\n\t\t\tdifference = new Range(\n\t\t\t\tthis.start,\n\t\t\t\tthis.end._getTransformedByDeletion( sourcePosition, howMany )\n\t\t\t);\n\t\t} // else, `moveRange` contains this range.\n\n\t\tif ( difference ) {\n\t\t\tresult = difference._getTransformedByInsertion( insertPosition, howMany, common !== null || spread );\n\t\t} else {\n\t\t\tresult = [];\n\t\t}\n\n\t\tif ( common ) {\n\t\t\tconst transformedCommon = new Range(\n\t\t\t\tcommon.start._getCombined( moveRange.start, insertPosition ),\n\t\t\t\tcommon.end._getCombined( moveRange.start, insertPosition )\n\t\t\t);\n\n\t\t\tif ( result.length == 2 ) {\n\t\t\t\tresult.splice( 1, 0, transformedCommon );\n\t\t\t} else {\n\t\t\t\tresult.push( transformedCommon );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a copy of this range that is transformed by deletion of `howMany` nodes from `deletePosition`.\n\t *\n\t * If the deleted range is intersecting with the transformed range, the transformed range will be shrank.\n\t *\n\t * If the deleted range contains transformed range, `null` will be returned.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} deletionPosition Position from which nodes are removed.\n\t * @param {Number} howMany How many nodes are removed.\n\t * @returns {module:engine/model/range~Range|null} Result of the transformation.\n\t */\n\t_getTransformedByDeletion( deletePosition, howMany ) {\n\t\tlet newStart = this.start._getTransformedByDeletion( deletePosition, howMany );\n\t\tlet newEnd = this.end._getTransformedByDeletion( deletePosition, howMany );\n\n\t\tif ( newStart == null && newEnd == null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( newStart == null ) {\n\t\t\tnewStart = deletePosition;\n\t\t}\n\n\t\tif ( newEnd == null ) {\n\t\t\tnewEnd = deletePosition;\n\t\t}\n\n\t\treturn new Range( newStart, newEnd );\n\t}\n\n\t/**\n\t * Creates a new range, spreading from specified {@link module:engine/model/position~Position position} to a position moved by\n\t * given `shift`. If `shift` is a negative value, shifted position is treated as the beginning of the range.\n\t *\n\t * @protected\n\t * @param {module:engine/model/position~Position} position Beginning of the range.\n\t * @param {Number} shift How long the range should be.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createFromPositionAndShift( position, shift ) {\n\t\tconst start = position;\n\t\tconst end = position.getShiftedBy( shift );\n\n\t\treturn shift > 0 ? new this( start, end ) : new this( end, start );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/model/element~Element element} which starts before the first child of\n\t * that element and ends after the last child of that element.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createIn( element ) {\n\t\treturn new this( Position._createAt( element, 0 ), Position._createAt( element, element.maxOffset ) );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tstatic _createOn( item ) {\n\t\treturn this._createFromPositionAndShift( Position._createBefore( item ), item.offsetSize );\n\t}\n\n\t/**\n\t * Combines all ranges from the passed array into a one range. At least one range has to be passed.\n\t * Passed ranges must not have common parts.\n\t *\n\t * The first range from the array is a reference range. If other ranges start or end on the exactly same position where\n\t * the reference range, they get combined into one range.\n\t *\n\t *\t\t[ ][] [ ][ ][ ][ ][] [ ] // Passed ranges, shown sorted\n\t *\t\t[ ] // The result of the function if the first range was a reference range.\n\t *\t [ ] // The result of the function if the third-to-seventh range was a reference range.\n\t *\t [ ] // The result of the function if the last range was a reference range.\n\t *\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to combine.\n\t * @returns {module:engine/model/range~Range} Combined range.\n\t */\n\tstatic _createFromRanges( ranges ) {\n\t\tif ( ranges.length === 0 ) {\n\t\t\t/**\n\t\t\t * At least one range has to be passed to\n\t\t\t * {@link module:engine/model/range~Range._createFromRanges `Range._createFromRanges()`}.\n\t\t\t *\n\t\t\t * @error range-create-from-ranges-empty-array\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'range-create-from-ranges-empty-array',\n\t\t\t\tnull\n\t\t\t);\n\t\t} else if ( ranges.length == 1 ) {\n\t\t\treturn ranges[ 0 ].clone();\n\t\t}\n\n\t\t// 1. Set the first range in `ranges` array as a reference range.\n\t\t// If we are going to return just a one range, one of the ranges need to be the reference one.\n\t\t// Other ranges will be stuck to that range, if possible.\n\t\tconst ref = ranges[ 0 ];\n\n\t\t// 2. Sort all the ranges so it's easier to process them.\n\t\tranges.sort( ( a, b ) => {\n\t\t\treturn a.start.isAfter( b.start ) ? 1 : -1;\n\t\t} );\n\n\t\t// 3. Check at which index the reference range is now.\n\t\tconst refIndex = ranges.indexOf( ref );\n\n\t\t// 4. At this moment we don't need the original range.\n\t\t// We are going to modify the result and we need to return a new instance of Range.\n\t\t// We have to create a copy of the reference range.\n\t\tconst result = new this( ref.start, ref.end );\n\n\t\t// 5. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tif ( refIndex > 0 ) {\n\t\t\tfor ( let i = refIndex - 1; true; i++ ) {\n\t\t\t\tif ( ranges[ i ].end.isEqual( result.start ) ) {\n\t\t\t\t\tresult.start = Position._createAt( ranges[ i ].start );\n\t\t\t\t} else {\n\t\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 6. Ranges should be checked and glued starting from the range that is closest to the reference range.\n\t\t// Since ranges are sorted, start with the range with index that is closest to reference range index.\n\t\tfor ( let i = refIndex + 1; i < ranges.length; i++ ) {\n\t\t\tif ( ranges[ i ].start.isEqual( result.end ) ) {\n\t\t\t\tresult.end = Position._createAt( ranges[ i ].end );\n\t\t\t} else {\n\t\t\t\t// If ranges are not starting/ending at the same position there is no point in looking further.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Creates a `Range` instance from given plain object (i.e. parsed JSON string).\n\t *\n\t * @param {Object} json Plain object to be converted to `Range`.\n\t * @param {module:engine/model/document~Document} doc Document object that will be range owner.\n\t * @returns {module:engine/model/element~Element} `Range` instance created using given plain object.\n\t */\n\tstatic fromJSON( json, doc ) {\n\t\treturn new this( Position.fromJSON( json.start, doc ), Position.fromJSON( json.end, doc ) );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `${ this.root } [ ${ this.start.path.join( ', ' ) } ] - [ ${ this.end.path.join( ', ' ) } ]`;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelPosition: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\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/conversion/mapper\n */\n\nimport ModelPosition from '../model/position';\nimport ModelRange from '../model/range';\n\nimport ViewPosition from '../view/position';\nimport ViewRange from '../view/range';\nimport ViewText from '../view/text';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Maps elements, positions and markers between {@link module:engine/view/document~Document the view} and\n * {@link module:engine/model/model the model}.\n *\n * The instance of the Mapper used for the editing pipeline is available in\n * {@link module:engine/controller/editingcontroller~EditingController#mapper `editor.editing.mapper`}.\n *\n * Mapper uses bound elements to find corresponding elements and positions, so, to get proper results,\n * all model elements should be {@link module:engine/conversion/mapper~Mapper#bindElements bound}.\n *\n * To map complex model to/from view relations, you may provide custom callbacks for\n * {@link module:engine/conversion/mapper~Mapper#event:modelToViewPosition modelToViewPosition event} and\n * {@link module:engine/conversion/mapper~Mapper#event:viewToModelPosition viewToModelPosition event} that are fired whenever\n * a position mapping request occurs.\n * Those events are fired by {@link module:engine/conversion/mapper~Mapper#toViewPosition toViewPosition}\n * and {@link module:engine/conversion/mapper~Mapper#toModelPosition toModelPosition} methods. `Mapper` adds it's own default callbacks\n * with `'lowest'` priority. To override default `Mapper` mapping, add custom callback with higher priority and\n * stop the event.\n */\nexport default class Mapper {\n\t/**\n\t * Creates an instance of the mapper.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Model element to view element mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._modelToViewMapping = new WeakMap();\n\n\t\t/**\n\t\t * View element to model element mapping.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakMap}\n\t\t */\n\t\tthis._viewToModelMapping = new WeakMap();\n\n\t\t/**\n\t\t * A map containing callbacks between view element names and functions evaluating length of view elements\n\t\t * in model.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._viewToModelLengthCallbacks = new Map();\n\n\t\t/**\n\t\t * Model marker name to view elements mapping.\n\t\t *\n\t\t * Keys are `String`s while values are `Set`s with {@link module:engine/view/element~Element view elements}.\n\t\t * One marker (name) can be mapped to multiple elements.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._markerNameToElements = new Map();\n\n\t\t/**\n\t\t * View element to model marker names mapping.\n\t\t *\n\t\t * This is reverse to {@link ~Mapper#_markerNameToElements} map.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._elementToMarkerNames = new Map();\n\n\t\t/**\n\t\t * Stores marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element\n\t\t * has been removed, moved or renamed).\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<module:engine/model/markercollection~Marker>}\n\t\t */\n\t\tthis._unboundMarkerNames = new Set();\n\n\t\t// Default mapper algorithm for mapping model position to view position.\n\t\tthis.on( 'modelToViewPosition', ( evt, data ) => {\n\t\t\tif ( data.viewPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewContainer = this._modelToViewMapping.get( data.modelPosition.parent );\n\n\t\t\tdata.viewPosition = this.findPositionIn( viewContainer, data.modelPosition.offset );\n\t\t}, { priority: 'low' } );\n\n\t\t// Default mapper algorithm for mapping view position to model position.\n\t\tthis.on( 'viewToModelPosition', ( evt, data ) => {\n\t\t\tif ( data.modelPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewBlock = this.findMappedViewAncestor( data.viewPosition );\n\t\t\tconst modelParent = this._viewToModelMapping.get( viewBlock );\n\t\t\tconst modelOffset = this._toModelOffset( data.viewPosition.parent, data.viewPosition.offset, viewBlock );\n\n\t\t\tdata.modelPosition = ModelPosition._createAt( modelParent, modelOffset );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Marks model and view elements as corresponding. Corresponding elements can be retrieved by using\n\t * the {@link module:engine/conversion/mapper~Mapper#toModelElement toModelElement} and\n\t * {@link module:engine/conversion/mapper~Mapper#toViewElement toViewElement} methods.\n\t * The information that elements are bound is also used to translate positions.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element.\n\t * @param {module:engine/view/element~Element} viewElement View element.\n\t */\n\tbindElements( modelElement, viewElement ) {\n\t\tthis._modelToViewMapping.set( modelElement, viewElement );\n\t\tthis._viewToModelMapping.set( viewElement, modelElement );\n\t}\n\n\t/**\n\t * Unbinds given {@link module:engine/view/element~Element view element} from the map.\n\t *\n\t * **Note:** view-to-model binding will be removed, if it existed. However, corresponding model-to-view binding\n\t * will be removed only if model element is still bound to passed `viewElement`.\n\t *\n\t * This behavior lets for re-binding model element to another view element without fear of losing the new binding\n\t * when the previously bound view element is unbound.\n\t *\n\t * @param {module:engine/view/element~Element} viewElement View element to unbind.\n\t */\n\tunbindViewElement( viewElement ) {\n\t\tconst modelElement = this.toModelElement( viewElement );\n\n\t\tthis._viewToModelMapping.delete( viewElement );\n\n\t\tif ( this._elementToMarkerNames.has( viewElement ) ) {\n\t\t\tfor ( const markerName of this._elementToMarkerNames.get( viewElement ) ) {\n\t\t\t\tthis._unboundMarkerNames.add( markerName );\n\t\t\t}\n\t\t}\n\n\t\tif ( this._modelToViewMapping.get( modelElement ) == viewElement ) {\n\t\t\tthis._modelToViewMapping.delete( modelElement );\n\t\t}\n\t}\n\n\t/**\n\t * Unbinds given {@link module:engine/model/element~Element model element} from the map.\n\t *\n\t * **Note:** model-to-view binding will be removed, if it existed. However, corresponding view-to-model binding\n\t * will be removed only if view element is still bound to passed `modelElement`.\n\t *\n\t * This behavior lets for re-binding view element to another model element without fear of losing the new binding\n\t * when the previously bound model element is unbound.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element to unbind.\n\t */\n\tunbindModelElement( modelElement ) {\n\t\tconst viewElement = this.toViewElement( modelElement );\n\n\t\tthis._modelToViewMapping.delete( modelElement );\n\n\t\tif ( this._viewToModelMapping.get( viewElement ) == modelElement ) {\n\t\t\tthis._viewToModelMapping.delete( viewElement );\n\t\t}\n\t}\n\n\t/**\n\t * Binds given marker name with given {@link module:engine/view/element~Element view element}. The element\n\t * will be added to the current set of elements bound with given marker name.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to bind.\n\t * @param {String} name Marker name.\n\t */\n\tbindElementToMarker( element, name ) {\n\t\tconst elements = this._markerNameToElements.get( name ) || new Set();\n\t\telements.add( element );\n\n\t\tconst names = this._elementToMarkerNames.get( element ) || new Set();\n\t\tnames.add( name );\n\n\t\tthis._markerNameToElements.set( name, elements );\n\t\tthis._elementToMarkerNames.set( element, names );\n\t}\n\n\t/**\n\t * Unbinds an element from given marker name.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to unbind.\n\t * @param {String} name Marker name.\n\t */\n\tunbindElementFromMarkerName( element, name ) {\n\t\tconst nameToElements = this._markerNameToElements.get( name );\n\n\t\tif ( nameToElements ) {\n\t\t\tnameToElements.delete( element );\n\n\t\t\tif ( nameToElements.size == 0 ) {\n\t\t\t\tthis._markerNameToElements.delete( name );\n\t\t\t}\n\t\t}\n\n\t\tconst elementToNames = this._elementToMarkerNames.get( element );\n\n\t\tif ( elementToNames ) {\n\t\t\telementToNames.delete( name );\n\n\t\t\tif ( elementToNames.size == 0 ) {\n\t\t\t\tthis._elementToMarkerNames.delete( element );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns all marker names of markers which has changed due to unbinding a view element (so it is assumed that the view element\n\t * has been removed, moved or renamed) since the last flush. After returning, the marker names list is cleared.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tflushUnboundMarkerNames() {\n\t\tconst markerNames = Array.from( this._unboundMarkerNames );\n\n\t\tthis._unboundMarkerNames.clear();\n\n\t\treturn markerNames;\n\t}\n\n\t/**\n\t * Removes all model to view and view to model bindings.\n\t */\n\tclearBindings() {\n\t\tthis._modelToViewMapping = new WeakMap();\n\t\tthis._viewToModelMapping = new WeakMap();\n\t\tthis._markerNameToElements = new Map();\n\t\tthis._elementToMarkerNames = new Map();\n\t\tthis._unboundMarkerNames = new Set();\n\t}\n\n\t/**\n\t * Gets the corresponding model element.\n\t *\n\t * **Note:** {@link module:engine/view/uielement~UIElement} does not have corresponding element in model.\n\t *\n\t * @param {module:engine/view/element~Element} viewElement View element.\n\t * @returns {module:engine/model/element~Element|undefined} Corresponding model element or `undefined` if not found.\n\t */\n\ttoModelElement( viewElement ) {\n\t\treturn this._viewToModelMapping.get( viewElement );\n\t}\n\n\t/**\n\t * Gets the corresponding view element.\n\t *\n\t * @param {module:engine/model/element~Element} modelElement Model element.\n\t * @returns {module:engine/view/element~Element|undefined} Corresponding view element or `undefined` if not found.\n\t */\n\ttoViewElement( modelElement ) {\n\t\treturn this._modelToViewMapping.get( modelElement );\n\t}\n\n\t/**\n\t * Gets the corresponding model range.\n\t *\n\t * @param {module:engine/view/range~Range} viewRange View range.\n\t * @returns {module:engine/model/range~Range} Corresponding model range.\n\t */\n\ttoModelRange( viewRange ) {\n\t\treturn new ModelRange( this.toModelPosition( viewRange.start ), this.toModelPosition( viewRange.end ) );\n\t}\n\n\t/**\n\t * Gets the corresponding view range.\n\t *\n\t * @param {module:engine/model/range~Range} modelRange Model range.\n\t * @returns {module:engine/view/range~Range} Corresponding view range.\n\t */\n\ttoViewRange( modelRange ) {\n\t\treturn new ViewRange( this.toViewPosition( modelRange.start ), this.toViewPosition( modelRange.end ) );\n\t}\n\n\t/**\n\t * Gets the corresponding model position.\n\t *\n\t * @fires viewToModelPosition\n\t * @param {module:engine/view/position~Position} viewPosition View position.\n\t * @returns {module:engine/model/position~Position} Corresponding model position.\n\t */\n\ttoModelPosition( viewPosition ) {\n\t\tconst data = {\n\t\t\tviewPosition,\n\t\t\tmapper: this\n\t\t};\n\n\t\tthis.fire( 'viewToModelPosition', data );\n\n\t\treturn data.modelPosition;\n\t}\n\n\t/**\n\t * Gets the corresponding view position.\n\t *\n\t * @fires modelToViewPosition\n\t * @param {module:engine/model/position~Position} modelPosition Model position.\n\t * @param {Object} [options] Additional options for position mapping process.\n\t * @param {Boolean} [options.isPhantom=false] Should be set to `true` if the model position to map is pointing to a place\n\t * in model tree which no longer exists. For example, it could be an end of a removed model range.\n\t * @returns {module:engine/view/position~Position} Corresponding view position.\n\t */\n\ttoViewPosition( modelPosition, options = { isPhantom: false } ) {\n\t\tconst data = {\n\t\t\tmodelPosition,\n\t\t\tmapper: this,\n\t\t\tisPhantom: options.isPhantom\n\t\t};\n\n\t\tthis.fire( 'modelToViewPosition', data );\n\n\t\treturn data.viewPosition;\n\t}\n\n\t/**\n\t * Gets all view elements bound to the given marker name.\n\t *\n\t * @param {String} name Marker name.\n\t * @returns {Set.<module:engine/view/element~Element>|null} View elements bound with given marker name or `null`\n\t * if no elements are bound to given marker name.\n\t */\n\tmarkerNameToElements( name ) {\n\t\tconst boundElements = this._markerNameToElements.get( name );\n\n\t\tif ( !boundElements ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst elements = new Set();\n\n\t\tfor ( const element of boundElements ) {\n\t\t\tif ( element.is( 'attributeElement' ) ) {\n\t\t\t\tfor ( const clone of element.getElementsWithSameId() ) {\n\t\t\t\t\telements.add( clone );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\telements.add( element );\n\t\t\t}\n\t\t}\n\n\t\treturn elements;\n\t}\n\n\t/**\n\t * Registers a callback that evaluates the length in the model of a view element with given name.\n\t *\n\t * The callback is fired with one argument, which is a view element instance. The callback is expected to return\n\t * a number representing the length of view element in model.\n\t *\n\t *\t\t// List item in view may contain nested list, which have other list items. In model though,\n\t *\t\t// the lists are represented by flat structure. Because of those differences, length of list view element\n\t *\t\t// may be greater than one. In the callback it's checked how many nested list items are in evaluated list item.\n\t *\n\t *\t\tfunction getViewListItemLength( element ) {\n\t *\t\t\tlet length = 1;\n\t *\n\t *\t\t\tfor ( let child of element.getChildren() ) {\n\t *\t\t\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t *\t\t\t\t\tfor ( let item of child.getChildren() ) {\n\t *\t\t\t\t\t\tlength += getViewListItemLength( item );\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\n\t *\t\t\treturn length;\n\t *\t\t}\n\t *\n\t *\t\tmapper.registerViewToModelLength( 'li', getViewListItemLength );\n\t *\n\t * @param {String} viewElementName Name of view element for which callback is registered.\n\t * @param {Function} lengthCallback Function return a length of view element instance in model.\n\t */\n\tregisterViewToModelLength( viewElementName, lengthCallback ) {\n\t\tthis._viewToModelLengthCallbacks.set( viewElementName, lengthCallback );\n\t}\n\n\t/**\n\t * For given `viewPosition`, finds and returns the closest ancestor of this position that has a mapping to\n\t * the model.\n\t *\n\t * @param {module:engine/view/position~Position} viewPosition Position for which mapped ancestor should be found.\n\t * @returns {module:engine/view/element~Element}\n\t */\n\tfindMappedViewAncestor( viewPosition ) {\n\t\tlet parent = viewPosition.parent;\n\n\t\twhile ( !this._viewToModelMapping.has( parent ) ) {\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn parent;\n\t}\n\n\t/**\n\t * Calculates model offset based on the view position and the block element.\n\t *\n\t * Example:\n\t *\n\t *\t\t<p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, p ) -> 5\n\t *\n\t * Is a sum of:\n\t *\n\t *\t\t<p>foo|<b>bar</b></p> // _toModelOffset( p, 3, p ) -> 3\n\t *\t\t<p>foo<b>ba|r</b></p> // _toModelOffset( b, 2, b ) -> 2\n\t *\n\t * @private\n\t * @param {module:engine/view/element~Element} viewParent Position parent.\n\t * @param {Number} viewOffset Position offset.\n\t * @param {module:engine/view/element~Element} viewBlock Block used as a base to calculate offset.\n\t * @returns {Number} Offset in the model.\n\t */\n\t_toModelOffset( viewParent, viewOffset, viewBlock ) {\n\t\tif ( viewBlock != viewParent ) {\n\t\t\t// See example.\n\t\t\tconst offsetToParentStart = this._toModelOffset( viewParent.parent, viewParent.index, viewBlock );\n\t\t\tconst offsetInParent = this._toModelOffset( viewParent, viewOffset, viewParent );\n\n\t\t\treturn offsetToParentStart + offsetInParent;\n\t\t}\n\n\t\t// viewBlock == viewParent, so we need to calculate the offset in the parent element.\n\n\t\t// If the position is a text it is simple (\"ba|r\" -> 2).\n\t\tif ( viewParent.is( '$text' ) ) {\n\t\t\treturn viewOffset;\n\t\t}\n\n\t\t// If the position is in an element we need to sum lengths of siblings ( <b> bar </b> foo | -> 3 + 3 = 6 ).\n\t\tlet modelOffset = 0;\n\n\t\tfor ( let i = 0; i < viewOffset; i++ ) {\n\t\t\tmodelOffset += this.getModelLength( viewParent.getChild( i ) );\n\t\t}\n\n\t\treturn modelOffset;\n\t}\n\n\t/**\n\t * Gets the length of the view element in the model.\n\t *\n\t * The length is calculated as follows:\n\t * * if {@link #registerViewToModelLength length mapping callback} is provided for given `viewNode` it is used to\n\t * evaluate model length (`viewNode` is used as first and only parameter passed to the callback),\n\t * * length of a {@link module:engine/view/text~Text text node} is equal to the length of it's\n\t * {@link module:engine/view/text~Text#data data},\n\t * * length of a {@link module:engine/view/uielement~UIElement ui element} is equal to 0,\n\t * * length of a mapped {@link module:engine/view/element~Element element} is equal to 1,\n\t * * length of a not-mapped {@link module:engine/view/element~Element element} is equal to the length of it's children.\n\t *\n\t * Examples:\n\t *\n\t *\t\tfoo -> 3 // Text length is equal to it's data length.\n\t *\t\t<p>foo</p> -> 1 // Length of an element which is mapped is by default equal to 1.\n\t *\t\t<b>foo</b> -> 3 // Length of an element which is not mapped is a length of its children.\n\t *\t\t<div><p>x</p><p>y</p></div> -> 2 // Assuming that <div> is not mapped and <p> are mapped.\n\t *\n\t * @param {module:engine/view/element~Element} viewNode View node.\n\t * @returns {Number} Length of the node in the tree model.\n\t */\n\tgetModelLength( viewNode ) {\n\t\tif ( this._viewToModelLengthCallbacks.get( viewNode.name ) ) {\n\t\t\tconst callback = this._viewToModelLengthCallbacks.get( viewNode.name );\n\n\t\t\treturn callback( viewNode );\n\t\t} else if ( this._viewToModelMapping.has( viewNode ) ) {\n\t\t\treturn 1;\n\t\t} else if ( viewNode.is( '$text' ) ) {\n\t\t\treturn viewNode.data.length;\n\t\t} else if ( viewNode.is( 'uiElement' ) ) {\n\t\t\treturn 0;\n\t\t} else {\n\t\t\tlet len = 0;\n\n\t\t\tfor ( const child of viewNode.getChildren() ) {\n\t\t\t\tlen += this.getModelLength( child );\n\t\t\t}\n\n\t\t\treturn len;\n\t\t}\n\t}\n\n\t/**\n\t * Finds the position in the view node (or its children) with the expected model offset.\n\t *\n\t * Example:\n\t *\n\t *\t\t<p>fo<b>bar</b>bom</p> -> expected offset: 4\n\t *\n\t *\t\tfindPositionIn( p, 4 ):\n\t *\t\t<p>|fo<b>bar</b>bom</p> -> expected offset: 4, actual offset: 0\n\t *\t\t<p>fo|<b>bar</b>bom</p> -> expected offset: 4, actual offset: 2\n\t *\t\t<p>fo<b>bar</b>|bom</p> -> expected offset: 4, actual offset: 5 -> we are too far\n\t *\n\t *\t\tfindPositionIn( b, 4 - ( 5 - 3 ) ):\n\t *\t\t<p>fo<b>|bar</b>bom</p> -> expected offset: 2, actual offset: 0\n\t *\t\t<p>fo<b>bar|</b>bom</p> -> expected offset: 2, actual offset: 3 -> we are too far\n\t *\n\t *\t\tfindPositionIn( bar, 2 - ( 3 - 3 ) ):\n\t *\t\tWe are in the text node so we can simple find the offset.\n\t *\t\t<p>fo<b>ba|r</b>bom</p> -> expected offset: 2, actual offset: 2 -> position found\n\t *\n\t * @param {module:engine/view/element~Element} viewParent Tree view element in which we are looking for the position.\n\t * @param {Number} expectedOffset Expected offset.\n\t * @returns {module:engine/view/position~Position} Found position.\n\t */\n\tfindPositionIn( viewParent, expectedOffset ) {\n\t\t// Last scanned view node.\n\t\tlet viewNode;\n\t\t// Length of the last scanned view node.\n\t\tlet lastLength = 0;\n\n\t\tlet modelOffset = 0;\n\t\tlet viewOffset = 0;\n\n\t\t// In the text node it is simple: offset in the model equals offset in the text.\n\t\tif ( viewParent.is( '$text' ) ) {\n\t\t\treturn new ViewPosition( viewParent, expectedOffset );\n\t\t}\n\n\t\t// In other cases we add lengths of child nodes to find the proper offset.\n\n\t\t// If it is smaller we add the length.\n\t\twhile ( modelOffset < expectedOffset ) {\n\t\t\tviewNode = viewParent.getChild( viewOffset );\n\t\t\tlastLength = this.getModelLength( viewNode );\n\t\t\tmodelOffset += lastLength;\n\t\t\tviewOffset++;\n\t\t}\n\n\t\t// If it equals we found the position.\n\t\tif ( modelOffset == expectedOffset ) {\n\t\t\treturn this._moveViewPositionToTextNode( new ViewPosition( viewParent, viewOffset ) );\n\t\t}\n\t\t// If it is higher we need to enter last child.\n\t\telse {\n\t\t\t// ( modelOffset - lastLength ) is the offset to the child we enter,\n\t\t\t// so we subtract it from the expected offset to fine the offset in the child.\n\t\t\treturn this.findPositionIn( viewNode, expectedOffset - ( modelOffset - lastLength ) );\n\t\t}\n\t}\n\n\t/**\n\t * Because we prefer positions in text nodes over positions next to text node moves view position to the text node\n\t * if it was next to it.\n\t *\n\t *\t\t<p>[]<b>foo</b></p> -> <p>[]<b>foo</b></p> // do not touch if position is not directly next to text\n\t *\t\t<p>foo[]<b>foo</b></p> -> <p>foo{}<b>foo</b></p> // move to text node\n\t *\t\t<p><b>[]foo</b></p> -> <p><b>{}foo</b></p> // move to text node\n\t *\n\t * @private\n\t * @param {module:engine/view/position~Position} viewPosition Position potentially next to text node.\n\t * @returns {module:engine/view/position~Position} Position in text node if possible.\n\t */\n\t_moveViewPositionToTextNode( viewPosition ) {\n\t\t// If the position is just after text node, put it at the end of that text node.\n\t\t// If the position is just before text node, put it at the beginning of that text node.\n\t\tconst nodeBefore = viewPosition.nodeBefore;\n\t\tconst nodeAfter = viewPosition.nodeAfter;\n\n\t\tif ( nodeBefore instanceof ViewText ) {\n\t\t\treturn new ViewPosition( nodeBefore, nodeBefore.data.length );\n\t\t} else if ( nodeAfter instanceof ViewText ) {\n\t\t\treturn new ViewPosition( nodeAfter, 0 );\n\t\t}\n\n\t\t// Otherwise, just return the given position.\n\t\treturn viewPosition;\n\t}\n\n\t/**\n\t * Fired for each model-to-view position mapping request. The purpose of this event is to enable custom model-to-view position\n\t * mapping. Callbacks added to this event take {@link module:engine/model/position~Position model position} and are expected to\n\t * calculate {@link module:engine/view/position~Position view position}. Calculated view position should be added as `viewPosition`\n\t * value in `data` object that is passed as one of parameters to the event callback.\n\t *\n\t * \t\t// Assume that \"captionedImage\" model element is converted to <img> and following <span> elements in view,\n\t * \t\t// and the model element is bound to <img> element. Force mapping model positions inside \"captionedImage\" to that\n\t * \t\t// <span> element.\n\t *\t\tmapper.on( 'modelToViewPosition', ( evt, data ) => {\n\t *\t\t\tconst positionParent = modelPosition.parent;\n\t *\n\t *\t\t\tif ( positionParent.name == 'captionedImage' ) {\n\t *\t\t\t\tconst viewImg = data.mapper.toViewElement( positionParent );\n\t *\t\t\t\tconst viewCaption = viewImg.nextSibling; // The <span> element.\n\t *\n\t *\t\t\t\tdata.viewPosition = new ViewPosition( viewCaption, modelPosition.offset );\n\t *\n\t *\t\t\t\t// Stop the event if other callbacks should not modify calculated value.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** keep in mind that sometimes a \"phantom\" model position is being converted. \"Phantom\" model position is\n\t * a position that points to a non-existing place in model. Such position might still be valid for conversion, though\n\t * (it would point to a correct place in view when converted). One example of such situation is when a range is\n\t * removed from model, there may be a need to map the range's end (which is no longer valid model position). To\n\t * handle such situation, check `data.isPhantom` flag:\n\t *\n\t * \t\t// Assume that there is \"customElement\" model element and whenever position is before it, we want to move it\n\t * \t\t// to the inside of the view element bound to \"customElement\".\n\t *\t\tmapper.on( 'modelToViewPosition', ( evt, data ) => {\n\t *\t\t\tif ( data.isPhantom ) {\n\t *\t\t\t\treturn;\n\t *\t\t\t}\n\t *\n\t *\t\t\t// Below line might crash for phantom position that does not exist in model.\n\t *\t\t\tconst sibling = data.modelPosition.nodeBefore;\n\t *\n\t *\t\t\t// Check if this is the element we are interested in.\n\t *\t\t\tif ( !sibling.is( 'element', 'customElement' ) ) {\n\t *\t\t\t\treturn;\n\t *\t\t\t}\n\t *\n\t *\t\t\tconst viewElement = data.mapper.toViewElement( sibling );\n\t *\n\t *\t\t\tdata.viewPosition = new ViewPosition( sibling, 0 );\n\t *\n\t *\t\t\tevt.stop();\n\t *\t\t} );\n\t *\n\t * **Note:** default mapping callback is provided with `low` priority setting and does not cancel the event, so it is possible to\n\t * attach a custom callback after default callback and also use `data.viewPosition` calculated by default callback\n\t * (for example to fix it).\n\t *\n\t * **Note:** default mapping callback will not fire if `data.viewPosition` is already set.\n\t *\n\t * **Note:** these callbacks are called **very often**. For efficiency reasons, it is advised to use them only when position\n\t * mapping between given model and view elements is unsolvable using just elements mapping and default algorithm. Also,\n\t * the condition that checks if special case scenario happened should be as simple as possible.\n\t *\n\t * @event modelToViewPosition\n\t * @param {Object} data Data pipeline object that can store and pass data between callbacks. The callback should add\n\t * `viewPosition` value to that object with calculated {@link module:engine/view/position~Position view position}.\n\t * @param {module:engine/conversion/mapper~Mapper} data.mapper Mapper instance that fired the event.\n\t */\n\n\t/**\n\t * Fired for each view-to-model position mapping request. See {@link module:engine/conversion/mapper~Mapper#event:modelToViewPosition}.\n\t *\n\t * \t\t// See example in `modelToViewPosition` event description.\n\t * \t\t// This custom mapping will map positions from <span> element next to <img> to the \"captionedImage\" element.\n\t *\t\tmapper.on( 'viewToModelPosition', ( evt, data ) => {\n\t *\t\t\tconst positionParent = viewPosition.parent;\n\t *\n\t *\t\t\tif ( positionParent.hasClass( 'image-caption' ) ) {\n\t *\t\t\t\tconst viewImg = positionParent.previousSibling;\n\t *\t\t\t\tconst modelImg = data.mapper.toModelElement( viewImg );\n\t *\n\t *\t\t\t\tdata.modelPosition = new ModelPosition( modelImg, viewPosition.offset );\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** default mapping callback is provided with `low` priority setting and does not cancel the event, so it is possible to\n\t * attach a custom callback after default callback and also use `data.modelPosition` calculated by default callback\n\t * (for example to fix it).\n\t *\n\t * **Note:** default mapping callback will not fire if `data.modelPosition` is already set.\n\t *\n\t * **Note:** these callbacks are called **very often**. For efficiency reasons, it is advised to use them only when position\n\t * mapping between given model and view elements is unsolvable using just elements mapping and default algorithm. Also,\n\t * the condition that checks if special case scenario happened should be as simple as possible.\n\t *\n\t * @event viewToModelPosition\n\t * @param {Object} data Data pipeline object that can store and pass data between callbacks. The callback should add\n\t * `modelPosition` value to that object with calculated {@link module:engine/model/position~Position model position}.\n\t * @param {module:engine/conversion/mapper~Mapper} data.mapper Mapper instance that fired the event.\n\t */\n}\n\nmix( Mapper, EmitterMixin );\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/conversion/modelconsumable\n */\n\nimport TextProxy from '../model/textproxy';\n\n/**\n * Manages a list of consumable values for {@link module:engine/model/item~Item model items}.\n *\n * Consumables are various aspects of the model. A model item can be broken down into singular properties that might be\n * taken into consideration when converting that item.\n *\n * `ModelConsumable` is used by {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} while analyzing changed\n * parts of {@link module:engine/model/document~Document the document}. The added / changed / removed model items are broken down\n * into singular properties (the item itself and it's attributes). All those parts are saved in `ModelConsumable`. Then,\n * during conversion, when given part of model item is converted (i.e. the view element has been inserted into the view,\n * but without attributes), consumable value is removed from `ModelConsumable`.\n *\n * For model items, `ModelConsumable` stores consumable values of one of following types: `insert`, `addattribute:<attributeKey>`,\n * `changeattributes:<attributeKey>`, `removeattributes:<attributeKey>`.\n *\n * In most cases, it is enough to let {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n * gather consumable values, so there is no need to use\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#add add method} directly.\n * However, it is important to understand how consumable values can be\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.\n * See {@link module:engine/conversion/downcasthelpers default downcast converters} for more information.\n *\n * Keep in mind, that one conversion event may have multiple callbacks (converters) attached to it. Each of those is\n * able to convert one or more parts of the model. However, when one of those callbacks actually converts\n * something, other should not, because they would duplicate the results. Using `ModelConsumable` helps avoiding\n * this situation, because callbacks should only convert those values, which were not yet consumed from `ModelConsumable`.\n *\n * Consuming multiple values in a single callback:\n *\n *\t\t// Converter for custom `image` element that might have a `caption` element inside which changes\n *\t\t// how the image is displayed in the view:\n *\t\t//\n *\t\t// Model:\n *\t\t//\n *\t\t// [image]\n *\t\t// └─ [caption]\n *\t\t// └─ foo\n *\t\t//\n *\t\t// View:\n *\t\t//\n *\t\t// <figure>\n *\t\t// ├─ <img />\n *\t\t// └─ <caption>\n *\t\t// └─ foo\n *\t\tmodelConversionDispatcher.on( 'insert:image', ( evt, data, conversionApi ) => {\n *\t\t\t// First, consume the `image` element.\n *\t\t\tconversionApi.consumable.consume( data.item, 'insert' );\n *\n *\t\t\t// Just create normal image element for the view.\n *\t\t\t// Maybe it will be \"decorated\" later.\n *\t\t\tconst viewImage = new ViewElement( 'img' );\n *\t\t\tconst insertPosition = conversionApi.mapper.toViewPosition( data.range.start );\n *\t\t\tconst viewWriter = conversionApi.writer;\n *\n *\t\t\t// Check if the `image` element has children.\n *\t\t\tif ( data.item.childCount > 0 ) {\n *\t\t\t\tconst modelCaption = data.item.getChild( 0 );\n *\n *\t\t\t\t// `modelCaption` insertion change is consumed from consumable values.\n *\t\t\t\t// It will not be converted by other converters, but it's children (probably some text) will be.\n *\t\t\t\t// Through mapping, converters for text will know where to insert contents of `modelCaption`.\n *\t\t\t\tif ( conversionApi.consumable.consume( modelCaption, 'insert' ) ) {\n *\t\t\t\t\tconst viewCaption = new ViewElement( 'figcaption' );\n *\n *\t\t\t\t\tconst viewImageHolder = new ViewElement( 'figure', null, [ viewImage, viewCaption ] );\n *\n *\t\t\t\t\tconversionApi.mapper.bindElements( modelCaption, viewCaption );\n *\t\t\t\t\tconversionApi.mapper.bindElements( data.item, viewImageHolder );\n *\t\t\t\t\tviewWriter.insert( insertPosition, viewImageHolder );\n *\t\t\t\t}\n *\t\t\t} else {\n *\t\t\t\tconversionApi.mapper.bindElements( data.item, viewImage );\n *\t\t\t\tviewWriter.insert( insertPosition, viewImage );\n *\t\t\t}\n *\n *\t\t\tevt.stop();\n *\t\t} );\n */\nexport default class ModelConsumable {\n\t/**\n\t * Creates an empty consumables list.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Contains list of consumable values.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/conversion/modelconsumable~ModelConsumable#_consumable\n\t\t */\n\t\tthis._consumable = new Map();\n\n\t\t/**\n\t\t * For each {@link module:engine/model/textproxy~TextProxy} added to `ModelConsumable`, this registry holds parent\n\t\t * of that `TextProxy` and start and end indices of that `TextProxy`. This allows identification of `TextProxy`\n\t\t * instances that points to the same part of the model but are different instances. Each distinct `TextProxy`\n\t\t * is given unique `Symbol` which is then registered as consumable. This process is transparent for `ModelConsumable`\n\t\t * API user because whenever `TextProxy` is added, tested, consumed or reverted, internal mechanisms of\n\t\t * `ModelConsumable` translates `TextProxy` to that unique `Symbol`.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/conversion/modelconsumable~ModelConsumable#_textProxyRegistry\n\t\t */\n\t\tthis._textProxyRegistry = new Map();\n\t}\n\n\t/**\n\t * Adds a consumable value to the consumables list and links it with given model item.\n\t *\n\t *\t\tmodelConsumable.add( modelElement, 'insert' ); // Add `modelElement` insertion change to consumable values.\n\t *\t\tmodelConsumable.add( modelElement, 'addAttribute:bold' ); // Add `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.add( modelElement, 'removeAttribute:bold' ); // Add `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.add( modelSelection, 'selection' ); // Add `modelSelection` to consumable values.\n\t *\t\tmodelConsumable.add( modelRange, 'range' ); // Add `modelRange` to consumable values.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection that has the consumable.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t */\n\tadd( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tif ( !this._consumable.has( item ) ) {\n\t\t\tthis._consumable.set( item, new Map() );\n\t\t}\n\n\t\tthis._consumable.get( item ).set( type, true );\n\t}\n\n\t/**\n\t * Removes given consumable value from given model item.\n\t *\n\t *\t\tmodelConsumable.consume( modelElement, 'insert' ); // Remove `modelElement` insertion change from consumable values.\n\t *\t\tmodelConsumable.consume( modelElement, 'addAttribute:bold' ); // Remove `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.consume( modelElement, 'removeAttribute:bold' ); // Remove `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.consume( modelSelection, 'selection' ); // Remove `modelSelection` from consumable values.\n\t *\t\tmodelConsumable.consume( modelRange, 'range' ); // Remove 'modelRange' from consumable values.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection from which consumable will be consumed.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t * @returns {Boolean} `true` if consumable value was available and was consumed, `false` otherwise.\n\t */\n\tconsume( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tif ( this.test( item, type ) ) {\n\t\t\tthis._consumable.get( item ).set( type, false );\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Tests whether there is a consumable value of given type connected with given model item.\n\t *\n\t *\t\tmodelConsumable.test( modelElement, 'insert' ); // Check for `modelElement` insertion change.\n\t *\t\tmodelConsumable.test( modelElement, 'addAttribute:bold' ); // Check for `bold` attribute insertion on `modelElement` change.\n\t *\t\tmodelConsumable.test( modelElement, 'removeAttribute:bold' ); // Check for `bold` attribute removal on `modelElement` change.\n\t *\t\tmodelConsumable.test( modelSelection, 'selection' ); // Check if `modelSelection` is consumable.\n\t *\t\tmodelConsumable.test( modelRange, 'range' ); // Check if `modelRange` is consumable.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection to be tested.\n\t * @param {String} type Consumable type. Will be normalized to a proper form, that is either `<word>` or `<part>:<part>`.\n\t * Second colon and everything after will be cut. Passing event name is a safe and good practice.\n\t * @returns {null|Boolean} `null` if such consumable was never added, `false` if the consumable values was\n\t * already consumed or `true` if it was added and not consumed yet.\n\t */\n\ttest( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tconst itemConsumables = this._consumable.get( item );\n\n\t\tif ( itemConsumables === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst value = itemConsumables.get( type );\n\n\t\tif ( value === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn value;\n\t}\n\n\t/**\n\t * Reverts consuming of consumable value.\n\t *\n\t *\t\tmodelConsumable.revert( modelElement, 'insert' ); // Revert consuming `modelElement` insertion change.\n\t *\t\tmodelConsumable.revert( modelElement, 'addAttribute:bold' ); // Revert consuming `bold` attribute insert from `modelElement`.\n\t *\t\tmodelConsumable.revert( modelElement, 'removeAttribute:bold' ); // Revert consuming `bold` attribute remove from `modelElement`.\n\t *\t\tmodelConsumable.revert( modelSelection, 'selection' ); // Revert consuming `modelSelection`.\n\t *\t\tmodelConsumable.revert( modelRange, 'range' ); // Revert consuming `modelRange`.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection|module:engine/model/range~Range} item\n\t * Model item, range or selection to be reverted.\n\t * @param {String} type Consumable type.\n\t * @returns {null|Boolean} `true` if consumable has been reversed, `false` otherwise. `null` if the consumable has\n\t * never been added.\n\t */\n\trevert( item, type ) {\n\t\ttype = _normalizeConsumableType( type );\n\n\t\tif ( item instanceof TextProxy ) {\n\t\t\titem = this._getSymbolForTextProxy( item );\n\t\t}\n\n\t\tconst test = this.test( item, type );\n\n\t\tif ( test === false ) {\n\t\t\tthis._consumable.get( item ).set( type, true );\n\n\t\t\treturn true;\n\t\t} else if ( test === true ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Gets a unique symbol for passed {@link module:engine/model/textproxy~TextProxy} instance. All `TextProxy` instances that\n\t * have same parent, same start index and same end index will get the same symbol.\n\t *\n\t * Used internally to correctly consume `TextProxy` instances.\n\t *\n\t * @private\n\t * @param {module:engine/model/textproxy~TextProxy} textProxy `TextProxy` instance to get a symbol for.\n\t * @returns {Symbol} Symbol representing all equal instances of `TextProxy`.\n\t */\n\t_getSymbolForTextProxy( textProxy ) {\n\t\tlet symbol = null;\n\n\t\tconst startMap = this._textProxyRegistry.get( textProxy.startOffset );\n\n\t\tif ( startMap ) {\n\t\t\tconst endMap = startMap.get( textProxy.endOffset );\n\n\t\t\tif ( endMap ) {\n\t\t\t\tsymbol = endMap.get( textProxy.parent );\n\t\t\t}\n\t\t}\n\n\t\tif ( !symbol ) {\n\t\t\tsymbol = this._addSymbolForTextProxy( textProxy.startOffset, textProxy.endOffset, textProxy.parent );\n\t\t}\n\n\t\treturn symbol;\n\t}\n\n\t/**\n\t * Adds a symbol for given properties that characterizes a {@link module:engine/model/textproxy~TextProxy} instance.\n\t *\n\t * Used internally to correctly consume `TextProxy` instances.\n\t *\n\t * @private\n\t * @param {Number} startIndex Text proxy start index in it's parent.\n\t * @param {Number} endIndex Text proxy end index in it's parent.\n\t * @param {module:engine/model/element~Element} parent Text proxy parent.\n\t * @returns {Symbol} Symbol generated for given properties.\n\t */\n\t_addSymbolForTextProxy( start, end, parent ) {\n\t\tconst symbol = Symbol( 'textProxySymbol' );\n\t\tlet startMap, endMap;\n\n\t\tstartMap = this._textProxyRegistry.get( start );\n\n\t\tif ( !startMap ) {\n\t\t\tstartMap = new Map();\n\t\t\tthis._textProxyRegistry.set( start, startMap );\n\t\t}\n\n\t\tendMap = startMap.get( end );\n\n\t\tif ( !endMap ) {\n\t\t\tendMap = new Map();\n\t\t\tstartMap.set( end, endMap );\n\t\t}\n\n\t\tendMap.set( parent, symbol );\n\n\t\treturn symbol;\n\t}\n}\n\n// Returns a normalized consumable type name from given string. A normalized consumable type name is a string that has\n// at most one colon, for example: `insert` or `addMarker:highlight`. If string to normalize has more \"parts\" (more colons),\n// the other parts are dropped, for example: `addattribute:bold:$text` -> `addattributes:bold`.\n//\n// @param {String} type Consumable type.\n// @returns {String} Normalized consumable type.\nfunction _normalizeConsumableType( type ) {\n\tconst parts = type.split( ':' );\n\n\treturn parts.length > 1 ? parts[ 0 ] + ':' + parts[ 1 ] : parts[ 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/conversion/downcastdispatcher\n */\n\nimport Consumable from './modelconsumable';\nimport Range from '../model/range';\nimport Position, { getNodeAfterPosition, getTextNodeAtPosition } from '../model/position';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The downcast dispatcher is a central point of downcasting (conversion from the model to the view), which is a process of reacting\n * to changes in the model and firing a set of events. Callbacks listening to these events are called converters. The\n * converters' role is to convert the model changes to changes in view (for example, adding view nodes or\n * changing attributes on view elements).\n *\n * During the conversion process, downcast dispatcher fires events basing on the state of the model and prepares\n * data for these events. It is important to understand that the events are connected with the changes done on the model,\n * for example: \"a node has been inserted\" or \"an attribute has changed\". This is in contrary to upcasting (a view-to-model conversion)\n * where you convert the view state (view nodes) to a model tree.\n *\n * The events are prepared basing on a diff created by {@link module:engine/model/differ~Differ Differ}, which buffers them\n * and then passes to the downcast dispatcher as a diff between the old model state and the new model state.\n *\n * Note that because the changes are converted, there is a need to have a mapping between the model structure and the view structure.\n * To map positions and elements during the downcast (a model-to-view conversion), use {@link module:engine/conversion/mapper~Mapper}.\n *\n * Downcast dispatcher fires the following events for model tree changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`} &ndash;\n * If a range of nodes was inserted to the model tree.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove `remove`} &ndash;\n * If a range of nodes was removed from the model tree.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`} &ndash;\n * If an attribute was added, changed or removed from a model node.\n *\n * For {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert`}\n * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute`},\n * downcast dispatcher generates {@link module:engine/conversion/modelconsumable~ModelConsumable consumables}.\n * These are used to have control over which changes have already been consumed. It is useful when some converters\n * overwrite others or convert multiple changes (for example, it converts an insertion of an element and also converts that\n * element's attributes during the insertion).\n *\n * Additionally, downcast dispatcher fires events for {@link module:engine/model/markercollection~Marker marker} changes:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} &ndash; If a marker was added.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} &ndash; If a marker was removed.\n *\n * Note that changing a marker is done through removing the marker from the old range and adding it to the new range,\n * so both events are fired.\n *\n * Finally, downcast dispatcher also handles firing events for the {@link module:engine/model/selection model selection}\n * conversion:\n *\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:selection}\n * &ndash; Converts the selection from the model to the view.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute}\n * &ndash; Fired for every selection attribute.\n * * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}\n * &ndash; Fired for every marker that contains a selection.\n *\n * Unlike the model tree and the markers, the events for selection are not fired for changes but for a selection state.\n *\n * When providing custom listeners for a downcast dispatcher, remember to check whether a given change has not been\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} yet.\n *\n * When providing custom listeners for downcast dispatcher, keep in mind that any callback that has\n * {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed} a value from a consumable and\n * converted the change should also stop the event (for efficiency purposes).\n *\n * When providing custom listeners for downcast dispatcher, remember to use the provided\n * {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} to apply changes to the view document.\n *\n * You can read more about conversion in the following guides:\n *\n * * {@glink framework/guides/deep-dive/conversion/conversion-introduction Advanced conversion concepts &mdash; attributes}\n * * {@glink framework/guides/deep-dive/conversion/conversion-extending-output Extending the editor output }\n * * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion}\n *\n * An example of a custom converter for the downcast dispatcher:\n *\n *\t\t// You will convert inserting a \"paragraph\" model element into the model.\n *\t\tdowncastDispatcher.on( 'insert:paragraph', ( evt, data, conversionApi ) => {\n *\t\t\t// Remember to check whether the change has not been consumed yet and consume it.\n *\t\t\tif ( conversionApi.consumable.consume( data.item, 'insert' ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\t// Translate the position in the model to a position in the view.\n *\t\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n *\n *\t\t\t// Create a <p> element that will be inserted into the view at the `viewPosition`.\n *\t\t\tconst viewElement = conversionApi.writer.createContainerElement( 'p' );\n *\n *\t\t\t// Bind the newly created view element to the model element so positions will map accordingly in the future.\n *\t\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n *\n *\t\t\t// Add the newly created view element to the view.\n *\t\t\tconversionApi.writer.insert( viewPosition, viewElement );\n *\n *\t\t\t// Remember to stop the event propagation.\n *\t\t\tevt.stop();\n *\t\t} );\n */\nexport default class DowncastDispatcher {\n\t/**\n\t * Creates a downcast dispatcher instance.\n\t *\n\t * @see module:engine/conversion/downcastdispatcher~DowncastConversionApi\n\t * @param {Object} conversionApi Additional properties for an interface that will be passed to events fired\n\t * by the downcast dispatcher.\n\t */\n\tconstructor( conversionApi ) {\n\t\t/**\n\t\t * An interface passed by the dispatcher to the event callbacks.\n\t\t *\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastConversionApi}\n\t\t */\n\t\tthis.conversionApi = Object.assign( { dispatcher: this }, conversionApi );\n\n\t\t/**\n\t\t * Maps conversion event names that will trigger element reconversion for a given element name.\n\t\t *\n\t\t * @type {Map<String, String>}\n\t\t * @private\n\t\t */\n\t\tthis._reconversionEventsMapping = new Map();\n\t}\n\n\t/**\n\t * Takes a {@link module:engine/model/differ~Differ model differ} object with buffered changes and fires conversion basing on it.\n\t *\n\t * @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with the converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\tconvertChanges( differ, markers, writer ) {\n\t\t// Before the view is updated, remove markers which have changed.\n\t\tfor ( const change of differ.getMarkersToRemove() ) {\n\t\t\tthis.convertMarkerRemove( change.name, change.range, writer );\n\t\t}\n\n\t\tconst changes = this._mapChangesWithAutomaticReconversion( differ );\n\n\t\t// Convert changes that happened on model tree.\n\t\tfor ( const entry of changes ) {\n\t\t\tif ( entry.type === 'insert' ) {\n\t\t\t\tthis.convertInsert( Range._createFromPositionAndShift( entry.position, entry.length ), writer );\n\t\t\t} else if ( entry.type === 'remove' ) {\n\t\t\t\tthis.convertRemove( entry.position, entry.length, entry.name, writer );\n\t\t\t} else if ( entry.type === 'reconvert' ) {\n\t\t\t\tthis.reconvertElement( entry.element, writer );\n\t\t\t} else {\n\t\t\t\t// Defaults to 'attribute' change.\n\t\t\t\tthis.convertAttribute( entry.range, entry.attributeKey, entry.attributeOldValue, entry.attributeNewValue, writer );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const markerName of this.conversionApi.mapper.flushUnboundMarkerNames() ) {\n\t\t\tconst markerRange = markers.get( markerName ).getRange();\n\n\t\t\tthis.convertMarkerRemove( markerName, markerRange, writer );\n\t\t\tthis.convertMarkerAdd( markerName, markerRange, writer );\n\t\t}\n\n\t\t// After the view is updated, convert markers which have changed.\n\t\tfor ( const change of differ.getMarkersToAdd() ) {\n\t\t\tthis.convertMarkerAdd( change.name, change.range, writer );\n\t\t}\n\t}\n\n\t/**\n\t * Starts a conversion of a range insertion.\n\t *\n\t * For each node in the range, {@link #event:insert `insert` event is fired}. For each attribute on each node,\n\t * {@link #event:attribute `attribute` event is fired}.\n\t *\n\t * @fires insert\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range The inserted range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\tconvertInsert( range, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list of things that can be consumed, consisting of nodes and their attributes.\n\t\tthis.conversionApi.consumable = this._createInsertConsumable( range );\n\n\t\t// Fire a separate insert event for each node and text fragment contained in the range.\n\t\tfor ( const data of Array.from( range ).map( walkerValueToEventData ) ) {\n\t\t\tthis._convertInsertWithAttributes( data );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires conversion of a single node removal. Fires {@link #event:remove remove event} with provided data.\n\t *\n\t * @param {module:engine/model/position~Position} position Position from which node was removed.\n\t * @param {Number} length Offset size of removed node.\n\t * @param {String} name Name of removed node.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertRemove( position, length, name, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'remove:' + name, { position, length }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts a conversion of an attribute change on a given `range`.\n\t *\n\t * For each node in the given `range`, {@link #event:attribute attribute event} is fired with the passed data.\n\t *\n\t * @fires attribute\n\t * @param {module:engine/model/range~Range} range Changed range.\n\t * @param {String} key Key of the attribute that has changed.\n\t * @param {*} oldValue Attribute value before the change or `null` if the attribute has not been set before.\n\t * @param {*} newValue New attribute value or `null` if the attribute has been removed.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify view document.\n\t */\n\tconvertAttribute( range, key, oldValue, newValue, writer ) {\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list with attributes to consume.\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( range, `attribute:${ key }` );\n\n\t\t// Create a separate attribute event for each node in the range.\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\t\t\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\t\t\tconst data = {\n\t\t\t\titem,\n\t\t\t\trange: itemRange,\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: oldValue,\n\t\t\t\tattributeNewValue: newValue\n\t\t\t};\n\n\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts the reconversion of an element. It will:\n\t *\n\t * * Fire an {@link #event:insert `insert` event} for the element to reconvert.\n\t * * Fire an {@link #event:attribute `attribute` event} for element attributes.\n\t *\n\t * This will not reconvert children of the element if they have existing (already converted) views. For newly inserted child elements\n\t * it will behave the same as {@link #convertInsert}.\n\t *\n\t * Element reconversion is defined by the `triggerBy` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * @fires insert\n\t * @fires attribute\n\t * @param {module:engine/model/element~Element} element The element to be reconverted.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer The view writer that should be used to modify the view document.\n\t */\n\treconvertElement( element, writer ) {\n\t\tconst elementRange = Range._createOn( element );\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create a list of things that can be consumed, consisting of nodes and their attributes.\n\t\tthis.conversionApi.consumable = this._createInsertConsumable( elementRange );\n\n\t\tconst mapper = this.conversionApi.mapper;\n\t\tconst currentView = mapper.toViewElement( element );\n\n\t\t// Remove the old view but do not remove mapper mappings - those will be used to revive existing elements.\n\t\twriter.remove( currentView );\n\n\t\t// Convert the element - without converting children.\n\t\tthis._convertInsertWithAttributes( {\n\t\t\titem: element,\n\t\t\trange: elementRange\n\t\t} );\n\n\t\tconst convertedViewElement = mapper.toViewElement( element );\n\n\t\t// Iterate over children of reconverted element in order to...\n\t\tfor ( const value of Range._createIn( element ) ) {\n\t\t\tconst { item } = value;\n\n\t\t\tconst view = elementOrTextProxyToView( item, mapper );\n\n\t\t\t// ...either bring back previously converted view...\n\t\t\tif ( view ) {\n\t\t\t\t// Do not move views that are already in converted element - those might be created by the main element converter in case\n\t\t\t\t// when main element converts also its direct children.\n\t\t\t\tif ( view.root !== convertedViewElement.root ) {\n\t\t\t\t\twriter.move(\n\t\t\t\t\t\twriter.createRangeOn( view ),\n\t\t\t\t\t\tmapper.toViewPosition( Position._createBefore( item ) )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// ... or by converting newly inserted elements.\n\t\t\telse {\n\t\t\t\tthis._convertInsertWithAttributes( walkerValueToEventData( value ) );\n\t\t\t}\n\t\t}\n\n\t\t// After reconversion is done we can unbind the old view.\n\t\tmapper.unbindViewElement( currentView );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Starts the model selection conversion.\n\t *\n\t * Fires events for a given {@link module:engine/model/selection~Selection selection} to start the selection conversion.\n\t *\n\t * @fires selection\n\t * @fires addMarker\n\t * @fires attribute\n\t * @param {module:engine/model/selection~Selection} selection The selection to convert.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Markers connected with the converted model.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertSelection( selection, markers, writer ) {\n\t\tconst markersAtSelection = Array.from( markers.getMarkersAtPosition( selection.getFirstPosition() ) );\n\n\t\tthis.conversionApi.writer = writer;\n\t\tthis.conversionApi.consumable = this._createSelectionConsumable( selection, markersAtSelection );\n\n\t\tthis.fire( 'selection', { selection }, this.conversionApi );\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const marker of markersAtSelection ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tif ( !shouldMarkerChangeBeConverted( selection.getFirstPosition(), marker, this.conversionApi.mapper ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\tmarkerName: marker.name,\n\t\t\t\tmarkerRange\n\t\t\t};\n\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'addMarker:' + marker.name ) ) {\n\t\t\t\tthis.fire( 'addMarker:' + marker.name, data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconst data = {\n\t\t\t\titem: selection,\n\t\t\t\trange: selection.getFirstRange(),\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: null,\n\t\t\t\tattributeNewValue: selection.getAttribute( key )\n\t\t\t};\n\n\t\t\t// Do not fire event if the attribute has been consumed.\n\t\t\tif ( this.conversionApi.consumable.test( selection, 'attribute:' + data.attributeKey ) ) {\n\t\t\t\tthis.fire( 'attribute:' + data.attributeKey + ':$text', data, this.conversionApi );\n\t\t\t}\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Converts the added marker. Fires the {@link #event:addMarker `addMarker`} event for each item\n\t * in the marker's range. If the range is collapsed, a single event is dispatched. See the event description for more details.\n\t *\n\t * @fires addMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange The marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertMarkerAdd( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard.\n\t\tif ( markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// In markers' case, event name == consumable name.\n\t\tconst eventName = 'addMarker:' + markerName;\n\n\t\t//\n\t\t// First, fire an event for the whole marker.\n\t\t//\n\t\tconst consumable = new Consumable();\n\t\tconsumable.add( markerRange, eventName );\n\n\t\tthis.conversionApi.consumable = consumable;\n\n\t\tthis.fire( eventName, { markerName, markerRange }, this.conversionApi );\n\n\t\t//\n\t\t// Do not fire events for each item inside the range if the range got consumed.\n\t\t//\n\t\tif ( !consumable.test( markerRange, eventName ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t//\n\t\t// Then, fire an event for each item inside the marker range.\n\t\t//\n\t\tthis.conversionApi.consumable = this._createConsumableForRange( markerRange, eventName );\n\n\t\tfor ( const item of markerRange.getItems() ) {\n\t\t\t// Do not fire event for already consumed items.\n\t\t\tif ( !this.conversionApi.consumable.test( item, eventName ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = { item, range: Range._createOn( item ), markerName, markerRange };\n\n\t\t\tthis.fire( eventName, data, this.conversionApi );\n\t\t}\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Fires the conversion of the marker removal. Fires the {@link #event:removeMarker `removeMarker`} event with the provided data.\n\t *\n\t * @fires removeMarker\n\t * @param {String} markerName Marker name.\n\t * @param {module:engine/model/range~Range} markerRange The marker range.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that should be used to modify the view document.\n\t */\n\tconvertMarkerRemove( markerName, markerRange, writer ) {\n\t\t// Do not convert if range is in graveyard.\n\t\tif ( markerRange.root.rootName == '$graveyard' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.conversionApi.writer = writer;\n\n\t\tthis.fire( 'removeMarker:' + markerName, { markerName, markerRange }, this.conversionApi );\n\n\t\tthis._clearConversionApi();\n\t}\n\n\t/**\n\t * Maps the model element \"insert\" reconversion for given event names. The event names must be fully specified:\n\t *\n\t * * For \"attribute\" change event, it should include the main element name, i.e: `'attribute:attributeName:elementName'`.\n\t * * For child node change events, these should use the child event name as well, i.e:\n\t * * For adding a node: `'insert:childElementName'`.\n\t * * For removing a node: `'remove:childElementName'`.\n\t *\n\t * **Note**: This method should not be used directly. The reconversion is defined by the `triggerBy()` configuration of the\n\t * `elementToElement()` conversion helper.\n\t *\n\t * @protected\n\t * @param {String} modelName The name of the main model element for which the events will trigger the reconversion.\n\t * @param {String} eventName The name of an event that would trigger conversion for a given model element.\n\t */\n\t_mapReconversionTriggerEvent( modelName, eventName ) {\n\t\tthis._reconversionEventsMapping.set( eventName, modelName );\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume from a given range,\n\t * assuming that the range has just been inserted to the model.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The inserted range.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createInsertConsumable( range ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const value of range ) {\n\t\t\tconst item = value.item;\n\n\t\t\tconsumable.add( item, 'insert' );\n\n\t\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\t\tconsumable.add( item, 'attribute:' + key );\n\t\t\t}\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with values to consume for a given range.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The affected range.\n\t * @param {String} type Consumable type.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createConsumableForRange( range, type ) {\n\t\tconst consumable = new Consumable();\n\n\t\tfor ( const item of range.getItems() ) {\n\t\t\tconsumable.add( item, type );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/modelconsumable~ModelConsumable} with selection consumable values.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The selection to create the consumable from.\n\t * @param {Iterable.<module:engine/model/markercollection~Marker>} markers Markers that contain the selection.\n\t * @returns {module:engine/conversion/modelconsumable~ModelConsumable} The values to consume.\n\t */\n\t_createSelectionConsumable( selection, markers ) {\n\t\tconst consumable = new Consumable();\n\n\t\tconsumable.add( selection, 'selection' );\n\n\t\tfor ( const marker of markers ) {\n\t\t\tconsumable.add( selection, 'addMarker:' + marker.name );\n\t\t}\n\n\t\tfor ( const key of selection.getAttributeKeys() ) {\n\t\t\tconsumable.add( selection, 'attribute:' + key );\n\t\t}\n\n\t\treturn consumable;\n\t}\n\n\t/**\n\t * Tests passed `consumable` to check whether given event can be fired and if so, fires it.\n\t *\n\t * @private\n\t * @fires insert\n\t * @fires attribute\n\t * @param {String} type Event type.\n\t * @param {Object} data Event data.\n\t */\n\t_testAndFire( type, data ) {\n\t\tif ( !this.conversionApi.consumable.test( data.item, type ) ) {\n\t\t\t// Do not fire event if the item was consumed.\n\t\t\treturn;\n\t\t}\n\n\t\tthis.fire( getEventName( type, data ), data, this.conversionApi );\n\t}\n\n\t/**\n\t * Clears the conversion API object.\n\t *\n\t * @private\n\t */\n\t_clearConversionApi() {\n\t\tdelete this.conversionApi.writer;\n\t\tdelete this.conversionApi.consumable;\n\t}\n\n\t/**\n\t * Internal method for converting element insertion. It will fire events for the inserted element and events for its attributes.\n\t *\n\t * @private\n\t * @fires insert\n\t * @fires attribute\n\t * @param {Object} data Event data.\n\t */\n\t_convertInsertWithAttributes( data ) {\n\t\tthis._testAndFire( 'insert', data );\n\n\t\t// Fire a separate addAttribute event for each attribute that was set on inserted items.\n\t\t// This is important because most attributes converters will listen only to add/change/removeAttribute events.\n\t\t// If we would not add this part, attributes on inserted nodes would not be converted.\n\t\tfor ( const key of data.item.getAttributeKeys() ) {\n\t\t\tdata.attributeKey = key;\n\t\t\tdata.attributeOldValue = null;\n\t\t\tdata.attributeNewValue = data.item.getAttribute( key );\n\n\t\t\tthis._testAndFire( `attribute:${ key }`, data );\n\t\t}\n\t}\n\n\t/**\n\t * Returns differ changes together with added \"reconvert\" type changes for {@link #reconvertElement}. These are defined by\n\t * a the `triggerBy()` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * This method will remove every mapped insert or remove change with a single \"reconvert\" change.\n\t *\n\t * For instance: Having a `triggerBy()` configuration defined for the `<complex>` element that issues this element reconversion on\n\t * `foo` and `bar` attributes change, and a set of changes for this element:\n\t *\n\t *\t\tconst differChanges = [\n\t *\t\t\t{ type: 'attribute', attributeKey: 'foo', ... },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'bar', ... },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'baz', ... }\n\t *\t\t];\n\t *\n\t * This method will return:\n\t *\n\t *\t\tconst updatedChanges = [\n\t *\t\t\t{ type: 'reconvert', element: complexElementInstance },\n\t *\t\t\t{ type: 'attribute', attributeKey: 'baz', ... }\n\t *\t\t];\n\t *\n\t * In the example above, the `'baz'` attribute change will fire an {@link #event:attribute attribute event}\n\t *\n\t * @param {module:engine/model/differ~Differ} differ The differ object with buffered changes.\n\t * @returns {Array.<Object>} Updated set of changes.\n\t * @private\n\t */\n\t_mapChangesWithAutomaticReconversion( differ ) {\n\t\tconst itemsToReconvert = new Set();\n\t\tconst updated = [];\n\n\t\tfor ( const entry of differ.getChanges() ) {\n\t\t\tconst position = entry.position || entry.range.start;\n\t\t\t// Cached parent - just in case. See https://github.com/ckeditor/ckeditor5/issues/6579.\n\t\t\tconst positionParent = position.parent;\n\t\t\tconst textNode = getTextNodeAtPosition( position, positionParent );\n\n\t\t\t// Reconversion is done only on elements so skip text changes.\n\t\t\tif ( textNode ) {\n\t\t\t\tupdated.push( entry );\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst element = entry.type === 'attribute' ? getNodeAfterPosition( position, positionParent, null ) : positionParent;\n\n\t\t\t// Case of text node set directly in root. For now used only in tests but can be possible when enabled in paragraph-like roots.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5/issues/762.\n\t\t\tif ( element.is( '$text' ) ) {\n\t\t\t\tupdated.push( entry );\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet eventName;\n\n\t\t\tif ( entry.type === 'attribute' ) {\n\t\t\t\teventName = `attribute:${ entry.attributeKey }:${ element.name }`;\n\t\t\t} else {\n\t\t\t\teventName = `${ entry.type }:${ entry.name }`;\n\t\t\t}\n\n\t\t\tif ( this._isReconvertTriggerEvent( eventName, element.name ) ) {\n\t\t\t\tif ( itemsToReconvert.has( element ) ) {\n\t\t\t\t\t// Element is already reconverted, so skip this change.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\titemsToReconvert.add( element );\n\n\t\t\t\t// Add special \"reconvert\" change.\n\t\t\t\tupdated.push( { type: 'reconvert', element } );\n\t\t\t} else {\n\t\t\t\tupdated.push( entry );\n\t\t\t}\n\t\t}\n\n\t\treturn updated;\n\t}\n\n\t/**\n\t * Checks if the resulting change should trigger element reconversion.\n\t *\n\t * These are defined by a `triggerBy()` configuration for the\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`} conversion helper.\n\t *\n\t * @private\n\t * @param {String} eventName The event name to check.\n\t * @param {String} elementName The element name to check.\n\t * @returns {Boolean}\n\t */\n\t_isReconvertTriggerEvent( eventName, elementName ) {\n\t\treturn this._reconversionEventsMapping.get( eventName ) === elementName;\n\t}\n\n\t/**\n\t * Fired for inserted nodes.\n\t *\n\t * `insert` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `insert:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been inserted,\n\t * or {@link module:engine/model/element~Element#name name} of inserted element.\n\t *\n\t * This way listeners can either listen to a general `insert` event or specific event (for example `insert:paragraph`).\n\t *\n\t * @event insert\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item} data.item Inserted item.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over inserted item.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for removed nodes.\n\t *\n\t * `remove` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `remove:name`. `name` is either `'$text'`, when {@link module:engine/model/text~Text a text node} has been removed,\n\t * or the {@link module:engine/model/element~Element#name name} of removed element.\n\t *\n\t * This way listeners can either listen to a general `remove` event or specific event (for example `remove:paragraph`).\n\t *\n\t * @event remove\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/position~Position} data.position Position from which the node has been removed.\n\t * @param {Number} data.length Offset size of the removed node.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired in the following cases:\n\t *\n\t * * when an attribute has been added, changed, or removed from a node,\n\t * * when a node with an attribute is inserted,\n\t * * when collapsed model selection attribute is converted.\n\t *\n\t * `attribute` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `attribute:attributeKey:name`. `attributeKey` is the key of added/changed/removed attribute.\n\t * `name` is either `'$text'` if change was on {@link module:engine/model/text~Text a text node},\n\t * or the {@link module:engine/model/element~Element#name name} of element which attribute has changed.\n\t *\n\t * This way listeners can either listen to a general `attribute:bold` event or specific event (for example `attribute:src:image`).\n\t *\n\t * @event attribute\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} data.item Changed item\n\t * or converted selection.\n\t * @param {module:engine/model/range~Range} data.range Range spanning over changed item or selection range.\n\t * @param {String} data.attributeKey Attribute key.\n\t * @param {*} data.attributeOldValue Attribute value before the change. This is `null` when selection attribute is converted.\n\t * @param {*} data.attributeNewValue New attribute value.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired for {@link module:engine/model/selection~Selection selection} changes.\n\t *\n\t * @event selection\n\t * @param {module:engine/model/selection~Selection} selection Selection that is converted.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when a new marker is added to the model. Also fired when a collapsed model selection that is inside a marker is converted.\n\t *\n\t * `addMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `addMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `addMarker:foo` or `addMarker:foo:abc` and\n\t * `addMarker:foo:bar` events.\n\t *\n\t * If the marker range is not collapsed:\n\t *\n\t * * the event is fired for each item in the marker range one by one,\n\t * * `conversionApi.consumable` includes each item of the marker range and the consumable value is same as the event name.\n\t *\n\t * If the marker range is collapsed:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes marker range with the event name.\n\t *\n\t * If the selection inside a marker is converted:\n\t *\n\t * * there is only one event,\n\t * * `conversionApi.consumable` includes the selection instance with the event name.\n\t *\n\t * @event addMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/item~Item|module:engine/model/selection~Selection} data.item Item inside the new marker or\n\t * the selection that is being converted.\n\t * @param {module:engine/model/range~Range} [data.range] Range spanning over converted item. Available only in marker conversion, if\n\t * the marker range was not collapsed.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n\n\t/**\n\t * Fired when a marker is removed from the model.\n\t *\n\t * `removeMarker` is a namespace for a class of events. Names of actually called events follow this pattern:\n\t * `removeMarker:markerName`. By specifying certain marker names, you can make the events even more gradual. For example,\n\t * if markers are named `foo:abc`, `foo:bar`, then it is possible to listen to `removeMarker:foo` or `removeMarker:foo:abc` and\n\t * `removeMarker:foo:bar` events.\n\t *\n\t * @event removeMarker\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/model/range~Range} data.markerRange Marker range.\n\t * @param {String} data.markerName Marker name.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface\n\t * to be used by callback, passed in `DowncastDispatcher` constructor.\n\t */\n}\n\nmix( DowncastDispatcher, EmitterMixin );\n\n// Helper function, checks whether change of `marker` at `modelPosition` should be converted. Marker changes are not\n// converted if they happen inside an element with custom conversion method.\n//\n// @param {module:engine/model/position~Position} modelPosition\n// @param {module:engine/model/markercollection~Marker} marker\n// @param {module:engine/conversion/mapper~Mapper} mapper\n// @returns {Boolean}\nfunction shouldMarkerChangeBeConverted( modelPosition, marker, mapper ) {\n\tconst range = marker.getRange();\n\tconst ancestors = Array.from( modelPosition.getAncestors() );\n\tancestors.shift(); // Remove root element. It cannot be passed to `model.Range#containsItem`.\n\tancestors.reverse();\n\n\tconst hasCustomHandling = ancestors.some( element => {\n\t\tif ( range.containsItem( element ) ) {\n\t\t\tconst viewElement = mapper.toViewElement( element );\n\n\t\t\treturn !!viewElement.getCustomProperty( 'addHighlight' );\n\t\t}\n\t} );\n\n\treturn !hasCustomHandling;\n}\n\nfunction getEventName( type, data ) {\n\tconst name = data.item.name || '$text';\n\n\treturn `${ type }:${ name }`;\n}\n\nfunction walkerValueToEventData( value ) {\n\tconst item = value.item;\n\tconst itemRange = Range._createFromPositionAndShift( value.previousPosition, value.length );\n\n\treturn {\n\t\titem,\n\t\trange: itemRange\n\t};\n}\n\nfunction elementOrTextProxyToView( item, mapper ) {\n\tif ( item.is( 'textProxy' ) ) {\n\t\tconst mappedPosition = mapper.toViewPosition( Position._createBefore( item ) );\n\t\tconst positionParent = mappedPosition.parent;\n\n\t\treturn positionParent.is( '$text' ) ? positionParent : null;\n\t}\n\n\treturn mapper.toViewElement( item );\n}\n\n/**\n * Conversion interface that is registered for given {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n * and is passed as one of parameters when {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher dispatcher}\n * fires its events.\n *\n * @interface module:engine/conversion/downcastdispatcher~DowncastConversionApi\n */\n\n/**\n * The {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} instance.\n *\n * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #dispatcher\n */\n\n/**\n * Stores the information about what parts of a processed model item are still waiting to be handled. After a piece of a model item was\n * converted, an appropriate consumable value should be {@link module:engine/conversion/modelconsumable~ModelConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/modelconsumable~ModelConsumable} #consumable\n */\n\n/**\n * The {@link module:engine/conversion/mapper~Mapper} instance.\n *\n * @member {module:engine/conversion/mapper~Mapper} #mapper\n */\n\n/**\n * The {@link module:engine/model/schema~Schema} instance set for the model that is downcast.\n *\n * @member {module:engine/model/schema~Schema} #schema\n */\n\n/**\n * The {@link module:engine/view/downcastwriter~DowncastWriter} instance used to manipulate the data during conversion.\n *\n * @member {module:engine/view/downcastwriter~DowncastWriter} #writer\n */\n\n/**\n * An object with an additional configuration which can be used during the conversion process. Available only for data downcast conversion.\n *\n * @member {Object} #options\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/selection\n */\n\nimport Position from './position';\nimport Node from './node';\nimport Range from './range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n/**\n * Selection is a set of {@link module:engine/model/range~Range ranges}. It has a direction specified by its\n * {@link module:engine/model/selection~Selection#anchor anchor} and {@link module:engine/model/selection~Selection#focus focus}\n * (it can be {@link module:engine/model/selection~Selection#isBackward forward or backward}).\n * Additionally, selection may have its own attributes (think whether text typed in in this selection\n * should have those attributes e.g. whether you type a bolded text).\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Selection {\n\t/**\n\t * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}\n\t * or creates an empty selection if no arguments were passed.\n\t *\n\t *\t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\tconst selection = writer.createSelection( documentSelection );\n\t *\n\t *\t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates selection at the given offset in the given element.\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * Selection's constructor allow passing additional options (`'backward'`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\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\tconstructor( selectable, placeOrOffset, options ) {\n\t\t/**\n\t\t * Specifies whether the last added range was added as a backward or forward range.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._lastRangeBackward = false;\n\n\t\t/**\n\t\t * Stores selection ranges.\n\t\t *\n\t\t * @protected\n\t\t * @type {Array.<module:engine/model/range~Range>}\n\t\t */\n\t\tthis._ranges = [];\n\n\t\t/**\n\t\t * List of attributes set on current selection.\n\t\t *\n\t\t * @protected\n\t\t * @type {Map.<String,*>}\n\t\t */\n\t\tthis._attrs = new Map();\n\n\t\tif ( selectable ) {\n\t\t\tthis.setTo( selectable, placeOrOffset, options );\n\t\t}\n\t}\n\n\t/**\n\t * Selection anchor. Anchor is the position from which the selection was started. If a user is making a selection\n\t * by dragging the mouse, the anchor is where the user pressed the mouse button (the beginning of the selection).\n\t *\n\t * Anchor and {@link #focus} define the direction of the selection, which is important\n\t * when expanding/shrinking selection. The focus moves, while the anchor should remain in the same place.\n\t *\n\t * Anchor is always set to the {@link module:engine/model/range~Range#start start} or\n\t * {@link module:engine/model/range~Range#end end} position of the last of selection's ranges. Whether it is\n\t * the `start` or `end` depends on the specified `options.backward`. See the {@link #setTo `setTo()`} method.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #focus\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget anchor() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.end : range.start;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Selection focus. Focus is the position where the selection ends. If a user is making a selection\n\t * by dragging the mouse, the focus is where the mouse cursor is.\n\t *\n\t * May be set to `null` if there are no ranges in the selection.\n\t *\n\t * @see #anchor\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget focus() {\n\t\tif ( this._ranges.length > 0 ) {\n\t\t\tconst range = this._ranges[ this._ranges.length - 1 ];\n\n\t\t\treturn this._lastRangeBackward ? range.start : range.end;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Whether the selection is collapsed. Selection is collapsed when there is exactly one range in it\n\t * and it is collapsed.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\tconst length = this._ranges.length;\n\n\t\tif ( length === 1 ) {\n\t\t\treturn this._ranges[ 0 ].isCollapsed;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the number of ranges in the selection.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._ranges.length;\n\t}\n\n\t/**\n\t * Specifies whether the selection's {@link #focus} precedes the selection's {@link #anchor}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn !this.isCollapsed && this._lastRangeBackward;\n\t}\n\n\t/**\n\t * Checks whether this selection is equal to the given selection. Selections are equal if they have the same directions,\n\t * the same number of ranges and all ranges from one selection equal to ranges from the another selection.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} otherSelection\n\t * Selection to compare with.\n\t * @returns {Boolean} `true` if selections are equal, `false` otherwise.\n\t */\n\tisEqual( otherSelection ) {\n\t\tif ( this.rangeCount != otherSelection.rangeCount ) {\n\t\t\treturn false;\n\t\t} else if ( this.rangeCount === 0 ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif ( !this.anchor.isEqual( otherSelection.anchor ) || !this.focus.isEqual( otherSelection.focus ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const thisRange of this._ranges ) {\n\t\t\tlet found = false;\n\n\t\t\tfor ( const otherRange of otherSelection._ranges ) {\n\t\t\t\tif ( thisRange.isEqual( otherRange ) ) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !found ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Returns an iterable object that iterates over copies of selection ranges.\n\t *\n\t * @returns {Iterable.<module:engine/model/range~Range>}\n\t */\n\t* getRanges() {\n\t\tfor ( const range of this._ranges ) {\n\t\t\tyield new Range( range.start, range.end );\n\t\t}\n\t}\n\n\t/**\n\t * Returns a copy of the first range in the selection.\n\t * First range is the one which {@link module:engine/model/range~Range#start start} position\n\t * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges\n\t * (not to confuse with the first range added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\tlet first = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !first || range.start.isBefore( first.start ) ) {\n\t\t\t\tfirst = range;\n\t\t\t}\n\t\t}\n\n\t\treturn first ? new Range( first.start, first.end ) : null;\n\t}\n\n\t/**\n\t * Returns a copy of the last range in the selection.\n\t * Last range is the one which {@link module:engine/model/range~Range#end end} position\n\t * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most\n\t * recently added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\tlet last = null;\n\n\t\tfor ( const range of this._ranges ) {\n\t\t\tif ( !last || range.end.isAfter( last.end ) ) {\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\treturn last ? new Range( last.start, last.end ) : null;\n\t}\n\n\t/**\n\t * Returns the first position in the selection.\n\t * First position is the position that {@link module:engine/model/position~Position#isBefore is before}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\tconst first = this.getFirstRange();\n\n\t\treturn first ? first.start.clone() : null;\n\t}\n\n\t/**\n\t * Returns the last position in the selection.\n\t * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\tconst lastRange = this.getLastRange();\n\n\t\treturn lastRange ? lastRange.end.clone() : null;\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable}.\n\t *\n\t *\t\t// Removes all selection's ranges.\n\t *\t\tselection.setTo( null );\n\t *\n\t *\t\t// Sets selection to the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tselection.setTo( 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\tselection.setTo( ranges );\n\t *\n\t *\t\t// Sets selection to other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tselection.setTo( otherSelection );\n\t *\n\t *\t\t// Sets selection to the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = new DocumentSelection( doc );\n\t *\t\tselection.setTo( documentSelection );\n\t *\n\t *\t\t// Sets collapsed selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tselection.setTo( position );\n\t *\n\t *\t\t// Sets collapsed selection at the position of the given node and an offset.\n\t *\t\tselection.setTo( 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\tselection.setTo( 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\tselection.setTo( paragraph, 'on' );\n\t *\n\t * `Selection#setTo()`' method allow passing additional options (`backward`) as the last argument.\n\t *\n\t *\t\t// Sets backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\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\tsetTo( selectable, placeOrOffset, options ) {\n\t\tif ( selectable === null ) {\n\t\t\tthis._setRanges( [] );\n\t\t} else if ( selectable instanceof Selection ) {\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable && typeof selectable.getRanges == 'function' ) {\n\t\t\t// We assume that the selectable is a DocumentSelection.\n\t\t\t// It can't be imported here, because it would lead to circular imports.\n\t\t\tthis._setRanges( selectable.getRanges(), selectable.isBackward );\n\t\t} else if ( selectable instanceof Range ) {\n\t\t\tthis._setRanges( [ selectable ], !!placeOrOffset && !!placeOrOffset.backward );\n\t\t} else if ( selectable instanceof Position ) {\n\t\t\tthis._setRanges( [ new Range( selectable ) ] );\n\t\t} else if ( selectable instanceof Node ) {\n\t\t\tconst backward = !!options && !!options.backward;\n\t\t\tlet range;\n\n\t\t\tif ( placeOrOffset == 'in' ) {\n\t\t\t\trange = Range._createIn( selectable );\n\t\t\t} else if ( placeOrOffset == 'on' ) {\n\t\t\t\trange = Range._createOn( selectable );\n\t\t\t} else if ( placeOrOffset !== undefined ) {\n\t\t\t\trange = new Range( Position._createAt( selectable, placeOrOffset ) );\n\t\t\t} else {\n\t\t\t\t/**\n\t\t\t\t * selection.setTo requires the second parameter when the first parameter is a node.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-setto-required-second-parameter\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-selection-setto-required-second-parameter', [ this, selectable ] );\n\t\t\t}\n\n\t\t\tthis._setRanges( [ range ], backward );\n\t\t} else if ( isIterable( selectable ) ) {\n\t\t\t// We assume that the selectable is an iterable of ranges.\n\t\t\tthis._setRanges( selectable, placeOrOffset && !!placeOrOffset.backward );\n\t\t} else {\n\t\t\t/**\n\t\t\t * Cannot set the selection to the given place.\n\t\t\t *\n\t\t\t * Invalid parameters were specified when setting the selection. Common issues:\n\t\t\t *\n\t\t\t * * A {@link module:engine/model/textproxy~TextProxy} instance was passed instead of\n\t\t\t * a real {@link module:engine/model/text~Text}.\n\t\t\t * * View nodes were passed instead of model nodes.\n\t\t\t * * `null`/`undefined` was passed.\n\t\t\t *\n\t\t\t * @error model-selection-setto-not-selectable\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-selection-setto-not-selectable', [ this, selectable ] );\n\t\t}\n\t}\n\n\t/**\n\t * Replaces all ranges that were added to the selection with given array of ranges. Last range of the array\n\t * is treated like the last added range and is used to set {@link module:engine/model/selection~Selection#anchor} and\n\t * {@link module:engine/model/selection~Selection#focus}. Accepts a flag describing in which direction the selection is made.\n\t *\n\t * @protected\n\t * @fires change:range\n\t * @param {Iterable.<module:engine/model/range~Range>} newRanges Ranges to set.\n\t * @param {Boolean} [isLastBackward=false] Flag describing if last added range was selected forward - from start to end (`false`)\n\t * or backward - from end to start (`true`).\n\t */\n\t_setRanges( newRanges, isLastBackward = false ) {\n\t\tnewRanges = Array.from( newRanges );\n\n\t\t// Check whether there is any range in new ranges set that is different than all already added ranges.\n\t\tconst anyNewRange = newRanges.some( newRange => {\n\t\t\tif ( !( newRange instanceof Range ) ) {\n\t\t\t\t/**\n\t\t\t\t * Selection range set to an object that is not an instance of {@link module:engine/model/range~Range}.\n\t\t\t\t *\n\t\t\t\t * Only {@link module:engine/model/range~Range} instances can be used to set a selection.\n\t\t\t\t * Common mistakes leading to this error are:\n\t\t\t\t *\n\t\t\t\t * * using DOM `Range` object,\n\t\t\t\t * * incorrect CKEditor 5 installation with multiple `ckeditor5-engine` packages having different versions.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-set-ranges-not-range\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-set-ranges-not-range',\n\t\t\t\t\t[ this, newRanges ]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this._ranges.every( oldRange => {\n\t\t\t\treturn !oldRange.isEqual( newRange );\n\t\t\t} );\n\t\t} );\n\n\t\t// Don't do anything if nothing changed.\n\t\tif ( newRanges.length === this._ranges.length && !anyNewRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._removeAllRanges();\n\n\t\tfor ( const range of newRanges ) {\n\t\t\tthis._pushRange( range );\n\t\t}\n\n\t\tthis._lastRangeBackward = !!isLastBackward;\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/selection~Selection#focus} to the specified location.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.\n\t *\n\t * @fires change: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 * first parameter is a {@link module:engine/model/item~Item model item}.\n\t */\n\tsetFocus( itemOrPosition, offset ) {\n\t\tif ( this.anchor === null ) {\n\t\t\t/**\n\t\t\t * Cannot set selection focus if there are no ranges in selection.\n\t\t\t *\n\t\t\t * @error model-selection-setfocus-no-ranges\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-selection-setfocus-no-ranges', [ this, itemOrPosition ] );\n\t\t}\n\n\t\tconst newFocus = Position._createAt( itemOrPosition, offset );\n\n\t\tif ( newFocus.compareWith( this.focus ) == 'same' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst anchor = this.anchor;\n\n\t\tif ( this._ranges.length ) {\n\t\t\tthis._popRange();\n\t\t}\n\n\t\tif ( newFocus.compareWith( anchor ) == 'before' ) {\n\t\t\tthis._pushRange( new Range( newFocus, anchor ) );\n\t\t\tthis._lastRangeBackward = true;\n\t\t} else {\n\t\t\tthis._pushRange( new Range( anchor, newFocus ) );\n\t\t\tthis._lastRangeBackward = false;\n\t\t}\n\n\t\tthis.fire( 'change:range', { directChange: true } );\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._attrs.get( key );\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._attrs.entries();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._attrs.keys();\n\t}\n\n\t/**\n\t * Checks if the selection has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on selection, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._attrs.has( key );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the selection.\n\t *\n\t * If given attribute was set on the selection, fires the {@link #event:change:range} event with\n\t * removed attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to remove.\n\t */\n\tremoveAttribute( key ) {\n\t\tif ( this.hasAttribute( key ) ) {\n\t\t\tthis._attrs.delete( key );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t *\n\t * If the attribute value has changed, fires the {@link #event:change:range} event with\n\t * the attribute key.\n\t *\n\t * @fires change:attribute\n\t * @param {String} key Key of attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\tsetAttribute( key, value ) {\n\t\tif ( this.getAttribute( key ) !== value ) {\n\t\t\tthis._attrs.set( key, value );\n\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: [ key ], directChange: true } );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\tif ( this.rangeCount !== 1 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.getFirstRange().getContainedElement();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'model:selection' ); // -> true\n\t *\n\t *\t\tselection.is( 'view:selection' ); // -> false\n\t *\t\tselection.is( 'range' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' || type === 'model:selection';\n\t}\n\n\t/**\n\t * Gets elements of type {@link module:engine/model/schema~Schema#isBlock \"block\"} touched by the selection.\n\t *\n\t * This method's result can be used for example to apply block styling to all blocks covered by this selection.\n\t *\n\t * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements\n\t * but will not return blocks nested in other blocks.\n\t *\n\t * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<blockQuote>\n\t *\t\t\t<paragraph>b</paragraph>\n\t *\t\t</blockQuote>\n\t *\t\t<paragraph>c]d</paragraph>\n\t *\n\t * In this case the paragraph will also be returned, despite the collapsed selection:\n\t *\n\t *\t\t<paragraph>[]a</paragraph>\n\t *\n\t * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:\n\t *\n\t *\t\t[<blockA></blockA>\n\t *\t\t<blockB>\n\t *\t\t\t<blockC></blockC>\n\t *\t\t\t<blockD></blockD>\n\t *\t\t</blockB>\n\t *\t\t<blockE></blockE>]\n\t *\n\t * If the selection is inside a block all the inner blocks (A & B) are returned:\n\t *\n\t * \t\t<block>\n\t *\t\t\t<blockA>[a</blockA>\n\t * \t\t\t<blockB>b]</blockB>\n\t * \t\t</block>\n\t *\n\t * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective\n\t * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<paragraph>b</paragraph>\n\t *\t\t<paragraph>]c</paragraph> // this block will not be returned\n\t *\n\t * @returns {Iterable.<module:engine/model/element~Element>}\n\t */\n\t* getSelectedBlocks() {\n\t\tconst visited = new WeakSet();\n\n\t\tfor ( const range of this.getRanges() ) {\n\t\t\t// Get start block of range in case of a collapsed range.\n\t\t\tconst startBlock = getParentBlock( range.start, visited );\n\n\t\t\tif ( startBlock && isTopBlockInRange( startBlock, range ) ) {\n\t\t\t\tyield startBlock;\n\t\t\t}\n\n\t\t\tfor ( const value of range.getWalker() ) {\n\t\t\t\tconst block = value.item;\n\n\t\t\t\tif ( value.type == 'elementEnd' && isUnvisitedTopBlock( block, visited, range ) ) {\n\t\t\t\t\tyield block;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst endBlock = getParentBlock( range.end, visited );\n\n\t\t\t// #984. Don't return the end block if the range ends right at its beginning.\n\t\t\tif ( endBlock && !range.end.isTouching( Position._createAt( endBlock, 0 ) ) && isTopBlockInRange( endBlock, range ) ) {\n\t\t\t\tyield endBlock;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Checks whether the selection contains the entire content of the given element. This means that selection must start\n\t * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position\n\t * touching the element's end.\n\t *\n\t * By default, this method will check whether the entire content of the selection's current root is selected.\n\t * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.\n\t *\n\t * @param {module:engine/model/element~Element} [element=this.anchor.root]\n\t * @returns {Boolean}\n\t */\n\tcontainsEntireContent( element = this.anchor.root ) {\n\t\tconst limitStartPosition = Position._createAt( element, 0 );\n\t\tconst limitEndPosition = Position._createAt( element, 'end' );\n\n\t\treturn limitStartPosition.isTouching( this.getFirstPosition() ) &&\n\t\t\tlimitEndPosition.isTouching( this.getLastPosition() );\n\t}\n\n\t/**\n\t * Adds given range to internal {@link #_ranges ranges array}. Throws an error\n\t * if given range is intersecting with any range that is already stored in this selection.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to add.\n\t */\n\t_pushRange( range ) {\n\t\tthis._checkRange( range );\n\t\tthis._ranges.push( new Range( range.start, range.end ) );\n\t}\n\n\t/**\n\t * Checks if given range intersects with ranges that are already in the selection. Throws an error if it does.\n\t *\n\t * @protected\n\t * @param {module:engine/model/range~Range} range Range to check.\n\t */\n\t_checkRange( range ) {\n\t\tfor ( let i = 0; i < this._ranges.length; i++ ) {\n\t\t\tif ( range.isIntersecting( this._ranges[ i ] ) ) {\n\t\t\t\t/**\n\t\t\t\t * Trying to add a range that intersects with another range in the selection.\n\t\t\t\t *\n\t\t\t\t * @error model-selection-range-intersects\n\t\t\t\t * @param {module:engine/model/range~Range} addedRange Range that was added to the selection.\n\t\t\t\t * @param {module:engine/model/range~Range} intersectingRange Range in the selection that intersects with `addedRange`.\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'model-selection-range-intersects',\n\t\t\t\t\t[ this, range ],\n\t\t\t\t\t{ addedRange: range, intersectingRange: this._ranges[ i ] }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Deletes ranges from internal range array. Uses {@link #_popRange _popRange} to\n\t * ensure proper ranges removal.\n\t *\n\t * @protected\n\t */\n\t_removeAllRanges() {\n\t\twhile ( this._ranges.length > 0 ) {\n\t\t\tthis._popRange();\n\t\t}\n\t}\n\n\t/**\n\t * Removes most recently added range from the selection.\n\t *\n\t * @protected\n\t */\n\t_popRange() {\n\t\tthis._ranges.pop();\n\t}\n\n\t/**\n\t * Fired when selection range(s) changed.\n\t *\n\t * @event change:range\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its position\n\t * was directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed because the structure of the model has been changed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t */\n\n\t/**\n\t * Fired when selection attribute changed.\n\t *\n\t * @event change:attribute\n\t * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n\t * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n\t * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its attributes\n\t * were directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n\t * changed in the model and its attributes were refreshed (which means an indirect change).\n\t * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n\t * which mean that they are not updated once the document changes.\n\t * @param {Array.<String>} attributeKeys Array containing keys of attributes that changed.\n\t */\n}\n\nmix( Selection, EmitterMixin );\n\n// Checks whether the given element extends $block in the schema and has a parent (is not a root).\n// Marks it as already visited.\nfunction isUnvisitedBlock( element, visited ) {\n\tif ( visited.has( element ) ) {\n\t\treturn false;\n\t}\n\n\tvisited.add( element );\n\n\treturn element.root.document.model.schema.isBlock( element ) && element.parent;\n}\n\n// Checks if the given element is a $block was not previously visited and is a top block in a range.\nfunction isUnvisitedTopBlock( element, visited, range ) {\n\treturn isUnvisitedBlock( element, visited ) && isTopBlockInRange( element, range );\n}\n\n// Finds the lowest element in position's ancestors which is a block.\n// It will search until first ancestor that is a limit element.\n// Marks all ancestors as already visited to not include any of them later on.\nfunction getParentBlock( position, visited ) {\n\tconst element = position.parent;\n\tconst schema = element.root.document.model.schema;\n\n\tconst ancestors = position.parent.getAncestors( { parentFirst: true, includeSelf: true } );\n\n\tlet hasParentLimit = false;\n\n\tconst block = ancestors.find( element => {\n\t\t// Stop searching after first parent node that is limit element.\n\t\tif ( hasParentLimit ) {\n\t\t\treturn false;\n\t\t}\n\n\t\thasParentLimit = schema.isLimit( element );\n\n\t\treturn !hasParentLimit && isUnvisitedBlock( element, visited );\n\t} );\n\n\t// Mark all ancestors of this position's parent, because find() might've stopped early and\n\t// the found block may be a child of another block.\n\tancestors.forEach( element => visited.add( element ) );\n\n\treturn block;\n}\n\n// Checks if the blocks is not nested in other block inside a range.\n//\n// @param {module:engine/model/element~Element} block Block to check.\n// @param {module:engine/model/range~Range} range Range to check.\nfunction isTopBlockInRange( block, range ) {\n\tconst parentBlock = findAncestorBlock( block );\n\n\tif ( !parentBlock ) {\n\t\treturn true;\n\t}\n\n\t// Add loose flag to check as parentRange can be equal to range.\n\tconst isParentInRange = range.containsRange( Range._createOn( parentBlock ), true );\n\n\treturn !isParentInRange;\n}\n\n// Returns first ancestor block of a node.\n//\n// @param {module:engine/model/node~Node} node\n// @returns {module:engine/model/node~Node|undefined}\nfunction findAncestorBlock( node ) {\n\tconst schema = node.root.document.model.schema;\n\n\tlet parent = node.parent;\n\n\twhile ( parent ) {\n\t\tif ( schema.isBlock( parent ) ) {\n\t\t\treturn parent;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n}\n\n/**\n * An entity that is used to set selection.\n *\n * See also {@link module:engine/model/selection~Selection#setTo}\n *\n * @typedef {\n * module:engine/model/selection~Selection|\n * module:engine/model/documentselection~DocumentSelection|\n * module:engine/model/position~Position|\n * module:engine/model/range~Range|\n * module:engine/model/node~Node|\n * Iterable.<module:engine/model/range~Range>|\n * null\n * } module:engine/model/selection~Selectable\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/liverange\n */\n\nimport Range from './range';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * `LiveRange` is a type of {@link module:engine/model/range~Range Range}\n * that updates itself as {@link module:engine/model/document~Document document}\n * is changed through operations. It may be used as a bookmark.\n *\n * **Note:** Be very careful when dealing with `LiveRange`. Each `LiveRange` instance bind events that might\n * have to be unbound. Use {@link module:engine/model/liverange~LiveRange#detach detach} whenever you don't need `LiveRange` anymore.\n */\nexport default class LiveRange extends Range {\n\t/**\n\t * Creates a live range.\n\t *\n\t * @see module:engine/model/range~Range\n\t */\n\tconstructor( start, end ) {\n\t\tsuper( start, end );\n\n\t\tbindWithDocument.call( this );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by `LiveRange`. Use it whenever you don't need `LiveRange` instance\n\t * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was\n\t * referring to it).\n\t */\n\tdetach() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tliveRange.is( 'range' ); // -> true\n\t *\t\tliveRange.is( 'model:range' ); // -> true\n\t *\t\tliveRange.is( 'liveRange' ); // -> true\n\t *\t\tliveRange.is( 'model:liveRange' ); // -> true\n\t *\n\t *\t\tliveRange.is( 'view:range' ); // -> false\n\t *\t\tliveRange.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'liveRange' || type === 'model:liveRange' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype == 'range' || type === 'model:range';\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/range~Range range instance} that is equal to this live range.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\ttoRange() {\n\t\treturn new Range( this.start, this.end );\n\t}\n\n\t/**\n\t * Creates a `LiveRange` instance that is equal to the given range.\n\t *\n\t * @param {module:engine/model/range~Range} range\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\tstatic fromRange( range ) {\n\t\treturn new LiveRange( range.start, range.end );\n\t}\n\n\t/**\n\t * @see module:engine/model/range~Range._createIn\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createIn\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * @see module:engine/model/range~Range._createOn\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createOn\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * @see module:engine/model/range~Range._createFromPositionAndShift\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liverange~LiveRange._createFromPositionAndShift\n\t * @param {module:engine/model/position~Position} position\n\t * @param {Number} shift\n\t * @returns {module:engine/model/liverange~LiveRange}\n\t */\n\n\t/**\n\t * Fired when `LiveRange` instance boundaries have changed due to changes in the\n\t * {@link module:engine/model/document~Document document}.\n\t *\n\t * @event change:range\n\t * @param {module:engine/model/range~Range} oldRange Range with start and end position equal to start and end position of this live\n\t * range before it got changed.\n\t * @param {Object} data Object with additional information about the change.\n\t * @param {module:engine/model/position~Position|null} data.deletionPosition Source position for remove and merge changes.\n\t * Available if the range was moved to the graveyard root, `null` otherwise.\n\t */\n\n\t/**\n\t * Fired when `LiveRange` instance boundaries have not changed after a change in {@link module:engine/model/document~Document document}\n\t * but the change took place inside the range, effectively changing its content.\n\t *\n\t * @event change:content\n\t * @param {module:engine/model/range~Range} range Range with start and end position equal to start and end position of\n\t * change range.\n\t * @param {Object} data Object with additional information about the change.\n\t * @param {null} data.deletionPosition Due to the nature of this event, this property is always set to `null`. It is passed\n\t * for compatibility with the {@link module:engine/model/liverange~LiveRange#event:change:range} event.\n\t */\n}\n\n// Binds this `LiveRange` to the {@link module:engine/model/document~Document document}\n// that owns this range's {@link module:engine/model/range~Range#root root}.\n//\n// @private\nfunction bindWithDocument() {\n\tthis.listenTo(\n\t\tthis.root.document.model,\n\t\t'applyOperation',\n\t\t( event, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttransform.call( this, operation );\n\t\t},\n\t\t{ priority: 'low' }\n\t);\n}\n\n// Updates this range accordingly to the updates applied to the model. Bases on change events.\n//\n// @private\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\nfunction transform( operation ) {\n\t// Transform the range by the operation. Join the result ranges if needed.\n\tconst ranges = this.getTransformedByOperation( operation );\n\tconst result = Range._createFromRanges( ranges );\n\n\tconst boundariesChanged = !result.isEqual( this );\n\tconst contentChanged = doesOperationChangeRangeContent( this, operation );\n\n\tlet deletionPosition = null;\n\n\tif ( boundariesChanged ) {\n\t\t// If range boundaries have changed, fire `change:range` event.\n\t\t//\n\t\tif ( result.root.rootName == '$graveyard' ) {\n\t\t\t// If the range was moved to the graveyard root, set `deletionPosition`.\n\t\t\tif ( operation.type == 'remove' ) {\n\t\t\t\tdeletionPosition = operation.sourcePosition;\n\t\t\t} else {\n\t\t\t\t// Merge operation.\n\t\t\t\tdeletionPosition = operation.deletionPosition;\n\t\t\t}\n\t\t}\n\n\t\tconst oldRange = this.toRange();\n\n\t\tthis.start = result.start;\n\t\tthis.end = result.end;\n\n\t\tthis.fire( 'change:range', oldRange, { deletionPosition } );\n\t} else if ( contentChanged ) {\n\t\t// If range boundaries have not changed, but there was change inside the range, fire `change:content` event.\n\t\tthis.fire( 'change:content', this.toRange(), { deletionPosition } );\n\t}\n}\n\n// Checks whether given operation changes something inside the range (even if it does not change boundaries).\n//\n// @private\n// @param {module:engine/model/range~Range} range Range to check.\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\n// @returns {Boolean}\nfunction doesOperationChangeRangeContent( range, operation ) {\n\tswitch ( operation.type ) {\n\t\tcase 'insert':\n\t\t\treturn range.containsPosition( operation.position );\n\t\tcase 'move':\n\t\tcase 'remove':\n\t\tcase 'reinsert':\n\t\tcase 'merge':\n\t\t\treturn range.containsPosition( operation.sourcePosition ) ||\n\t\t\t\trange.start.isEqual( operation.sourcePosition ) ||\n\t\t\t\trange.containsPosition( operation.targetPosition );\n\t\tcase 'split':\n\t\t\treturn range.containsPosition( operation.splitPosition ) || range.containsPosition( operation.insertionPosition );\n\t}\n\n\treturn false;\n}\n\nmix( LiveRange, EmitterMixin );\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/documentselection\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\n\nimport Selection from './selection';\nimport LiveRange from './liverange';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport toMap from '@ckeditor/ckeditor5-utils/src/tomap';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\n\nconst storePrefix = 'selection:';\n\n/**\n * `DocumentSelection` is a special selection which is used as the\n * {@link module:engine/model/document~Document#selection document's selection}.\n * There can be only one instance of `DocumentSelection` per document.\n *\n * Document selection can only be changed by using the {@link module:engine/model/writer~Writer} instance\n * inside the {@link module:engine/model/model~Model#change `change()`} block, as it provides a secure way to modify model.\n *\n * `DocumentSelection` is automatically updated upon changes in the {@link module:engine/model/document~Document document}\n * to always contain valid ranges. Its attributes are inherited from the text unless set explicitly.\n *\n * Differences between {@link module:engine/model/selection~Selection} and `DocumentSelection` are:\n * * there is always a range in `DocumentSelection` - even if no ranges were added there is a \"default range\"\n * present in the selection,\n * * ranges added to this selection updates automatically when the document changes,\n * * attributes of `DocumentSelection` are updated automatically according to selection ranges.\n *\n * Since `DocumentSelection` uses {@link module:engine/model/liverange~LiveRange live ranges}\n * and is updated when {@link module:engine/model/document~Document document}\n * changes, it cannot be set on {@link module:engine/model/node~Node nodes}\n * that are inside {@link module:engine/model/documentfragment~DocumentFragment document fragment}.\n * If you need to represent a selection in document fragment,\n * use {@link module:engine/model/selection~Selection Selection class} instead.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class DocumentSelection {\n\t/**\n\t * Creates an empty live selection for given {@link module:engine/model/document~Document}.\n\t *\n\t * @param {module:engine/model/document~Document} doc Document which owns this selection.\n\t */\n\tconstructor( doc ) {\n\t\t/**\n\t\t * Selection used internally by that class (`DocumentSelection` is a proxy to that selection).\n\t\t *\n\t\t * @protected\n\t\t */\n\t\tthis._selection = new LiveSelection( doc );\n\n\t\tthis._selection.delegate( 'change:range' ).to( this );\n\t\tthis._selection.delegate( 'change:attribute' ).to( this );\n\t\tthis._selection.delegate( 'change:marker' ).to( this );\n\t}\n\n\t/**\n\t * Returns whether the selection is collapsed. Selection is collapsed when there is exactly one range which is\n\t * collapsed.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isCollapsed() {\n\t\treturn this._selection.isCollapsed;\n\t}\n\n\t/**\n\t * Selection anchor. Anchor may be described as a position where the most recent part of the selection starts.\n\t * Together with {@link #focus} they define the direction of selection, which is important\n\t * when expanding/shrinking selection. Anchor is always {@link module:engine/model/range~Range#start start} or\n\t * {@link module:engine/model/range~Range#end end} position of the most recently added range.\n\t *\n\t * Is set to `null` if there are no ranges in selection.\n\t *\n\t * @see #focus\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget anchor() {\n\t\treturn this._selection.anchor;\n\t}\n\n\t/**\n\t * Selection focus. Focus is a position where the selection ends.\n\t *\n\t * Is set to `null` if there are no ranges in selection.\n\t *\n\t * @see #anchor\n\t * @readonly\n\t * @type {module:engine/model/position~Position|null}\n\t */\n\tget focus() {\n\t\treturn this._selection.focus;\n\t}\n\n\t/**\n\t * Returns number of ranges in selection.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget rangeCount() {\n\t\treturn this._selection.rangeCount;\n\t}\n\n\t/**\n\t * Describes whether `Documentselection` has own range(s) set, or if it is defaulted to\n\t * {@link module:engine/model/document~Document#_getDefaultRange document's default range}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget hasOwnRange() {\n\t\treturn this._selection.hasOwnRange;\n\t}\n\n\t/**\n\t * Specifies whether the {@link #focus}\n\t * precedes {@link #anchor}.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isBackward() {\n\t\treturn this._selection.isBackward;\n\t}\n\n\t/**\n\t * Describes whether the gravity is overridden (using {@link module:engine/model/writer~Writer#overrideSelectionGravity}) or not.\n\t *\n\t * Note that the gravity remains overridden as long as will not be restored the same number of times as it was overridden.\n\t *\n\t * @readonly\n\t * @returns {Boolean}\n\t */\n\tget isGravityOverridden() {\n\t\treturn this._selection.isGravityOverridden;\n\t}\n\n\t/**\n\t * A collection of selection {@link module:engine/model/markercollection~Marker markers}.\n\t * Marker is a selection marker when selection range is inside the marker range.\n\t *\n\t * **Note**: Only markers from {@link ~DocumentSelection#observeMarkers observed markers groups} are collected.\n\t *\n\t * @readonly\n\t * @type {module:utils/collection~Collection}\n\t */\n\tget markers() {\n\t\treturn this._selection.markers;\n\t}\n\n\t/**\n\t * Used for the compatibility with the {@link module:engine/model/selection~Selection#isEqual} method.\n\t *\n\t * @protected\n\t */\n\tget _ranges() {\n\t\treturn this._selection._ranges;\n\t}\n\n\t/**\n\t * Returns an iterable that iterates over copies of selection ranges.\n\t *\n\t * @returns {Iterable.<module:engine/model/range~Range>}\n\t */\n\tgetRanges() {\n\t\treturn this._selection.getRanges();\n\t}\n\n\t/**\n\t * Returns the first position in the selection.\n\t * First position is the position that {@link module:engine/model/position~Position#isBefore is before}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetFirstPosition() {\n\t\treturn this._selection.getFirstPosition();\n\t}\n\n\t/**\n\t * Returns the last position in the selection.\n\t * Last position is the position that {@link module:engine/model/position~Position#isAfter is after}\n\t * any other position in the selection.\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/position~Position|null}\n\t */\n\tgetLastPosition() {\n\t\treturn this._selection.getLastPosition();\n\t}\n\n\t/**\n\t * Returns a copy of the first range in the selection.\n\t * First range is the one which {@link module:engine/model/range~Range#start start} position\n\t * {@link module:engine/model/position~Position#isBefore is before} start position of all other ranges\n\t * (not to confuse with the first range added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetFirstRange() {\n\t\treturn this._selection.getFirstRange();\n\t}\n\n\t/**\n\t * Returns a copy of the last range in the selection.\n\t * Last range is the one which {@link module:engine/model/range~Range#end end} position\n\t * {@link module:engine/model/position~Position#isAfter is after} end position of all other ranges (not to confuse with the range most\n\t * recently added to the selection).\n\t *\n\t * Returns `null` if there are no ranges in selection.\n\t *\n\t * @returns {module:engine/model/range~Range|null}\n\t */\n\tgetLastRange() {\n\t\treturn this._selection.getLastRange();\n\t}\n\n\t/**\n\t * Gets elements of type {@link module:engine/model/schema~Schema#isBlock \"block\"} touched by the selection.\n\t *\n\t * This method's result can be used for example to apply block styling to all blocks covered by this selection.\n\t *\n\t * **Note:** `getSelectedBlocks()` returns blocks that are nested in other non-block elements\n\t * but will not return blocks nested in other blocks.\n\t *\n\t * In this case the function will return exactly all 3 paragraphs (note: `<blockQuote>` is not a block itself):\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<blockQuote>\n\t *\t\t\t<paragraph>b</paragraph>\n\t *\t\t</blockQuote>\n\t *\t\t<paragraph>c]d</paragraph>\n\t *\n\t * In this case the paragraph will also be returned, despite the collapsed selection:\n\t *\n\t *\t\t<paragraph>[]a</paragraph>\n\t *\n\t * In such a scenario, however, only blocks A, B & E will be returned as blocks C & D are nested in block B:\n\t *\n\t *\t\t[<blockA></blockA>\n\t *\t\t<blockB>\n\t *\t\t\t<blockC></blockC>\n\t *\t\t\t<blockD></blockD>\n\t *\t\t</blockB>\n\t *\t\t<blockE></blockE>]\n\t *\n\t * If the selection is inside a block all the inner blocks (A & B) are returned:\n\t *\n\t * \t\t<block>\n\t *\t\t\t<blockA>[a</blockA>\n\t * \t\t\t<blockB>b]</blockB>\n\t * \t\t</block>\n\t *\n\t * **Special case**: If a selection ends at the beginning of a block, that block is not returned as from user perspective\n\t * this block wasn't selected. See [#984](https://github.com/ckeditor/ckeditor5-engine/issues/984) for more details.\n\t *\n\t *\t\t<paragraph>[a</paragraph>\n\t *\t\t<paragraph>b</paragraph>\n\t *\t\t<paragraph>]c</paragraph> // this block will not be returned\n\t *\n\t * @returns {Iterable.<module:engine/model/element~Element>}\n\t */\n\tgetSelectedBlocks() {\n\t\treturn this._selection.getSelectedBlocks();\n\t}\n\n\t/**\n\t * Returns the selected element. {@link module:engine/model/element~Element Element} is considered as selected if there is only\n\t * one range in the selection, and that range contains exactly one element.\n\t * Returns `null` if there is no selected element.\n\t *\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\tgetSelectedElement() {\n\t\treturn this._selection.getSelectedElement();\n\t}\n\n\t/**\n\t * Checks whether the selection contains the entire content of the given element. This means that selection must start\n\t * at a position {@link module:engine/model/position~Position#isTouching touching} the element's start and ends at position\n\t * touching the element's end.\n\t *\n\t * By default, this method will check whether the entire content of the selection's current root is selected.\n\t * Useful to check if e.g. the user has just pressed <kbd>Ctrl</kbd> + <kbd>A</kbd>.\n\t *\n\t * @param {module:engine/model/element~Element} [element=this.anchor.root]\n\t * @returns {Boolean}\n\t */\n\tcontainsEntireContent( element ) {\n\t\treturn this._selection.containsEntireContent( element );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by document selection.\n\t */\n\tdestroy() {\n\t\tthis._selection.destroy();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attribute keys.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetAttributeKeys() {\n\t\treturn this._selection.getAttributeKeys();\n\t}\n\n\t/**\n\t * Returns iterable that iterates over this selection's attributes.\n\t *\n\t * Attributes are returned as arrays containing two items. First one is attribute key and second is attribute value.\n\t * This format is accepted by native `Map` object and also can be passed in `Node` constructor.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\tgetAttributes() {\n\t\treturn this._selection.getAttributes();\n\t}\n\n\t/**\n\t * Gets an attribute value for given key or `undefined` if that attribute is not set on the selection.\n\t *\n\t * @param {String} key Key of attribute to look for.\n\t * @returns {*} Attribute value or `undefined`.\n\t */\n\tgetAttribute( key ) {\n\t\treturn this._selection.getAttribute( key );\n\t}\n\n\t/**\n\t * Checks if the selection has an attribute for given key.\n\t *\n\t * @param {String} key Key of attribute to check.\n\t * @returns {Boolean} `true` if attribute with given key is set on selection, `false` otherwise.\n\t */\n\thasAttribute( key ) {\n\t\treturn this._selection.hasAttribute( key );\n\t}\n\n\t/**\n\t * Refreshes selection attributes and markers according to the current position in the model.\n\t */\n\trefresh() {\n\t\tthis._selection._updateMarkers();\n\t\tthis._selection._updateAttributes( false );\n\t}\n\n\t/**\n\t * Registers a marker group prefix or a marker name to be collected in the\n\t * {@link ~DocumentSelection#markers selection markers collection}.\n\t *\n\t * See also {@link module:engine/model/markercollection~MarkerCollection#getMarkersGroup `MarkerCollection#getMarkersGroup()`}.\n\t *\n\t * @param {String} prefixOrName The marker group prefix or marker name.\n\t */\n\tobserveMarkers( prefixOrName ) {\n\t\tthis._selection.observeMarkers( prefixOrName );\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tselection.is( 'selection' ); // -> true\n\t *\t\tselection.is( 'documentSelection' ); // -> true\n\t *\t\tselection.is( 'model:selection' ); // -> true\n\t *\t\tselection.is( 'model:documentSelection' ); // -> true\n\t *\n\t *\t\tselection.is( 'view:selection' ); // -> false\n\t *\t\tselection.is( 'element' ); // -> false\n\t *\t\tselection.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'selection' ||\n\t\t\ttype == 'model:selection' ||\n\t\t\ttype == 'documentSelection' ||\n\t\t\ttype == 'model:documentSelection';\n\t}\n\n\t/**\n\t * Moves {@link module:engine/model/documentselection~DocumentSelection#focus} to the specified location.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionFocus} method.\n\t *\n\t * The location can be specified in the same form as\n\t * {@link module:engine/model/writer~Writer#createPositionAt writer.createPositionAt()} parameters.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelectionFocus\n\t * @protected\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 */\n\t_setFocus( itemOrPosition, offset ) {\n\t\tthis._selection.setFocus( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Sets this selection's ranges and direction to the specified location based on the given\n\t * {@link module:engine/model/selection~Selectable selectable}.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelection} method.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelection\n\t * @protected\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\t_setTo( selectable, placeOrOffset, options ) {\n\t\tthis._selection.setTo( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Sets attribute on the selection. If attribute with the same key already is set, it's value is overwritten.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#setSelectionAttribute} method.\n\t *\n\t * @see module:engine/model/writer~Writer#setSelectionAttribute\n\t * @protected\n\t * @param {String} key Key of the attribute to set.\n\t * @param {*} value Attribute value.\n\t */\n\t_setAttribute( key, value ) {\n\t\tthis._selection.setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes an attribute with given key from the selection.\n\t * If the given attribute was set on the selection, fires the {@link module:engine/model/selection~Selection#event:change:range}\n\t * event with removed attribute key.\n\t * Should be used only within the {@link module:engine/model/writer~Writer#removeSelectionAttribute} method.\n\t *\n\t * @see module:engine/model/writer~Writer#removeSelectionAttribute\n\t * @protected\n\t * @param {String} key Key of the attribute to remove.\n\t */\n\t_removeAttribute( key ) {\n\t\tthis._selection.removeAttribute( key );\n\t}\n\n\t/**\n\t * Returns an iterable that iterates through all selection attributes stored in current selection's parent.\n\t *\n\t * @protected\n\t * @returns {Iterable.<*>}\n\t */\n\t_getStoredAttributes() {\n\t\treturn this._selection._getStoredAttributes();\n\t}\n\n\t/**\n\t * Temporarily changes the gravity of the selection from the left to the right.\n\t *\n\t * The gravity defines from which direction the selection inherits its attributes. If it's the default left\n\t * gravity, the selection (after being moved by the 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 * 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 * @see module:engine/model/writer~Writer#overrideSelectionGravity\n\t * @protected\n\t * @returns {String} The unique id which allows restoring the gravity.\n\t */\n\t_overrideGravity() {\n\t\treturn this._selection.overrideGravity();\n\t}\n\n\t/**\n\t * Restores the {@link ~DocumentSelection#_overrideGravity overridden gravity}.\n\t *\n\t * Restoring the gravity is only possible using the unique identifier returned by\n\t * {@link ~DocumentSelection#_overrideGravity}. 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 * @see module:engine/model/writer~Writer#restoreSelectionGravity\n\t * @protected\n\t * @param {String} uid The unique id returned by {@link #_overrideGravity}.\n\t */\n\t_restoreGravity( uid ) {\n\t\tthis._selection.restoreGravity( uid );\n\t}\n\n\t/**\n\t * Generates and returns an attribute key for selection attributes store, basing on original attribute key.\n\t *\n\t * @protected\n\t * @param {String} key Attribute key to convert.\n\t * @returns {String} Converted attribute key, applicable for selection store.\n\t */\n\tstatic _getStoreAttributeKey( key ) {\n\t\treturn storePrefix + key;\n\t}\n\n\t/**\n\t * Checks whether the given attribute key is an attribute stored on an element.\n\t *\n\t * @protected\n\t * @param {String} key\n\t * @returns {Boolean}\n\t */\n\tstatic _isStoreAttributeKey( key ) {\n\t\treturn key.startsWith( storePrefix );\n\t}\n}\n\nmix( DocumentSelection, EmitterMixin );\n\n/**\n * Fired when selection range(s) changed.\n *\n * @event change:range\n * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its position\n * was directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n * changed because the structure of the model has been changed (which means an indirect change).\n * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n * which mean that they are not updated once the document changes.\n */\n\n/**\n * Fired when selection attribute changed.\n *\n * @event change:attribute\n * @param {Boolean} directChange In case of {@link module:engine/model/selection~Selection} class it is always set\n * to `true` which indicates that the selection change was caused by a direct use of selection's API.\n * The {@link module:engine/model/documentselection~DocumentSelection}, however, may change because its attributes\n * were directly changed through the {@link module:engine/model/writer~Writer writer} or because its position was\n * changed in the model and its attributes were refreshed (which means an indirect change).\n * The indirect change does not occur in case of normal (detached) selections because they are \"static\" (as \"not live\")\n * which mean that they are not updated once the document changes.\n * @param {Array.<String>} attributeKeys Array containing keys of attributes that changed.\n */\n\n/**\n * Fired when selection marker(s) changed.\n *\n * @event change:marker\n * @param {Boolean} directChange This is always set to `false` in case of `change:marker` event as there is no possibility\n * to change markers directly through {@link module:engine/model/documentselection~DocumentSelection} API.\n * See also {@link module:engine/model/documentselection~DocumentSelection#event:change:range} and\n * {@link module:engine/model/documentselection~DocumentSelection#event:change:attribute}.\n * @param {Array.<module:engine/model/markercollection~Marker>} oldMarkers Markers in which the selection was before the change.\n */\n\n// `LiveSelection` is used internally by {@link module:engine/model/documentselection~DocumentSelection} and shouldn't be used directly.\n//\n// LiveSelection` is automatically updated upon changes in the {@link module:engine/model/document~Document document}\n// to always contain valid ranges. Its attributes are inherited from the text unless set explicitly.\n//\n// Differences between {@link module:engine/model/selection~Selection} and `LiveSelection` are:\n// * there is always a range in `LiveSelection` - even if no ranges were added there is a \"default range\"\n// present in the selection,\n// * ranges added to this selection updates automatically when the document changes,\n// * attributes of `LiveSelection` are updated automatically according to selection ranges.\n//\n// @extends module:engine/model/selection~Selection\n//\nclass LiveSelection extends Selection {\n\t// Creates an empty live selection for given {@link module:engine/model/document~Document}.\n\t// @param {module:engine/model/document~Document} doc Document which owns this selection.\n\tconstructor( doc ) {\n\t\tsuper();\n\n\t\t// List of selection markers.\n\t\t// Marker is a selection marker when selection range is inside the marker range.\n\t\t//\n\t\t// @type {module:utils/collection~Collection}\n\t\tthis.markers = new Collection( { idProperty: 'name' } );\n\n\t\t// Document which owns this selection.\n\t\t//\n\t\t// @protected\n\t\t// @member {module:engine/model/model~Model}\n\t\tthis._model = doc.model;\n\n\t\t// Document which owns this selection.\n\t\t//\n\t\t// @protected\n\t\t// @member {module:engine/model/document~Document}\n\t\tthis._document = doc;\n\n\t\t// Keeps mapping of attribute name to priority with which the attribute got modified (added/changed/removed)\n\t\t// last time. Possible values of priority are: `'low'` and `'normal'`.\n\t\t//\n\t\t// Priorities are used by internal `LiveSelection` mechanisms. All attributes set using `LiveSelection`\n\t\t// attributes API are set with `'normal'` priority.\n\t\t//\n\t\t// @private\n\t\t// @member {Map} module:engine/model/liveselection~LiveSelection#_attributePriority\n\t\tthis._attributePriority = new Map();\n\n\t\t// Position to which the selection should be set if the last selection range was moved to the graveyard.\n\t\t// @private\n\t\t// @member {module:engine/model/position~Position} module:engine/model/liveselection~LiveSelection#_selectionRestorePosition\n\t\tthis._selectionRestorePosition = null;\n\n\t\t// Flag that informs whether the selection ranges have changed. It is changed on true when `LiveRange#change:range` event is fired.\n\t\t// @private\n\t\t// @member {Array} module:engine/model/liveselection~LiveSelection#_hasChangedRange\n\t\tthis._hasChangedRange = false;\n\n\t\t// Each overriding gravity adds an UID to the set and each removal removes it.\n\t\t// Gravity is overridden when there's at least one UID in the set.\n\t\t// Gravity is restored when the set is empty.\n\t\t// This is to prevent conflicts when gravity is overridden by more than one feature at the same time.\n\t\t// @private\n\t\t// @type {Set}\n\t\tthis._overriddenGravityRegister = new Set();\n\n\t\t// Prefixes of marker names that should affect `LiveSelection#markers` collection.\n\t\t// @private\n\t\t// @type {Set}\n\t\tthis._observedMarkers = new Set();\n\n\t\t// Ensure selection is correct after each operation.\n\t\tthis.listenTo( this._model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation || operation.type == 'marker' || operation.type == 'rename' || operation.type == 'noop' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Fix selection if the last range was removed from it and we have a position to which we can restore the selection.\n\t\t\tif ( this._ranges.length == 0 && this._selectionRestorePosition ) {\n\t\t\t\tthis._fixGraveyardSelection( this._selectionRestorePosition );\n\t\t\t}\n\n\t\t\t// \"Forget\" the restore position even if it was not \"used\".\n\t\t\tthis._selectionRestorePosition = null;\n\n\t\t\tif ( this._hasChangedRange ) {\n\t\t\t\tthis._hasChangedRange = false;\n\t\t\t\tthis.fire( 'change:range', { directChange: false } );\n\t\t\t}\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Ensure selection is correct and up to date after each range change.\n\t\tthis.on( 'change:range', () => {\n\t\t\tfor ( const range of this.getRanges() ) {\n\t\t\t\tif ( !this._document._validateSelectionRange( range ) ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Range from {@link module:engine/model/documentselection~DocumentSelection document selection}\n\t\t\t\t\t * starts or ends at incorrect position.\n\t\t\t\t\t *\n\t\t\t\t\t * @error document-selection-wrong-position\n\t\t\t\t\t * @param {module:engine/model/range~Range} range\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'document-selection-wrong-position',\n\t\t\t\t\t\tthis,\n\t\t\t\t\t\t{ range }\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Update markers data stored by the selection after each marker change.\n\t\t// This handles only marker changes done through marker operations (not model tree changes).\n\t\tthis.listenTo( this._model.markers, 'update', ( evt, marker, oldRange, newRange ) => {\n\t\t\tthis._updateMarker( marker, newRange );\n\t\t} );\n\n\t\t// Ensure selection is up to date after each change block.\n\t\tthis.listenTo( this._document, 'change', ( evt, batch ) => {\n\t\t\tclearAttributesStoredInElement( this._model, batch );\n\t\t} );\n\t}\n\n\tget isCollapsed() {\n\t\tconst length = this._ranges.length;\n\n\t\treturn length === 0 ? this._document._getDefaultRange().isCollapsed : super.isCollapsed;\n\t}\n\n\tget anchor() {\n\t\treturn super.anchor || this._document._getDefaultRange().start;\n\t}\n\n\tget focus() {\n\t\treturn super.focus || this._document._getDefaultRange().end;\n\t}\n\n\tget rangeCount() {\n\t\treturn this._ranges.length ? this._ranges.length : 1;\n\t}\n\n\t// Describes whether `LiveSelection` has own range(s) set, or if it is defaulted to\n\t// {@link module:engine/model/document~Document#_getDefaultRange document's default range}.\n\t//\n\t// @readonly\n\t// @type {Boolean}\n\tget hasOwnRange() {\n\t\treturn this._ranges.length > 0;\n\t}\n\n\t// When set to `true` then selection attributes on node before the caret won't be taken\n\t// into consideration while updating selection attributes.\n\t//\n\t// @protected\n\t// @type {Boolean}\n\tget isGravityOverridden() {\n\t\treturn !!this._overriddenGravityRegister.size;\n\t}\n\n\t// Unbinds all events previously bound by live selection.\n\tdestroy() {\n\t\tfor ( let i = 0; i < this._ranges.length; i++ ) {\n\t\t\tthis._ranges[ i ].detach();\n\t\t}\n\n\t\tthis.stopListening();\n\t}\n\n\t* getRanges() {\n\t\tif ( this._ranges.length ) {\n\t\t\tyield* super.getRanges();\n\t\t} else {\n\t\t\tyield this._document._getDefaultRange();\n\t\t}\n\t}\n\n\tgetFirstRange() {\n\t\treturn super.getFirstRange() || this._document._getDefaultRange();\n\t}\n\n\tgetLastRange() {\n\t\treturn super.getLastRange() || this._document._getDefaultRange();\n\t}\n\n\tsetTo( selectable, optionsOrPlaceOrOffset, options ) {\n\t\tsuper.setTo( selectable, optionsOrPlaceOrOffset, options );\n\t\tthis._updateAttributes( true );\n\t\tthis._updateMarkers();\n\t}\n\n\tsetFocus( itemOrPosition, offset ) {\n\t\tsuper.setFocus( itemOrPosition, offset );\n\t\tthis._updateAttributes( true );\n\t\tthis._updateMarkers();\n\t}\n\n\tsetAttribute( key, value ) {\n\t\tif ( this._setAttribute( key, value ) ) {\n\t\t\t// Fire event with exact data.\n\t\t\tconst attributeKeys = [ key ];\n\t\t\tthis.fire( 'change:attribute', { attributeKeys, directChange: true } );\n\t\t}\n\t}\n\n\tremoveAttribute( key ) {\n\t\tif ( this._removeAttribute( key ) ) {\n\t\t\t// Fire event with exact data.\n\t\t\tconst attributeKeys = [ key ];\n\t\t\tthis.fire( 'change:attribute', { attributeKeys, directChange: true } );\n\t\t}\n\t}\n\n\toverrideGravity() {\n\t\tconst overrideUid = uid();\n\n\t\t// Remember that another overriding has been requested. It will need to be removed\n\t\t// before the gravity is to be restored.\n\t\tthis._overriddenGravityRegister.add( overrideUid );\n\n\t\tif ( this._overriddenGravityRegister.size === 1 ) {\n\t\t\tthis._updateAttributes( true );\n\t\t}\n\n\t\treturn overrideUid;\n\t}\n\n\trestoreGravity( uid ) {\n\t\tif ( !this._overriddenGravityRegister.has( uid ) ) {\n\t\t\t/**\n\t\t\t * Restoring gravity for an unknown UID is not possible. Make sure you are using a correct\n\t\t\t * UID obtained from the {@link module:engine/model/writer~Writer#overrideSelectionGravity} to restore.\n\t\t\t *\n\t\t\t * @error document-selection-gravity-wrong-restore\n\t\t\t * @param {String} uid The unique identifier returned by\n\t\t\t * {@link module:engine/model/documentselection~DocumentSelection#_overrideGravity}.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'document-selection-gravity-wrong-restore',\n\t\t\t\tthis,\n\t\t\t\t{ uid }\n\t\t\t);\n\t\t}\n\n\t\tthis._overriddenGravityRegister.delete( uid );\n\n\t\t// Restore gravity only when all overriding have been restored.\n\t\tif ( !this.isGravityOverridden ) {\n\t\t\tthis._updateAttributes( true );\n\t\t}\n\t}\n\n\tobserveMarkers( prefixOrName ) {\n\t\tthis._observedMarkers.add( prefixOrName );\n\t\tthis._updateMarkers();\n\t}\n\n\t_popRange() {\n\t\tthis._ranges.pop().detach();\n\t}\n\n\t_pushRange( range ) {\n\t\tconst liveRange = this._prepareRange( range );\n\n\t\t// `undefined` is returned when given `range` is in graveyard root.\n\t\tif ( liveRange ) {\n\t\t\tthis._ranges.push( liveRange );\n\t\t}\n\t}\n\n\t// Prepares given range to be added to selection. Checks if it is correct,\n\t// converts it to {@link module:engine/model/liverange~LiveRange LiveRange}\n\t// and sets listeners listening to the range's change event.\n\t//\n\t// @private\n\t// @param {module:engine/model/range~Range} range\n\t_prepareRange( range ) {\n\t\tthis._checkRange( range );\n\n\t\tif ( range.root == this._document.graveyard ) {\n\t\t\t// @if CK_DEBUG // console.warn( 'Trying to add a Range that is in the graveyard root. Range rejected.' );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst liveRange = LiveRange.fromRange( range );\n\n\t\t// If selection range is moved to the graveyard remove it from the selection object.\n\t\t// Also, save some data that can be used to restore selection later, on `Model#applyOperation` event.\n\t\tliveRange.on( 'change:range', ( evt, oldRange, data ) => {\n\t\t\tthis._hasChangedRange = true;\n\n\t\t\tif ( liveRange.root == this._document.graveyard ) {\n\t\t\t\tthis._selectionRestorePosition = data.deletionPosition;\n\n\t\t\t\tconst index = this._ranges.indexOf( liveRange );\n\t\t\t\tthis._ranges.splice( index, 1 );\n\t\t\t\tliveRange.detach();\n\t\t\t}\n\t\t} );\n\n\t\treturn liveRange;\n\t}\n\n\t_updateMarkers() {\n\t\tif ( !this._observedMarkers.size ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markers = [];\n\t\tlet changed = false;\n\n\t\tfor ( const marker of this._model.markers ) {\n\t\t\tconst markerGroup = marker.name.split( ':', 1 )[ 0 ];\n\n\t\t\tif ( !this._observedMarkers.has( markerGroup ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tfor ( const selectionRange of this.getRanges() ) {\n\t\t\t\tif ( markerRange.containsRange( selectionRange, !selectionRange.isCollapsed ) ) {\n\t\t\t\t\tmarkers.push( marker );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst oldMarkers = Array.from( this.markers );\n\n\t\tfor ( const marker of markers ) {\n\t\t\tif ( !this.markers.has( marker ) ) {\n\t\t\t\tthis.markers.add( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tfor ( const marker of Array.from( this.markers ) ) {\n\t\t\tif ( !markers.includes( marker ) ) {\n\t\t\t\tthis.markers.remove( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( changed ) {\n\t\t\tthis.fire( 'change:marker', { oldMarkers, directChange: false } );\n\t\t}\n\t}\n\n\t_updateMarker( marker, markerRange ) {\n\t\tconst markerGroup = marker.name.split( ':', 1 )[ 0 ];\n\n\t\tif ( !this._observedMarkers.has( markerGroup ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet changed = false;\n\n\t\tconst oldMarkers = Array.from( this.markers );\n\t\tconst hasMarker = this.markers.has( marker );\n\n\t\tif ( !markerRange ) {\n\t\t\tif ( hasMarker ) {\n\t\t\t\tthis.markers.remove( marker );\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t} else {\n\t\t\tlet contained = false;\n\n\t\t\tfor ( const selectionRange of this.getRanges() ) {\n\t\t\t\tif ( markerRange.containsRange( selectionRange, !selectionRange.isCollapsed ) ) {\n\t\t\t\t\tcontained = true;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( contained && !hasMarker ) {\n\t\t\t\tthis.markers.add( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t} else if ( !contained && hasMarker ) {\n\t\t\t\tthis.markers.remove( marker );\n\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( changed ) {\n\t\t\tthis.fire( 'change:marker', { oldMarkers, directChange: false } );\n\t\t}\n\t}\n\n\t// Updates this selection attributes according to its ranges and the {@link module:engine/model/document~Document model document}.\n\t//\n\t// @protected\n\t// @param {Boolean} clearAll\n\t// @fires change:attribute\n\t_updateAttributes( clearAll ) {\n\t\tconst newAttributes = toMap( this._getSurroundingAttributes() );\n\t\tconst oldAttributes = toMap( this.getAttributes() );\n\n\t\tif ( clearAll ) {\n\t\t\t// If `clearAll` remove all attributes and reset priorities.\n\t\t\tthis._attributePriority = new Map();\n\t\t\tthis._attrs = new Map();\n\t\t} else {\n\t\t\t// If not, remove only attributes added with `low` priority.\n\t\t\tfor ( const [ key, priority ] of this._attributePriority ) {\n\t\t\t\tif ( priority == 'low' ) {\n\t\t\t\t\tthis._attrs.delete( key );\n\t\t\t\t\tthis._attributePriority.delete( key );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis._setAttributesTo( newAttributes );\n\n\t\t// Let's evaluate which attributes really changed.\n\t\tconst changed = [];\n\n\t\t// First, loop through all attributes that are set on selection right now.\n\t\t// Check which of them are different than old attributes.\n\t\tfor ( const [ newKey, newValue ] of this.getAttributes() ) {\n\t\t\tif ( !oldAttributes.has( newKey ) || oldAttributes.get( newKey ) !== newValue ) {\n\t\t\t\tchanged.push( newKey );\n\t\t\t}\n\t\t}\n\n\t\t// Then, check which of old attributes got removed.\n\t\tfor ( const [ oldKey ] of oldAttributes ) {\n\t\t\tif ( !this.hasAttribute( oldKey ) ) {\n\t\t\t\tchanged.push( oldKey );\n\t\t\t}\n\t\t}\n\n\t\t// Fire event with exact data (fire only if anything changed).\n\t\tif ( changed.length > 0 ) {\n\t\t\tthis.fire( 'change:attribute', { attributeKeys: changed, directChange: false } );\n\t\t}\n\t}\n\n\t// Internal method for setting `LiveSelection` attribute. Supports attribute priorities (through `directChange`\n\t// parameter).\n\t//\n\t// @private\n\t// @param {String} key Attribute key.\n\t// @param {*} value Attribute value.\n\t// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change\n\t// is caused by `Batch` API.\n\t// @returns {Boolean} Whether value has changed.\n\t_setAttribute( key, value, directChange = true ) {\n\t\tconst priority = directChange ? 'normal' : 'low';\n\n\t\tif ( priority == 'low' && this._attributePriority.get( key ) == 'normal' ) {\n\t\t\t// Priority too low.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst oldValue = super.getAttribute( key );\n\n\t\t// Don't do anything if value has not changed.\n\t\tif ( oldValue === value ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._attrs.set( key, value );\n\n\t\t// Update priorities map.\n\t\tthis._attributePriority.set( key, priority );\n\n\t\treturn true;\n\t}\n\n\t// Internal method for removing `LiveSelection` attribute. Supports attribute priorities (through `directChange`\n\t// parameter).\n\t//\n\t// NOTE: Even if attribute is not present in the selection but is provided to this method, it's priority will\n\t// be changed according to `directChange` parameter.\n\t//\n\t// @private\n\t// @param {String} key Attribute key.\n\t// @param {Boolean} [directChange=true] `true` if the change is caused by `Selection` API, `false` if change\n\t// is caused by `Batch` API.\n\t// @returns {Boolean} Whether attribute was removed. May not be true if such attributes didn't exist or the\n\t// existing attribute had higher priority.\n\t_removeAttribute( key, directChange = true ) {\n\t\tconst priority = directChange ? 'normal' : 'low';\n\n\t\tif ( priority == 'low' && this._attributePriority.get( key ) == 'normal' ) {\n\t\t\t// Priority too low.\n\t\t\treturn false;\n\t\t}\n\n\t\t// Update priorities map.\n\t\tthis._attributePriority.set( key, priority );\n\n\t\t// Don't do anything if value has not changed.\n\t\tif ( !super.hasAttribute( key ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._attrs.delete( key );\n\n\t\treturn true;\n\t}\n\n\t// Internal method for setting multiple `LiveSelection` attributes. Supports attribute priorities (through\n\t// `directChange` parameter).\n\t//\n\t// @private\n\t// @param {Map.<String,*>} attrs Iterable object containing attributes to be set.\n\t// @returns {Set.<String>} Changed attribute keys.\n\t_setAttributesTo( attrs ) {\n\t\tconst changed = new Set();\n\n\t\tfor ( const [ oldKey, oldValue ] of this.getAttributes() ) {\n\t\t\t// Do not remove attribute if attribute with same key and value is about to be set.\n\t\t\tif ( attrs.get( oldKey ) === oldValue ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// All rest attributes will be removed so changed attributes won't change .\n\t\t\tthis._removeAttribute( oldKey, false );\n\t\t}\n\n\t\tfor ( const [ key, value ] of attrs ) {\n\t\t\t// Attribute may not be set because of attributes or because same key/value is already added.\n\t\t\tconst gotAdded = this._setAttribute( key, value, false );\n\n\t\t\tif ( gotAdded ) {\n\t\t\t\tchanged.add( key );\n\t\t\t}\n\t\t}\n\n\t\treturn changed;\n\t}\n\n\t// Returns an iterable that iterates through all selection attributes stored in current selection's parent.\n\t//\n\t// @protected\n\t// @returns {Iterable.<*>}\n\t* _getStoredAttributes() {\n\t\tconst selectionParent = this.getFirstPosition().parent;\n\n\t\tif ( this.isCollapsed && selectionParent.isEmpty ) {\n\t\t\tfor ( const key of selectionParent.getAttributeKeys() ) {\n\t\t\t\tif ( key.startsWith( storePrefix ) ) {\n\t\t\t\t\tconst realKey = key.substr( storePrefix.length );\n\n\t\t\t\t\tyield [ realKey, selectionParent.getAttribute( key ) ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Checks model text nodes that are closest to the selection's first position and returns attributes of first\n\t// found element. If there are no text nodes in selection's first position parent, it returns selection\n\t// attributes stored in that parent.\n\t//\n\t// @private\n\t// @returns {Iterable.<*>} Collection of attributes.\n\t_getSurroundingAttributes() {\n\t\tconst position = this.getFirstPosition();\n\t\tconst schema = this._model.schema;\n\n\t\tlet attrs = null;\n\n\t\tif ( !this.isCollapsed ) {\n\t\t\t// 1. If selection is a range...\n\t\t\tconst range = this.getFirstRange();\n\n\t\t\t// ...look for a first character node in that range and take attributes from it.\n\t\t\tfor ( const value of range ) {\n\t\t\t\t// If the item is an object, we don't want to get attributes from its children.\n\t\t\t\tif ( value.item.is( 'element' ) && schema.isObject( value.item ) ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif ( value.type == 'text' ) {\n\t\t\t\t\tattrs = value.item.getAttributes();\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// 2. If the selection is a caret or the range does not contain a character node...\n\n\t\t\tconst nodeBefore = position.textNode ? position.textNode : position.nodeBefore;\n\t\t\tconst nodeAfter = position.textNode ? position.textNode : position.nodeAfter;\n\n\t\t\t// When gravity is overridden then don't take node before into consideration.\n\t\t\tif ( !this.isGravityOverridden ) {\n\t\t\t\t// ...look at the node before caret and take attributes from it if it is a character node.\n\t\t\t\tattrs = getAttrsIfCharacter( nodeBefore );\n\t\t\t}\n\n\t\t\t// 3. If not, look at the node after caret...\n\t\t\tif ( !attrs ) {\n\t\t\t\tattrs = getAttrsIfCharacter( nodeAfter );\n\t\t\t}\n\n\t\t\t// 4. If not, try to find the first character on the left, that is in the same node.\n\t\t\t// When gravity is overridden then don't take node before into consideration.\n\t\t\tif ( !this.isGravityOverridden && !attrs ) {\n\t\t\t\tlet node = nodeBefore;\n\n\t\t\t\twhile ( node && !schema.isInline( node ) && !attrs ) {\n\t\t\t\t\tnode = node.previousSibling;\n\t\t\t\t\tattrs = getAttrsIfCharacter( node );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 5. If not found, try to find the first character on the right, that is in the same node.\n\t\t\tif ( !attrs ) {\n\t\t\t\tlet node = nodeAfter;\n\n\t\t\t\twhile ( node && !schema.isInline( node ) && !attrs ) {\n\t\t\t\t\tnode = node.nextSibling;\n\t\t\t\t\tattrs = getAttrsIfCharacter( node );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// 6. If not found, selection should retrieve attributes from parent.\n\t\t\tif ( !attrs ) {\n\t\t\t\tattrs = this._getStoredAttributes();\n\t\t\t}\n\t\t}\n\n\t\treturn attrs;\n\t}\n\n\t// Fixes the selection after all its ranges got removed.\n\t//\n\t// @private\n\t// @param {module:engine/model/position~Position} deletionPosition Position where the deletion happened.\n\t_fixGraveyardSelection( deletionPosition ) {\n\t\t// Find a range that is a correct selection range and is closest to the position where the deletion happened.\n\t\tconst selectionRange = this._model.schema.getNearestSelectionRange( deletionPosition );\n\n\t\t// If nearest valid selection range has been found - add it in the place of old range.\n\t\tif ( selectionRange ) {\n\t\t\t// Check the range, convert it to live range, bind events, etc.\n\t\t\tthis._pushRange( selectionRange );\n\t\t}\n\t\t// If nearest valid selection range cannot be found don't add any range. Selection will be set to the default range.\n\t}\n}\n\n// Helper function for {@link module:engine/model/liveselection~LiveSelection#_updateAttributes}.\n//\n// It takes model item, checks whether it is a text node (or text proxy) and, if so, returns it's attributes. If not, returns `null`.\n//\n// @param {module:engine/model/item~Item|null} node\n// @returns {Boolean}\nfunction getAttrsIfCharacter( node ) {\n\tif ( node instanceof TextProxy || node instanceof Text ) {\n\t\treturn node.getAttributes();\n\t}\n\n\treturn null;\n}\n\n// Removes selection attributes from element which is not empty anymore.\n//\n// @param {module:engine/model/model~Model} model\n// @param {module:engine/model/batch~Batch} batch\nfunction clearAttributesStoredInElement( model, batch ) {\n\tconst differ = model.document.differ;\n\n\tfor ( const entry of differ.getChanges() ) {\n\t\tif ( entry.type != 'insert' ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst changeParent = entry.position.parent;\n\t\tconst isNoLongerEmpty = entry.length === changeParent.maxOffset;\n\n\t\tif ( isNoLongerEmpty ) {\n\t\t\tmodel.enqueueChange( batch, writer => {\n\t\t\t\tconst storedAttributes = Array.from( changeParent.getAttributeKeys() )\n\t\t\t\t\t.filter( key => key.startsWith( storePrefix ) );\n\n\t\t\t\tfor ( const key of storedAttributes ) {\n\t\t\t\t\twriter.removeAttribute( key, changeParent );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/conversionhelpers\n */\n\n/**\n * Base class for conversion helpers.\n */\nexport default class ConversionHelpers {\n\t/**\n\t * Creates a conversion helpers instance.\n\t *\n\t * @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher>} dispatchers\n\t */\n\tconstructor( dispatchers ) {\n\t\tthis._dispatchers = dispatchers;\n\t}\n\n\t/**\n\t * Registers a conversion helper.\n\t *\n\t * **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}`\n\t * method description.\n\t *\n\t * @param {Function} conversionHelper The function to be called on event.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tadd( conversionHelper ) {\n\t\tfor ( const dispatcher of this._dispatchers ) {\n\t\t\tconversionHelper( dispatcher );\n\t\t}\n\n\t\treturn this;\n\t}\n}\n","import baseClone from './_baseClone.js';\n\n/** Used to compose bitmasks for cloning. */\nvar CLONE_DEEP_FLAG = 1,\n CLONE_SYMBOLS_FLAG = 4;\n\n/**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\nfunction cloneDeep(value) {\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);\n}\n\nexport default cloneDeep;\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 * Contains downcast (model-to-view) converters for {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}.\n *\n * @module engine/conversion/downcasthelpers\n */\n\nimport ModelRange from '../model/range';\nimport ModelSelection from '../model/selection';\nimport ModelElement from '../model/element';\n\nimport ViewAttributeElement from '../view/attributeelement';\nimport DocumentSelection from '../model/documentselection';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * Downcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class DowncastHelpers extends ConversionHelpers {\n\t/**\n\t * Model element to view element conversion helper.\n\t *\n\t * This conversion results in creating a view element. For example, model `<paragraph>Foo</paragraph>` becomes `<p>Foo</p>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'div',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'fancyParagraph',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: ( modelElement, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createContainerElement( 'h' + modelElement.getAttribute( 'level' ) );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The element-to-element conversion supports the reconversion mechanism. This is helpful in the conversion to complex view structures\n\t * where multiple atomic element-to-element and attribute-to-attribute or attribute-to-element could be used. By specifying\n\t * `triggerBy()` events you can trigger reconverting the model to full view tree structures at once.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).elementToElement( {\n\t *\t\t\tmodel: 'complex',\n\t *\t\t\tview: ( modelElement, conversionApi ) => createComplexViewFromModel( modelElement, conversionApi ),\n\t *\t\t\ttriggerBy: {\n\t *\t\t\t\tattributes: [ 'foo', 'bar' ],\n\t *\t\t\t\tchildren: [ 'slot' ]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * You can read more about element-to-element conversion in the\n\t * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion} guide.\n\t *\n\t * @method #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model element to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n\t * that takes the model element and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as parameters and returns a view container element.\n\t * @param {Object} [config.triggerBy] Reconversion triggers. At least one trigger must be defined.\n\t * @param {Array.<String>} config.triggerBy.attributes The name of the element's attributes whose change will trigger element\n\t * reconversion.\n\t * @param {Array.<String>} config.triggerBy.children The name of direct children whose adding or removing will trigger element\n\t * reconversion.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( downcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view element conversion helper.\n\t *\n\t * This conversion results in wrapping view nodes with a view attribute element. For example, a model text node with\n\t * `\"Foo\"` as data and the `bold` attribute becomes `<strong>Foo</strong>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'b',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'invert',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'font-light', 'bg-dark' ]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalues: [ 'big', 'small' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tbig: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '1.2em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '0.8em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: ( modelAttributeValue, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'font-weight:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'color',\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: ( modelAttributeValue, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createAttributeElement( 'span', {\n\t *\t\t\t\t\tstyle: 'color:' + modelAttributeValue\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n\t * of `String`s with possible values if the model attribute is an enumerable.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n\t * that takes the model attribute value and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as parameters and returns a view\n\t * attribute element. If `config.model.values` is given, `config.view` should be an object assigning values from `config.model.values`\n\t * to view element definitions or functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToElement( config ) {\n\t\treturn this.add( downcastAttributeToElement( config ) );\n\t}\n\n\t/**\n\t * Model attribute to view attribute conversion helper.\n\t *\n\t * This conversion results in adding an attribute to a view node, basing on an attribute from a model node. For example,\n\t * `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>`.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tview: 'href',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'source'\n\t *\t\t\t},\n\t *\t\t\tview: 'src'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'styled',\n\t *\t\t\t\tvalues: [ 'dark', 'light' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tdark: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-dark' ]\n\t *\t\t\t\t},\n\t *\t\t\t\tlight: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'styled', 'styled-light' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'styled',\n\t *\t\t\tview: modelAttributeValue => ( {\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: 'styled-' + modelAttributeValue\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t * **Note**: Downcasting to a style property requires providing `value` as an object:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t *\t\t\tmodel: 'lineHeight',\n\t *\t\t\tview: modelAttributeValue => ( {\n\t *\t\t\t\tkey: 'style',\n\t *\t\t\t\tvalue: {\n\t *\t\t\t\t\t'line-height': modelAttributeValue,\n\t *\t\t\t\t\t'border-bottom': '1px dotted #ba2'\n\t *\t\t\t\t}\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n\t * the attribute key, possible values and, optionally, an element name to convert from.\n\t * @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n\t * the model attribute value and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as parameters and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n\t * array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n\t * If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n\t * `{ key, value }` objects or a functions.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( downcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * Model marker to view element conversion helper.\n\t *\n\t * **Note**: This method should be used only for editing downcast. For data downcast, use\n\t * {@link #markerToData `#markerToData()`} that produces valid HTML data.\n\t *\n\t * This conversion results in creating a view element on the boundaries of the converted marker. If the converted marker\n\t * is collapsed, only one element is created. For example, model marker set like this: `<paragraph>F[oo b]ar</paragraph>`\n\t * becomes `<p>F<span data-marker=\"search\"></span>oo b<span data-marker=\"search\"></span>ar</p>` in the view.\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'marker-search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: 'search-result',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tattributes: {\n\t *\t\t\t\t\t'data-marker': 'search'\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tview: ( markerData, conversionApi ) => {\n\t *\t\t\t\tconst { writer } = conversionApi;\n\t *\n\t *\t\t\t\treturn writer.createUIElement( 'span', {\n\t *\t\t\t\t\t'data-marker': 'search',\n\t *\t\t\t\t\t'data-start': markerData.isOpening\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate both boundary elements. The function\n\t * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and should return an instance of the\n\t * {@link module:engine/view/uielement~UIElement view UI element}. The `data` object and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi `conversionApi`} are passed from\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}. Additionally,\n\t * the `data.isOpening` parameter is passed, which is set to `true` for the marker start boundary element, and `false` to\n\t * the marker end boundary element.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function that\n\t * takes the model marker data and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and returns a view UI element.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToElement( config ) {\n\t\treturn this.add( downcastMarkerToElement( config ) );\n\t}\n\n\t/**\n\t * Model marker to highlight conversion helper.\n\t *\n\t * This conversion results in creating a highlight on view nodes. For this kind of conversion,\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} should be provided.\n\t *\n\t * For text nodes, a `<span>` {@link module:engine/view/attributeelement~AttributeElement} is created and it wraps all text nodes\n\t * in the converted marker range. For example, a model marker set like this: `<paragraph>F[oo b]ar</paragraph>` becomes\n\t * `<p>F<span class=\"comment\">oo b</span>ar</p>` in the view.\n\t *\n\t * {@link module:engine/view/containerelement~ContainerElement} may provide a custom way of handling highlight. Most often,\n\t * the element itself is given classes and attributes described in the highlight descriptor (instead of being wrapped in `<span>`).\n\t * For example, a model marker set like this: `[<image src=\"foo.jpg\"></image>]` becomes `<img src=\"foo.jpg\" class=\"comment\"></img>`\n\t * in the view.\n\t *\n\t * For container elements, the conversion is two-step. While the converter processes the highlight descriptor and passes it\n\t * to a container element, it is the container element instance itself that applies values from the highlight descriptor.\n\t * So, in a sense, the converter takes care of stating what should be applied on what, while the element decides how to apply that.\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( { model: 'comment', view: { classes: 'comment' } } );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: { classes: 'comment' },\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'downcast' ).markerToHighlight( {\n\t *\t\t\tmodel: 'comment',\n\t *\t\t\tview: ( data, conversionApi ) => {\n\t *\t\t\t\t// Assuming that the marker name is in a form of comment:commentType:commentId.\n\t *\t\t\t\tconst [ , commentType, commentId ] = data.markerName.split( ':' );\n\t *\n\t *\t\t\t\treturn {\n\t *\t\t\t\t\tclasses: [ 'comment', 'comment-' + commentType ],\n\t *\t\t\t\t\tattributes: { 'data-comment-id': commentId }\n\t *\t\t\t\t};\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * If a function is passed as the `config.view` parameter, it will be used to generate the highlight descriptor. The function\n\t * receives the `data` object and {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API}\n\t * as a parameters and should return a\n\t * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor}.\n\t * The `data` object properties are passed from {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker}.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToHighlight\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n\t * that will be used for highlighting or a function that takes the model marker data and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a parameters\n\t * and returns a highlight descriptor.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToHighlight( config ) {\n\t\treturn this.add( downcastMarkerToHighlight( config ) );\n\t}\n\n\t/**\n\t * Model marker converter for data downcast.\n\t *\n\t * This conversion creates a representation for model marker boundaries in the view:\n\t *\n\t * * If the marker boundary is at a position where text nodes are allowed, then a view element with the specified tag name\n\t * and `name` attribute is added at this position.\n\t * * In other cases, a specified attribute is set on a view element that is before or after the marker boundary.\n\t *\n\t * Typically, marker names use the `group:uniqueId:otherData` convention. For example: `comment:e34zfk9k2n459df53sjl34:zx32c`.\n\t * The default configuration for this conversion is that the first part is the `group` part and the rest of\n\t * the marker name becomes the `name` part.\n\t *\n\t * Tag and attribute names and values are generated from the marker name:\n\t *\n\t * * Templates for attributes are `data-[group]-start-before=\"[name]\"`, `data-[group]-start-after=\"[name]\"`,\n\t * `data-[group]-end-before=\"[name]\"` and `data-[group]-end-after=\"[name]\"`.\n\t * * Templates for view elements are `<[group]-start name=\"[name]\">` and `<[group]-end name=\"[name]\">`.\n\t *\n\t * Attributes mark whether the given marker's start or end boundary is before or after the given element.\n\t * Attributes `data-[group]-start-before` and `data-[group]-end-after` are favored.\n\t * The other two are used when the former two cannot be used.\n\t *\n\t * The conversion configuration can take a function that will generate different group and name parts.\n\t * If such function is set as the `config.view` parameter, it is passed a marker name and it is expected to return an object with two\n\t * properties: `group` and `name`. If the function returns a falsy value, the conversion will not take place.\n\t *\n\t * Basic usage:\n\t *\n\t *\t\t// Using the default conversion.\n\t *\t\t// In this case, all markers whose name starts with 'comment:' will be converted.\n\t *\t\t// The `group` parameter will be set to `comment`.\n\t *\t\t// The `name` parameter will be the rest of the marker name (without `:`).\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t} );\n\t *\n\t * An example of a view that may be generated by this conversion (assuming a marker with the name `comment:commentId:uid` marked\n\t * by `[]`):\n\t *\n\t *\t\t// Model:\n\t *\t\t<paragraph>Foo[bar</paragraph>\n\t *\t\t<image src=\"abc.jpg\"></image>]\n\t *\n\t *\t\t// View:\n\t *\t\t<p>Foo<comment-start name=\"commentId:uid\"></comment-start>bar</p>\n\t *\t\t<figure data-comment-end-after=\"commentId:uid\" class=\"image\"><img src=\"abc.jpg\" /></figure>\n\t *\n\t * In the example above, the comment starts before \"bar\" and ends after the image.\n\t *\n\t * If the `name` part is empty, the following view may be generated:\n\t *\n\t *\t\t<p>Foo <myMarker-start></myMarker-start>bar</p>\n\t *\t\t<figure data-myMarker-end-after=\"\" class=\"image\"><img src=\"abc.jpg\" /></figure>\n\t *\n\t * **Note:** A situation where some markers have the `name` part and some do not have it is incorrect and should be avoided.\n\t *\n\t * Examples where `data-group-start-after` and `data-group-end-before` are used:\n\t *\n\t *\t\t// Model:\n\t *\t\t<blockQuote>[]<paragraph>Foo</paragraph></blockQuote>\n\t *\n\t * \t\t// View:\n\t *\t\t<blockquote><p data-group-end-before=\"name\" data-group-start-before=\"name\">Foo</p></blockquote>\n\t *\n\t * Similarly, when a marker is collapsed after the last element:\n\t *\n\t *\t\t// Model:\n\t *\t\t<blockQuote><paragraph>Foo</paragraph>[]</blockQuote>\n\t *\n\t *\t\t// View:\n\t *\t\t<blockquote><p data-group-end-after=\"name\" data-group-start-after=\"name\">Foo</p></blockquote>\n\t *\n\t * When there are multiple markers from the same group stored in the same attribute of the same element, their\n\t * name parts are put together in the attribute value, for example: `data-group-start-before=\"name1,name2,name3\"`.\n\t *\n\t * Other examples of usage:\n\t *\n\t *\t\t// Using a custom function which is the same as the default conversion:\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t\tview: markerName => ( {\n\t *\t\t\t\tgroup: 'comment',\n\t *\t\t\t\tname: markerName.substr( 8 ) // Removes 'comment:' part.\n\t *\t\t\t} )\n\t *\t\t} );\n\t *\n\t *\t\t// Using the converter priority:\n\t *\t\teditor.conversion.for( 'dataDowncast' ).markerToData( {\n\t *\t\t\tmodel: 'comment'\n\t *\t\t\tview: markerName => ( {\n\t *\t\t\t\tgroup: 'comment',\n\t *\t\t\t\tname: markerName.substr( 8 ) // Removes 'comment:' part.\n\t *\t\t\t} ),\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t * This kind of conversion is useful for saving data into the database, so it should be used in the data conversion pipeline.\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #markerToData\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.model The name of the model marker (or model marker group) to convert.\n\t * @param {Function} [config.view] A function that takes the model marker name and\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi downcast conversion API} as a parameters\n\t * and returns an object with the `group` and `name` properties.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers}\n\t */\n\tmarkerToData( config ) {\n\t\treturn this.add( downcastMarkerToData( config ) );\n\t}\n}\n\n/**\n * Function factory that creates a default downcast converter for text insertion changes.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'insert:$text', insertText() );\n *\n * @returns {Function} Insert text event converter.\n */\nexport function insertText() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\t\tconst viewText = viewWriter.createText( data.item.data );\n\n\t\tviewWriter.insert( viewPosition, viewText );\n\t};\n}\n\n/**\n * Function factory that creates a default downcast converter for node remove changes.\n *\n *\t\tmodelDispatcher.on( 'remove', remove() );\n *\n * @returns {Function} Remove event converter.\n */\nexport function remove() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Find view range start position by mapping model position at which the remove happened.\n\t\tconst viewStart = conversionApi.mapper.toViewPosition( data.position );\n\n\t\tconst modelEnd = data.position.getShiftedBy( data.length );\n\t\tconst viewEnd = conversionApi.mapper.toViewPosition( modelEnd, { isPhantom: true } );\n\n\t\tconst viewRange = conversionApi.writer.createRange( viewStart, viewEnd );\n\n\t\t// Trim the range to remove in case some UI elements are on the view range boundaries.\n\t\tconst removed = conversionApi.writer.remove( viewRange.getTrimmed() );\n\n\t\t// After the range is removed, unbind all view elements from the model.\n\t\t// Range inside view document fragment is used to unbind deeply.\n\t\tfor ( const child of conversionApi.writer.createRangeIn( removed ).getItems() ) {\n\t\t\tconversionApi.mapper.unbindViewElement( child );\n\t\t}\n\t};\n}\n\n/**\n * Creates a `<span>` {@link module:engine/view/attributeelement~AttributeElement view attribute element} from the information\n * provided by the {@link module:engine/conversion/downcasthelpers~HighlightDescriptor highlight descriptor} object. If a priority\n * is not provided in the descriptor, the default priority will be used.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n * @returns {module:engine/view/attributeelement~AttributeElement}\n */\nexport function createViewElementFromHighlightDescriptor( writer, descriptor ) {\n\tconst viewElement = writer.createAttributeElement( 'span', descriptor.attributes );\n\n\tif ( descriptor.classes ) {\n\t\tviewElement._addClass( descriptor.classes );\n\t}\n\n\tif ( descriptor.priority ) {\n\t\tviewElement._priority = descriptor.priority;\n\t}\n\n\tviewElement._id = descriptor.id;\n\n\treturn viewElement;\n}\n\n/**\n * Function factory that creates a converter which converts a non-collapsed {@link module:engine/model/selection~Selection model selection}\n * to a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object and maps model positions from the selection to view positions.\n *\n *\t\tmodelDispatcher.on( 'selection', convertRangeSelection() );\n *\n * @returns {Function} Selection converter.\n */\nexport function convertRangeSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewRanges = [];\n\n\t\tfor ( const range of selection.getRanges() ) {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( range );\n\t\t\tviewRanges.push( viewRange );\n\t\t}\n\n\t\tconversionApi.writer.setSelection( viewRanges, { backward: selection.isBackward } );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts a collapsed {@link module:engine/model/selection~Selection model selection} to\n * a {@link module:engine/view/documentselection~DocumentSelection view selection}. The converter consumes appropriate\n * value from the `consumable` object, maps the model selection position to the view position and breaks\n * {@link module:engine/view/attributeelement~AttributeElement attribute elements} at the selection position.\n *\n *\t\tmodelDispatcher.on( 'selection', convertCollapsedSelection() );\n *\n * An example of the view state before and after converting the collapsed selection:\n *\n *\t\t <p><strong>f^oo<strong>bar</p>\n *\t\t-> <p><strong>f</strong>^<strong>oo</strong>bar</p>\n *\n * By breaking attribute elements like `<strong>`, the selection is in a correct element. Then, when the selection attribute is\n * converted, broken attributes might be merged again, or the position where the selection is may be wrapped\n * with different, appropriate attribute elements.\n *\n * See also {@link module:engine/conversion/downcasthelpers~clearAttributes} which does a clean-up\n * by merging attributes.\n *\n * @returns {Function} Selection converter.\n */\nexport function convertCollapsedSelection() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst selection = data.selection;\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( selection, 'selection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst modelPosition = selection.getFirstPosition();\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\t\tconst brokenPosition = viewWriter.breakAttributes( viewPosition );\n\n\t\tviewWriter.setSelection( brokenPosition );\n\t};\n}\n\n/**\n * Function factory that creates a converter which clears artifacts after the previous\n * {@link module:engine/model/selection~Selection model selection} conversion. It removes all empty\n * {@link module:engine/view/attributeelement~AttributeElement view attribute elements} and merges sibling attributes at all start and end\n * positions of all ranges.\n *\n *\t\t <p><strong>^</strong></p>\n *\t\t-> <p>^</p>\n *\n *\t\t <p><strong>foo</strong>^<strong>bar</strong>bar</p>\n *\t\t-> <p><strong>foo^bar<strong>bar</p>\n *\n *\t\t <p><strong>foo</strong><em>^</em><strong>bar</strong>bar</p>\n *\t\t-> <p><strong>foo^bar<strong>bar</p>\n *\n * This listener should be assigned before any converter for the new selection:\n *\n *\t\tmodelDispatcher.on( 'selection', clearAttributes() );\n *\n * See {@link module:engine/conversion/downcasthelpers~convertCollapsedSelection}\n * which does the opposite by breaking attributes in the selection position.\n *\n * @returns {Function} Selection converter.\n */\nexport function clearAttributes() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tfor ( const range of viewSelection.getRanges() ) {\n\t\t\t// Not collapsed selection should not have artifacts.\n\t\t\tif ( range.isCollapsed ) {\n\t\t\t\t// Position might be in the node removed by the view writer.\n\t\t\t\tif ( range.end.parent.isAttached() ) {\n\t\t\t\t\tconversionApi.writer.mergeAttributes( range.start );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tviewWriter.setSelection( null );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n * It can also be used to convert selection attributes. In that case, an empty attribute element will be created and the\n * selection will be put inside it.\n *\n * Attributes from the model are converted to a view element that will be wrapping these view nodes that are bound to\n * model elements having the given attribute. This is useful for attributes like `bold` that may be set on text nodes in the model\n * but are represented as an element in the view:\n *\n *\t\t[paragraph] MODEL ====> VIEW <p>\n *\t\t\t|- a {bold: true} |- <b>\n *\t\t\t|- b {bold: true} | |- ab\n *\t\t\t|- c |- c\n *\n * Passed `Function` will be provided with the attribute value and then all the parameters of the\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute `attribute` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be the wrapping element.\n * When the provided `Function` does not return any element, no conversion will take place.\n *\n * The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n *\n *\t\tmodelDispatcher.on( 'attribute:bold', wrap( ( modelAttributeValue, { writer } ) => {\n *\t\t\treturn writer.createAttributeElement( 'strong' );\n *\t\t} );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element that will be used for wrapping.\n * @returns {Function} Set/change attribute converter.\n */\nexport function wrap( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Recreate current wrapping node. It will be used to unwrap view range if the attribute value has changed\n\t\t// or the attribute was removed.\n\t\tconst oldViewElement = elementCreator( data.attributeOldValue, conversionApi );\n\n\t\t// Create node to wrap with.\n\t\tconst newViewElement = elementCreator( data.attributeNewValue, conversionApi );\n\n\t\tif ( !oldViewElement && !newViewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\t// Selection attribute conversion.\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), newViewElement );\n\t\t} else {\n\t\t\t// Node attribute conversion.\n\t\t\tlet viewRange = conversionApi.mapper.toViewRange( data.range );\n\n\t\t\t// First, unwrap the range from current wrapper.\n\t\t\tif ( data.attributeOldValue !== null && oldViewElement ) {\n\t\t\t\tviewRange = viewWriter.unwrap( viewRange, oldViewElement );\n\t\t\t}\n\n\t\t\tif ( data.attributeNewValue !== null && newViewElement ) {\n\t\t\t\tviewWriter.wrap( viewRange, newViewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts node insertion changes from the model to the view.\n * The function passed will be provided with all the parameters of the dispatcher's\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert `insert` event}.\n * It is expected that the function returns an {@link module:engine/view/element~Element}.\n * The result of the function will be inserted into the view.\n *\n * The converter automatically consumes the corresponding value from the consumables list, stops the event (see\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}) and binds the model and view elements.\n *\n *\t\tdowncastDispatcher.on(\n *\t\t\t'insert:myElem',\n *\t\t\tinsertElement( ( modelItem, { writer } ) => {\n *\t\t\t\tconst text = writer.createText( 'myText' );\n *\t\t\t\tconst myElem = writer.createElement( 'myElem', { myAttr: 'my-' + modelItem.getAttribute( 'myAttr' ) }, text );\n *\n *\t\t\t\t// Do something fancy with `myElem` using `modelItem` or other parameters.\n *\n *\t\t\t\treturn myElem;\n *\t\t\t}\n *\t\t) );\n *\n * @protected\n * @param {Function} elementCreator Function returning a view element, which will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewElement = elementCreator( data.item, conversionApi );\n\n\t\tif ( !viewElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconversionApi.mapper.bindElements( data.item, viewElement );\n\t\tconversionApi.writer.insert( viewPosition, viewElement );\n\t};\n}\n\n/**\n * Function factory that creates a converter which converts marker adding change to the\n * {@link module:engine/view/uielement~UIElement view UI element}.\n *\n * The view UI element that will be added to the view depends on the passed parameter. See {@link ~insertElement}.\n * In case of a non-collapsed range, the UI element will not wrap nodes but separate elements will be placed at the beginning\n * and at the end of the range.\n *\n * This converter binds created UI elements with the marker name using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.\n *\n * @protected\n * @param {module:engine/view/uielement~UIElement|Function} elementCreator A view UI element or a function returning the view element\n * that will be inserted.\n * @returns {Function} Insert element event converter.\n */\nexport function insertUIElement( elementCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Create two view elements. One will be inserted at the beginning of marker, one at the end.\n\t\t// If marker is collapsed, only \"opening\" element will be inserted.\n\t\tdata.isOpening = true;\n\t\tconst viewStartElement = elementCreator( data, conversionApi );\n\n\t\tdata.isOpening = false;\n\t\tconst viewEndElement = elementCreator( data, conversionApi );\n\n\t\tif ( !viewStartElement || !viewEndElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markerRange = data.markerRange;\n\n\t\t// Marker that is collapsed has consumable build differently that non-collapsed one.\n\t\t// For more information see `addMarker` event description.\n\t\t// If marker's range is collapsed - check if it can be consumed.\n\t\tif ( markerRange.isCollapsed && !conversionApi.consumable.consume( markerRange, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If marker's range is not collapsed - consume all items inside.\n\t\tfor ( const value of markerRange ) {\n\t\t\tif ( !conversionApi.consumable.consume( value.item, evt.name ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst mapper = conversionApi.mapper;\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// Add \"opening\" element.\n\t\tviewWriter.insert( mapper.toViewPosition( markerRange.start ), viewStartElement );\n\t\tconversionApi.mapper.bindElementToMarker( viewStartElement, data.markerName );\n\n\t\t// Add \"closing\" element only if range is not collapsed.\n\t\tif ( !markerRange.isCollapsed ) {\n\t\t\tviewWriter.insert( mapper.toViewPosition( markerRange.end ), viewEndElement );\n\t\t\tconversionApi.mapper.bindElementToMarker( viewEndElement, data.markerName );\n\t\t}\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that returns a default downcast converter for removing a {@link module:engine/view/uielement~UIElement UI element}\n// based on marker remove change.\n//\n// This converter unbinds elements from the marker name.\n//\n// @returns {Function} Removed UI element converter.\nfunction removeUIElement() {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\t\t\tconversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Function factory that creates a default converter for model markers.\n//\n// See {@link DowncastHelpers#markerToData} for more information what type of view is generated.\n//\n// This converter binds created UI elements and affected view elements with the marker name\n// using {@link module:engine/conversion/mapper~Mapper#bindElementToMarker}.\n//\n// @returns {Function} Add marker converter.\nfunction insertMarkerData( viewCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewMarkerData = viewCreator( data.markerName, conversionApi );\n\n\t\tif ( !viewMarkerData ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst markerRange = data.markerRange;\n\n\t\tif ( !conversionApi.consumable.consume( markerRange, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Adding closing data first to keep the proper order in the view.\n\t\thandleMarkerBoundary( markerRange, false, conversionApi, data, viewMarkerData );\n\t\thandleMarkerBoundary( markerRange, true, conversionApi, data, viewMarkerData );\n\n\t\tevt.stop();\n\t};\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary at the beginning or end of given `range`.\nfunction handleMarkerBoundary( range, isStart, conversionApi, data, viewMarkerData ) {\n\tconst modelPosition = isStart ? range.start : range.end;\n\tconst canInsertElement = conversionApi.schema.checkChild( modelPosition, '$text' );\n\n\tif ( canInsertElement ) {\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( modelPosition );\n\n\t\tinsertMarkerAsElement( viewPosition, isStart, conversionApi, data, viewMarkerData );\n\t} else {\n\t\tlet modelElement;\n\t\tlet isBefore;\n\n\t\t// If possible, we want to add `data-group-start-before` and `data-group-end-after` attributes.\n\t\t// Below `if` is constructed in a way that will favor adding these attributes.\n\t\t//\n\t\t// Also, I assume that there will be always an element either after or before the position.\n\t\t// If not, then it is a case when we are not in a position where text is allowed and also there are no elements around...\n\t\tif ( isStart && modelPosition.nodeAfter || !isStart && !modelPosition.nodeBefore ) {\n\t\t\tmodelElement = modelPosition.nodeAfter;\n\t\t\tisBefore = true;\n\t\t} else {\n\t\t\tmodelElement = modelPosition.nodeBefore;\n\t\t\tisBefore = false;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( modelElement );\n\n\t\tinsertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData );\n\t}\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary in the view as an attribute on a view element.\nfunction insertMarkerAsAttribute( viewElement, isStart, isBefore, conversionApi, data, viewMarkerData ) {\n\tconst attributeName = `data-${ viewMarkerData.group }-${ isStart ? 'start' : 'end' }-${ isBefore ? 'before' : 'after' }`;\n\n\tconst markerNames = viewElement.hasAttribute( attributeName ) ? viewElement.getAttribute( attributeName ).split( ',' ) : [];\n\n\t// Adding marker name at the beginning to have the same order in the attribute as there is with marker elements.\n\tmarkerNames.unshift( viewMarkerData.name );\n\n\tconversionApi.writer.setAttribute( attributeName, markerNames.join( ',' ), viewElement );\n\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n}\n\n// Helper function for `insertMarkerData()` that marks a marker boundary in the view as a separate view ui element.\nfunction insertMarkerAsElement( position, isStart, conversionApi, data, viewMarkerData ) {\n\tconst viewElementName = `${ viewMarkerData.group }-${ isStart ? 'start' : 'end' }`;\n\n\tconst attrs = viewMarkerData.name ? { 'name': viewMarkerData.name } : null;\n\tconst viewElement = conversionApi.writer.createUIElement( viewElementName, attrs );\n\n\tconversionApi.writer.insert( position, viewElement );\n\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n}\n\n// Function factory that creates a converter for removing a model marker data added by the {@link #insertMarkerData} converter.\n//\n// @returns {Function} Remove marker converter.\nfunction removeMarkerData( viewCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewData = viewCreator( data.markerName, conversionApi );\n\n\t\tif ( !viewData ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\n\t\t\tif ( element.is( 'containerElement' ) ) {\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-start-before`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-start-after`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-end-before`, element );\n\t\t\t\tremoveMarkerFromAttribute( `data-${ viewData.group }-end-after`, element );\n\t\t\t} else {\n\t\t\t\tconversionApi.writer.clear( conversionApi.writer.createRangeOn( element ), element );\n\t\t\t}\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\n\t\tfunction removeMarkerFromAttribute( attributeName, element ) {\n\t\t\tif ( element.hasAttribute( attributeName ) ) {\n\t\t\t\tconst markerNames = new Set( element.getAttribute( attributeName ).split( ',' ) );\n\t\t\t\tmarkerNames.delete( viewData.name );\n\n\t\t\t\tif ( markerNames.size == 0 ) {\n\t\t\t\t\tconversionApi.writer.removeAttribute( attributeName, element );\n\t\t\t\t} else {\n\t\t\t\t\tconversionApi.writer.setAttribute( attributeName, Array.from( markerNames ).join( ',' ), element );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts set/change/remove attribute changes from the model to the view.\n//\n// Attributes from the model are converted to the view element attributes in the view. You may provide a custom function to generate\n// a key-value attribute pair to add/change/remove. If not provided, model attributes will be converted to view element\n// attributes on a one-to-one basis.\n//\n// *Note:** The provided attribute creator should always return the same `key` for a given attribute from the model.\n//\n// The converter automatically consumes the corresponding value from the consumables list and stops the event (see\n// {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher}).\n//\n//\t\tmodelDispatcher.on( 'attribute:customAttr:myElem', changeAttribute( ( value, data ) => {\n//\t\t\t// Change attribute key from `customAttr` to `class` in the view.\n//\t\t\tconst key = 'class';\n//\t\t\tlet value = data.attributeNewValue;\n//\n//\t\t\t// Force attribute value to 'empty' if the model element is empty.\n//\t\t\tif ( data.item.childCount === 0 ) {\n//\t\t\t\tvalue = 'empty';\n//\t\t\t}\n//\n//\t\t\t// Return the key-value pair.\n//\t\t\treturn { key, value };\n//\t\t} ) );\n//\n// @param {Function} [attributeCreator] Function returning an object with two properties: `key` and `value`, which\n// represent the attribute key and attribute value to be set on a {@link module:engine/view/element~Element view element}.\n// The function is passed the model attribute value as the first parameter and additional data about the change as the second parameter.\n// @returns {Function} Set/change attribute converter.\nfunction changeAttribute( attributeCreator ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst oldAttribute = attributeCreator( data.attributeOldValue, conversionApi );\n\t\tconst newAttribute = attributeCreator( data.attributeNewValue, conversionApi );\n\n\t\tif ( !oldAttribute && !newAttribute ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// If model item cannot be mapped to a view element, it means item is not an `Element` instance but a `TextProxy` node.\n\t\t// Only elements can have attributes in a view so do not proceed for anything else (#1587).\n\t\tif ( !viewElement ) {\n\t\t\t/**\n\t\t\t * This error occurs when a {@link module:engine/model/textproxy~TextProxy text node's} attribute is to be downcasted\n\t\t\t * by {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `Attribute to Attribute converter`}.\n\t\t\t * In most cases it is caused by converters misconfiguration when only \"generic\" converter is defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToAttribute( {\n\t\t\t *\t\t\tmodel: 'attribute-name',\n\t\t\t *\t\t\tview: 'attribute-name'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * and given attribute is used on text node, for example:\n\t\t\t *\n\t\t\t *\t\tmodel.change( writer => {\n\t\t\t *\t\t\twriter.insertText( 'Foo', { 'attribute-name': 'bar' }, parent, 0 );\n\t\t\t *\t\t} );\n\t\t\t *\n\t\t\t * In such cases, to convert the same attribute for both {@link module:engine/model/element~Element}\n\t\t\t * and {@link module:engine/model/textproxy~TextProxy `Text`} nodes, text specific\n\t\t\t * {@link module:engine/conversion/conversion~Conversion#attributeToElement `Attribute to Element converter`}\n\t\t\t * with higher {@link module:utils/priorities~PriorityString priority} must also be defined:\n\t\t\t *\n\t\t\t *\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\t *\t\t\tmodel: {\n\t\t\t *\t\t\t\tkey: 'attribute-name',\n\t\t\t *\t\t\t\tname: '$text'\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tview: ( value, { writer } ) => {\n\t\t\t *\t\t\t\treturn writer.createAttributeElement( 'span', { 'attribute-name': value } );\n\t\t\t *\t\t\t},\n\t\t\t *\t\t\tconverterPriority: 'high'\n\t\t\t *\t\t} ) );\n\t\t\t *\n\t\t\t * @error conversion-attribute-to-attribute-on-text\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-attribute-to-attribute-on-text',\n\t\t\t\t[ data, conversionApi ]\n\t\t\t);\n\t\t}\n\n\t\t// First remove the old attribute if there was one.\n\t\tif ( data.attributeOldValue !== null && oldAttribute ) {\n\t\t\tif ( oldAttribute.key == 'class' ) {\n\t\t\t\tconst classes = toArray( oldAttribute.value );\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.removeClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( oldAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( oldAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.removeStyle( key, viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.removeAttribute( oldAttribute.key, viewElement );\n\t\t\t}\n\t\t}\n\n\t\t// Then set the new attribute.\n\t\tif ( data.attributeNewValue !== null && newAttribute ) {\n\t\t\tif ( newAttribute.key == 'class' ) {\n\t\t\t\tconst classes = toArray( newAttribute.value );\n\n\t\t\t\tfor ( const className of classes ) {\n\t\t\t\t\tviewWriter.addClass( className, viewElement );\n\t\t\t\t}\n\t\t\t} else if ( newAttribute.key == 'style' ) {\n\t\t\t\tconst keys = Object.keys( newAttribute.value );\n\n\t\t\t\tfor ( const key of keys ) {\n\t\t\t\t\tviewWriter.setStyle( key, newAttribute.value[ key ], viewElement );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tviewWriter.setAttribute( newAttribute.key, newAttribute.value, viewElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the text inside marker's range. The converter wraps the text with\n// {@link module:engine/view/attributeelement~AttributeElement} created from the provided descriptor.\n// See {link module:engine/conversion/downcasthelpers~createViewElementFromHighlightDescriptor}.\n//\n// It can also be used to convert the selection that is inside a marker. In that case, an empty attribute element will be\n// created and the selection will be put inside it.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds the created {@link module:engine/view/attributeelement~AttributeElement attribute elemens} with the marker name\n// using the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightText( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) && !data.item.is( '$textProxy' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewElement = createViewElementFromHighlightDescriptor( viewWriter, descriptor );\n\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\tif ( data.item instanceof ModelSelection || data.item instanceof DocumentSelection ) {\n\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), viewElement, viewSelection );\n\t\t} else {\n\t\t\tconst viewRange = conversionApi.mapper.toViewRange( data.range );\n\t\t\tconst rangeAfterWrap = viewWriter.wrap( viewRange, viewElement );\n\n\t\t\tfor ( const element of rangeAfterWrap.getItems() ) {\n\t\t\t\tif ( element.is( 'attributeElement' ) && element.isSimilar( viewElement ) ) {\n\t\t\t\t\tconversionApi.mapper.bindElementToMarker( element, data.markerName );\n\n\t\t\t\t\t// One attribute element is enough, because all of them are bound together by the view writer.\n\t\t\t\t\t// Mapper uses this binding to get all the elements no matter how many of them are registered in the mapper.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Converter function factory. It creates a function which applies the marker's highlight to an element inside the marker's range.\n//\n// The converter checks if an element has the `addHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property} and, if so, uses it to apply the highlight.\n// In such case the converter will consume all element's children, assuming that they were handled by the element itself.\n//\n// When the `addHighlight` custom property is not present, the element is not converted in any special way.\n// This means that converters will proceed to convert the element's child nodes.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter binds altered {@link module:engine/view/containerelement~ContainerElement container elements} with the marker name using\n// the {@link module:engine/conversion/mapper~Mapper#bindElementToMarker} method.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction highlightElement( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.item ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !( data.item instanceof ModelElement ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.test( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\n\t\tif ( viewElement && viewElement.getCustomProperty( 'addHighlight' ) ) {\n\t\t\t// Consume element itself.\n\t\t\tconversionApi.consumable.consume( data.item, evt.name );\n\n\t\t\t// Consume all children nodes.\n\t\t\tfor ( const value of ModelRange._createIn( data.item ) ) {\n\t\t\t\tconversionApi.consumable.consume( value.item, evt.name );\n\t\t\t}\n\n\t\t\tviewElement.getCustomProperty( 'addHighlight' )( viewElement, descriptor, conversionApi.writer );\n\n\t\t\tconversionApi.mapper.bindElementToMarker( viewElement, data.markerName );\n\t\t}\n\t};\n}\n\n// Function factory that creates a converter which converts the removing model marker to the view.\n//\n// Both text nodes and elements are handled by this converter but they are handled a bit differently.\n//\n// Text nodes are unwrapped using the {@link module:engine/view/attributeelement~AttributeElement attribute element} created from the\n// provided highlight descriptor. See {link module:engine/conversion/downcasthelpers~HighlightDescriptor}.\n//\n// For elements, the converter checks if an element has the `removeHighlight` function stored as a\n// {@link module:engine/view/element~Element#_setCustomProperty custom property}. If so, it uses it to remove the highlight.\n// In such case, the children of that element will not be converted.\n//\n// When `removeHighlight` is not present, the element is not converted in any special way.\n// The converter will proceed to convert the element's child nodes instead.\n//\n// If the highlight descriptor does not provide the `priority` property, `10` will be used.\n//\n// If the highlight descriptor does not provide the `id` property, the name of the marker will be used.\n//\n// This converter unbinds elements from the marker name.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} highlightDescriptor\n// @returns {Function}\nfunction removeHighlight( highlightDescriptor ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// This conversion makes sense only for non-collapsed range.\n\t\tif ( data.markerRange.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst descriptor = prepareDescriptor( highlightDescriptor, data, conversionApi );\n\n\t\tif ( !descriptor ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// View element that will be used to unwrap `AttributeElement`s.\n\t\tconst viewHighlightElement = createViewElementFromHighlightDescriptor( conversionApi.writer, descriptor );\n\n\t\t// Get all elements bound with given marker name.\n\t\tconst elements = conversionApi.mapper.markerNameToElements( data.markerName );\n\n\t\tif ( !elements ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const element of elements ) {\n\t\t\tconversionApi.mapper.unbindElementFromMarkerName( element, data.markerName );\n\n\t\t\tif ( element.is( 'attributeElement' ) ) {\n\t\t\t\tconversionApi.writer.unwrap( conversionApi.writer.createRangeOn( element ), viewHighlightElement );\n\t\t\t} else {\n\t\t\t\t// if element.is( 'containerElement' ).\n\t\t\t\telement.getCustomProperty( 'removeHighlight' )( element, descriptor.id, conversionApi.writer );\n\t\t\t}\n\t\t}\n\n\t\tconversionApi.writer.clearClonedElementsGroup( data.markerName );\n\n\t\tevt.stop();\n\t};\n}\n\n// Model element to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#elementToElement `.elementToElement()` downcast helper} for examples and config params description.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view\n// @param {Object} [config.triggerBy]\n// @param {Array.<String>} [config.triggerBy.attributes]\n// @param {Array.<String>} [config.triggerBy.children]\n// @returns {Function} Conversion helper.\nfunction downcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'container' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'insert:' + config.model, insertElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\n\t\tif ( config.triggerBy ) {\n\t\t\tif ( config.triggerBy.attributes ) {\n\t\t\t\tfor ( const attributeKey of config.triggerBy.attributes ) {\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `attribute:${ attributeKey }:${ config.model }` );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( config.triggerBy.children ) {\n\t\t\t\tfor ( const childName of config.triggerBy.children ) {\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `insert:${ childName }` );\n\t\t\t\t\tdispatcher._mapReconversionTriggerEvent( config.model, `remove:${ childName }` );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Model attribute to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToElement `.attributeToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values }` object. `values` is an array\n// of `String`s with possible values if the model attribute is an enumerable.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function|Object} config.view A view element definition or a function\n// that takes the model attribute value and {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer}\n// as parameters and returns a view attribute element. If `config.model.values` is\n// given, `config.view` should be an object assigning values from `config.model.values` to view element definitions or functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToElementConfig( config.view[ modelValue ], 'attribute' );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToElementConfig( config.view, 'attribute' );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, wrap( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model attribute to view attribute conversion helper.\n//\n// See {@link ~DowncastHelpers#attributeToAttribute `.attributeToAttribute()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.model The key of the attribute to convert from or a `{ key, values, [ name ] }` object describing\n// the attribute key, possible values and, optionally, an element name to convert from.\n// @param {String|Object|Function} config.view A view attribute key, or a `{ key, value }` object or a function that takes\n// the model attribute value and returns a `{ key, value }` object. If `key` is `'class'`, `value` can be a `String` or an\n// array of `String`s. If `key` is `'style'`, `value` is an object with key-value pairs. In other cases, `value` is a `String`.\n// If `config.model.values` is set, `config.view` should be an object assigning values from `config.model.values` to\n// `{ key, value }` objects or a functions.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst modelKey = config.model.key ? config.model.key : config.model;\n\tlet eventName = 'attribute:' + modelKey;\n\n\tif ( config.model.name ) {\n\t\teventName += ':' + config.model.name;\n\t}\n\n\tif ( config.model.values ) {\n\t\tfor ( const modelValue of config.model.values ) {\n\t\t\tconfig.view[ modelValue ] = normalizeToAttributeConfig( config.view[ modelValue ] );\n\t\t}\n\t} else {\n\t\tconfig.view = normalizeToAttributeConfig( config.view );\n\t}\n\n\tconst elementCreator = getFromAttributeCreator( config );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, changeAttribute( elementCreator ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to view element conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} config.view A view element definition or a function\n// that takes the model marker data as a parameter and returns a view UI element.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconfig.view = normalizeToElementConfig( config.view, 'ui' );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, insertUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeUIElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to view data conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToData `markerToData()` downcast helper} to learn more.\n//\n// @param {Object} config\n// @param {String} config.model\n// @param {Function} [config.view]\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal']\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToData( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst group = config.model;\n\n\t// Default conversion.\n\tif ( !config.view ) {\n\t\tconfig.view = markerName => ( {\n\t\t\tgroup,\n\t\t\tname: markerName.substr( config.model.length + 1 )\n\t\t} );\n\t}\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + group, insertMarkerData( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + group, removeMarkerData( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Model marker to highlight conversion helper.\n//\n// See {@link ~DowncastHelpers#markerToElement `.markerToElement()` downcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String} config.model The name of the model marker (or model marker group) to convert.\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor|Function} config.view A highlight descriptor\n// that will be used for highlighting or a function that takes the model marker data as a parameter and returns a highlight descriptor.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction downcastMarkerToHighlight( config ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightText( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'addMarker:' + config.model, highlightElement( config.view ), { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'removeMarker:' + config.model, removeHighlight( config.view ), { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// Takes `config.view`, and if it is an {@link module:engine/view/elementdefinition~ElementDefinition}, converts it\n// to a function (because lower level converters accept only element creator functions).\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition|Function} view View configuration.\n// @param {'container'|'attribute'|'ui'} viewElementType View element type to create.\n// @returns {Function} Element creator function to use in lower level converters.\nfunction normalizeToElementConfig( view, viewElementType ) {\n\tif ( typeof view == 'function' ) {\n\t\t// If `view` is already a function, don't do anything.\n\t\treturn view;\n\t}\n\n\treturn ( modelData, conversionApi ) => createViewElementFromDefinition( view, conversionApi, viewElementType );\n}\n\n// Creates a view element instance from the provided {@link module:engine/view/elementdefinition~ElementDefinition} and class.\n//\n// @param {module:engine/view/elementdefinition~ElementDefinition} viewElementDefinition\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {'container'|'attribute'|'ui'} viewElementType\n// @returns {module:engine/view/element~Element}\nfunction createViewElementFromDefinition( viewElementDefinition, conversionApi, viewElementType ) {\n\tif ( typeof viewElementDefinition == 'string' ) {\n\t\t// If `viewElementDefinition` is given as a `String`, normalize it to an object with `name` property.\n\t\tviewElementDefinition = { name: viewElementDefinition };\n\t}\n\n\tlet element;\n\tconst viewWriter = conversionApi.writer;\n\tconst attributes = Object.assign( {}, viewElementDefinition.attributes );\n\n\tif ( viewElementType == 'container' ) {\n\t\telement = viewWriter.createContainerElement( viewElementDefinition.name, attributes );\n\t} else if ( viewElementType == 'attribute' ) {\n\t\tconst options = {\n\t\t\tpriority: viewElementDefinition.priority || ViewAttributeElement.DEFAULT_PRIORITY\n\t\t};\n\n\t\telement = viewWriter.createAttributeElement( viewElementDefinition.name, attributes, options );\n\t} else {\n\t\t// 'ui'.\n\t\telement = viewWriter.createUIElement( viewElementDefinition.name, attributes );\n\t}\n\n\tif ( viewElementDefinition.styles ) {\n\t\tconst keys = Object.keys( viewElementDefinition.styles );\n\n\t\tfor ( const key of keys ) {\n\t\t\tviewWriter.setStyle( key, viewElementDefinition.styles[ key ], element );\n\t\t}\n\t}\n\n\tif ( viewElementDefinition.classes ) {\n\t\tconst classes = viewElementDefinition.classes;\n\n\t\tif ( typeof classes == 'string' ) {\n\t\t\tviewWriter.addClass( classes, element );\n\t\t} else {\n\t\t\tfor ( const className of classes ) {\n\t\t\t\tviewWriter.addClass( className, element );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction getFromAttributeCreator( config ) {\n\tif ( config.model.values ) {\n\t\treturn ( modelAttributeValue, conversionApi ) => {\n\t\t\tconst view = config.view[ modelAttributeValue ];\n\n\t\t\tif ( view ) {\n\t\t\t\treturn view( modelAttributeValue, conversionApi );\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\t} else {\n\t\treturn config.view;\n\t}\n}\n\n// Takes the configuration, adds default parameters if they do not exist and normalizes other parameters to be used in downcast converters\n// for generating a view attribute.\n//\n// @param {Object} view View configuration.\nfunction normalizeToAttributeConfig( view ) {\n\tif ( typeof view == 'string' ) {\n\t\treturn modelAttributeValue => ( { key: view, value: modelAttributeValue } );\n\t} else if ( typeof view == 'object' ) {\n\t\t// { key, value, ... }\n\t\tif ( view.value ) {\n\t\t\treturn () => view;\n\t\t}\n\t\t// { key, ... }\n\t\telse {\n\t\t\treturn modelAttributeValue => ( { key: view.key, value: modelAttributeValue } );\n\t\t}\n\t} else {\n\t\t// function.\n\t\treturn view;\n\t}\n}\n\n// Helper function for `highlight`. Prepares the actual descriptor object using value passed to the converter.\nfunction prepareDescriptor( highlightDescriptor, data, conversionApi ) {\n\t// If passed descriptor is a creator function, call it. If not, just use passed value.\n\tconst descriptor = typeof highlightDescriptor == 'function' ?\n\t\thighlightDescriptor( data, conversionApi ) :\n\t\thighlightDescriptor;\n\n\tif ( !descriptor ) {\n\t\treturn null;\n\t}\n\n\t// Apply default descriptor priority.\n\tif ( !descriptor.priority ) {\n\t\tdescriptor.priority = 10;\n\t}\n\n\t// Default descriptor id is marker name.\n\tif ( !descriptor.id ) {\n\t\tdescriptor.id = data.markerName;\n\t}\n\n\treturn descriptor;\n}\n\n/**\n * An object describing how the marker highlight should be represented in the view.\n *\n * Each text node contained in a highlighted range will be wrapped in a `<span>`\n * {@link module:engine/view/attributeelement~AttributeElement view attribute element} with CSS class(es), attributes and a priority\n * described by this object.\n *\n * Additionally, each {@link module:engine/view/containerelement~ContainerElement container element} can handle displaying the highlight\n * separately by providing the `addHighlight` and `removeHighlight` custom properties. In this case:\n *\n * * The `HighlightDescriptor` object is passed to the `addHighlight` function upon conversion and should be used to apply the highlight to\n * the element.\n * * The descriptor `id` is passed to the `removeHighlight` function upon conversion and should be used to remove the highlight with the\n * given ID from the element.\n *\n * @typedef {Object} module:engine/conversion/downcasthelpers~HighlightDescriptor\n *\n * @property {String|Array.<String>} classes A CSS class or an array of classes to set. If the descriptor is used to\n * create an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these classes will be set\n * on that attribute element. If the descriptor is applied to an element, usually these classes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n *\n * @property {String} [id] Descriptor identifier. If not provided, it defaults to the converted marker's name.\n *\n * @property {Number} [priority] Descriptor priority. If not provided, it defaults to `10`. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element}, it will be that element's\n * {@link module:engine/view/attributeelement~AttributeElement#priority priority}. If the descriptor is applied to an element,\n * the priority will be used to determine which descriptor is more important.\n *\n * @property {Object} [attributes] Attributes to set. If the descriptor is used to create\n * an {@link module:engine/view/attributeelement~AttributeElement attribute element} over text nodes, these attributes will be set on that\n * attribute element. If the descriptor is applied to an element, usually these attributes will be set on that element, however,\n * this depends on how the element converts the descriptor.\n */\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/autoparagraphing\n */\n\n/**\n * Fixes all empty roots.\n *\n * @protected\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @returns {Boolean} `true` if any change has been applied, `false` otherwise.\n */\nexport function autoParagraphEmptyRoots( writer ) {\n\tconst { schema, document } = writer.model;\n\n\tfor ( const rootName of document.getRootNames() ) {\n\t\tconst root = document.getRoot( rootName );\n\n\t\tif ( root.isEmpty && !schema.checkChild( root, '$text' ) ) {\n\t\t\t// If paragraph element is allowed in the root, create paragraph element.\n\t\t\tif ( schema.checkChild( root, 'paragraph' ) ) {\n\t\t\t\twriter.insertElement( 'paragraph', root );\n\n\t\t\t\t// Other roots will get fixed in the next post-fixer round. Those will be triggered\n\t\t\t\t// in the same batch no matter if this method was triggered by the post-fixing or not\n\t\t\t\t// (the above insertElement call will trigger the post-fixers).\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if the given node wrapped with a paragraph would be accepted by the schema in the given position.\n *\n * @protected\n * @param {module:engine/model/position~Position} position The position at which to check.\n * @param {module:engine/model/node~Node|String} nodeOrType The child node or child type to check.\n * @param {module:engine/model/schema~Schema} schema A schema instance used for element validation.\n */\nexport function isParagraphable( position, nodeOrType, schema ) {\n\tconst context = schema.createContext( position );\n\n\t// When paragraph is allowed in this context...\n\tif ( !schema.checkChild( context, 'paragraph' ) ) {\n\t\treturn false;\n\t}\n\n\t// And a node would be allowed in this paragraph...\n\tif ( !schema.checkChild( context.push( 'paragraph' ), nodeOrType ) ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n/**\n * Inserts a new paragraph at the given position and returns a position inside that paragraph.\n *\n * @protected\n * @param {module:engine/model/position~Position} position The position where a paragraph should be inserted.\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @returns {module:engine/model/position~Position} Position inside the created paragraph.\n */\nexport function wrapInParagraph( position, writer ) {\n\tconst paragraph = writer.createElement( 'paragraph' );\n\n\twriter.insert( paragraph, position );\n\n\treturn writer.createPositionAt( paragraph, 0 );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport Matcher from '../view/matcher';\nimport ConversionHelpers from './conversionhelpers';\n\nimport { cloneDeep } from 'lodash-es';\nimport { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport priorities from '@ckeditor/ckeditor5-utils/src/priorities';\nimport { isParagraphable, wrapInParagraph } from '../model/utils/autoparagraphing';\n\n/**\n * Contains {@link module:engine/view/view view} to {@link module:engine/model/model model} converters for\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}.\n *\n * @module engine/conversion/upcasthelpers\n */\n\n/**\n * Upcast conversion helper functions.\n *\n * @extends module:engine/conversion/conversionhelpers~ConversionHelpers\n */\nexport default class UpcastHelpers extends ConversionHelpers {\n\t/**\n\t * View element to model element conversion helper.\n\t *\n\t * This conversion results in creating a model element. For example,\n\t * view `<p>Foo</p>` becomes `<paragraph>Foo</paragraph>` in the model.\n\t *\n\t * Keep in mind that the element will be inserted only if it is allowed\n\t * by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: 'p',\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t},\n\t *\t\t\tmodel: 'fancyParagraph'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t * \t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'heading'\n\t * \t\t\t},\n\t * \t\t\tmodel: ( viewElement, conversionApi ) => {\n\t * \t\t\t\tconst modelWriter = conversionApi.writer;\n\t *\n\t * \t\t\t\treturn modelWriter.createElement( 'heading', { level: viewElement.getAttribute( 'data-level' ) } );\n\t * \t\t\t}\n\t * \t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToElement\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n\t * set, the converter will fire for every view element.\n\t * @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element instance or a\n\t * function that takes a view element and {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API}\n\t * and returns a model element. The model element will be inserted in the model.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToElement( config ) {\n\t\treturn this.add( upcastElementToElement( config ) );\n\t}\n\n\t/**\n\t * View element to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `<strong>Foo</strong>` becomes\n\t * `Foo` {@link module:engine/model/text~Text model text node} with `bold` attribute set to `true`.\n\t *\n\t * This helper is meant to set a model attribute on all the elements that are inside the converted element:\n\t *\n\t *\t\t<strong>Foo</strong> --> <strong><p>Foo</p></strong> --> <paragraph><$text bold=\"true\">Foo</$text></paragraph>\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `<strong>` is over `<p>` element, `bold=\"true\"` was added to the text. See\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute} for comparison.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: 'strong',\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: 'bold'\n\t *\t\t\t},\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: [ 'styled', 'styled-dark' ]\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * \t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-size': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\t\t\t\t\tconst value = fontSize.substr( 0, fontSize.length - 2 );\n\t *\n\t *\t\t\t\t\tif ( value <= 10 ) {\n\t *\t\t\t\t\t\treturn 'small';\n\t *\t\t\t\t\t} else if ( value > 12 ) {\n\t *\t\t\t\t\t\treturn 'big';\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #elementToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.\n\t * If `String` is given, the model attribute value will be set to `true`.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToAttribute( config ) {\n\t\treturn this.add( upcastElementToAttribute( config ) );\n\t}\n\n\t/**\n\t * View attribute to model attribute conversion helper.\n\t *\n\t * This conversion results in setting an attribute on a model node. For example, view `<img src=\"foo.jpg\"></img>` becomes\n\t * `<image source=\"foo.jpg\"></image>` in the model.\n\t *\n\t * This helper is meant to convert view attributes from view elements which got converted to the model, so the view attribute\n\t * is set only on the corresponding model node:\n\t *\n\t *\t\t<div class=\"dark\"><div>foo</div></div> --> <div dark=\"true\"><div>foo</div></div>\n\t *\n\t * Above, `class=\"dark\"` attribute is added only to the `<div>` elements that has it. This is in contrary to\n\t * {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute} which sets attributes for\n\t * all the children in the model:\n\t *\n\t *\t\t<strong>Foo</strong> --> <strong><p>Foo</p></strong> --> <paragraph><$text bold=\"true\">Foo</$text></paragraph>\n\t *\n\t * Above is a sample of HTML code, that goes through autoparagraphing (first step) and then is converted (second step).\n\t * Even though `<strong>` is over `<p>` element, `bold=\"true\"` was added to the text.\n\t *\n\t * Keep in mind that the attribute will be set only if it is allowed by {@link module:engine/model/schema~Schema schema} configuration.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: 'src',\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: { key: 'src' },\n\t *\t\t\tmodel: 'source',\n\t *\t\t\tconverterPriority: 'normal'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'data-style',\n\t *\t\t\t\tvalue: /[\\s\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: 'styled'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'img',\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: 'styled-dark'\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled',\n\t *\t\t\t\tvalue: 'dark'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tkey: 'class',\n\t *\t\t\t\tvalue: /styled-[\\S]+/\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'styled'\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => {\n\t *\t\t\t\t\tconst regexp = /styled-([\\S]+)/;\n\t *\t\t\t\t\tconst match = viewElement.getAttribute( 'class' ).match( regexp );\n\t *\n\t *\t\t\t\t\treturn match[ 1 ];\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Converting styles works a bit differently as it requires `view.styles` to be an object and by default\n\t * a model attribute will be set to `true` by such a converter. You can set the model attribute to any value by providing the `value`\n\t * callback that returns the desired value.\n\t *\n\t *\t\t// Default conversion of font-weight style will result in setting bold attribute to true.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: 'bold'\n\t *\t\t} );\n\t *\n\t *\t\t// This converter will pass any style value to the `lineHeight` model attribute.\n\t *\t\teditor.conversion.for( 'upcast' ).attributeToAttribute( {\n\t *\t\t\tview: {\n\t *\t\t\t\tstyles: {\n\t *\t\t\t\t\t'line-height': /[\\s\\S]+/\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'lineHeight',\n\t *\t\t\t\tvalue: ( viewElement, conversionApi ) => viewElement.getStyle( 'line-height' )\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #attributeToAttribute\n\t * @param {Object} config Conversion configuration.\n\t * @param {String|Object} config.view Specifies which view attribute will be converted. If a `String` is passed,\n\t * attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n\t * specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n\t * property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n\t * a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n\t * @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n\t * the model attribute. `value` property may be set as a function that takes a view element and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the value.\n\t * If `String` is given, the model attribute value will be same as view attribute value.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tattributeToAttribute( config ) {\n\t\treturn this.add( upcastAttributeToAttribute( config ) );\n\t}\n\n\t/**\n\t * View element to model marker conversion helper.\n\t *\n\t * **Note**: This method was deprecated. Please use {@link #dataToMarker} instead.\n\t *\n\t * This conversion results in creating a model marker. For example, if the marker was stored in a view as an element:\n\t * `<p>Fo<span data-marker=\"comment\" data-comment-id=\"7\"></span>o</p><p>B<span data-marker=\"comment\" data-comment-id=\"7\"></span>ar</p>`,\n\t * after the conversion is done, the marker will be available in\n\t * {@link module:engine/model/model~Model#markers model document markers}.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: 'search',\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: 'marker-search',\n\t *\t\t\tmodel: ( viewElement, conversionApi ) => 'comment:' + viewElement.getAttribute( 'data-comment-id' )\n\t *\t\t} );\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).elementToMarker( {\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tattributes: {\n\t *\t\t\t\t\t'data-marker': 'search'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tmodel: 'search'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @deprecated\n\t * @method #elementToMarker\n\t * @param {Object} config Conversion configuration.\n\t * @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n\t * @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n\t * a model marker name.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\telementToMarker( config ) {\n\t\t/**\n\t\t * The {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker `UpcastHelpers#elementToMarker()`}\n\t\t * method was deprecated and will be removed in the near future.\n\t\t * Please use {@link module:engine/conversion/upcasthelpers~UpcastHelpers#dataToMarker `UpcastHelpers#dataToMarker()`} instead.\n\t\t *\n\t\t * @error upcast-helpers-element-to-marker-deprecated\n\t\t */\n\t\tlogWarning( 'upcast-helpers-element-to-marker-deprecated' );\n\n\t\treturn this.add( upcastElementToMarker( config ) );\n\t}\n\n\t/**\n\t * View-to-model marker conversion helper.\n\t *\n\t * Converts view data created by {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`}\n\t * back to a model marker.\n\t *\n\t * This converter looks for specific view elements and view attributes that mark marker boundaries. See\n\t * {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToData `#markerToData()`} to learn what view data\n\t * is expected by this converter.\n\t *\n\t * The `config.view` property is equal to the marker group name to convert.\n\t *\n\t * By default, this converter creates markers with the `group:name` name convention (to match the default `markerToData` conversion).\n\t *\n\t * The conversion configuration can take a function that will generate a marker name.\n\t * If such function is set as the `config.model` parameter, it is passed the `name` part from the view element or attribute and it is\n\t * expected to return a string with the marker name.\n\t *\n\t * Basic usage:\n\t *\n\t *\t\t// Using the default conversion.\n\t *\t\t// In this case, all markers from the `comment` group will be converted.\n\t *\t\t// The conversion will look for `<comment-start>` and `<comment-end>` tags and\n\t *\t\t// `data-comment-start-before`, `data-comment-start-after`,\n\t *\t\t// `data-comment-end-before` and `data-comment-end-after` attributes.\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment'\n\t *\t\t} );\n\t *\n\t * An example of a model that may be generated by this conversion:\n\t *\n\t *\t\t// View:\n\t *\t\t<p>Foo<comment-start name=\"commentId:uid\"></comment-start>bar</p>\n\t *\t\t<figure data-comment-end-after=\"commentId:uid\" class=\"image\"><img src=\"abc.jpg\" /></figure>\n\t *\n\t *\t\t// Model:\n\t *\t\t<paragraph>Foo[bar</paragraph>\n\t *\t\t<image src=\"abc.jpg\"></image>]\n\t *\n\t * Where `[]` are boundaries of a marker that will receive the `comment:commentId:uid` name.\n\t *\n\t * Other examples of usage:\n\t *\n\t *\t\t// Using a custom function which is the same as the default conversion:\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment',\n\t *\t\t\tmodel: ( name, conversionApi ) => 'comment:' + name,\n\t *\t\t} );\n\t *\n\t *\t\t// Using the converter priority:\n\t *\t\teditor.conversion.for( 'upcast' ).dataToMarker( {\n\t *\t\t\tview: 'comment',\n\t *\t\t\tmodel: ( name, conversionApi ) => 'comment:' + name,\n\t *\t\t\tconverterPriority: 'high'\n\t *\t\t} );\n\t *\n\t * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter\n\t * to the conversion process.\n\t *\n\t * @method #dataToMarker\n\t * @param {Object} config Conversion configuration.\n\t * @param {String} config.view The marker group name to convert.\n\t * @param {Function} [config.model] A function that takes the `name` part from the view element or attribute and\n\t * {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi upcast conversion API} and returns the marker name.\n\t * @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n\t * @returns {module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tdataToMarker( config ) {\n\t\treturn this.add( upcastDataToMarker( config ) );\n\t}\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/documentfragment~DocumentFragment view document fragment}\n * or all children of {@link module:engine/view/element~Element} into\n * {@link module:engine/model/documentfragment~DocumentFragment model document fragment}.\n * This is the \"entry-point\" converter for upcast (view to model conversion). This converter starts the conversion of all children\n * of passed view document fragment. Those children {@link module:engine/view/node~Node view nodes} are then handled by other converters.\n *\n * This also a \"default\", last resort converter for all view elements that has not been converted by other converters.\n * When a view element is being converted to the model but it does not have converter specified, that view element\n * will be converted to {@link module:engine/model/documentfragment~DocumentFragment model document fragment} and returned.\n *\n * @returns {Function} Universal converter for view {@link module:engine/view/documentfragment~DocumentFragment fragments} and\n * {@link module:engine/view/element~Element elements} that returns\n * {@link module:engine/model/documentfragment~DocumentFragment model fragment} with children of converted view item.\n */\nexport function convertToModelFragment() {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Second argument in `consumable.consume` is discarded for ViewDocumentFragment but is needed for ViewElement.\n\t\tif ( !data.modelRange && conversionApi.consumable.consume( data.viewItem, { name: true } ) ) {\n\t\t\tconst { modelRange, modelCursor } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n\n\t\t\tdata.modelRange = modelRange;\n\t\t\tdata.modelCursor = modelCursor;\n\t\t}\n\t};\n}\n\n/**\n * Function factory, creates a converter that converts {@link module:engine/view/text~Text} to {@link module:engine/model/text~Text}.\n *\n * @returns {Function} {@link module:engine/view/text~Text View text} converter.\n */\nexport function convertText() {\n\treturn ( evt, data, { schema, consumable, writer } ) => {\n\t\tlet position = data.modelCursor;\n\n\t\t// When node is already converted then do nothing.\n\t\tif ( !consumable.test( data.viewItem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !schema.checkChild( position, '$text' ) ) {\n\t\t\tif ( !isParagraphable( position, '$text', schema ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tposition = wrapInParagraph( position, writer );\n\t\t}\n\n\t\tconsumable.consume( data.viewItem );\n\n\t\tconst text = writer.createText( data.viewItem.data );\n\n\t\twriter.insert( text, position );\n\n\t\tdata.modelRange = writer.createRange(\n\t\t\tposition,\n\t\t\tposition.getShiftedBy( text.offsetSize )\n\t\t);\n\t\tdata.modelCursor = data.modelRange.end;\n\t};\n}\n\n/**\n * Function factory, creates a callback function which converts a {@link module:engine/view/selection~Selection\n * view selection} taken from the {@link module:engine/view/document~Document#event:selectionChange} event\n * and sets in on the {@link module:engine/model/document~Document#selection model}.\n *\n * **Note**: because there is no view selection change dispatcher nor any other advanced view selection to model\n * conversion mechanism, the callback should be set directly on view document.\n *\n *\t\tview.document.on( 'selectionChange', convertSelectionChange( modelDocument, mapper ) );\n *\n * @param {module:engine/model/model~Model} model Data model.\n * @param {module:engine/conversion/mapper~Mapper} mapper Conversion mapper.\n * @returns {Function} {@link module:engine/view/document~Document#event:selectionChange} callback function.\n */\nexport function convertSelectionChange( model, mapper ) {\n\treturn ( evt, data ) => {\n\t\tconst viewSelection = data.newSelection;\n\n\t\tconst ranges = [];\n\n\t\tfor ( const viewRange of viewSelection.getRanges() ) {\n\t\t\tranges.push( mapper.toModelRange( viewRange ) );\n\t\t}\n\n\t\tconst modelSelection = model.createSelection( ranges, { backward: viewSelection.isBackward } );\n\n\t\tif ( !modelSelection.isEqual( model.document.selection ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( modelSelection );\n\t\t\t} );\n\t\t}\n\t};\n}\n\n// View element to model element conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToElement `.elementToElement()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} [config.view] Pattern matching all view elements which should be converted. If not\n// set, the converter will fire for every view element.\n// @param {String|module:engine/model/element~Element|Function} config.model Name of the model element, a model element\n// instance or a function that takes a view element and returns a model element. The model element will be inserted in the model.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToElement( config ) {\n\tconfig = cloneDeep( config );\n\n\tconst converter = prepareToElementConverter( config );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'normal' } );\n\t};\n}\n\n// View element to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToAttribute `.elementToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be set to `true`.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeModelAttributeConfig( config );\n\n\tconst converter = prepareToAttributeConverter( config, false );\n\n\tconst elementName = getViewElementNameFromConfig( config.view );\n\tconst eventName = elementName ? 'element:' + elementName : 'element';\n\n\treturn dispatcher => {\n\t\tdispatcher.on( eventName, converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View attribute to model attribute conversion helper.\n//\n// See {@link ~UpcastHelpers#attributeToAttribute `.attributeToAttribute()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {String|Object} config.view Specifies which view attribute will be converted. If a `String` is passed,\n// attributes with given key will be converted. If an `Object` is passed, it must have a required `key` property,\n// specifying view attribute key, and may have an optional `value` property, specifying view attribute value and optional `name`\n// property specifying a view element name from/on which the attribute should be converted. `value` can be given as a `String`,\n// a `RegExp` or a function callback, that takes view attribute value as the only parameter and returns `Boolean`.\n// @param {String|Object} config.model Model attribute key or an object with `key` and `value` properties, describing\n// the model attribute. `value` property may be set as a function that takes a view element and returns the value.\n// If `String` is given, the model attribute value will be same as view attribute value.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='low'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastAttributeToAttribute( config ) {\n\tconfig = cloneDeep( config );\n\n\tlet viewKey = null;\n\n\tif ( typeof config.view == 'string' || config.view.key ) {\n\t\tviewKey = normalizeViewAttributeKeyValueConfig( config );\n\t}\n\n\tnormalizeModelAttributeConfig( config, viewKey );\n\n\tconst converter = prepareToAttributeConverter( config, true );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element', converter, { priority: config.converterPriority || 'low' } );\n\t};\n}\n\n// View element to model marker conversion helper.\n//\n// See {@link ~UpcastHelpers#elementToMarker `.elementToMarker()` upcast helper} for examples.\n//\n// @param {Object} config Conversion configuration.\n// @param {module:engine/view/matcher~MatcherPattern} config.view Pattern matching all view elements which should be converted.\n// @param {String|Function} config.model Name of the model marker, or a function that takes a view element and returns\n// a model marker name.\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal'] Converter priority.\n// @returns {Function} Conversion helper.\nfunction upcastElementToMarker( config ) {\n\tconfig = cloneDeep( config );\n\n\tnormalizeElementToMarkerConfig( config );\n\n\treturn upcastElementToElement( config );\n}\n\n// View data to model marker conversion helper.\n//\n// See {@link ~UpcastHelpers#dataToMarker} to learn more.\n//\n// @param {Object} config\n// @param {String} config.view\n// @param {Function} [config.model]\n// @param {module:utils/priorities~PriorityString} [config.converterPriority='normal']\n// @returns {Function} Conversion helper.\nfunction upcastDataToMarker( config ) {\n\tconfig = cloneDeep( config );\n\n\t// Default conversion.\n\tif ( !config.model ) {\n\t\tconfig.model = name => {\n\t\t\treturn name ? config.view + ':' + name : config.view;\n\t\t};\n\t}\n\n\tconst converterStart = prepareToElementConverter( normalizeDataToMarkerConfig( config, 'start' ) );\n\tconst converterEnd = prepareToElementConverter( normalizeDataToMarkerConfig( config, 'end' ) );\n\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:' + config.view + '-start', converterStart, { priority: config.converterPriority || 'normal' } );\n\t\tdispatcher.on( 'element:' + config.view + '-end', converterEnd, { priority: config.converterPriority || 'normal' } );\n\n\t\t// Below is a hack that is needed to properly handle `converterPriority` for both elements and attributes.\n\t\t// Attribute conversion needs to be performed *after* element conversion.\n\t\t// This converter handles both element conversion and attribute conversion, which means that if a single\n\t\t// `config.converterPriority` is used, it will lead to problems. For example, if `'high'` priority is used,\n\t\t// then attribute conversion will be performed before a lot of element upcast converters.\n\t\t// On the other hand we want to support `config.converterPriority` and overwriting conveters.\n\t\t//\n\t\t// To have it work, we need to do some extra processing for priority for attribute converter.\n\t\t// Priority `'low'` value should be the base value and then we will change it depending on `config.converterPriority` value.\n\t\t//\n\t\t// This hack probably would not be needed if attributes are upcasted separately.\n\t\t//\n\t\tconst basePriority = priorities.get( 'low' );\n\t\tconst maxPriority = priorities.get( 'highest' );\n\t\tconst priorityFactor = priorities.get( config.converterPriority ) / maxPriority; // Number in range [ -1, 1 ].\n\n\t\tdispatcher.on( 'element', upcastAttributeToMarker( config ), { priority: basePriority + priorityFactor } );\n\t};\n}\n\n// Function factory, returns a callback function which converts view attributes to a model marker.\n//\n// The converter looks for elements with `data-group-start-before`, `data-group-start-after`, `data-group-end-before`\n// and `data-group-end-after` attributes and inserts `$marker` model elements before/after those elements.\n// `group` part is specified in `config.view`.\n//\n// @param {Object} config\n// @param {String} config.view\n// @param {Function} [config.model]\n// @returns {Function} Marker converter.\nfunction upcastAttributeToMarker( config ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst attrName = `data-${ config.view }`;\n\n\t\t// This converter wants to add a model element, marking a marker, before/after an element (or maybe even group of elements).\n\t\t// To do that, we can use `data.modelRange` which is set on an element (or a group of elements) that has been upcasted.\n\t\t// But, if the processed view element has not been upcasted yet (it does not have been converted), we need to\n\t\t// fire conversion for its children first, then we will have `data.modelRange` available.\n\t\tif ( !data.modelRange ) {\n\t\t\tdata = Object.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-end-after' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.end, data.viewItem.getAttribute( attrName + '-end-after' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-start-after' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.end, data.viewItem.getAttribute( attrName + '-start-after' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-end-before' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.start, data.viewItem.getAttribute( attrName + '-end-before' ).split( ',' ) );\n\t\t}\n\n\t\tif ( conversionApi.consumable.consume( data.viewItem, { attributes: attrName + '-start-before' } ) ) {\n\t\t\taddMarkerElements( data.modelRange.start, data.viewItem.getAttribute( attrName + '-start-before' ).split( ',' ) );\n\t\t}\n\n\t\tfunction addMarkerElements( position, markerViewNames ) {\n\t\t\tfor ( const markerViewName of markerViewNames ) {\n\t\t\t\tconst markerName = config.model( markerViewName, conversionApi );\n\t\t\t\tconst element = conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\n\t\t\t\tconversionApi.writer.insert( element, position );\n\n\t\t\t\tif ( data.modelCursor.isEqual( position ) ) {\n\t\t\t\t\tdata.modelCursor = data.modelCursor.getShiftedBy( 1 );\n\t\t\t\t} else {\n\t\t\t\t\tdata.modelCursor = data.modelCursor._getTransformedByInsertion( position, 1 );\n\t\t\t\t}\n\n\t\t\t\tdata.modelRange = data.modelRange._getTransformedByInsertion( position, 1 )[ 0 ];\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Helper function for from-view-element conversion. Checks if `config.view` directly specifies converted view element's name\n// and if so, returns it.\n//\n// @param {Object} config Conversion view config.\n// @returns {String|null} View element name or `null` if name is not directly set.\nfunction getViewElementNameFromConfig( viewConfig ) {\n\tif ( typeof viewConfig == 'string' ) {\n\t\treturn viewConfig;\n\t}\n\n\tif ( typeof viewConfig == 'object' && typeof viewConfig.name == 'string' ) {\n\t\treturn viewConfig.name;\n\t}\n\n\treturn null;\n}\n\n// Helper for to-model-element conversion. Takes a config object and returns a proper converter function.\n//\n// @param {Object} config Conversion configuration.\n// @returns {Function} View to model converter.\nfunction prepareToElementConverter( config ) {\n\tconst matcher = new Matcher( config.view );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst matcherResult = matcher.match( data.viewItem );\n\n\t\tif ( !matcherResult ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst match = matcherResult.match;\n\n\t\t// Force consuming element's name.\n\t\tmatch.name = true;\n\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelElement = getModelElement( config.model, data.viewItem, conversionApi );\n\n\t\tif ( !modelElement ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.safeInsert( modelElement, data.modelCursor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconversionApi.consumable.consume( data.viewItem, match );\n\t\tconversionApi.convertChildren( data.viewItem, modelElement );\n\t\tconversionApi.updateConversionResult( modelElement, data );\n\t};\n}\n\n// Helper function for upcasting-to-element converter. Takes the model configuration, the converted view element\n// and a writer instance and returns a model element instance to be inserted in the model.\n//\n// @param {String|Function|module:engine/model/element~Element} model Model conversion configuration.\n// @param {module:engine/view/node~Node} input The converted view node.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi The upcast conversion API.\nfunction getModelElement( model, input, conversionApi ) {\n\tif ( model instanceof Function ) {\n\t\treturn model( input, conversionApi );\n\t} else {\n\t\treturn conversionApi.writer.createElement( model );\n\t}\n}\n\n// Helper function view-attribute-to-model-attribute helper. Normalizes `config.view` which was set as `String` or\n// as an `Object` with `key`, `value` and `name` properties. Normalized `config.view` has is compatible with\n// {@link module:engine/view/matcher~MatcherPattern}.\n//\n// @param {Object} config Conversion config.\n// @returns {String} Key of the converted view attribute.\nfunction normalizeViewAttributeKeyValueConfig( config ) {\n\tif ( typeof config.view == 'string' ) {\n\t\tconfig.view = { key: config.view };\n\t}\n\n\tconst key = config.view.key;\n\tlet normalized;\n\n\tif ( key == 'class' || key == 'style' ) {\n\t\tconst keyName = key == 'class' ? 'classes' : 'styles';\n\n\t\tnormalized = {\n\t\t\t[ keyName ]: config.view.value\n\t\t};\n\t} else {\n\t\tconst value = typeof config.view.value == 'undefined' ? /[\\s\\S]*/ : config.view.value;\n\n\t\tnormalized = {\n\t\t\tattributes: {\n\t\t\t\t[ key ]: value\n\t\t\t}\n\t\t};\n\t}\n\n\tif ( config.view.name ) {\n\t\tnormalized.name = config.view.name;\n\t}\n\n\tconfig.view = normalized;\n\n\treturn key;\n}\n\n// Helper function that normalizes `config.model` in from-model-attribute conversion. `config.model` can be set\n// as a `String`, an `Object` with only `key` property or an `Object` with `key` and `value` properties. Normalized\n// `config.model` is an `Object` with `key` and `value` properties.\n//\n// @param {Object} config Conversion config.\n// @param {String} viewAttributeKeyToCopy Key of the converted view attribute. If it is set, model attribute value\n// will be equal to view attribute value.\nfunction normalizeModelAttributeConfig( config, viewAttributeKeyToCopy = null ) {\n\tconst defaultModelValue = viewAttributeKeyToCopy === null ? true : viewElement => viewElement.getAttribute( viewAttributeKeyToCopy );\n\n\tconst key = typeof config.model != 'object' ? config.model : config.model.key;\n\tconst value = typeof config.model != 'object' || typeof config.model.value == 'undefined' ? defaultModelValue : config.model.value;\n\n\tconfig.model = { key, value };\n}\n\n// Helper for to-model-attribute conversion. Takes the model attribute name and conversion configuration and returns\n// a proper converter function.\n//\n// @param {String} modelAttributeKey The key of the model attribute to set on a model node.\n// @param {Object|Array.<Object>} config Conversion configuration. It is possible to provide multiple configurations in an array.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\nfunction prepareToAttributeConverter( config, shallow ) {\n\tconst matcher = new Matcher( config.view );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst match = matcher.match( data.viewItem );\n\n\t\t// If there is no match, this callback should not do anything.\n\t\tif ( !match ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelKey = config.model.key;\n\t\tconst modelValue = typeof config.model.value == 'function' ?\n\t\t\tconfig.model.value( data.viewItem, conversionApi ) : config.model.value;\n\n\t\t// Do not convert if attribute building function returned falsy value.\n\t\tif ( modelValue === null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( onlyViewNameIsDefined( config.view, data.viewItem ) ) {\n\t\t\tmatch.match.name = true;\n\t\t} else {\n\t\t\t// Do not test or consume `name` consumable.\n\t\t\tdelete match.match.name;\n\t\t}\n\n\t\t// Try to consume appropriate values from consumable values list.\n\t\tif ( !conversionApi.consumable.test( data.viewItem, match.match ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Since we are converting to attribute we need a range on which we will set the attribute.\n\t\t// If the range is not created yet, let's create it by converting children of the current node first.\n\t\tif ( !data.modelRange ) {\n\t\t\t// Convert children and set conversion result as a current data.\n\t\t\tdata = Object.assign( data, conversionApi.convertChildren( data.viewItem, data.modelCursor ) );\n\t\t}\n\n\t\t// Set attribute on current `output`. `Schema` is checked inside this helper function.\n\t\tconst attributeWasSet = setAttributeOn( data.modelRange, { key: modelKey, value: modelValue }, shallow, conversionApi );\n\n\t\t// It may happen that a converter will try to set an attribute that is not allowed in the given context.\n\t\t// In such a situation we cannot consume the attribute. See: https://github.com/ckeditor/ckeditor5/pull/9249#issuecomment-815658459.\n\t\tif ( attributeWasSet ) {\n\t\t\tconversionApi.consumable.consume( data.viewItem, match.match );\n\t\t}\n\t};\n}\n\n// Helper function that checks if element name should be consumed in attribute converters.\n//\n// @param {Object} config Conversion view config.\n// @returns {Boolean}\nfunction onlyViewNameIsDefined( viewConfig, viewItem ) {\n\t// https://github.com/ckeditor/ckeditor5-engine/issues/1786\n\tconst configToTest = typeof viewConfig == 'function' ? viewConfig( viewItem ) : viewConfig;\n\n\tif ( typeof configToTest == 'object' && !getViewElementNameFromConfig( configToTest ) ) {\n\t\treturn false;\n\t}\n\n\treturn !configToTest.classes && !configToTest.attributes && !configToTest.styles;\n}\n\n// Helper function for to-model-attribute converter. Sets model attribute on given range. Checks {@link module:engine/model/schema~Schema}\n// to ensure proper model structure.\n//\n// If any node on the given range has already defined an attribute with the same name, its value will not be updated.\n//\n// @param {module:engine/model/range~Range} modelRange Model range on which attribute should be set.\n// @param {Object} modelAttribute Model attribute to set.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion API.\n// @param {Boolean} shallow If set to `true` the attribute will be set only on top-level nodes. Otherwise, it will be set\n// on all elements in the range.\n// @returns {Boolean} `true` if attribute was set on at least one node from given `modelRange`.\nfunction setAttributeOn( modelRange, modelAttribute, shallow, conversionApi ) {\n\tlet result = false;\n\n\t// Set attribute on each item in range according to Schema.\n\tfor ( const node of Array.from( modelRange.getItems( { shallow } ) ) ) {\n\t\t// Skip if not allowed.\n\t\tif ( !conversionApi.schema.checkAttribute( node, modelAttribute.key ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mark the node as consumed even if the attribute will not be updated because it's in a valid context (schema)\n\t\t// and would be converted if the attribute wouldn't be present. See #8921.\n\t\tresult = true;\n\n\t\t// Do not override the attribute if it's already present.\n\t\tif ( node.hasAttribute( modelAttribute.key ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconversionApi.writer.setAttribute( modelAttribute.key, modelAttribute.value, node );\n\t}\n\n\treturn result;\n}\n\n// Helper function for upcasting-to-marker conversion. Takes the config in a format requested by `upcastElementToMarker()`\n// function and converts it to a format that is supported by `upcastElementToElement()` function.\n//\n// @param {Object} config Conversion configuration.\nfunction normalizeElementToMarkerConfig( config ) {\n\tconst oldModel = config.model;\n\n\tconfig.model = ( viewElement, conversionApi ) => {\n\t\tconst markerName = typeof oldModel == 'string' ? oldModel : oldModel( viewElement, conversionApi );\n\n\t\treturn conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\t};\n}\n\n// Helper function for upcasting-to-marker conversion. Takes the config in a format requested by `upcastDataToMarker()`\n// function and converts it to a format that is supported by `upcastElementToElement()` function.\n//\n// @param {Object} config Conversion configuration.\nfunction normalizeDataToMarkerConfig( config, type ) {\n\tconst configForElements = {};\n\n\t// Upcast <markerGroup-start> and <markerGroup-end> elements.\n\tconfigForElements.view = config.view + '-' + type;\n\n\tconfigForElements.model = ( viewElement, conversionApi ) => {\n\t\tconst viewName = viewElement.getAttribute( 'name' );\n\t\tconst markerName = config.model( viewName, conversionApi );\n\n\t\treturn conversionApi.writer.createElement( '$marker', { 'data-name': markerName } );\n\t};\n\n\treturn configForElements;\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/controller/editingcontroller\n */\n\nimport RootEditableElement from '../view/rooteditableelement';\nimport View from '../view/view';\nimport Mapper from '../conversion/mapper';\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { clearAttributes, convertCollapsedSelection, convertRangeSelection, insertText, remove } from '../conversion/downcasthelpers';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { convertSelectionChange } from '../conversion/upcasthelpers';\n\n// @if CK_DEBUG_ENGINE // const { dumpTrees, initDocumentDumping } = require( '../dev-utils/utils' );\n\n/**\n * Controller for the editing pipeline. The editing pipeline controls {@link ~EditingController#model model} rendering,\n * including selection handling. It also creates the {@link ~EditingController#view view} which builds a\n * browser-independent virtualization over the DOM elements. The editing controller also attaches default converters.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class EditingController {\n\t/**\n\t * Creates an editing controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Editing model.\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( model, stylesProcessor ) {\n\t\t/**\n\t\t * Editor model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Editing view controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/view~View}\n\t\t */\n\t\tthis.view = new View( stylesProcessor );\n\n\t\t/**\n\t\t * Mapper which describes the model-view binding.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher that converts changes from the model to {@link #view the editing view}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher} #downcastDispatcher\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper,\n\t\t\tschema: model.schema\n\t\t} );\n\n\t\tconst doc = this.model.document;\n\t\tconst selection = doc.selection;\n\t\tconst markers = this.model.markers;\n\n\t\t// When plugins listen on model changes (on selection change, post fixers, etc.) and change the view as a result of\n\t\t// model's change, they might trigger view rendering before the conversion is completed (e.g. before the selection\n\t\t// is converted). We disable rendering for the length of the outermost model change() block to prevent that.\n\t\t//\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1528\n\t\tthis.listenTo( this.model, '_beforeChanges', () => {\n\t\t\tthis.view._disableRendering( true );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( this.model, '_afterChanges', () => {\n\t\t\tthis.view._disableRendering( false );\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Whenever model document is changed, convert those changes to the view (using model.Document#differ).\n\t\t// Do it on 'low' priority, so changes are converted after other listeners did their job.\n\t\t// Also convert model selection.\n\t\tthis.listenTo( doc, 'change', () => {\n\t\t\tthis.view.change( writer => {\n\t\t\t\tthis.downcastDispatcher.convertChanges( doc.differ, markers, writer );\n\t\t\t\tthis.downcastDispatcher.convertSelection( selection, markers, writer );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\n\t\t// Convert selection from the view to the model when it changes in the view.\n\t\tthis.listenTo( this.view.document, 'selectionChange', convertSelectionChange( this.model, this.mapper ) );\n\n\t\t// Attach default model converters.\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\t\tthis.downcastDispatcher.on( 'remove', remove(), { priority: 'low' } );\n\n\t\t// Attach default model selection converters.\n\t\tthis.downcastDispatcher.on( 'selection', clearAttributes(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertRangeSelection(), { priority: 'low' } );\n\t\tthis.downcastDispatcher.on( 'selection', convertCollapsedSelection(), { priority: 'low' } );\n\n\t\t// Binds {@link module:engine/view/document~Document#roots view roots collection} to\n\t\t// {@link module:engine/model/document~Document#roots model roots collection} so creating\n\t\t// model root automatically creates corresponding view root.\n\t\tthis.view.document.roots.bindTo( this.model.document.roots ).using( root => {\n\t\t\t// $graveyard is a special root that has no reflection in the view.\n\t\t\tif ( root.rootName == '$graveyard' ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst viewRoot = new RootEditableElement( this.view.document, root.name );\n\n\t\t\tviewRoot.rootName = root.rootName;\n\t\t\tthis.mapper.bindElements( root, viewRoot );\n\n\t\t\treturn viewRoot;\n\t\t} );\n\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.model.document );\n\t\t// @if CK_DEBUG_ENGINE // initDocumentDumping( this.view.document );\n\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.model.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // dumpTrees( this.view.document, this.model.document.version );\n\n\t\t// @if CK_DEBUG_ENGINE // this.model.document.on( 'change', () => {\n\t\t// @if CK_DEBUG_ENGINE //\tdumpTrees( this.view.document, this.model.document.version );\n\t\t// @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Removes all event listeners attached to the `EditingController`. Destroys all objects created\n\t * by `EditingController` that need to be destroyed.\n\t */\n\tdestroy() {\n\t\tthis.view.destroy();\n\t\tthis.stopListening();\n\t}\n}\n\nmix( EditingController, ObservableMixin );\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 core/commandcollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Collection of commands. Its instance is available in {@link module:core/editor/editor~Editor#commands `editor.commands`}.\n */\nexport default class CommandCollection {\n\t/**\n\t * Creates collection instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Command map.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._commands = new Map();\n\t}\n\n\t/**\n\t * Registers a new command.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @param {module:core/command~Command} command\n\t */\n\tadd( commandName, command ) {\n\t\tthis._commands.set( commandName, command );\n\t}\n\n\t/**\n\t * Retrieves a command from the collection.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @returns {module:core/command~Command}\n\t */\n\tget( commandName ) {\n\t\treturn this._commands.get( commandName );\n\t}\n\n\t/**\n\t * Executes a command.\n\t *\n\t * @param {String} commandName The name of the command.\n\t * @param {*} [...commandParams] Command parameters.\n\t * @returns {*} The value returned by the {@link module:core/command~Command#execute `command.execute()`}.\n\t */\n\texecute( commandName, ...args ) {\n\t\tconst command = this.get( commandName );\n\n\t\tif ( !command ) {\n\t\t\t/**\n\t\t\t * Command does not exist.\n\t\t\t *\n\t\t\t * @error commandcollection-command-not-found\n\t\t\t * @param {String} commandName Name of the command.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'commandcollection-command-not-found', this, { commandName } );\n\t\t}\n\n\t\treturn command.execute( ...args );\n\t}\n\n\t/**\n\t * Returns iterator of command names.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tyield* this._commands.keys();\n\t}\n\n\t/**\n\t * Returns iterator of command instances.\n\t *\n\t * @returns {Iterable.<module:core/command~Command>}\n\t */\n\t* commands() {\n\t\tyield* this._commands.values();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Returns `[ commandName, commandInstance ]` pairs.\n\t *\n\t * @returns {Iterable.<Array>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._commands[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Destroys all collection commands.\n\t */\n\tdestroy() {\n\t\tfor ( const command of this.commands() ) {\n\t\t\tcommand.destroy();\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/viewconsumable\n */\n\nimport { isArray } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Class used for handling consumption of view {@link module:engine/view/element~Element elements},\n * {@link module:engine/view/text~Text text nodes} and {@link module:engine/view/documentfragment~DocumentFragment document fragments}.\n * Element's name and its parts (attributes, classes and styles) can be consumed separately. Consuming an element's name\n * does not consume its attributes, classes and styles.\n * To add items for consumption use {@link module:engine/conversion/viewconsumable~ViewConsumable#add add method}.\n * To test items use {@link module:engine/conversion/viewconsumable~ViewConsumable#test test method}.\n * To consume items use {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consume method}.\n * To revert already consumed items use {@link module:engine/conversion/viewconsumable~ViewConsumable#revert revert method}.\n *\n *\t\tviewConsumable.add( element, { name: true } ); // Adds element's name as ready to be consumed.\n *\t\tviewConsumable.add( textNode ); // Adds text node for consumption.\n *\t\tviewConsumable.add( docFragment ); // Adds document fragment for consumption.\n *\t\tviewConsumable.test( element, { name: true } ); // Tests if element's name can be consumed.\n *\t\tviewConsumable.test( textNode ); // Tests if text node can be consumed.\n *\t\tviewConsumable.test( docFragment ); // Tests if document fragment can be consumed.\n *\t\tviewConsumable.consume( element, { name: true } ); // Consume element's name.\n *\t\tviewConsumable.consume( textNode ); // Consume text node.\n *\t\tviewConsumable.consume( docFragment ); // Consume document fragment.\n *\t\tviewConsumable.revert( element, { name: true } ); // Revert already consumed element's name.\n *\t\tviewConsumable.revert( textNode ); // Revert already consumed text node.\n *\t\tviewConsumable.revert( docFragment ); // Revert already consumed document fragment.\n */\nexport default class ViewConsumable {\n\t/**\n\t * Creates new ViewConsumable.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Map of consumable elements. If {@link module:engine/view/element~Element element} is used as a key,\n\t\t * {@link module:engine/conversion/viewconsumable~ViewElementConsumables ViewElementConsumables} instance is stored as value.\n\t\t * For {@link module:engine/view/text~Text text nodes} and\n\t\t * {@link module:engine/view/documentfragment~DocumentFragment document fragments} boolean value is stored as value.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map.<module:engine/conversion/viewconsumable~ViewElementConsumables|Boolean>}\n\t\t*/\n\t\tthis._consumables = new Map();\n\t}\n\n\t/**\n\t * Adds {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} as ready to be consumed.\n\t *\n\t *\t\tviewConsumable.add( p, { name: true } ); // Adds element's name to consume.\n\t *\t\tviewConsumable.add( p, { attributes: 'name' } ); // Adds element's attribute.\n\t *\t\tviewConsumable.add( p, { classes: 'foobar' } ); // Adds element's class.\n\t *\t\tviewConsumable.add( p, { styles: 'color' } ); // Adds element's style\n\t *\t\tviewConsumable.add( p, { attributes: 'name', styles: 'color' } ); // Adds attribute and style.\n\t *\t\tviewConsumable.add( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be provided.\n\t *\t\tviewConsumable.add( textNode ); // Adds text node to consume.\n\t *\t\tviewConsumable.add( docFragment ); // Adds document fragment to consume.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * attribute is provided - it should be handled separately by providing actual style/class.\n\t *\n\t *\t\tviewConsumable.add( p, { attributes: 'style' } ); // This call will throw an exception.\n\t *\t\tviewConsumable.add( p, { styles: 'color' } ); // This is properly handled style.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t */\n\tadd( element, consumables ) {\n\t\tlet elementConsumables;\n\n\t\t// For text nodes and document fragments just mark them as consumable.\n\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\tthis._consumables.set( element, true );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// For elements create new ViewElementConsumables or update already existing one.\n\t\tif ( !this._consumables.has( element ) ) {\n\t\t\telementConsumables = new ViewElementConsumables( element );\n\t\t\tthis._consumables.set( element, elementConsumables );\n\t\t} else {\n\t\t\telementConsumables = this._consumables.get( element );\n\t\t}\n\n\t\telementConsumables.add( consumables );\n\t}\n\n\t/**\n\t * Tests if {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} can be consumed.\n\t * It returns `true` when all items included in method's call can be consumed. Returns `false` when\n\t * first already consumed item is found and `null` when first non-consumable item is found.\n\t *\n\t *\t\tviewConsumable.test( p, { name: true } ); // Tests element's name.\n\t *\t\tviewConsumable.test( p, { attributes: 'name' } ); // Tests attribute.\n\t *\t\tviewConsumable.test( p, { classes: 'foobar' } ); // Tests class.\n\t *\t\tviewConsumable.test( p, { styles: 'color' } ); // Tests style.\n\t *\t\tviewConsumable.test( p, { attributes: 'name', styles: 'color' } ); // Tests attribute and style.\n\t *\t\tviewConsumable.test( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be tested.\n\t *\t\tviewConsumable.test( textNode ); // Tests text node.\n\t *\t\tviewConsumable.test( docFragment ); // Tests document fragment.\n\t *\n\t * Testing classes and styles as attribute will test if all added classes/styles can be consumed.\n\t *\n\t *\t\tviewConsumable.test( p, { attributes: 'class' } ); // Tests if all added classes can be consumed.\n\t *\t\tviewConsumable.test( p, { attributes: 'style' } ); // Tests if all added styles can be consumed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t * @returns {Boolean|null} Returns `true` when all items included in method's call can be consumed. Returns `false`\n\t * when first already consumed item is found and `null` when first non-consumable item is found.\n\t */\n\ttest( element, consumables ) {\n\t\tconst elementConsumables = this._consumables.get( element );\n\n\t\tif ( elementConsumables === undefined ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// For text nodes and document fragments return stored boolean value.\n\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\treturn elementConsumables;\n\t\t}\n\n\t\t// For elements test consumables object.\n\t\treturn elementConsumables.test( consumables );\n\t}\n\n\t/**\n\t * Consumes {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t * It returns `true` when all items included in method's call can be consumed, otherwise returns `false`.\n\t *\n\t *\t\tviewConsumable.consume( p, { name: true } ); // Consumes element's name.\n\t *\t\tviewConsumable.consume( p, { attributes: 'name' } ); // Consumes element's attribute.\n\t *\t\tviewConsumable.consume( p, { classes: 'foobar' } ); // Consumes element's class.\n\t *\t\tviewConsumable.consume( p, { styles: 'color' } ); // Consumes element's style.\n\t *\t\tviewConsumable.consume( p, { attributes: 'name', styles: 'color' } ); // Consumes attribute and style.\n\t *\t\tviewConsumable.consume( p, { classes: [ 'baz', 'bar' ] } ); // Multiple consumables can be consumed.\n\t *\t\tviewConsumable.consume( textNode ); // Consumes text node.\n\t *\t\tviewConsumable.consume( docFragment ); // Consumes document fragment.\n\t *\n\t * Consuming classes and styles as attribute will test if all added classes/styles can be consumed.\n\t *\n\t *\t\tviewConsumable.consume( p, { attributes: 'class' } ); // Consume only if all added classes can be consumed.\n\t *\t\tviewConsumable.consume( p, { attributes: 'style' } ); // Consume only if all added styles can be consumed.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t * @returns {Boolean} Returns `true` when all items included in method's call can be consumed,\n\t * otherwise returns `false`.\n\t */\n\tconsume( element, consumables ) {\n\t\tif ( this.test( element, consumables ) ) {\n\t\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\t\t// For text nodes and document fragments set value to false.\n\t\t\t\tthis._consumables.set( element, false );\n\t\t\t} else {\n\t\t\t\t// For elements - consume consumables object.\n\t\t\t\tthis._consumables.get( element ).consume( consumables );\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Reverts {@link module:engine/view/element~Element view element}, {@link module:engine/view/text~Text text node} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment document fragment} so they can be consumed once again.\n\t * Method does not revert items that were never previously added for consumption, even if they are included in\n\t * method's call.\n\t *\n\t *\t\tviewConsumable.revert( p, { name: true } ); // Reverts element's name.\n\t *\t\tviewConsumable.revert( p, { attributes: 'name' } ); // Reverts element's attribute.\n\t *\t\tviewConsumable.revert( p, { classes: 'foobar' } ); // Reverts element's class.\n\t *\t\tviewConsumable.revert( p, { styles: 'color' } ); // Reverts element's style.\n\t *\t\tviewConsumable.revert( p, { attributes: 'name', styles: 'color' } ); // Reverts attribute and style.\n\t *\t\tviewConsumable.revert( p, { classes: [ 'baz', 'bar' ] } ); // Multiple names can be reverted.\n\t *\t\tviewConsumable.revert( textNode ); // Reverts text node.\n\t *\t\tviewConsumable.revert( docFragment ); // Reverts document fragment.\n\t *\n\t * Reverting classes and styles as attribute will revert all classes/styles that were previously added for\n\t * consumption.\n\t *\n\t *\t\tviewConsumable.revert( p, { attributes: 'class' } ); // Reverts all classes added for consumption.\n\t *\t\tviewConsumable.revert( p, { attributes: 'style' } ); // Reverts all styles added for consumption.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/text~Text|module:engine/view/documentfragment~DocumentFragment} element\n\t * @param {Object} [consumables] Used only if first parameter is {@link module:engine/view/element~Element view element} instance.\n\t * @param {Boolean} consumables.name If set to true element's name will be included.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names.\n\t */\n\trevert( element, consumables ) {\n\t\tconst elementConsumables = this._consumables.get( element );\n\n\t\tif ( elementConsumables !== undefined ) {\n\t\t\tif ( element.is( '$text' ) || element.is( 'documentFragment' ) ) {\n\t\t\t\t// For text nodes and document fragments - set consumable to true.\n\t\t\t\tthis._consumables.set( element, true );\n\t\t\t} else {\n\t\t\t\t// For elements - revert items from consumables object.\n\t\t\t\telementConsumables.revert( consumables );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates consumable object from {@link module:engine/view/element~Element view element}. Consumable object will include\n\t * element's name and all its attributes, classes and styles.\n\t *\n\t * @static\n\t * @param {module:engine/view/element~Element} element\n\t * @returns {Object} consumables\n\t */\n\tstatic consumablesFromElement( element ) {\n\t\tconst consumables = {\n\t\t\telement,\n\t\t\tname: true,\n\t\t\tattributes: [],\n\t\t\tclasses: [],\n\t\t\tstyles: []\n\t\t};\n\n\t\tconst attributes = element.getAttributeKeys();\n\n\t\tfor ( const attribute of attributes ) {\n\t\t\t// Skip classes and styles - will be added separately.\n\t\t\tif ( attribute == 'style' || attribute == 'class' ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconsumables.attributes.push( attribute );\n\t\t}\n\n\t\tconst classes = element.getClassNames();\n\n\t\tfor ( const className of classes ) {\n\t\t\tconsumables.classes.push( className );\n\t\t}\n\n\t\tconst styles = element.getStyleNames();\n\n\t\tfor ( const style of styles ) {\n\t\t\tconsumables.styles.push( style );\n\t\t}\n\n\t\treturn consumables;\n\t}\n\n\t/**\n\t * Creates {@link module:engine/conversion/viewconsumable~ViewConsumable ViewConsumable} instance from\n\t * {@link module:engine/view/node~Node node} or {@link module:engine/view/documentfragment~DocumentFragment document fragment}.\n\t * Instance will contain all elements, child nodes, attributes, styles and classes added for consumption.\n\t *\n\t * @static\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} from View node or document fragment\n\t * from which `ViewConsumable` will be created.\n\t * @param {module:engine/conversion/viewconsumable~ViewConsumable} [instance] If provided, given `ViewConsumable` instance will be used\n\t * to add all consumables. It will be returned instead of a new instance.\n\t */\n\tstatic createFrom( from, instance ) {\n\t\tif ( !instance ) {\n\t\t\tinstance = new ViewConsumable( from );\n\t\t}\n\n\t\tif ( from.is( '$text' ) ) {\n\t\t\tinstance.add( from );\n\n\t\t\treturn instance;\n\t\t}\n\n\t\t// Add `from` itself, if it is an element.\n\t\tif ( from.is( 'element' ) ) {\n\t\t\tinstance.add( from, ViewConsumable.consumablesFromElement( from ) );\n\t\t}\n\n\t\tif ( from.is( 'documentFragment' ) ) {\n\t\t\tinstance.add( from );\n\t\t}\n\n\t\tfor ( const child of from.getChildren() ) {\n\t\t\tinstance = ViewConsumable.createFrom( child, instance );\n\t\t}\n\n\t\treturn instance;\n\t}\n}\n\n/**\n * This is a private helper-class for {@link module:engine/conversion/viewconsumable~ViewConsumable}.\n * It represents and manipulates consumable parts of a single {@link module:engine/view/element~Element}.\n *\n * @private\n */\nclass ViewElementConsumables {\n\t/**\n\t * Creates ViewElementConsumables instance.\n\t *\n\t * @param {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment} from View node or document fragment\n\t * from which `ViewElementConsumables` is being created.\n\t */\n\tconstructor( from ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @member {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment}\n\t\t */\n\t\tthis.element = from;\n\n\t\t/**\n\t\t * Flag indicating if name of the element can be consumed.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._canConsumeName = null;\n\n\t\t/**\n\t\t * Contains maps of element's consumables: attributes, classes and styles.\n\t\t *\n\t\t * @private\n\t\t * @member {Object}\n\t\t */\n\t\tthis._consumables = {\n\t\t\tattributes: new Map(),\n\t\t\tstyles: new Map(),\n\t\t\tclasses: new Map()\n\t\t};\n\t}\n\n\t/**\n\t * Adds consumable parts of the {@link module:engine/view/element~Element view element}.\n\t * Element's name itself can be marked to be consumed (when element's name is consumed its attributes, classes and\n\t * styles still could be consumed):\n\t *\n\t *\t\tconsumables.add( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.add( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.add( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * attribute is provided - it should be handled separately by providing `style` and `class` in consumables object.\n\t *\n\t * @param {Object} consumables Object describing which parts of the element can be consumed.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be added as consumable.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to add as consumable.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to add as consumable.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to add as consumable.\n\t */\n\tadd( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = true;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._add( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Tests if parts of the {@link module:engine/view/node~Node view node} can be consumed.\n\t *\n\t * Element's name can be tested:\n\t *\n\t *\t\tconsumables.test( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.test( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.test( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be tested.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be tested.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to test.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to test.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to test.\n\t * @returns {Boolean|null} `true` when all tested items can be consumed, `null` when even one of the items\n\t * was never marked for consumption and `false` when even one of the items was already consumed.\n\t */\n\ttest( consumables ) {\n\t\t// Check if name can be consumed.\n\t\tif ( consumables.name && !this._canConsumeName ) {\n\t\t\treturn this._canConsumeName;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tconst value = this._test( type, consumables[ type ] );\n\n\t\t\t\tif ( value !== true ) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Return true only if all can be consumed.\n\t\treturn true;\n\t}\n\n\t/**\n\t * Consumes parts of {@link module:engine/view/element~Element view element}. This function does not check if consumable item\n\t * is already consumed - it consumes all consumable items provided.\n\t * Element's name can be consumed:\n\t *\n\t *\t\tconsumables.consume( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.consume( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.consume( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be consumed.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be consumed.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to consume.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to consume.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to consume.\n\t */\n\tconsume( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = false;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._consume( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Revert already consumed parts of {@link module:engine/view/element~Element view Element}, so they can be consumed once again.\n\t * Element's name can be reverted:\n\t *\n\t *\t\tconsumables.revert( { name: true } );\n\t *\n\t * Attributes classes and styles:\n\t *\n\t *\t\tconsumables.revert( { attributes: 'title', classes: 'foo', styles: 'color' } );\n\t *\t\tconsumables.revert( { attributes: [ 'title', 'name' ], classes: [ 'foo', 'bar' ] );\n\t *\n\t * @param {Object} consumables Object describing which parts of the element should be reverted.\n\t * @param {Boolean} consumables.name If set to `true` element's name will be reverted.\n\t * @param {String|Array.<String>} consumables.attributes Attribute name or array of attribute names to revert.\n\t * @param {String|Array.<String>} consumables.classes Class name or array of class names to revert.\n\t * @param {String|Array.<String>} consumables.styles Style name or array of style names to revert.\n\t */\n\trevert( consumables ) {\n\t\tif ( consumables.name ) {\n\t\t\tthis._canConsumeName = true;\n\t\t}\n\n\t\tfor ( const type in this._consumables ) {\n\t\t\tif ( type in consumables ) {\n\t\t\t\tthis._revert( type, consumables[ type ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that adds consumables of a given type: attribute, class or style.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `viewconsumable-invalid-attribute` when `class` or `style`\n\t * type is provided - it should be handled separately by providing actual style/class type.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_add( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\t/**\n\t\t\t\t * Class and style attributes should be handled separately in\n\t\t\t\t * {@link module:engine/conversion/viewconsumable~ViewConsumable#add `ViewConsumable#add()`}.\n\t\t\t\t *\n\t\t\t\t * What you have done is trying to use:\n\t\t\t\t *\n\t\t\t\t *\t\tconsumables.add( { attributes: [ 'class', 'style' ] } );\n\t\t\t\t *\n\t\t\t\t * While each class and style should be registered separately:\n\t\t\t\t *\n\t\t\t\t *\t\tconsumables.add( { classes: 'some-class', styles: 'font-weight' } );\n\t\t\t\t *\n\t\t\t\t * @error viewconsumable-invalid-attribute\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'viewconsumable-invalid-attribute', this );\n\t\t\t}\n\n\t\t\tconsumables.set( name, true );\n\n\t\t\tif ( type === 'styles' ) {\n\t\t\t\tfor ( const alsoName of this.element.document.stylesProcessor.getRelatedStyles( name ) ) {\n\t\t\t\t\tconsumables.set( alsoName, true );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that tests consumables of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t * @returns {Boolean|null} Returns `true` if all items can be consumed, `null` when one of the items cannot be\n\t * consumed and `false` when one of the items is already consumed.\n\t */\n\t_test( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// Check all classes/styles if class/style attribute is tested.\n\t\t\t\tconst value = this._test( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\n\t\t\t\tif ( value !== true ) {\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst value = consumables.get( name );\n\t\t\t\t// Return null if attribute is not found.\n\t\t\t\tif ( value === undefined ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tif ( !value ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Helper method that consumes items of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_consume( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// If class or style is provided for consumption - consume them all.\n\t\t\t\tthis._consume( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\t\t\t} else {\n\t\t\t\tconsumables.set( name, false );\n\n\t\t\t\tif ( type == 'styles' ) {\n\t\t\t\t\tfor ( const toConsume of this.element.document.stylesProcessor.getRelatedStyles( name ) ) {\n\t\t\t\t\t\tconsumables.set( toConsume, false );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Helper method that reverts items of a given type: attribute, class or style.\n\t *\n\t * @private\n\t * @param {String} type Type of the consumable item: `attributes`, `classes` or , `styles`.\n\t * @param {String|Array.<String>} item Consumable item or array of items.\n\t */\n\t_revert( type, item ) {\n\t\tconst items = isArray( item ) ? item : [ item ];\n\t\tconst consumables = this._consumables[ type ];\n\n\t\tfor ( const name of items ) {\n\t\t\tif ( type === 'attributes' && ( name === 'class' || name === 'style' ) ) {\n\t\t\t\tconst consumableName = name == 'class' ? 'classes' : 'styles';\n\n\t\t\t\t// If class or style is provided for reverting - revert them all.\n\t\t\t\tthis._revert( consumableName, [ ...this._consumables[ consumableName ].keys() ] );\n\t\t\t} else {\n\t\t\t\tconst value = consumables.get( name );\n\n\t\t\t\tif ( value === false ) {\n\t\t\t\t\tconsumables.set( name, true );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/schema\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport Range from './range';\nimport Position from './position';\nimport Element from './element';\nimport Text from './text';\nimport TreeWalker from './treewalker';\n\n/**\n * The model's schema. It defines allowed and disallowed structures of nodes as well as nodes' attributes.\n * The schema is usually defined by features and based on them the editing framework and features\n * make decisions how to change and process the model.\n *\n * The instance of schema is available in {@link module:engine/model/model~Model#schema `editor.model.schema`}.\n *\n * Read more about the schema in:\n *\n * * {@glink framework/guides/architecture/editing-engine#schema Schema} section of the\n * {@glink framework/guides/architecture/editing-engine Introduction to the Editing engine architecture}.\n * * {@glink framework/guides/deep-dive/schema Schema deep dive} guide.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Schema {\n\t/**\n\t * Creates schema instance.\n\t */\n\tconstructor() {\n\t\tthis._sourceDefinitions = {};\n\n\t\t/**\n\t\t * A dictionary containing attribute properties.\n\t\t *\n\t\t * @private\n\t\t * @member {Object.<String,String>}\n\t\t */\n\t\tthis._attributeProperties = {};\n\n\t\tthis.decorate( 'checkChild' );\n\t\tthis.decorate( 'checkAttribute' );\n\n\t\tthis.on( 'checkAttribute', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.on( 'checkChild', ( evt, args ) => {\n\t\t\targs[ 0 ] = new SchemaContext( args[ 0 ] );\n\t\t\targs[ 1 ] = this.getDefinition( args[ 1 ] );\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Registers schema item. Can only be called once for every item name.\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tinheritAllFrom: '$block'\n\t *\t\t} );\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\tregister( itemName, definition ) {\n\t\tif ( this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * A single item cannot be registered twice in the schema.\n\t\t\t *\n\t\t\t * This situation may happen when:\n\t\t\t *\n\t\t\t * * Two or more plugins called {@link #register `register()`} with the same name. This will usually mean that\n\t\t\t * there is a collision between plugins which try to use the same element in the model. Unfortunately,\n\t\t\t * the only way to solve this is by modifying one of these plugins to use a unique model element name.\n\t\t\t * * A single plugin was loaded twice. This happens when it is installed by npm/yarn in two versions\n\t\t\t * and usually means one or more of the following issues:\n\t\t\t * * a version mismatch (two of your dependencies require two different versions of this plugin),\n\t\t\t * * incorrect imports (this plugin is somehow imported twice in a way which confuses webpack),\n\t\t\t * * mess in `node_modules/` (`rm -rf node_modules/` may help).\n\t\t\t *\n\t\t\t * **Note:** Check the logged `itemName` to better understand which plugin was duplicated/conflicting.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element that is being registered twice.\n\t\t\t * @error schema-cannot-register-item-twice\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'schema-cannot-register-item-twice',\n\t\t\t\tthis,\n\t\t\t\t{\n\t\t\t\t\titemName\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ] = [\n\t\t\tObject.assign( {}, definition )\n\t\t];\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Extends a {@link #register registered} item's definition.\n\t *\n\t * Extending properties such as `allowIn` will add more items to the existing properties,\n\t * while redefining properties such as `isBlock` will override the previously defined ones.\n\t *\n\t *\t\tschema.register( 'foo', {\n\t *\t\t\tallowIn: '$root',\n\t *\t\t\tisBlock: true;\n\t *\t\t} );\n\t *\t\tschema.extend( 'foo', {\n\t *\t\t\tallowIn: 'blockQuote',\n\t *\t\t\tisBlock: false\n\t *\t\t} );\n\t *\n\t *\t\tschema.getDefinition( 'foo' );\n\t *\t\t//\t{\n\t *\t\t//\t\tallowIn: [ '$root', 'blockQuote' ],\n\t *\t\t// \t\tisBlock: false\n\t *\t\t//\t}\n\t *\n\t * @param {String} itemName\n\t * @param {module:engine/model/schema~SchemaItemDefinition} definition\n\t */\n\textend( itemName, definition ) {\n\t\tif ( !this._sourceDefinitions[ itemName ] ) {\n\t\t\t/**\n\t\t\t * Cannot extend an item which was not registered yet.\n\t\t\t *\n\t\t\t * This error happens when a plugin tries to extend the schema definition of an item which was not\n\t\t\t * {@link #register registered} yet.\n\t\t\t *\n\t\t\t * @param itemName The name of the model element which is being extended.\n\t\t\t * @error schema-cannot-extend-missing-item\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'schema-cannot-extend-missing-item', this, {\n\t\t\t\titemName\n\t\t\t} );\n\t\t}\n\n\t\tthis._sourceDefinitions[ itemName ].push( Object.assign( {}, definition ) );\n\n\t\tthis._clearCache();\n\t}\n\n\t/**\n\t * Returns data of all registered items.\n\t *\n\t * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,\n\t * checking a list of all block elements, etc).\n\t * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})\n\t * in other cases.\n\t *\n\t * @returns {Object.<String,module:engine/model/schema~SchemaCompiledItemDefinition>}\n\t */\n\tgetDefinitions() {\n\t\tif ( !this._compiledDefinitions ) {\n\t\t\tthis._compile();\n\t\t}\n\n\t\treturn this._compiledDefinitions;\n\t}\n\n\t/**\n\t * Returns a definition of the given item or `undefined` if an item is not registered.\n\t *\n\t * This method should normally be used for reflection purposes (e.g. defining a clone of a certain element,\n\t * checking a list of all block elements, etc).\n\t * Use specific methods (such as {@link #checkChild `checkChild()`} or {@link #isLimit `isLimit()`})\n\t * in other cases.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t * @returns {module:engine/model/schema~SchemaCompiledItemDefinition}\n\t */\n\tgetDefinition( item ) {\n\t\tlet itemName;\n\n\t\tif ( typeof item == 'string' ) {\n\t\t\titemName = item;\n\t\t} else if ( item.is && ( item.is( '$text' ) || item.is( '$textProxy' ) ) ) {\n\t\t\titemName = '$text';\n\t\t}\n\t\t// Element or module:engine/model/schema~SchemaContextItem.\n\t\telse {\n\t\t\titemName = item.name;\n\t\t}\n\n\t\treturn this.getDefinitions()[ itemName ];\n\t}\n\n\t/**\n\t * Returns `true` if the given item is registered in the schema.\n\t *\n\t *\t\tschema.isRegistered( 'paragraph' ); // -> true\n\t *\t\tschema.isRegistered( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isRegistered( 'foo' ); // -> false\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisRegistered( item ) {\n\t\treturn !!this.getDefinition( item );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a block by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isBlock` property.\n\t *\n\t *\t\tschema.isBlock( 'paragraph' ); // -> true\n\t *\t\tschema.isBlock( '$root' ); // -> false\n\t *\n\t *\t\tconst paragraphElement = writer.createElement( 'paragraph' );\n\t *\t\tschema.isBlock( paragraphElement ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisBlock( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isBlock );\n\t}\n\n\t/**\n\t * Returns `true` if the given item should be treated as a limit element.\n\t *\n\t * It considers an item to be a limit element if its\n\t * {@link module:engine/model/schema~SchemaItemDefinition}'s\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isLimit `isLimit`} or\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property\n\t * was set to `true`.\n\t *\n\t *\t\tschema.isLimit( 'paragraph' ); // -> false\n\t *\t\tschema.isLimit( '$root' ); // -> true\n\t *\t\tschema.isLimit( editor.model.document.getRoot() ); // -> true\n\t *\t\tschema.isLimit( 'image' ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisLimit( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isLimit || def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item should be treated as an object element.\n\t *\n\t * It considers an item to be an object element if its\n\t * {@link module:engine/model/schema~SchemaItemDefinition}'s\n\t * {@link module:engine/model/schema~SchemaItemDefinition#isObject `isObject`} property\n\t * was set to `true`.\n\t *\n\t *\t\tschema.isObject( 'paragraph' ); // -> false\n\t *\t\tschema.isObject( 'image' ); // -> true\n\t *\n\t *\t\tconst imageElement = writer.createElement( 'image' );\n\t *\t\tschema.isObject( imageElement ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisObject( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Note: Check out the implementation of #isLimit(), #isSelectable(), and #isContent()\n\t\t// to understand why these three constitute an object.\n\t\treturn !!( def.isObject || ( def.isLimit && def.isSelectable && def.isContent ) );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * an inline element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isInline` property.\n\t *\n\t *\t\tschema.isInline( 'paragraph' ); // -> false\n\t *\t\tschema.isInline( 'softBreak' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isInline( text ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the Schema deep dive\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisInline( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\treturn !!( def && def.isInline );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a selectable element by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isSelectable` property.\n\t *\n\t *\t\tschema.isSelectable( 'paragraph' ); // -> false\n\t *\t\tschema.isSelectable( 'heading1' ); // -> false\n\t *\t\tschema.isSelectable( 'image' ); // -> true\n\t *\t\tschema.isSelectable( 'tableCell' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isSelectable( text ); // -> false\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements} section of the Schema deep dive}\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisSelectable( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isSelectable || def.isObject );\n\t}\n\n\t/**\n\t * Returns `true` if the given item is defined to be\n\t * a content by the {@link module:engine/model/schema~SchemaItemDefinition}'s `isContent` property.\n\t *\n\t *\t\tschema.isContent( 'paragraph' ); // -> false\n\t *\t\tschema.isContent( 'heading1' ); // -> false\n\t *\t\tschema.isContent( 'image' ); // -> true\n\t *\t\tschema.isContent( 'horizontalLine' ); // -> true\n\t *\n\t *\t\tconst text = writer.createText( 'foo' );\n\t *\t\tschema.isContent( text ); // -> true\n\t *\n\t * See the {@glink framework/guides/deep-dive/schema#content-elements Content elements} section of the Schema deep dive}\n\t * guide for more details.\n\t *\n\t * @param {module:engine/model/item~Item|module:engine/model/schema~SchemaContextItem|String} item\n\t */\n\tisContent( item ) {\n\t\tconst def = this.getDefinition( item );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn !!( def.isContent || def.isObject );\n\t}\n\n\t/**\n\t * Checks whether the given node (`child`) can be a child of the given context.\n\t *\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> false\n\t *\n\t *\t\tschema.register( 'paragraph', {\n\t *\t\t\tallowIn: '$root'\n\t *\t\t} );\n\t *\t\tschema.checkChild( model.document.getRoot(), paragraph ); // -> true\n\t *\n\t * Note: When verifying whether the given node can be a child of the given context, the\n\t * schema also verifies the entire context &mdash; from its root to its last element. Therefore, it is possible\n\t * for `checkChild()` to return `false` even though the context's last element can contain the checked child.\n\t * It happens if one of the context's elements does not allow its child.\n\t *\n\t * @fires checkChild\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the child will be checked.\n\t * @param {module:engine/model/node~Node|String} def The child to check.\n\t */\n\tcheckChild( context, def ) {\n\t\t// Note: context and child are already normalized here to a SchemaContext and SchemaCompiledItemDefinition.\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this._checkContextMatch( def, context );\n\t}\n\n\t/**\n\t * Checks whether the given attribute can be applied in the given context (on the last\n\t * item of the context).\n\t *\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> false\n\t *\n\t *\t\tschema.extend( '$text', {\n\t *\t\t\tallowAttributes: 'bold'\n\t *\t\t} );\n\t *\t\tschema.checkAttribute( textNode, 'bold' ); // -> true\n\t *\n\t * @fires checkAttribute\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context The context in which the attribute will be checked.\n\t * @param {String} attributeName\n\t */\n\tcheckAttribute( context, attributeName ) {\n\t\tconst def = this.getDefinition( context.last );\n\n\t\tif ( !def ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn def.allowAttributes.includes( attributeName );\n\t}\n\n\t/**\n\t * Checks whether the given element (`elementToMerge`) can be merged with the specified base element (`positionOrBaseElement`).\n\t *\n\t * In other words &mdash; whether `elementToMerge`'s children {@link #checkChild are allowed} in the `positionOrBaseElement`.\n\t *\n\t * This check ensures that elements merged with {@link module:engine/model/writer~Writer#merge `Writer#merge()`}\n\t * will be valid.\n\t *\n\t * Instead of elements, you can pass the instance of the {@link module:engine/model/position~Position} class as the\n\t * `positionOrBaseElement`. It means that the elements before and after the position will be checked whether they can be merged.\n\t *\n\t * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrBaseElement The position or base\n\t * element to which the `elementToMerge` will be merged.\n\t * @param {module:engine/model/element~Element} elementToMerge The element to merge. Required if `positionOrBaseElement` is an element.\n\t * @returns {Boolean}\n\t */\n\tcheckMerge( positionOrBaseElement, elementToMerge = null ) {\n\t\tif ( positionOrBaseElement instanceof Position ) {\n\t\t\tconst nodeBefore = positionOrBaseElement.nodeBefore;\n\t\t\tconst nodeAfter = positionOrBaseElement.nodeAfter;\n\n\t\t\tif ( !( nodeBefore instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node before the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-before\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-before',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( !( nodeAfter instanceof Element ) ) {\n\t\t\t\t/**\n\t\t\t\t * The node after the merge position must be an element.\n\t\t\t\t *\n\t\t\t\t * @error schema-check-merge-no-element-after\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'schema-check-merge-no-element-after',\n\t\t\t\t\tthis\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this.checkMerge( nodeBefore, nodeAfter );\n\t\t}\n\n\t\tfor ( const child of elementToMerge.getChildren() ) {\n\t\t\tif ( !this.checkChild( positionOrBaseElement, child ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkChild} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow elements in specific contexts.\n\t *\n\t * This method is a shorthand for using the {@link #event:checkChild} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow heading1 directly inside a blockQuote.\n\t *\t\tschema.addChildCheck( ( context, childDefinition ) => {\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkChild', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst childDefinition = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkChild()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and\n\t * {@link module:engine/model/schema~SchemaCompiledItemDefinition} (child-to-check definition).\n\t * The callback may return `true/false` to override `checkChild()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkChild()`'s return value.\n\t */\n\taddChildCheck( callback ) {\n\t\tthis.on( 'checkChild', ( evt, [ ctx, childDef ] ) => {\n\t\t\t// checkChild() was called with a non-registered child.\n\t\t\t// In 99% cases such check should return false, so not to overcomplicate all callbacks\n\t\t\t// don't even execute them.\n\t\t\tif ( !childDef ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst retValue = callback( ctx, childDef );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Allows registering a callback to the {@link #checkAttribute} method calls.\n\t *\n\t * Callbacks allow you to implement rules which are not otherwise possible to achieve\n\t * by using the declarative API of {@link module:engine/model/schema~SchemaItemDefinition}.\n\t * For example, by using this method you can disallow attribute if node to which it is applied\n\t * is contained within some other element (e.g. you want to disallow `bold` on `$text` within `heading1`).\n\t *\n\t * This method is a shorthand for using the {@link #event:checkAttribute} event. For even better control,\n\t * you can use that event instead.\n\t *\n\t * Example:\n\t *\n\t *\t\t// Disallow bold on $text inside heading1.\n\t *\t\tschema.addAttributeCheck( ( context, attributeName ) => {\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\treturn false;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * Which translates to:\n\t *\n\t *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n\t *\t\t\tconst context = args[ 0 ];\n\t *\t\t\tconst attributeName = args[ 1 ];\n\t *\n\t *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n\t *\t\t\t\t// Prevent next listeners from being called.\n\t *\t\t\t\tevt.stop();\n\t *\t\t\t\t// Set the checkAttribute()'s return value.\n\t *\t\t\t\tevt.return = false;\n\t *\t\t\t}\n\t *\t\t}, { priority: 'high' } );\n\t *\n\t * @param {Function} callback The callback to be called. It is called with two parameters:\n\t * {@link module:engine/model/schema~SchemaContext} (context) instance and attribute name.\n\t * The callback may return `true/false` to override `checkAttribute()`'s return value. If it does not return\n\t * a boolean value, the default algorithm (or other callbacks) will define `checkAttribute()`'s return value.\n\t */\n\taddAttributeCheck( callback ) {\n\t\tthis.on( 'checkAttribute', ( evt, [ ctx, attributeName ] ) => {\n\t\t\tconst retValue = callback( ctx, attributeName );\n\n\t\t\tif ( typeof retValue == 'boolean' ) {\n\t\t\t\tevt.stop();\n\t\t\t\tevt.return = retValue;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * This method allows assigning additional metadata to the model attributes. For example,\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties#isFormatting` property} is\n\t * used to mark formatting attributes (like `bold` or `italic`).\n\t *\n\t *\t\t// Mark bold as a formatting attribute.\n\t *\t\tschema.setAttributeProperties( 'bold', {\n\t *\t\t\tisFormatting: true\n\t *\t\t} );\n\t *\n\t *\t\t// Override code not to be considered a formatting markup.\n\t *\t\tschema.setAttributeProperties( 'code', {\n\t *\t\t\tisFormatting: false\n\t *\t\t} );\n\t *\n\t * Properties are not limited to members defined in the\n\t * {@link module:engine/model/schema~AttributeProperties `AttributeProperties` type} and you can also use custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tcustomProperty: 'value'\n\t *\t\t} );\n\t *\n\t * Subsequent calls with the same attribute will extend its custom properties:\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\tone: 1\n\t *\t\t} );\n\t *\n\t *\t\tschema.setAttributeProperties( 'blockQuote', {\n\t *\t\t\ttwo: 2\n\t *\t\t} );\n\t *\n\t *\t\tconsole.log( schema.getAttributeProperties( 'blockQuote' ) );\n\t *\t\t// Logs: { one: 1, two: 2 }\n\t *\n\t * @param {String} attributeName A name of the attribute to receive the properties.\n\t * @param {module:engine/model/schema~AttributeProperties} properties A dictionary of properties.\n\t */\n\tsetAttributeProperties( attributeName, properties ) {\n\t\tthis._attributeProperties[ attributeName ] = Object.assign( this.getAttributeProperties( attributeName ), properties );\n\t}\n\n\t/**\n\t * Returns properties associated with a given model attribute. See {@link #setAttributeProperties `setAttributeProperties()`}.\n\t *\n\t * @param {String} attributeName A name of the attribute.\n\t * @returns {module:engine/model/schema~AttributeProperties}\n\t */\n\tgetAttributeProperties( attributeName ) {\n\t\treturn this._attributeProperties[ attributeName ] || {};\n\t}\n\n\t/**\n\t * Returns the lowest {@link module:engine/model/schema~Schema#isLimit limit element} containing the entire\n\t * selection/range/position or the root otherwise.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection|\n\t * module:engine/model/range~Range|module:engine/model/position~Position} selectionOrRangeOrPosition\n\t * The selection/range/position to check.\n\t * @returns {module:engine/model/element~Element} The lowest limit element containing\n\t * the entire `selectionOrRangeOrPosition`.\n\t */\n\tgetLimitElement( selectionOrRangeOrPosition ) {\n\t\tlet element;\n\n\t\tif ( selectionOrRangeOrPosition instanceof Position ) {\n\t\t\telement = selectionOrRangeOrPosition.parent;\n\t\t} else {\n\t\t\tconst ranges = selectionOrRangeOrPosition instanceof Range ?\n\t\t\t\t[ selectionOrRangeOrPosition ] :\n\t\t\t\tArray.from( selectionOrRangeOrPosition.getRanges() );\n\n\t\t\t// Find the common ancestor for all selection's ranges.\n\t\t\telement = ranges\n\t\t\t\t.reduce( ( element, range ) => {\n\t\t\t\t\tconst rangeCommonAncestor = range.getCommonAncestor();\n\n\t\t\t\t\tif ( !element ) {\n\t\t\t\t\t\treturn rangeCommonAncestor;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn element.getCommonAncestor( rangeCommonAncestor, { includeSelf: true } );\n\t\t\t\t}, null );\n\t\t}\n\n\t\twhile ( !this.isLimit( element ) ) {\n\t\t\tif ( element.parent ) {\n\t\t\t\telement = element.parent;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn element;\n\t}\n\n\t/**\n\t * Checks whether the attribute is allowed in selection:\n\t *\n\t * * if the selection is not collapsed, then checks if the attribute is allowed on any of nodes in that range,\n\t * * if the selection is collapsed, then checks if on the selection position there's a text with the\n\t * specified attribute allowed.\n\t *\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * Selection which will be checked.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Boolean}\n\t */\n\tcheckAttributeInSelection( selection, attribute ) {\n\t\tif ( selection.isCollapsed ) {\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\t\t\tconst context = [\n\t\t\t\t...firstPosition.getAncestors(),\n\t\t\t\tnew Text( '', selection.getAttributes() )\n\t\t\t];\n\n\t\t\t// Check whether schema allows for a text with the attribute in the selection.\n\t\t\treturn this.checkAttribute( context, attribute );\n\t\t} else {\n\t\t\tconst ranges = selection.getRanges();\n\n\t\t\t// For all ranges, check nodes in them until you find a node that is allowed to have the attribute.\n\t\t\tfor ( const range of ranges ) {\n\t\t\t\tfor ( const value of range ) {\n\t\t\t\t\tif ( this.checkAttribute( value.item, attribute ) ) {\n\t\t\t\t\t\t// If we found a node that is allowed to have the attribute, return true.\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we haven't found such node, return false.\n\t\treturn false;\n\t}\n\n\t/**\n\t * Transforms the given set of ranges into a set of ranges where the given attribute is allowed (and can be applied).\n\t *\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to be validated.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.<module:engine/model/range~Range>} Ranges in which the attribute is allowed.\n\t */\n\t* getValidRanges( ranges, attribute ) {\n\t\tranges = convertToMinimalFlatRanges( ranges );\n\n\t\tfor ( const range of ranges ) {\n\t\t\tyield* this._getValidRangesForRange( range, attribute );\n\t\t}\n\t}\n\n\t/**\n\t * Basing on given `position`, finds and returns a {@link module:engine/model/range~Range range} which is\n\t * nearest to that `position` and is a correct range for selection.\n\t *\n\t * The correct selection range might be collapsed when it is located in a position where the text node can be placed.\n\t * Non-collapsed range is returned when selection can be placed around element marked as an \"object\" in\n\t * the {@link module:engine/model/schema~Schema schema}.\n\t *\n\t * Direction of searching for the nearest correct selection range can be specified as:\n\t *\n\t * * `both` - searching will be performed in both ways,\n\t * * `forward` - searching will be performed only forward,\n\t * * `backward` - searching will be performed only backward.\n\t *\n\t * When valid selection range cannot be found, `null` is returned.\n\t *\n\t * @param {module:engine/model/position~Position} position Reference position where new selection range should be looked for.\n\t * @param {'both'|'forward'|'backward'} [direction='both'] Search direction.\n\t * @returns {module:engine/model/range~Range|null} Nearest selection range or `null` if one cannot be found.\n\t */\n\tgetNearestSelectionRange( position, direction = 'both' ) {\n\t\t// Return collapsed range if provided position is valid.\n\t\tif ( this.checkChild( position, '$text' ) ) {\n\t\t\treturn new Range( position );\n\t\t}\n\n\t\tlet backwardWalker, forwardWalker;\n\n\t\t// Never leave a limit element.\n\t\tconst limitElement = position.getAncestors().reverse().find( item => this.isLimit( item ) ) || position.root;\n\n\t\tif ( direction == 'both' || direction == 'backward' ) {\n\t\t\tbackwardWalker = new TreeWalker( {\n\t\t\t\tboundaries: Range._createIn( limitElement ),\n\t\t\t\tstartPosition: position,\n\t\t\t\tdirection: 'backward'\n\t\t\t} );\n\t\t}\n\n\t\tif ( direction == 'both' || direction == 'forward' ) {\n\t\t\tforwardWalker = new TreeWalker( {\n\t\t\t\tboundaries: Range._createIn( limitElement ),\n\t\t\t\tstartPosition: position\n\t\t\t} );\n\t\t}\n\n\t\tfor ( const data of combineWalkers( backwardWalker, forwardWalker ) ) {\n\t\t\tconst type = ( data.walker == backwardWalker ? 'elementEnd' : 'elementStart' );\n\t\t\tconst value = data.value;\n\n\t\t\tif ( value.type == type && this.isObject( value.item ) ) {\n\t\t\t\treturn Range._createOn( value.item );\n\t\t\t}\n\n\t\t\tif ( this.checkChild( value.nextPosition, '$text' ) ) {\n\t\t\t\treturn new Range( value.nextPosition );\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Tries to find position ancestors that allow to insert a given node.\n\t * It starts searching from the given position and goes node by node to the top of the model tree\n\t * as long as a {@link module:engine/model/schema~Schema#isLimit limit element}, an\n\t * {@link module:engine/model/schema~Schema#isObject object element} or a topmost ancestor is not reached.\n\t *\n\t * @param {module:engine/model/position~Position} position The position that the search will start from.\n\t * @param {module:engine/model/node~Node|String} node The node for which an allowed parent should be found or its name.\n\t * @returns {module:engine/model/element~Element|null} element Allowed parent or null if nothing was found.\n\t */\n\tfindAllowedParent( position, node ) {\n\t\tlet parent = position.parent;\n\n\t\twhile ( parent ) {\n\t\t\tif ( this.checkChild( parent, node ) ) {\n\t\t\t\treturn parent;\n\t\t\t}\n\n\t\t\t// Do not split limit elements.\n\t\t\tif ( this.isLimit( parent ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Removes attributes disallowed by the schema.\n\t *\n\t * @param {Iterable.<module:engine/model/node~Node>} nodes Nodes that will be filtered.\n\t * @param {module:engine/model/writer~Writer} writer\n\t */\n\tremoveDisallowedAttributes( nodes, writer ) {\n\t\tfor ( const node of nodes ) {\n\t\t\t// When node is a `Text` it has no children, so just filter it out.\n\t\t\tif ( node.is( '$text' ) ) {\n\t\t\t\tremoveDisallowedAttributeFromNode( this, node, writer );\n\t\t\t}\n\t\t\t// In a case of `Element` iterates through positions between nodes inside this element\n\t\t\t// and filter out node before the current position, or position parent when position\n\t\t\t// is at start of an element. Using positions prevent from omitting merged nodes\n\t\t\t// see https://github.com/ckeditor/ckeditor5-engine/issues/1789.\n\t\t\telse {\n\t\t\t\tconst rangeInNode = Range._createIn( node );\n\t\t\t\tconst positionsInRange = rangeInNode.getPositions();\n\n\t\t\t\tfor ( const position of positionsInRange ) {\n\t\t\t\t\tconst item = position.nodeBefore || position.parent;\n\n\t\t\t\t\tremoveDisallowedAttributeFromNode( this, item, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an instance of the schema context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t * @returns {module:engine/model/schema~SchemaContext}\n\t */\n\tcreateContext( context ) {\n\t\treturn new SchemaContext( context );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_clearCache() {\n\t\tthis._compiledDefinitions = null;\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_compile() {\n\t\tconst compiledDefinitions = {};\n\t\tconst sourceRules = this._sourceDefinitions;\n\t\tconst itemNames = Object.keys( sourceRules );\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompiledDefinitions[ itemName ] = compileBaseItemRule( sourceRules[ itemName ], itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowContentOf( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowWhere( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcompileAllowAttributesOf( compiledDefinitions, itemName );\n\t\t\tcompileInheritPropertiesFrom( compiledDefinitions, itemName );\n\t\t}\n\n\t\tfor ( const itemName of itemNames ) {\n\t\t\tcleanUpAllowIn( compiledDefinitions, itemName );\n\t\t\tcleanUpAllowAttributes( compiledDefinitions, itemName );\n\t\t}\n\n\t\tthis._compiledDefinitions = compiledDefinitions;\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/schema~SchemaCompiledItemDefinition} def\n\t * @param {module:engine/model/schema~SchemaContext} context\n\t * @param {Number} contextItemIndex\n\t */\n\t_checkContextMatch( def, context, contextItemIndex = context.length - 1 ) {\n\t\tconst contextItem = context.getItem( contextItemIndex );\n\n\t\tif ( def.allowIn.includes( contextItem.name ) ) {\n\t\t\tif ( contextItemIndex == 0 ) {\n\t\t\t\treturn true;\n\t\t\t} else {\n\t\t\t\tconst parentRule = this.getDefinition( contextItem );\n\n\t\t\t\treturn this._checkContextMatch( parentRule, context, contextItemIndex - 1 );\n\t\t\t}\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Takes a flat range and an attribute name. Traverses the range recursively and deeply to find and return all ranges\n\t * inside the given range on which the attribute can be applied.\n\t *\n\t * This is a helper function for {@link ~Schema#getValidRanges}.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The range to process.\n\t * @param {String} attribute The name of the attribute to check.\n\t * @returns {Iterable.<module:engine/model/range~Range>} Ranges in which the attribute is allowed.\n\t */\n\t* _getValidRangesForRange( range, attribute ) {\n\t\tlet start = range.start;\n\t\tlet end = range.start;\n\n\t\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'element' ) ) {\n\t\t\t\tyield* this._getValidRangesForRange( Range._createIn( item ), attribute );\n\t\t\t}\n\n\t\t\tif ( !this.checkAttribute( item, attribute ) ) {\n\t\t\t\tif ( !start.isEqual( end ) ) {\n\t\t\t\t\tyield new Range( start, end );\n\t\t\t\t}\n\n\t\t\t\tstart = Position._createAfter( item );\n\t\t\t}\n\n\t\t\tend = Position._createAfter( item );\n\t\t}\n\n\t\tif ( !start.isEqual( end ) ) {\n\t\t\tyield new Range( start, end );\n\t\t}\n\t}\n}\n\nmix( Schema, ObservableMixin );\n\n/**\n * Event fired when the {@link #checkChild} method is called. It allows plugging in\n * additional behavior, for example implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addChildCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkChild} method fires an event because it is\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in various ways, but the most important use case is overriding standard behavior of the\n * `checkChild()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkChild( context, child )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance and `child` to a\n * {@link module:engine/model/schema~SchemaCompiledItemDefinition} instance, so you do not have to worry about\n * the various ways how `context` and `child` may be passed to `checkChild()`.\n *\n * **Note:** `childDefinition` may be `undefined` if `checkChild()` was called with a non-registered element.\n *\n * So, in order to implement a rule \"disallow `heading1` in `blockQuote`\", you can add such a listener:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'blockQuote' ) && childDefinition && childDefinition.name == 'heading1' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing elements in specific contexts will be a far less common use case, because it is normally handled by the\n * `allowIn` rule from {@link module:engine/model/schema~SchemaItemDefinition}. But if you have a complex scenario\n * where `listItem` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst childDefinition = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo' ) && childDefinition.name == 'listItem' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkChild()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkChild\n * @param {Array} args The `checkChild()`'s arguments.\n */\n\n/**\n * Event fired when the {@link #checkAttribute} method is called. It allows plugging in\n * additional behavior, for example implementing rules which cannot be defined using the declarative\n * {@link module:engine/model/schema~SchemaItemDefinition} interface.\n *\n * **Note:** The {@link #addAttributeCheck} method is a more handy way to register callbacks. Internally,\n * it registers a listener to this event but comes with a simpler API and it is the recommended choice\n * in most of the cases.\n *\n * The {@link #checkAttribute} method fires an event because it is\n * {@link module:utils/observablemixin~ObservableMixin#decorate decorated} with it. Thanks to that you can\n * use this event in various ways, but the most important use case is overriding the standard behavior of the\n * `checkAttribute()` method. Let's see a typical listener template:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\t\t}, { priority: 'high' } );\n *\n * The listener is added with a `high` priority to be executed before the default method is really called. The `args` callback\n * parameter contains arguments passed to `checkAttribute( context, attributeName )`. However, the `context` parameter is already\n * normalized to a {@link module:engine/model/schema~SchemaContext} instance, so you do not have to worry about\n * the various ways how `context` may be passed to `checkAttribute()`.\n *\n * So, in order to implement a rule \"disallow `bold` in a text which is in a `heading1`, you can add such a listener:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'heading1 $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = false;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * Allowing attributes in specific contexts will be a far less common use case, because it is normally handled by the\n * `allowAttributes` rule from {@link module:engine/model/schema~SchemaItemDefinition}. But if you have a complex scenario\n * where `bold` should be allowed only in element `foo` which must be in element `bar`, then this would be the way:\n *\n *\t\tschema.on( 'checkAttribute', ( evt, args ) => {\n *\t\t\tconst context = args[ 0 ];\n *\t\t\tconst attributeName = args[ 1 ];\n *\n *\t\t\tif ( context.endsWith( 'bar foo $text' ) && attributeName == 'bold' ) {\n *\t\t\t\t// Prevent next listeners from being called.\n *\t\t\t\tevt.stop();\n *\t\t\t\t// Set the checkAttribute()'s return value.\n *\t\t\t\tevt.return = true;\n *\t\t\t}\n *\t\t}, { priority: 'high' } );\n *\n * @event checkAttribute\n * @param {Array} args The `checkAttribute()`'s arguments.\n */\n\n/**\n * A definition of a {@link module:engine/model/schema~Schema schema} item.\n *\n * You can define the following rules:\n *\n * * {@link ~SchemaItemDefinition#allowIn `allowIn`} &ndash; Defines in which other items this item will be allowed.\n * * {@link ~SchemaItemDefinition#allowAttributes `allowAttributes`} &ndash; Defines allowed attributes of the given item.\n * * {@link ~SchemaItemDefinition#allowContentOf `allowContentOf`} &ndash; Inherits \"allowed children\" from other items.\n * * {@link ~SchemaItemDefinition#allowWhere `allowWhere`} &ndash; Inherits \"allowed in\" from other items.\n * * {@link ~SchemaItemDefinition#allowAttributesOf `allowAttributesOf`} &ndash; Inherits attributes from other items.\n * * {@link ~SchemaItemDefinition#inheritTypesFrom `inheritTypesFrom`} &ndash; Inherits `is*` properties of other items.\n * * {@link ~SchemaItemDefinition#inheritAllFrom `inheritAllFrom`} &ndash;\n * A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.\n *\n * # The `is*` properties\n *\n * There are a couple commonly used `is*` properties. Their role is to assign additional semantics to schema items.\n * You can define more properties but you will also need to implement support for them in the existing editor features.\n *\n * * {@link ~SchemaItemDefinition#isBlock `isBlock`} &ndash; Whether this item is paragraph-like.\n * Generally speaking, content is usually made out of blocks like paragraphs, list items, images, headings, etc.\n * * {@link ~SchemaItemDefinition#isInline `isInline`} &ndash; Whether an item is \"text-like\" and should be treated as an inline node.\n * Examples of inline elements: `$text`, `softBreak` (`<br>`), etc.\n * * {@link ~SchemaItemDefinition#isLimit `isLimit`} &ndash; It can be understood as whether this element\n * should not be split by <kbd>Enter</kbd>. Examples of limit elements: `$root`, table cell, image caption, etc.\n * In other words, all actions that happen inside a limit element are limited to its content.\n * All objects are treated as limit elements, too.\n * * {@link ~SchemaItemDefinition#isObject `isObject`} &ndash; Whether an item is \"self-contained\" and should be treated as a whole.\n * Examples of object elements: `image`, `table`, `video`, etc. An object is also a limit, so\n * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.\n *\n * Read more about the meaning of these types in the\n * {@glink framework/guides/deep-dive/schema#defining-additional-semantics dedicated section of the Schema deep dive} guide.\n *\n * # Generic items\n *\n * There are three basic generic items: `$root`, `$block` and `$text`.\n * They are defined as follows:\n *\n *\t\tthis.schema.register( '$root', {\n *\t\t\tisLimit: true\n *\t\t} );\n *\t\tthis.schema.register( '$block', {\n *\t\t\tallowIn: '$root',\n *\t\t\tisBlock: true\n *\t\t} );\n *\t\tthis.schema.register( '$text', {\n *\t\t\tallowIn: '$block',\n *\t\t\tisInline: true\n *\t\t} );\n *\n * They reflect typical editor content that is contained within one root, consists of several blocks\n * (paragraphs, lists items, headings, images) which, in turn, may contain text inside.\n *\n * By inheriting from the generic items you can define new items which will get extended by other editor features.\n * Read more about generic types in the {@glink framework/guides/deep-dive/schema Schema deep dive} guide.\n *\n * # Example definitions\n *\n * Allow `paragraph` in roots and block quotes:\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowIn: [ '$root', 'blockQuote' ],\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Allow `paragraph` everywhere where `$block` is allowed (i.e. in `$root`):\n *\n *\t\tschema.register( 'paragraph', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tisBlock: true\n *\t\t} );\n *\n * Make `image` a block object, which is allowed everywhere where `$block` is.\n * Also, allow `src` and `alt` attributes in it:\n *\n *\t\tschema.register( 'image', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowAttributes: [ 'src', 'alt' ],\n *\t\t\tisBlock: true,\n *\t\t\tisObject: true\n *\t\t} );\n *\n * Make `caption` allowed in `image` and make it allow all the content of `$block`s (usually, `$text`).\n * Also, mark it as a limit element so it cannot be split:\n *\n *\t\tschema.register( 'caption', {\n *\t\t\tallowIn: 'image',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tisLimit: true\n *\t\t} );\n *\n * Make `listItem` inherit all from `$block` but also allow additional attributes:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tinheritAllFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * Which translates to:\n *\n *\t\tschema.register( 'listItem', {\n *\t\t\tallowWhere: '$block',\n *\t\t\tallowContentOf: '$block',\n *\t\t\tallowAttributesOf: '$block',\n *\t\t\tinheritTypesFrom: '$block',\n *\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n *\t\t} );\n *\n * # Tips\n *\n * * Check schema definitions of existing features to see how they are defined.\n * * If you want to publish your feature so other developers can use it, try to use\n * generic items as much as possible.\n * * Keep your model clean. Limit it to the actual data and store information in a normalized way.\n * * Remember about defining the `is*` properties. They do not affect the allowed structures, but they can\n * affect how the editor features treat your elements.\n *\n * @typedef {Object} module:engine/model/schema~SchemaItemDefinition\n *\n * @property {String|Array.<String>} allowIn Defines in which other items this item will be allowed.\n * @property {String|Array.<String>} allowAttributes Defines allowed attributes of the given item.\n * @property {String|Array.<String>} allowContentOf Inherits \"allowed children\" from other items.\n * @property {String|Array.<String>} allowWhere Inherits \"allowed in\" from other items.\n * @property {String|Array.<String>} allowAttributesOf Inherits attributes from other items.\n * @property {String|Array.<String>} inheritTypesFrom Inherits `is*` properties of other items.\n * @property {String} inheritAllFrom A shorthand for `allowContentOf`, `allowWhere`, `allowAttributesOf`, `inheritTypesFrom`.\n *\n * @property {Boolean} isBlock\n * Whether this item is paragraph-like. Generally speaking, content is usually made out of blocks\n * like paragraphs, list items, images, headings, etc. All these elements are marked as blocks. A block\n * should not allow another block inside. Note: There is also the `$block` generic item which has `isBlock` set to `true`.\n * Most block type items will inherit from `$block` (through `inheritAllFrom`).\n *\n * Read more about the block elements in the\n * {@glink framework/guides/deep-dive/schema#block-elements Block elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isInline\n * Whether an item is \"text-like\" and should be treated as an inline node. Examples of inline elements:\n * `$text`, `softBreak` (`<br>`), etc.\n *\n * Read more about the inline elements in the\n * {@glink framework/guides/deep-dive/schema#inline-elements Inline elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isLimit\n * It can be understood as whether this element should not be split by <kbd>Enter</kbd>.\n * Examples of limit elements: `$root`, table cell, image caption, etc. In other words, all actions that happen inside\n * a limit element are limited to its content.\n *\n * Read more about the limit elements in the\n * {@glink framework/guides/deep-dive/schema#limit-elements Limit elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isObject\n * Whether an item is \"self-contained\" and should be treated as a whole. Examples of object elements:\n * `image`, `table`, `video`, etc.\n *\n * **Note:** An object is also a limit, so\n * {@link module:engine/model/schema~Schema#isLimit `isLimit()`} returns `true` for object elements automatically.\n *\n * Read more about the object elements in the\n * {@glink framework/guides/deep-dive/schema#object-elements Object elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isSelectable\n * `true` when an element should be selectable as a whole by the user. Examples of selectable elements: `image`, `table`, `tableCell`, etc.\n *\n * **Note:** An object is also a selectable element, so\n * {@link module:engine/model/schema~Schema#isSelectable `isSelectable()`} returns `true` for object elements automatically.\n *\n * Read more about selectable elements in the\n * {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements} section of the Schema deep dive} guide.\n *\n * @property {Boolean} isContent\n * An item is a content when it always finds its way to the editor data output regardless of the number and type of its descendants.\n * Examples of content elements: `$text`, `image`, `table`, etc. (but not `paragraph`, `heading1` or `tableCell`).\n *\n * **Note:** An object is also a content element, so\n * {@link module:engine/model/schema~Schema#isContent `isContent()`} returns `true` for object elements automatically.\n *\n * Read more about content elements in the\n * {@glink framework/guides/deep-dive/schema#content-elements Content elements} section of the Schema deep dive} guide.\n */\n\n/**\n * A simplified version of {@link module:engine/model/schema~SchemaItemDefinition} after\n * compilation by the {@link module:engine/model/schema~Schema schema}.\n * Rules fed to the schema by {@link module:engine/model/schema~Schema#register}\n * and {@link module:engine/model/schema~Schema#extend} methods are defined in the\n * {@link module:engine/model/schema~SchemaItemDefinition} format.\n * Later on, they are compiled to `SchemaCompiledItemDefinition` so when you use e.g.\n * the {@link module:engine/model/schema~Schema#getDefinition} method you get the compiled version.\n *\n * The compiled version contains only the following properties:\n *\n * * The `name` property,\n * * The `is*` properties,\n * * The `allowIn` array,\n * * The `allowAttributes` array.\n *\n * @typedef {Object} module:engine/model/schema~SchemaCompiledItemDefinition\n */\n\n/**\n * A schema context &mdash; a list of ancestors of a given position in the document.\n *\n * Considering such position:\n *\n *\t\t<$root>\n *\t\t\t<blockQuote>\n *\t\t\t\t<paragraph>\n *\t\t\t\t\t^\n *\t\t\t\t</paragraph>\n *\t\t\t</blockQuote>\n *\t\t</$root>\n *\n * The context of this position is its {@link module:engine/model/position~Position#getAncestors lists of ancestors}:\n *\n *\t\t[ rootElement, blockQuoteElement, paragraphElement ]\n *\n * Contexts are used in the {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`} and\n * {@link module:engine/model/schema~Schema#event:checkAttribute `Schema#checkAttribute`} events as a definition\n * of a place in the document where the check occurs. The context instances are created based on the first arguments\n * of the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`} and\n * {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} methods so when\n * using these methods you need to use {@link module:engine/model/schema~SchemaContextDefinition}s.\n */\nexport class SchemaContext {\n\t/**\n\t * Creates an instance of the context.\n\t *\n\t * @param {module:engine/model/schema~SchemaContextDefinition} context\n\t */\n\tconstructor( context ) {\n\t\tif ( context instanceof SchemaContext ) {\n\t\t\treturn context;\n\t\t}\n\n\t\tif ( typeof context == 'string' ) {\n\t\t\tcontext = [ context ];\n\t\t} else if ( !Array.isArray( context ) ) {\n\t\t\t// `context` is item or position.\n\t\t\t// Position#getAncestors() doesn't accept any parameters but it works just fine here.\n\t\t\tcontext = context.getAncestors( { includeSelf: true } );\n\t\t}\n\n\t\tthis._items = context.map( mapContextItem );\n\t}\n\n\t/**\n\t * The number of items.\n\t *\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._items.length;\n\t}\n\n\t/**\n\t * The last item (the lowest node).\n\t *\n\t * @type {module:engine/model/schema~SchemaContextItem}\n\t */\n\tget last() {\n\t\treturn this._items[ this._items.length - 1 ];\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all context items.\n\t *\n\t * @returns {Iterable.<module:engine/model/schema~SchemaContextItem>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._items[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns a new schema context instance with an additional item.\n\t *\n\t * Item can be added as:\n\t *\n\t * \t\tconst context = new SchemaContext( [ '$root' ] );\n\t *\n\t * \t\t// An element.\n\t * \t\tconst fooElement = writer.createElement( 'fooElement' );\n\t * \t\tconst newContext = context.push( fooElement ); // [ '$root', 'fooElement' ]\n\t *\n\t * \t\t// A text node.\n\t * \t\tconst text = writer.createText( 'foobar' );\n\t * \t\tconst newContext = context.push( text ); // [ '$root', '$text' ]\n\t *\n\t * \t\t// A string (element name).\n\t * \t\tconst newContext = context.push( 'barElement' ); // [ '$root', 'barElement' ]\n\t *\n\t * **Note** {@link module:engine/model/node~Node} that is already in the model tree will be added as the only item\n\t * (without ancestors).\n\t *\n\t * @param {String|module:engine/model/node~Node|Array<String|module:engine/model/node~Node>} item An item that will be added\n\t * to the current context.\n\t * @returns {module:engine/model/schema~SchemaContext} A new schema context instance with an additional item.\n\t */\n\tpush( item ) {\n\t\tconst ctx = new SchemaContext( [ item ] );\n\n\t\tctx._items = [ ...this._items, ...ctx._items ];\n\n\t\treturn ctx;\n\t}\n\n\t/**\n\t * Gets an item on the given index.\n\t *\n\t * @returns {module:engine/model/schema~SchemaContextItem}\n\t */\n\tgetItem( index ) {\n\t\treturn this._items[ index ];\n\t}\n\n\t/**\n\t * Returns the names of items.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* getNames() {\n\t\tyield* this._items.map( item => item.name );\n\t}\n\n\t/**\n\t * Checks whether the context ends with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$text' ); // -> true\n\t *\t\tctx.endsWith( 'paragraph $text' ); // -> true\n\t *\t\tctx.endsWith( '$root' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tendsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).endsWith( query );\n\t}\n\n\t/**\n\t * Checks whether the context starts with the given nodes.\n\t *\n\t *\t\tconst ctx = new SchemaContext( [ rootElement, paragraphElement, textNode ] );\n\t *\n\t *\t\tctx.endsWith( '$root' ); // -> true\n\t *\t\tctx.endsWith( '$root paragraph' ); // -> true\n\t *\t\tctx.endsWith( '$text' ); // -> false\n\t *\t\tctx.endsWith( 'paragraph' ); // -> false\n\t *\n\t * @param {String} query\n\t * @returns {Boolean}\n\t */\n\tstartsWith( query ) {\n\t\treturn Array.from( this.getNames() ).join( ' ' ).startsWith( query );\n\t}\n}\n\n/**\n * The definition of a {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * Contexts can be created in multiple ways:\n *\n * * By defining a **node** in this cases this node and all its ancestors will be used.\n * * By defining a **position** in the document in this case all its ancestors will be used.\n * * By defining an **array of nodes** in this case this array defines the entire context.\n * * By defining a **name of node** - in this case node will be \"mocked\". It is not recommended because context\n * will be unrealistic (e.g. attributes of these nodes are not specified). However, at times this may be the only\n * way to define the context (e.g. when checking some hypothetical situation).\n * * By defining an **array of node names** (potentially, mixed with real nodes) The same as **name of node**\n * but it is possible to create a path.\n * * By defining a {@link module:engine/model/schema~SchemaContext} instance - in this case the same instance as provided\n * will be return.\n *\n * Examples of context definitions passed to the {@link module:engine/model/schema~Schema#checkChild `Schema#checkChild()`}\n * method:\n *\n *\t\t// Assuming that we have a $root > blockQuote > paragraph structure, the following code\n *\t\t// will check node 'foo' in the following context:\n *\t\t// [ rootElement, blockQuoteElement, paragraphElement ]\n *\t\tconst contextDefinition = paragraphElement;\n * \t\tconst childToCheck = 'foo';\n *\t\tschema.checkChild( contextDefinition, childToCheck );\n *\n *\t\t// Also check in [ rootElement, blockQuoteElement, paragraphElement ].\n *\t\tschema.checkChild( model.createPositionAt( paragraphElement, 0 ), 'foo' );\n *\n *\t\t// Check in [ rootElement, paragraphElement ].\n *\t\tschema.checkChild( [ rootElement, paragraphElement ], 'foo' );\n *\n *\t\t// Check only fakeParagraphElement.\n *\t\tschema.checkChild( 'paragraph', 'foo' );\n *\n *\t\t// Check in [ fakeRootElement, fakeBarElement, paragraphElement ].\n *\t\tschema.checkChild( [ '$root', 'bar', paragraphElement ], 'foo' );\n *\n * All these `checkChild()` calls will fire {@link module:engine/model/schema~Schema#event:checkChild `Schema#checkChild`}\n * events in which `args[ 0 ]` is an instance of the context. Therefore, you can write a listener like this:\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\n *\t\t\tconsole.log( Array.from( ctx.getNames() ) );\n *\t\t} );\n *\n * Which will log the following:\n *\n *\t\t[ '$root', 'blockQuote', 'paragraph' ]\n *\t\t[ '$root', 'paragraph' ]\n *\t\t[ '$root', 'bar', 'paragraph' ]\n *\n * Note: When using the {@link module:engine/model/schema~Schema#checkAttribute `Schema#checkAttribute()`} method\n * you may want to check whether a text node may have an attribute. A {@link module:engine/model/text~Text} is a\n * correct way to define a context so you can do this:\n *\n *\t\tschema.checkAttribute( textNode, 'bold' );\n *\n * But sometimes you want to check whether a text at a given position might've had some attribute,\n * in which case you can create a context by mixing in an array of elements with a `'$text'` string:\n *\n *\t\t// Check in [ rootElement, paragraphElement, textNode ].\n *\t\tschema.checkChild( [ ...positionInParagraph.getAncestors(), '$text' ], 'bold' );\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/position~Position|module:engine/model/schema~SchemaContext|\n * String|Array.<String|module:engine/model/node~Node>} module:engine/model/schema~SchemaContextDefinition\n */\n\n/**\n * An item of the {@link module:engine/model/schema~SchemaContext schema context}.\n *\n * It contains 3 properties:\n *\n * * `name` the name of this item,\n * * `* getAttributeKeys()` a generator of keys of item attributes,\n * * `getAttribute( keyName )` a method to get attribute values.\n *\n * The context item interface is a highly simplified version of {@link module:engine/model/node~Node} and its role\n * is to expose only the information which schema checks are able to provide (which is the name of the node and\n * node's attributes).\n *\n *\t\tschema.on( 'checkChild', ( evt, args ) => {\n *\t\t\tconst ctx = args[ 0 ];\n *\t\t\tconst firstItem = ctx.getItem( 0 );\n *\n *\t\t\tconsole.log( firstItem.name ); // -> '$root'\n *\t\t\tconsole.log( firstItem.getAttribute( 'foo' ) ); // -> 'bar'\n *\t\t\tconsole.log( Array.from( firstItem.getAttributeKeys() ) ); // -> [ 'foo', 'faa' ]\n *\t\t} );\n *\n * @typedef {Object} module:engine/model/schema~SchemaContextItem\n */\n\n/**\n * A structure containing additional metadata describing the attribute.\n *\n * See {@link module:engine/model/schema~Schema#setAttributeProperties `Schema#setAttributeProperties()`} for usage examples.\n *\n * @typedef {Object} module:engine/model/schema~AttributeProperties\n * @property {Boolean} [isFormatting] Indicates that the attribute should be considered as a visual formatting, like `bold`, `italic` or\n * `fontSize` rather than semantic attribute (such as `src`, `listType`, etc.). For example, it is used by the \"Remove format\" feature.\n * @property {Boolean} [copyOnEnter] Indicates that given text attribute should be copied to the next block when enter is pressed.\n */\n\nfunction compileBaseItemRule( sourceItemRules, itemName ) {\n\tconst itemRule = {\n\t\tname: itemName,\n\n\t\tallowIn: [],\n\t\tallowContentOf: [],\n\t\tallowWhere: [],\n\n\t\tallowAttributes: [],\n\t\tallowAttributesOf: [],\n\n\t\tinheritTypesFrom: []\n\t};\n\n\tcopyTypes( sourceItemRules, itemRule );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowIn' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowContentOf' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowWhere' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributes' );\n\tcopyProperty( sourceItemRules, itemRule, 'allowAttributesOf' );\n\n\tcopyProperty( sourceItemRules, itemRule, 'inheritTypesFrom' );\n\n\tmakeInheritAllWork( sourceItemRules, itemRule );\n\n\treturn itemRule;\n}\n\nfunction compileAllowContentOf( compiledDefinitions, itemName ) {\n\tfor ( const allowContentOfItemName of compiledDefinitions[ itemName ].allowContentOf ) {\n\t\t// The allowContentOf property may point to an unregistered element.\n\t\tif ( compiledDefinitions[ allowContentOfItemName ] ) {\n\t\t\tconst allowedChildren = getAllowedChildren( compiledDefinitions, allowContentOfItemName );\n\n\t\t\tallowedChildren.forEach( allowedItem => {\n\t\t\t\tallowedItem.allowIn.push( itemName );\n\t\t\t} );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowContentOf;\n}\n\nfunction compileAllowWhere( compiledDefinitions, itemName ) {\n\tfor ( const allowWhereItemName of compiledDefinitions[ itemName ].allowWhere ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowWhereItemName ];\n\n\t\t// The allowWhere property may point to an unregistered element.\n\t\tif ( inheritFrom ) {\n\t\t\tconst allowedIn = inheritFrom.allowIn;\n\n\t\t\tcompiledDefinitions[ itemName ].allowIn.push( ...allowedIn );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowWhere;\n}\n\nfunction compileAllowAttributesOf( compiledDefinitions, itemName ) {\n\tfor ( const allowAttributeOfItem of compiledDefinitions[ itemName ].allowAttributesOf ) {\n\t\tconst inheritFrom = compiledDefinitions[ allowAttributeOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst inheritAttributes = inheritFrom.allowAttributes;\n\n\t\t\tcompiledDefinitions[ itemName ].allowAttributes.push( ...inheritAttributes );\n\t\t}\n\t}\n\n\tdelete compiledDefinitions[ itemName ].allowAttributesOf;\n}\n\nfunction compileInheritPropertiesFrom( compiledDefinitions, itemName ) {\n\tconst item = compiledDefinitions[ itemName ];\n\n\tfor ( const inheritPropertiesOfItem of item.inheritTypesFrom ) {\n\t\tconst inheritFrom = compiledDefinitions[ inheritPropertiesOfItem ];\n\n\t\tif ( inheritFrom ) {\n\t\t\tconst typeNames = Object.keys( inheritFrom ).filter( name => name.startsWith( 'is' ) );\n\n\t\t\tfor ( const name of typeNames ) {\n\t\t\t\tif ( !( name in item ) ) {\n\t\t\t\t\titem[ name ] = inheritFrom[ name ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tdelete item.inheritTypesFrom;\n}\n\n// Remove items which weren't registered (because it may break some checks or we'd need to complicate them).\n// Make sure allowIn doesn't contain repeated values.\nfunction cleanUpAllowIn( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\tconst existingItems = itemRule.allowIn.filter( itemToCheck => compiledDefinitions[ itemToCheck ] );\n\n\titemRule.allowIn = Array.from( new Set( existingItems ) );\n}\n\nfunction cleanUpAllowAttributes( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\titemRule.allowAttributes = Array.from( new Set( itemRule.allowAttributes ) );\n}\n\nfunction copyTypes( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst typeNames = Object.keys( sourceItemRule ).filter( name => name.startsWith( 'is' ) );\n\n\t\tfor ( const name of typeNames ) {\n\t\t\titemRule[ name ] = sourceItemRule[ name ];\n\t\t}\n\t}\n}\n\nfunction copyProperty( sourceItemRules, itemRule, propertyName ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tif ( typeof sourceItemRule[ propertyName ] == 'string' ) {\n\t\t\titemRule[ propertyName ].push( sourceItemRule[ propertyName ] );\n\t\t} else if ( Array.isArray( sourceItemRule[ propertyName ] ) ) {\n\t\t\titemRule[ propertyName ].push( ...sourceItemRule[ propertyName ] );\n\t\t}\n\t}\n}\n\nfunction makeInheritAllWork( sourceItemRules, itemRule ) {\n\tfor ( const sourceItemRule of sourceItemRules ) {\n\t\tconst inheritFrom = sourceItemRule.inheritAllFrom;\n\n\t\tif ( inheritFrom ) {\n\t\t\titemRule.allowContentOf.push( inheritFrom );\n\t\t\titemRule.allowWhere.push( inheritFrom );\n\t\t\titemRule.allowAttributesOf.push( inheritFrom );\n\t\t\titemRule.inheritTypesFrom.push( inheritFrom );\n\t\t}\n\t}\n}\n\nfunction getAllowedChildren( compiledDefinitions, itemName ) {\n\tconst itemRule = compiledDefinitions[ itemName ];\n\n\treturn getValues( compiledDefinitions ).filter( def => def.allowIn.includes( itemRule.name ) );\n}\n\nfunction getValues( obj ) {\n\treturn Object.keys( obj ).map( key => obj[ key ] );\n}\n\nfunction mapContextItem( ctxItem ) {\n\tif ( typeof ctxItem == 'string' || ctxItem.is( 'documentFragment' ) ) {\n\t\treturn {\n\t\t\tname: typeof ctxItem == 'string' ? ctxItem : '$documentFragment',\n\n\t\t\t* getAttributeKeys() {},\n\n\t\t\tgetAttribute() {}\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\t// '$text' means text nodes and text proxies.\n\t\t\tname: ctxItem.is( 'element' ) ? ctxItem.name : '$text',\n\n\t\t\t* getAttributeKeys() {\n\t\t\t\tyield* ctxItem.getAttributeKeys();\n\t\t\t},\n\n\t\t\tgetAttribute( key ) {\n\t\t\t\treturn ctxItem.getAttribute( key );\n\t\t\t}\n\t\t};\n\t}\n}\n\n// Generator function returning values from provided walkers, switching between them at each iteration. If only one walker\n// is provided it will return data only from that walker.\n//\n// @param {module:engine/module/treewalker~TreeWalker} [backward] Walker iterating in backward direction.\n// @param {module:engine/module/treewalker~TreeWalker} [forward] Walker iterating in forward direction.\n// @returns {Iterable.<Object>} Object returned at each iteration contains `value` and `walker` (informing which walker returned\n// given value) fields.\nfunction* combineWalkers( backward, forward ) {\n\tlet done = false;\n\n\twhile ( !done ) {\n\t\tdone = true;\n\n\t\tif ( backward ) {\n\t\t\tconst step = backward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: backward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( forward ) {\n\t\t\tconst step = forward.next();\n\n\t\t\tif ( !step.done ) {\n\t\t\t\tdone = false;\n\t\t\t\tyield {\n\t\t\t\t\twalker: forward,\n\t\t\t\t\tvalue: step.value\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Takes an array of non-intersecting ranges. For each of them gets minimal flat ranges covering that range and returns\n// all those minimal flat ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges Ranges to process.\n// @returns {Iterable.<module:engine/model/range~Range>} Minimal flat ranges of given `ranges`.\nfunction* convertToMinimalFlatRanges( ranges ) {\n\tfor ( const range of ranges ) {\n\t\tyield* range.getMinimalFlatRanges();\n\t}\n}\n\nfunction removeDisallowedAttributeFromNode( schema, node, writer ) {\n\tfor ( const attribute of node.getAttributeKeys() ) {\n\t\tif ( !schema.checkAttribute( node, attribute ) ) {\n\t\t\twriter.removeAttribute( attribute, node );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/conversion/upcastdispatcher\n */\n\nimport ViewConsumable from './viewconsumable';\nimport ModelRange from '../model/range';\nimport ModelPosition from '../model/position';\nimport { SchemaContext } from '../model/schema';\nimport { isParagraphable, wrapInParagraph } from '../model/utils/autoparagraphing';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Upcast dispatcher is a central point of the view-to-model conversion, which is a process of\n * converting a given {@link module:engine/view/documentfragment~DocumentFragment view document fragment} or\n * {@link module:engine/view/element~Element view element} into a correct model structure.\n *\n * During the conversion process, the dispatcher fires events for all {@link module:engine/view/node~Node view nodes}\n * from the converted view document fragment.\n * Special callbacks called \"converters\" should listen to these events in order to convert the view nodes.\n *\n * The second parameter of the callback is the `data` object with the following properties:\n *\n * * `data.viewItem` contains a {@link module:engine/view/node~Node view node} or a\n * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}\n * that is converted at the moment and might be handled by the callback.\n * * `data.modelRange` is used to point to the result\n * of the current conversion (e.g. the element that is being inserted)\n * and is always a {@link module:engine/model/range~Range} when the conversion succeeds.\n * * `data.modelCursor` is a {@link module:engine/model/position~Position position} on which the converter should insert\n * the newly created items.\n *\n * The third parameter of the callback is an instance of {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi}\n * which provides additional tools for converters.\n *\n * You can read more about conversion in the following guides:\n *\n * * {@glink framework/guides/deep-dive/conversion/conversion-introduction Advanced conversion concepts &mdash; attributes}\n * * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion}\n *\n * Examples of event-based converters:\n *\n *\t\t// A converter for links (<a>).\n *\t\teditor.data.upcastDispatcher.on( 'element:a', ( evt, data, conversionApi ) => {\n *\t\t\tif ( conversionApi.consumable.consume( data.viewItem, { name: true, attributes: [ 'href' ] } ) ) {\n *\t\t\t\t// The <a> element is inline and is represented by an attribute in the model.\n *\t\t\t\t// This is why you need to convert only children.\n *\t\t\t\tconst { modelRange } = conversionApi.convertChildren( data.viewItem, data.modelCursor );\n *\n *\t\t\t\tfor ( let item of modelRange.getItems() ) {\n *\t\t\t\t\tif ( conversionApi.schema.checkAttribute( item, 'linkHref' ) ) {\n *\t\t\t\t\t\tconversionApi.writer.setAttribute( 'linkHref', data.viewItem.getAttribute( 'href' ), item );\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n *\t\t// Convert <p> element's font-size style.\n *\t\t// Note: You should use a low-priority observer in order to ensure that\n *\t\t// it is executed after the element-to-element converter.\n *\t\teditor.data.upcastDispatcher.on( 'element:p', ( evt, data, conversionApi ) => {\n *\t\t\tconst { consumable, schema, writer } = conversionApi;\n *\n *\t\t\tif ( !consumable.consume( data.viewItem, { style: 'font-size' } ) ) {\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\tconst fontSize = data.viewItem.getStyle( 'font-size' );\n *\n *\t\t\t// Do not go for the model element after data.modelCursor because it might happen\n *\t\t\t// that a single view element was converted to multiple model elements. Get all of them.\n *\t\t\tfor ( const item of data.modelRange.getItems( { shallow: true } ) ) {\n *\t\t\t\tif ( schema.checkAttribute( item, 'fontSize' ) ) {\n *\t\t\t\t\twriter.setAttribute( 'fontSize', fontSize, item );\n *\t\t\t\t}\n *\t\t\t}\n *\t\t}, { priority: 'low' } );\n *\n *\t\t// Convert all elements which have no custom converter into a paragraph (autoparagraphing).\n *\t\teditor.data.upcastDispatcher.on( 'element', ( evt, data, conversionApi ) => {\n *\t\t\t// Check if an element can be converted.\n *\t\t\tif ( !conversionApi.consumable.test( data.viewItem, { name: data.viewItem.name } ) ) {\n *\t\t\t\t// When an element is already consumed by higher priority converters, do nothing.\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\tconst paragraph = conversionApi.writer.createElement( 'paragraph' );\n *\n *\t\t\t// Try to safely insert a paragraph at the model cursor - it will find an allowed parent for the current element.\n *\t\t\tif ( !conversionApi.safeInsert( paragraph, data.modelCursor ) ) {\n *\t\t\t\t// When an element was not inserted, it means that you cannot insert a paragraph at this position.\n *\t\t\t\treturn;\n *\t\t\t}\n *\n *\t\t\t// Consume the inserted element.\n *\t\t\tconversionApi.consumable.consume( data.viewItem, { name: data.viewItem.name } ) );\n *\n *\t\t\t// Convert the children to a paragraph.\n *\t\t\tconst { modelRange } = conversionApi.convertChildren( data.viewItem, paragraph ) );\n *\n *\t\t\t// Update `modelRange` and `modelCursor` in the `data` as a conversion result.\n *\t\t\tconversionApi.updateConversionResult( paragraph, data );\n *\t\t}, { priority: 'low' } );\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n * @fires viewCleanup\n * @fires element\n * @fires text\n * @fires documentFragment\n */\nexport default class UpcastDispatcher {\n\t/**\n\t * Creates an upcast dispatcher that operates using the passed API.\n\t *\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi\n\t * @param {Object} [conversionApi] Additional properties for an interface that will be passed to events fired\n\t * by the upcast dispatcher.\n\t */\n\tconstructor( conversionApi = {} ) {\n\t\t/**\n\t\t * The list of elements that were created during splitting.\n\t\t *\n\t\t * After the conversion process the list is cleared.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:engine/model/element~Element,Array.<module:engine/model/element~Element>>}\n\t\t */\n\t\tthis._splitParts = new Map();\n\n\t\t/**\n\t\t * The list of cursor parent elements that were created during splitting.\n\t\t *\n\t\t * After the conversion process the list is cleared.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:engine/model/element~Element,Array.<module:engine/model/element~Element>>}\n\t\t */\n\t\tthis._cursorParents = new Map();\n\n\t\t/**\n\t\t * The position in the temporary structure where the converted content is inserted. The structure reflects the context of\n\t\t * the target position where the content will be inserted. This property is built based on the context parameter of the\n\t\t * convert method.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/position~Position|null}\n\t\t */\n\t\tthis._modelCursor = null;\n\n\t\t/**\n\t\t * An interface passed by the dispatcher to the event callbacks.\n\t\t *\n\t\t * @member {module:engine/conversion/upcastdispatcher~UpcastConversionApi}\n\t\t */\n\t\tthis.conversionApi = Object.assign( {}, conversionApi );\n\n\t\t// The below methods are bound to this `UpcastDispatcher` instance and set on `conversionApi`.\n\t\t// This way only a part of `UpcastDispatcher` API is exposed.\n\t\tthis.conversionApi.convertItem = this._convertItem.bind( this );\n\t\tthis.conversionApi.convertChildren = this._convertChildren.bind( this );\n\t\tthis.conversionApi.safeInsert = this._safeInsert.bind( this );\n\t\tthis.conversionApi.updateConversionResult = this._updateConversionResult.bind( this );\n\t\t// Advanced API - use only if custom position handling is needed.\n\t\tthis.conversionApi.splitToAllowedParent = this._splitToAllowedParent.bind( this );\n\t\tthis.conversionApi.getSplitParts = this._getSplitParts.bind( this );\n\t}\n\n\t/**\n\t * Starts the conversion process. The entry point for the conversion.\n\t *\n\t * @fires element\n\t * @fires text\n\t * @fires documentFragment\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element} viewItem\n\t * The part of the view to be converted.\n\t * @param {module:engine/model/writer~Writer} writer An instance of the model writer.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context=['$root']] Elements will be converted according to this context.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Model data that is the result of the conversion process\n\t * wrapped in `DocumentFragment`. Converted marker elements will be set as the document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t */\n\tconvert( viewItem, writer, context = [ '$root' ] ) {\n\t\tthis.fire( 'viewCleanup', viewItem );\n\n\t\t// Create context tree and set position in the top element.\n\t\t// Items will be converted according to this position.\n\t\tthis._modelCursor = createContextTree( context, writer );\n\n\t\t// Store writer in conversion as a conversion API\n\t\t// to be sure that conversion process will use the same batch.\n\t\tthis.conversionApi.writer = writer;\n\n\t\t// Create consumable values list for conversion process.\n\t\tthis.conversionApi.consumable = ViewConsumable.createFrom( viewItem );\n\n\t\t// Custom data stored by converter for conversion process.\n\t\tthis.conversionApi.store = {};\n\n\t\t// Do the conversion.\n\t\tconst { modelRange } = this._convertItem( viewItem, this._modelCursor );\n\n\t\t// Conversion result is always a document fragment so let's create it.\n\t\tconst documentFragment = writer.createDocumentFragment();\n\n\t\t// When there is a conversion result.\n\t\tif ( modelRange ) {\n\t\t\t// Remove all empty elements that were create while splitting.\n\t\t\tthis._removeEmptyElements();\n\n\t\t\t// Move all items that were converted in context tree to the document fragment.\n\t\t\tfor ( const item of Array.from( this._modelCursor.parent.getChildren() ) ) {\n\t\t\t\twriter.append( item, documentFragment );\n\t\t\t}\n\n\t\t\t// Extract temporary markers elements from model and set as static markers collection.\n\t\t\tdocumentFragment.markers = extractMarkersFromModelFragment( documentFragment, writer );\n\t\t}\n\n\t\t// Clear context position.\n\t\tthis._modelCursor = null;\n\n\t\t// Clear split elements & parents lists.\n\t\tthis._splitParts.clear();\n\t\tthis._cursorParents.clear();\n\n\t\t// Clear conversion API.\n\t\tthis.conversionApi.writer = null;\n\t\tthis.conversionApi.store = null;\n\n\t\t// Return fragment as conversion result.\n\t\treturn documentFragment;\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertItem\n\t */\n\t_convertItem( viewItem, modelCursor ) {\n\t\tconst data = Object.assign( { viewItem, modelCursor, modelRange: null } );\n\n\t\tif ( viewItem.is( 'element' ) ) {\n\t\t\tthis.fire( 'element:' + viewItem.name, data, this.conversionApi );\n\t\t} else if ( viewItem.is( '$text' ) ) {\n\t\t\tthis.fire( 'text', data, this.conversionApi );\n\t\t} else {\n\t\t\tthis.fire( 'documentFragment', data, this.conversionApi );\n\t\t}\n\n\t\t// Handle incorrect conversion result.\n\t\tif ( data.modelRange && !( data.modelRange instanceof ModelRange ) ) {\n\t\t\t/**\n\t\t\t * Incorrect conversion result was dropped.\n\t\t\t *\n\t\t\t * {@link module:engine/model/range~Range Model range} should be a conversion result.\n\t\t\t *\n\t\t\t * @error view-conversion-dispatcher-incorrect-result\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'view-conversion-dispatcher-incorrect-result', this );\n\t\t}\n\n\t\treturn { modelRange: data.modelRange, modelCursor: data.modelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#convertChildren\n\t */\n\t_convertChildren( viewItem, elementOrModelCursor ) {\n\t\tlet nextModelCursor = elementOrModelCursor.is( 'position' ) ?\n\t\t\telementOrModelCursor : ModelPosition._createAt( elementOrModelCursor, 0 );\n\n\t\tconst modelRange = new ModelRange( nextModelCursor );\n\n\t\tfor ( const viewChild of Array.from( viewItem.getChildren() ) ) {\n\t\t\tconst result = this._convertItem( viewChild, nextModelCursor );\n\n\t\t\tif ( result.modelRange instanceof ModelRange ) {\n\t\t\t\tmodelRange.end = result.modelRange.end;\n\t\t\t\tnextModelCursor = result.modelCursor;\n\t\t\t}\n\t\t}\n\n\t\treturn { modelRange, modelCursor: nextModelCursor };\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#safeInsert\n\t */\n\t_safeInsert( modelElement, position ) {\n\t\t// Find allowed parent for element that we are going to insert.\n\t\t// If current parent does not allow to insert element but one of the ancestors does\n\t\t// then split nodes to allowed parent.\n\t\tconst splitResult = this._splitToAllowedParent( modelElement, position );\n\n\t\t// When there is no split result it means that we can't insert element to model tree, so let's skip it.\n\t\tif ( !splitResult ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Insert element on allowed position.\n\t\tthis.conversionApi.writer.insert( modelElement, splitResult.position );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#updateConversionResult\n\t */\n\t_updateConversionResult( modelElement, data ) {\n\t\tconst parts = this._getSplitParts( modelElement );\n\n\t\tconst writer = this.conversionApi.writer;\n\n\t\t// Set conversion result range - only if not set already.\n\t\tif ( !data.modelRange ) {\n\t\t\tdata.modelRange = writer.createRange(\n\t\t\t\twriter.createPositionBefore( modelElement ),\n\t\t\t\twriter.createPositionAfter( parts[ parts.length - 1 ] )\n\t\t\t);\n\t\t}\n\n\t\tconst savedCursorParent = this._cursorParents.get( modelElement );\n\n\t\t// Now we need to check where the `modelCursor` should be.\n\t\tif ( savedCursorParent ) {\n\t\t\t// If we split parent to insert our element then we want to continue conversion in the new part of the split parent.\n\t\t\t//\n\t\t\t// before: <allowed><notAllowed>foo[]</notAllowed></allowed>\n\t\t\t// after: <allowed><notAllowed>foo</notAllowed> <converted></converted> <notAllowed>[]</notAllowed></allowed>\n\n\t\t\tdata.modelCursor = writer.createPositionAt( savedCursorParent, 0 );\n\t\t} else {\n\t\t\t// Otherwise just continue after inserted element.\n\n\t\t\tdata.modelCursor = data.modelRange.end;\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#splitToAllowedParent\n\t */\n\t_splitToAllowedParent( node, modelCursor ) {\n\t\tconst { schema, writer } = this.conversionApi;\n\n\t\t// Try to find allowed parent.\n\t\tlet allowedParent = schema.findAllowedParent( modelCursor, node );\n\n\t\tif ( allowedParent ) {\n\t\t\t// When current position parent allows to insert node then return this position.\n\t\t\tif ( allowedParent === modelCursor.parent ) {\n\t\t\t\treturn { position: modelCursor };\n\t\t\t}\n\n\t\t\t// When allowed parent is in context tree (it's outside the converted tree).\n\t\t\tif ( this._modelCursor.parent.getAncestors().includes( allowedParent ) ) {\n\t\t\t\tallowedParent = null;\n\t\t\t}\n\t\t}\n\n\t\tif ( !allowedParent ) {\n\t\t\t// Check if the node wrapped with a paragraph would be accepted by the schema.\n\t\t\tif ( !isParagraphable( modelCursor, node, schema ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tposition: wrapInParagraph( modelCursor, writer )\n\t\t\t};\n\t\t}\n\n\t\t// Split element to allowed parent.\n\t\tconst splitResult = this.conversionApi.writer.split( modelCursor, allowedParent );\n\n\t\t// Using the range returned by `model.Writer#split`, we will pair original elements with their split parts.\n\t\t//\n\t\t// The range returned from the writer spans \"over the split\" or, precisely saying, from the end of the original element (the one\n\t\t// that got split) to the beginning of the other part of that element:\n\t\t//\n\t\t// <limit><a><b><c>X[]Y</c></b><a></limit> ->\n\t\t// <limit><a><b><c>X[</c></b></a><a><b><c>]Y</c></b></a>\n\t\t//\n\t\t// After the split there cannot be any full node between the positions in `splitRange`. The positions are touching.\n\t\t// Also, because of how splitting works, it is easy to notice, that \"closing tags\" are in the reverse order than \"opening tags\".\n\t\t// Also, since we split all those elements, each of them has to have the other part.\n\t\t//\n\t\t// With those observations in mind, we will pair the original elements with their split parts by saving \"closing tags\" and matching\n\t\t// them with \"opening tags\" in the reverse order. For that we can use a stack.\n\t\tconst stack = [];\n\n\t\tfor ( const treeWalkerValue of splitResult.range.getWalker() ) {\n\t\t\tif ( treeWalkerValue.type == 'elementEnd' ) {\n\t\t\t\tstack.push( treeWalkerValue.item );\n\t\t\t} else {\n\t\t\t\t// There should not be any text nodes after the element is split, so the only other value is `elementStart`.\n\t\t\t\tconst originalPart = stack.pop();\n\t\t\t\tconst splitPart = treeWalkerValue.item;\n\n\t\t\t\tthis._registerSplitPair( originalPart, splitPart );\n\t\t\t}\n\t\t}\n\n\t\tconst cursorParent = splitResult.range.end.parent;\n\t\tthis._cursorParents.set( node, cursorParent );\n\n\t\treturn {\n\t\t\tposition: splitResult.position,\n\t\t\tcursorParent\n\t\t};\n\t}\n\n\t/**\n\t * Registers that a `splitPart` element is a split part of the `originalPart` element.\n\t *\n\t * The data set by this method is used by {@link #_getSplitParts} and {@link #_removeEmptyElements}.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} originalPart\n\t * @param {module:engine/model/element~Element} splitPart\n\t */\n\t_registerSplitPair( originalPart, splitPart ) {\n\t\tif ( !this._splitParts.has( originalPart ) ) {\n\t\t\tthis._splitParts.set( originalPart, [ originalPart ] );\n\t\t}\n\n\t\tconst list = this._splitParts.get( originalPart );\n\n\t\tthis._splitParts.set( splitPart, list );\n\t\tlist.push( splitPart );\n\t}\n\n\t/**\n\t * @private\n\t * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi#getSplitParts\n\t */\n\t_getSplitParts( element ) {\n\t\tlet parts;\n\n\t\tif ( !this._splitParts.has( element ) ) {\n\t\t\tparts = [ element ];\n\t\t} else {\n\t\t\tparts = this._splitParts.get( element );\n\t\t}\n\n\t\treturn parts;\n\t}\n\n\t/**\n\t * Checks if there are any empty elements created while splitting and removes them.\n\t *\n\t * This method works recursively to re-check empty elements again after at least one element was removed in the initial call,\n\t * as some elements might have become empty after other empty elements were removed from them.\n\t *\n\t * @private\n\t */\n\t_removeEmptyElements() {\n\t\tlet anyRemoved = false;\n\n\t\tfor ( const element of this._splitParts.keys() ) {\n\t\t\tif ( element.isEmpty ) {\n\t\t\t\tthis.conversionApi.writer.remove( element );\n\t\t\t\tthis._splitParts.delete( element );\n\n\t\t\t\tanyRemoved = true;\n\t\t\t}\n\t\t}\n\n\t\tif ( anyRemoved ) {\n\t\t\tthis._removeEmptyElements();\n\t\t}\n\t}\n\n\t/**\n\t * Fired before the first conversion event, at the beginning of the upcast (view-to-model conversion) process.\n\t *\n\t * @event viewCleanup\n\t * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element}\n\t * viewItem A part of the view to be converted.\n\t */\n\n\t/**\n\t * Fired when an {@link module:engine/view/element~Element} is converted.\n\t *\n\t * `element` is a namespace event for a class of events. Names of actually called events follow the pattern of\n\t * `element:<elementName>` where `elementName` is the name of the converted element. This way listeners may listen to\n\t * a conversion of all or just specific elements.\n\t *\n\t * @event element\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data The conversion data. Keep in mind that this object is\n\t * shared by reference between all callbacks that will be called. This means that callbacks can override values if needed, and these\n\t * values will be available in other callbacks.\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the\n\t * callback.\n\t */\n\n\t/**\n\t * Fired when a {@link module:engine/view/text~Text} is converted.\n\t *\n\t * @event text\n\t * @see #event:element\n\t */\n\n\t/**\n\t * Fired when a {@link module:engine/view/documentfragment~DocumentFragment} is converted.\n\t *\n\t * @event documentFragment\n\t * @see #event:element\n\t */\n}\n\nmix( UpcastDispatcher, EmitterMixin );\n\n// Traverses given model item and searches elements which marks marker range. Found element is removed from\n// DocumentFragment but path of this element is stored in a Map which is then returned.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/node~Node} modelItem Fragment of model.\n// @returns {Map<String, module:engine/model/range~Range>} List of static markers.\nfunction extractMarkersFromModelFragment( modelItem, writer ) {\n\tconst markerElements = new Set();\n\tconst markers = new Map();\n\n\t// Create ModelTreeWalker.\n\tconst range = ModelRange._createIn( modelItem ).getItems();\n\n\t// Walk through DocumentFragment and collect marker elements.\n\tfor ( const item of range ) {\n\t\t// Check if current element is a marker.\n\t\tif ( item.name == '$marker' ) {\n\t\t\tmarkerElements.add( item );\n\t\t}\n\t}\n\n\t// Walk through collected marker elements store its path and remove its from the DocumentFragment.\n\tfor ( const markerElement of markerElements ) {\n\t\tconst markerName = markerElement.getAttribute( 'data-name' );\n\t\tconst currentPosition = writer.createPositionBefore( markerElement );\n\n\t\t// When marker of given name is not stored it means that we have found the beginning of the range.\n\t\tif ( !markers.has( markerName ) ) {\n\t\t\tmarkers.set( markerName, new ModelRange( currentPosition.clone() ) );\n\t\t// Otherwise is means that we have found end of the marker range.\n\t\t} else {\n\t\t\tmarkers.get( markerName ).end = currentPosition.clone();\n\t\t}\n\n\t\t// Remove marker element from DocumentFragment.\n\t\twriter.remove( markerElement );\n\t}\n\n\treturn markers;\n}\n\n// Creates model fragment according to given context and returns position in the bottom (the deepest) element.\nfunction createContextTree( contextDefinition, writer ) {\n\tlet position;\n\n\tfor ( const item of new SchemaContext( contextDefinition ) ) {\n\t\tconst attributes = {};\n\n\t\tfor ( const key of item.getAttributeKeys() ) {\n\t\t\tattributes[ key ] = item.getAttribute( key );\n\t\t}\n\n\t\tconst current = writer.createElement( item.name, attributes );\n\n\t\tif ( position ) {\n\t\t\twriter.append( current, position );\n\t\t}\n\n\t\tposition = ModelPosition._createAt( current, 0 );\n\t}\n\n\treturn position;\n}\n\n/**\n * A set of conversion utilities available as the third parameter of the\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher upcast dispatcher}'s events.\n *\n * @interface module:engine/conversion/upcastdispatcher~UpcastConversionApi\n */\n\n/**\n * Starts the conversion of a given item by firing an appropriate event.\n *\n * Every fired event is passed (as the first parameter) an object with the `modelRange` property. Every event may set and/or\n * modify that property. When all callbacks are done, the final value of the `modelRange` property is returned by this method.\n * The `modelRange` must be a {@link module:engine/model/range~Range model range} or `null` (as set by default).\n *\n * @method #convertItem\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem Item to convert.\n * @param {module:engine/model/position~Position} modelCursor The conversion position.\n * @returns {Object} result The conversion result.\n * @returns {module:engine/model/range~Range|null} result.modelRange The model range containing the result of the item conversion,\n * created and modified by callbacks attached to the fired event, or `null` if the conversion result was incorrect.\n * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.\n */\n\n/**\n * Starts the conversion of all children of a given item by firing appropriate events for all the children.\n *\n * @method #convertChildren\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text\n * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment\n * @param {module:engine/view/item~Item} viewItem An element whose children should be converted.\n * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrElement A position or an element of\n * the conversion.\n * @returns {Object} result The conversion result.\n * @returns {module:engine/model/range~Range} result.modelRange The model range containing the results of the conversion of all children\n * of the given item. When no child was converted, the range is collapsed.\n * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.\n */\n\n/**\n * Safely inserts an element to the document, checking the {@link module:engine/model/schema~Schema schema} to find an allowed parent for\n * an element that you are going to insert, starting from the given position. If the current parent does not allow to insert the element\n * but one of the ancestors does, then splits the nodes to allowed parent.\n *\n * If the schema allows to insert the node in a given position, nothing is split.\n *\n * If it was not possible to find an allowed parent, `false` is returned and nothing is split.\n *\n * Otherwise, ancestors are split.\n *\n * For instance, if `<image>` is not allowed in `<paragraph>` but is allowed in `$root`:\n *\n *\t\t<paragraph>foo[]bar</paragraph>\n *\n *\t\t-> safe insert for `<image>` will split ->\n *\n *\t\t<paragraph>foo</paragraph>[]<paragraph>bar</paragraph>\n *\n * Example usage:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\tif ( !conversionApi.safeInsert( myElement, data.modelCursor ) ) {\n *\t\t\treturn;\n *\t\t}\n *\n * The split result is saved and {@link #updateConversionResult} should be used to update the\n * {@link module:engine/conversion/upcastdispatcher~UpcastConversionData conversion data}.\n *\n * @method #safeInsert\n * @param {module:engine/model/node~Node} node The node to insert.\n * @param {module:engine/model/position~Position} position The position where an element is going to be inserted.\n * @returns {Boolean} The split result. If it was not possible to find an allowed position, `false` is returned.\n */\n\n/**\n * Updates the conversion result and sets a proper {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelRange} and\n * the next {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelCursor} after the conversion.\n * Used together with {@link #safeInsert}, it enables you to easily convert elements without worrying if the node was split\n * during the conversion of its children.\n *\n * A usage example in converter code:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\tif ( !conversionApi.safeInsert( myElement, data.modelCursor ) ) {\n *\t\t\treturn;\n *\t\t}\n *\n *\t\t// Children conversion may split `myElement`.\n *\t\tconversionApi.convertChildren( data.viewItem, myElement );\n *\n *\t\tconversionApi.updateConversionResult( myElement, data );\n *\n * @method #updateConversionResult\n * @param {module:engine/model/element~Element} element\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data Conversion data.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the callback.\n */\n\n/**\n * Checks the {@link module:engine/model/schema~Schema schema} to find an allowed parent for an element that is going to be inserted\n * starting from the given position. If the current parent does not allow inserting an element but one of the ancestors does, the method\n * splits nodes to allowed parent.\n *\n * If the schema allows inserting the node in the given position, nothing is split and an object with that position is returned.\n *\n * If it was not possible to find an allowed parent, `null` is returned and nothing is split.\n *\n * Otherwise, ancestors are split and an object with a position and the copy of the split element is returned.\n *\n * For instance, if `<image>` is not allowed in `<paragraph>` but is allowed in `$root`:\n *\n *\t\t<paragraph>foo[]bar</paragraph>\n *\n *\t\t-> split for `<image>` ->\n *\n *\t\t<paragraph>foo</paragraph>[]<paragraph>bar</paragraph>\n *\n * In the example above, the position between `<paragraph>` elements will be returned as `position` and the second `paragraph`\n * as `cursorParent`.\n *\n * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.\n *\n * @method #splitToAllowedParent\n * @param {module:engine/model/position~Position} position The position where the element is going to be inserted.\n * @param {module:engine/model/node~Node} node The node to insert.\n * @returns {Object|null} The split result. If it was not possible to find an allowed position, `null` is returned.\n * @returns {module:engine/model/position~Position} The position between split elements.\n * @returns {module:engine/model/element~Element} [cursorParent] The element inside which the cursor should be placed to\n * continue the conversion. When the element is not defined it means that there was no split.\n */\n\n/**\n * Returns all the split parts of the given `element` that were created during upcasting through using {@link #splitToAllowedParent}.\n * It enables you to easily track these elements and continue processing them after they are split during the conversion of their children.\n *\n *\t\t<paragraph>Foo<image />bar<image />baz</paragraph> ->\n *\t\t<paragraph>Foo</paragraph><image /><paragraph>bar</paragraph><image /><paragraph>baz</paragraph>\n *\n * For a reference to any of above paragraphs, the function will return all three paragraphs (the original element included),\n * sorted in the order of their creation (the original element is the first one).\n *\n * If the given `element` was not split, an array with a single element is returned.\n *\n * A usage example in the converter code:\n *\n *\t\tconst myElement = conversionApi.writer.createElement( 'myElement' );\n *\n *\t\t// Children conversion may split `myElement`.\n *\t\tconversionApi.convertChildren( data.viewItem, data.modelCursor );\n *\n *\t\tconst splitParts = conversionApi.getSplitParts( myElement );\n *\t\tconst lastSplitPart = splitParts[ splitParts.length - 1 ];\n *\n *\t\t// Setting `data.modelRange` basing on split parts:\n *\t\tdata.modelRange = conversionApi.writer.createRange(\n *\t\t\tconversionApi.writer.createPositionBefore( myElement ),\n *\t\t\tconversionApi.writer.createPositionAfter( lastSplitPart )\n *\t\t);\n *\n *\t\t// Setting `data.modelCursor` to continue after the last split element:\n *\t\tdata.modelCursor = conversionApi.writer.createPositionAfter( lastSplitPart );\n *\n * **Tip:** If you are unable to get a reference to the original element (for example because the code is split into multiple converters\n * or even classes) but it has already been converted, you may want to check the first element in `data.modelRange`. This is a common\n * situation if an attribute converter is separated from an element converter.\n *\n * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.\n *\n * @method #getSplitParts\n * @param {module:engine/model/element~Element} element\n * @returns {Array.<module:engine/model/element~Element>}\n */\n\n/**\n * Stores information about what parts of the processed view item are still waiting to be handled. After a piece of view item\n * was converted, an appropriate consumable value should be\n * {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consumed}.\n *\n * @member {module:engine/conversion/viewconsumable~ViewConsumable} #consumable\n */\n\n/**\n * Custom data stored by converters for the conversion process. Custom properties of this object can be defined and use to\n * pass parameters between converters.\n *\n * The difference between this property and the `data` parameter of\n * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element} is that the `data` parameters allow you\n * to pass parameters within a single event and `store` within the whole conversion.\n *\n * @member {Object} #store\n */\n\n/**\n * The model's schema instance.\n *\n * @member {module:engine/model/schema~Schema} #schema\n */\n\n/**\n * The {@link module:engine/model/writer~Writer} instance used to manipulate the data during conversion.\n *\n * @member {module:engine/model/writer~Writer} #writer\n */\n\n/**\n * Conversion data.\n *\n * **Note:** Keep in mind that this object is shared by reference between all conversion callbacks that will be called.\n * This means that callbacks can override values if needed, and these values will be available in other callbacks.\n *\n * @typedef {Object} module:engine/conversion/upcastdispatcher~UpcastConversionData\n *\n * @property {module:engine/view/item~Item} viewItem The converted item.\n * @property {module:engine/model/position~Position} modelCursor The position where the converter should start changes.\n * Change this value for the next converter to tell where the conversion should continue.\n * @property {module:engine/model/range~Range} [modelRange] The current state of conversion result. Every change to\n * the converted element should be reflected by setting or modifying this property.\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/dataprocessor/basichtmlwriter\n */\n\n/* globals document */\n\n/**\n * Basic HTML writer. It uses the native `innerHTML` property for basic conversion\n * from a document fragment to an HTML string.\n *\n * @implements module:engine/dataprocessor/htmlwriter~HtmlWriter\n */\nexport default class BasicHtmlWriter {\n\t/**\n\t * Returns an HTML string created from the document fragment.\n\t *\n\t * @param {DocumentFragment} fragment\n\t * @returns {String}\n\t */\n\tgetHtml( fragment ) {\n\t\tconst doc = document.implementation.createHTMLDocument( '' );\n\t\tconst container = doc.createElement( 'div' );\n\t\tcontainer.appendChild( fragment );\n\n\t\treturn container.innerHTML;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/dataprocessor/htmldataprocessor\n */\n\n/* globals document, DOMParser */\n\nimport BasicHtmlWriter from './basichtmlwriter';\nimport DomConverter from '../view/domconverter';\n\n/**\n * The HTML data processor class.\n * This data processor implementation uses HTML as input and output data.\n *\n * @implements module:engine/dataprocessor/dataprocessor~DataProcessor\n */\nexport default class HtmlDataProcessor {\n\t/**\n\t * Creates a new instance of the HTML data processor class.\n\t *\n\t * @param {module:engine/view/document~Document} document The view document instance.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * A DOM parser instance used to parse an HTML string to an HTML document.\n\t\t *\n\t\t * @private\n\t\t * @member {DOMParser}\n\t\t */\n\t\tthis._domParser = new DOMParser();\n\n\t\t/**\n\t\t * A DOM converter used to convert DOM elements to view elements.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/domconverter~DomConverter}\n\t\t */\n\t\tthis._domConverter = new DomConverter( document, { blockFillerMode: 'nbsp' } );\n\n\t\t/**\n\t\t * A basic HTML writer instance used to convert DOM elements to an HTML string.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/dataprocessor/basichtmlwriter~BasicHtmlWriter}\n\t\t */\n\t\tthis._htmlWriter = new BasicHtmlWriter();\n\t}\n\n\t/**\n\t * Converts a provided {@link module:engine/view/documentfragment~DocumentFragment document fragment}\n\t * to data format &mdash; in this case to an HTML string.\n\t *\n\t * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment\n\t * @returns {String} HTML string.\n\t */\n\ttoData( viewFragment ) {\n\t\t// Convert view DocumentFragment to DOM DocumentFragment.\n\t\tconst domFragment = this._domConverter.viewToDom( viewFragment, document );\n\n\t\t// Convert DOM DocumentFragment to HTML output.\n\t\treturn this._htmlWriter.getHtml( domFragment );\n\t}\n\n\t/**\n\t * Converts the provided HTML string to a view tree.\n\t *\n\t * @param {String} data An HTML string.\n\t * @returns {module:engine/view/node~Node|module:engine/view/documentfragment~DocumentFragment|null} A converted view element.\n\t */\n\ttoView( data ) {\n\t\t// Convert input HTML data to DOM DocumentFragment.\n\t\tconst domFragment = this._toDom( data );\n\n\t\t// Convert DOM DocumentFragment to view DocumentFragment.\n\t\treturn this._domConverter.domToView( domFragment );\n\t}\n\n\t/**\n\t * Registers a {@link module:engine/view/matcher~MatcherPattern} for view elements whose content should be treated as raw data\n\t * and not processed during the conversion from the DOM to the view elements.\n\t *\n\t * The raw data can be later accessed by a\n\t * {@link module:engine/view/element~Element#getCustomProperty custom property of a view element} called `\"$rawContent\"`.\n\t *\n\t * @param {module:engine/view/matcher~MatcherPattern} pattern Pattern matching all view elements whose content should\n\t * be treated as raw data.\n\t */\n\tregisterRawContentMatcher( pattern ) {\n\t\tthis._domConverter.registerRawContentMatcher( pattern );\n\t}\n\n\t/**\n\t * If the processor is set to use marked fillers, it will insert nbsp fillers wrapped in spans\n\t * (`<span data-cke-filler=\"true\">&nbsp;</span>`), instead of regular nbsp characters (`&nbsp;`).\n\t *\n\t * This mode allows for more precise handling of block fillers (so they don't leak into editor content) but bloats the editor\n\t * data with additional markup.\n\t *\n\t * This mode may be required by some features and will be turned on by them automatically.\n\t *\n\t * @param {'default'|'marked'} type Whether to use default or marked nbsp block fillers.\n\t */\n\tuseFillerType( type ) {\n\t\tthis._domConverter.blockFillerMode = type == 'marked' ? 'markedNbsp' : 'nbsp';\n\t}\n\n\t/**\n\t * Converts an HTML string to its DOM representation. Returns a document fragment containing nodes parsed from\n\t * the provided data.\n\t *\n\t * @private\n\t * @param {String} data\n\t * @returns {DocumentFragment}\n\t */\n\t_toDom( data ) {\n\t\tconst document = this._domParser.parseFromString( data, 'text/html' );\n\t\tconst fragment = document.createDocumentFragment();\n\t\tconst nodes = document.body.childNodes;\n\n\t\twhile ( nodes.length > 0 ) {\n\t\t\tfragment.appendChild( nodes[ 0 ] );\n\t\t}\n\n\t\treturn fragment;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/controller/datacontroller\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\nimport Mapper from '../conversion/mapper';\n\nimport DowncastDispatcher from '../conversion/downcastdispatcher';\nimport { insertText } from '../conversion/downcasthelpers';\n\nimport UpcastDispatcher from '../conversion/upcastdispatcher';\nimport { convertText, convertToModelFragment } from '../conversion/upcasthelpers';\n\nimport ViewDocumentFragment from '../view/documentfragment';\nimport ViewDocument from '../view/document';\nimport ViewDowncastWriter from '../view/downcastwriter';\n\nimport ModelRange from '../model/range';\nimport { autoParagraphEmptyRoots } from '../model/utils/autoparagraphing';\nimport HtmlDataProcessor from '../dataprocessor/htmldataprocessor';\n\n/**\n * Controller for the data pipeline. The data pipeline controls how data is retrieved from the document\n * and set inside it. Hence, the controller features two methods which allow to {@link ~DataController#get get}\n * and {@link ~DataController#set set} data of the {@link ~DataController#model model}\n * using given:\n *\n * * {@link module:engine/dataprocessor/dataprocessor~DataProcessor data processor},\n * * downcast converters,\n * * upcast converters.\n *\n * An instance of the data controller is always available in the {@link module:core/editor/editor~Editor#data `editor.data`}\n * property:\n *\n *\t\teditor.data.get( { rootName: 'customRoot' } ); // -> '<p>Hello!</p>'\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class DataController {\n\t/**\n\t * Creates a data controller instance.\n\t *\n\t * @param {module:engine/model/model~Model} model Data model.\n\t * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor The styles processor instance.\n\t */\n\tconstructor( model, stylesProcessor ) {\n\t\t/**\n\t\t * Data model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * Mapper used for the conversion. It has no permanent bindings, because they are created when getting data and\n\t\t * cleared directly after the data are converted. However, the mapper is defined as a class property, because\n\t\t * it needs to be passed to the `DowncastDispatcher` as a conversion API.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/mapper~Mapper}\n\t\t */\n\t\tthis.mapper = new Mapper();\n\n\t\t/**\n\t\t * Downcast dispatcher used by the {@link #get get method}. Downcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/downcastdispatcher~DowncastDispatcher}\n\t\t */\n\t\tthis.downcastDispatcher = new DowncastDispatcher( {\n\t\t\tmapper: this.mapper,\n\t\t\tschema: model.schema\n\t\t} );\n\t\tthis.downcastDispatcher.on( 'insert:$text', insertText(), { priority: 'lowest' } );\n\n\t\t/**\n\t\t * Upcast dispatcher used by the {@link #set set method}. Upcast converters should be attached to it.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t\t */\n\t\tthis.upcastDispatcher = new UpcastDispatcher( {\n\t\t\tschema: model.schema\n\t\t} );\n\n\t\t/**\n\t\t * The view document used by the data controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/document~Document}\n\t\t */\n\t\tthis.viewDocument = new ViewDocument( stylesProcessor );\n\n\t\t/**\n\t\t * Styles processor used during the conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/view/stylesmap~StylesProcessor}\n\t\t */\n\t\tthis.stylesProcessor = stylesProcessor;\n\n\t\t/**\n\t\t * Data processor used specifically for HTML conversion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/dataprocessor/htmldataprocessor~HtmlDataProcessor} #htmlProcessor\n\t\t */\n\t\tthis.htmlProcessor = new HtmlDataProcessor( this.viewDocument );\n\n\t\t/**\n\t\t * Data processor used during the conversion.\n\t\t * Same instance as {@link #htmlProcessor} by default. Can be replaced at run time to handle different format, e.g. XML or Markdown.\n\t\t *\n\t\t * @member {module:engine/dataprocessor/dataprocessor~DataProcessor} #processor\n\t\t */\n\t\tthis.processor = this.htmlProcessor;\n\n\t\t/**\n\t\t * The view downcast writer just for data conversion purposes, i.e. to modify\n\t\t * the {@link #viewDocument}.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @member {module:engine/view/downcastwriter~DowncastWriter}\n\t\t */\n\t\tthis._viewWriter = new ViewDowncastWriter( this.viewDocument );\n\n\t\t// Define default converters for text and elements.\n\t\t//\n\t\t// Note that if there is no default converter for the element it will be skipped, for instance `<b>foo</b>` will be\n\t\t// converted to nothing. We therefore add `convertToModelFragment` as a last converter so it converts children of that\n\t\t// element to the document fragment and so `<b>foo</b>` will be converted to `foo` if there is no converter for `<b>`.\n\t\tthis.upcastDispatcher.on( 'text', convertText(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } );\n\t\tthis.upcastDispatcher.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } );\n\n\t\tthis.decorate( 'init' );\n\t\tthis.decorate( 'set' );\n\n\t\t// Fire the `ready` event when the initialization has completed. Such low-level listener gives possibility\n\t\t// to plug into the initialization pipeline without interrupting the initialization flow.\n\t\tthis.on( 'init', () => {\n\t\t\tthis.fire( 'ready' );\n\t\t}, { priority: 'lowest' } );\n\n\t\t// Fix empty roots after DataController is 'ready' (note that init method could be decorated and stopped).\n\t\t// We need to handle this event because initial data could be empty and post-fixer would not get triggered.\n\t\tthis.on( 'ready', () => {\n\t\t\tthis.model.enqueueChange( 'transparent', autoParagraphEmptyRoots );\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Returns the model's data converted by downcast dispatchers attached to {@link #downcastDispatcher} and\n\t * formatted by the {@link #processor data processor}.\n\t *\n\t * @param {Object} [options] Additional configuration for the retrieved data. `DataController` provides two optional\n\t * properties: `rootName` and `trim`. Other properties of this object are specified by various editor features.\n\t * @param {String} [options.rootName='main'] Root name.\n\t * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `empty` by default,\n\t * which means whenever editor content is considered empty, an empty string will be returned. To turn off trimming completely\n\t * use `'none'`. In such cases exact content will be returned (for example `<p>&nbsp;</p>` for an empty editor).\n\t * @returns {String} Output data.\n\t */\n\tget( options = {} ) {\n\t\tconst { rootName = 'main', trim = 'empty' } = options;\n\n\t\tif ( !this._checkIfRootsExists( [ rootName ] ) ) {\n\t\t\t/**\n\t\t\t * Cannot get data from a non-existing root. This error is thrown when {@link #get DataController#get() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #get} like:\n\t\t\t *\n\t\t\t *\t\tdata.get( { rootName: 'root2' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-get-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-get-non-existent-root', this );\n\t\t}\n\n\t\tconst root = this.model.document.getRoot( rootName );\n\n\t\tif ( trim === 'empty' && !this.model.hasContent( root, { ignoreWhitespaces: true } ) ) {\n\t\t\treturn '';\n\t\t}\n\n\t\treturn this.stringify( root, options );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model's element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast converters\n\t * attached to {@link #downcastDispatcher} and formatted by the {@link #processor data processor}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element whose content will be stringified.\n\t * @param {Object} [options] Additional configuration passed to the conversion process.\n\t * @returns {String} Output data.\n\t */\n\tstringify( modelElementOrFragment, options = {} ) {\n\t\t// Model -> view.\n\t\tconst viewDocumentFragment = this.toView( modelElementOrFragment, options );\n\n\t\t// View -> data.\n\t\treturn this.processor.toData( viewDocumentFragment );\n\t}\n\n\t/**\n\t * Returns the content of the given {@link module:engine/model/element~Element model element} or\n\t * {@link module:engine/model/documentfragment~DocumentFragment model document fragment} converted by the downcast\n\t * converters attached to {@link #downcastDispatcher} to a\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}.\n\t *\n\t * @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @param {Object} [options={}] Additional configuration that will be available through\n\t * {@link module:engine/conversion/downcastdispatcher~DowncastConversionApi#options} during the conversion process.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} Output view DocumentFragment.\n\t */\n\ttoView( modelElementOrFragment, options = {} ) {\n\t\tconst viewDocument = this.viewDocument;\n\t\tconst viewWriter = this._viewWriter;\n\n\t\t// Clear bindings so the call to this method gives correct results.\n\t\tthis.mapper.clearBindings();\n\n\t\t// First, convert elements.\n\t\tconst modelRange = ModelRange._createIn( modelElementOrFragment );\n\t\tconst viewDocumentFragment = new ViewDocumentFragment( viewDocument );\n\n\t\tthis.mapper.bindElements( modelElementOrFragment, viewDocumentFragment );\n\n\t\t// Make additional options available during conversion process through `conversionApi`.\n\t\tthis.downcastDispatcher.conversionApi.options = options;\n\n\t\t// We have no view controller and rendering to DOM in DataController so view.change() block is not used here.\n\t\tthis.downcastDispatcher.convertInsert( modelRange, viewWriter );\n\n\t\t// Convert markers.\n\t\t// For document fragment, simply take the markers assigned to this document fragment.\n\t\t// For model root, all markers in that root will be taken.\n\t\t// For model element, we need to check which markers are intersecting with this element and relatively modify the markers' ranges.\n\t\tconst markers = modelElementOrFragment.is( 'documentFragment' ) ?\n\t\t\tArray.from( modelElementOrFragment.markers ) :\n\t\t\t_getMarkersRelativeToElement( modelElementOrFragment );\n\n\t\tfor ( const [ name, range ] of markers ) {\n\t\t\tthis.downcastDispatcher.convertMarkerAdd( name, range, viewWriter );\n\t\t}\n\n\t\t// Clean `conversionApi`.\n\t\tdelete this.downcastDispatcher.conversionApi.options;\n\n\t\treturn viewDocumentFragment;\n\t}\n\n\t/**\n\t * Sets initial input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * Initial data can be set only to document that {@link module:engine/model/document~Document#version} is equal 0.\n\t *\n\t * **Note** This method is {@link module:utils/observablemixin~ObservableMixin#decorate decorated} which is\n\t * used by e.g. collaborative editing plugin that syncs remote data on init.\n\t *\n\t * When data is passed as a string it is initialized on a default `main` root:\n\t *\n\t *\t\tdataController.init( '<p>Foo</p>' ); // Initializes data on the `main` root.\n\t *\n\t * To initialize data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.init( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Initializes data on the `main` and `title` roots.\n\t *\n\t * @fires init\n\t * @param {String|Object.<String,String>} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to initialize data on multiple roots at once.\n\t * @returns {Promise} Promise that is resolved after the data is set on the editor.\n\t */\n\tinit( data ) {\n\t\tif ( this.model.document.version ) {\n\t\t\t/**\n\t\t\t * Cannot set initial data to not empty {@link module:engine/model/document~Document}.\n\t\t\t * Initial data should be set once, during {@link module:core/editor/editor~Editor} initialization,\n\t\t\t * when the {@link module:engine/model/document~Document#version} is equal 0.\n\t\t\t *\n\t\t\t * @error datacontroller-init-document-not-empty\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-document-not-empty', this );\n\t\t}\n\n\t\tlet initialData = {};\n\t\tif ( typeof data === 'string' ) {\n\t\t\tinitialData.main = data; // Default root is 'main'. To initiate data on a different root, object should be passed.\n\t\t} else {\n\t\t\tinitialData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( initialData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot init data on a non-existing root. This error is thrown when {@link #init DataController#init() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #init} like:\n\t\t\t *\n\t\t\t * \t\tdata.init( { main: '<p>Foo</p>', root2: '<p>Bar</p>' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-init-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-init-non-existent-root', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\tfor ( const rootName of Object.keys( initialData ) ) {\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\t\t\t\twriter.insert( this.parse( initialData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\n\t\treturn Promise.resolve();\n\t}\n\n\t/**\n\t * Sets input data parsed by the {@link #processor data processor} and\n\t * converted by the {@link #upcastDispatcher view-to-model converters}.\n\t * This method can be used any time to replace existing editor data by the new one without clearing the\n\t * {@link module:engine/model/document~Document#history document history}.\n\t *\n\t * This method also creates a batch with all the changes applied. If all you need is to parse data, use\n\t * the {@link #parse} method.\n\t *\n\t * When data is passed as a string it is set on a default `main` root:\n\t *\n\t *\t\tdataController.set( '<p>Foo</p>' ); // Sets data on the `main` root.\n\t *\n\t * To set data on a different root or multiple roots at once, object containing `rootName` - `data` pairs should be passed:\n\t *\n\t *\t\tdataController.set( { main: '<p>Foo</p>', title: '<h1>Bar</h1>' } ); // Sets data on the `main` and `title` roots.\n\t *\n\t * @fires set\n\t * @param {String|Object.<String,String>} data Input data as a string or an object containing `rootName` - `data`\n\t * pairs to set data on multiple roots at once.\n\t */\n\tset( data ) {\n\t\tlet newData = {};\n\n\t\tif ( typeof data === 'string' ) {\n\t\t\tnewData.main = data; // Default root is 'main'. To set data on a different root, object should be passed.\n\t\t} else {\n\t\t\tnewData = data;\n\t\t}\n\n\t\tif ( !this._checkIfRootsExists( Object.keys( newData ) ) ) {\n\t\t\t/**\n\t\t\t * Cannot set data on a non-existing root. This error is thrown when {@link #set DataController#set() method}\n\t\t\t * is called with non-existent root name. For example, if there is an editor instance with only `main` root,\n\t\t\t * calling {@link #set} like:\n\t\t\t *\n\t\t\t * \t\tdata.set( { main: '<p>Foo</p>', root2: '<p>Bar</p>' } );\n\t\t\t *\n\t\t\t * will throw this error.\n\t\t\t *\n\t\t\t * @error datacontroller-set-non-existent-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'datacontroller-set-non-existent-root', this );\n\t\t}\n\n\t\tthis.model.enqueueChange( 'transparent', writer => {\n\t\t\twriter.setSelection( null );\n\t\t\twriter.removeSelectionAttribute( this.model.document.selection.getAttributeKeys() );\n\n\t\t\tfor ( const rootName of Object.keys( newData ) ) {\n\t\t\t\t// Save to model.\n\t\t\t\tconst modelRoot = this.model.document.getRoot( rootName );\n\n\t\t\t\twriter.remove( writer.createRangeIn( modelRoot ) );\n\t\t\t\twriter.insert( this.parse( newData[ rootName ], modelRoot ), modelRoot, 0 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the data parsed by the {@link #processor data processor} and then converted by upcast converters\n\t * attached to the {@link #upcastDispatcher}.\n\t *\n\t * @see #set\n\t * @param {String} data Data to parse.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Parsed data.\n\t */\n\tparse( data, context = '$root' ) {\n\t\t// data -> view\n\t\tconst viewDocumentFragment = this.processor.toView( data );\n\n\t\t// view -> model\n\t\treturn this.toModel( viewDocumentFragment, context );\n\t}\n\n\t/**\n\t * Returns the result of the given {@link module:engine/view/element~Element view element} or\n\t * {@link module:engine/view/documentfragment~DocumentFragment view document fragment} converted by the\n\t * {@link #upcastDispatcher view-to-model converters}, wrapped by {@link module:engine/model/documentfragment~DocumentFragment}.\n\t *\n\t * When marker elements were converted during the conversion process, it will be set as a document fragment's\n\t * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.\n\t *\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElementOrFragment\n\t * Element or document fragment whose content will be converted.\n\t * @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will\n\t * be converted to the model. See: {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#convert}.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} Output document fragment.\n\t */\n\ttoModel( viewElementOrFragment, context = '$root' ) {\n\t\treturn this.model.change( writer => {\n\t\t\treturn this.upcastDispatcher.convert( viewElementOrFragment, writer, context );\n\t\t} );\n\t}\n\n\t/**\n\t * Adds a style processor normalization rules.\n\t *\n\t * You can implement your own rules as well as use one of the available processor rules:\n\t *\n\t * * background: {@link module:engine/view/styles/background~addBackgroundRules}\n\t * * border: {@link module:engine/view/styles/border~addBorderRules}\n\t * * margin: {@link module:engine/view/styles/margin~addMarginRules}\n\t * * padding: {@link module:engine/view/styles/padding~addPaddingRules}\n\t *\n\t * @param {Function} callback\n\t */\n\taddStyleProcessorRules( callback ) {\n\t\tcallback( this.stylesProcessor );\n\t}\n\n\t/**\n\t * Registers a {@link module:engine/view/matcher~MatcherPattern} on {@link #htmlProcessor htmlProcessor}\n\t * and {@link #processor processor} for view elements whose content should be treated as a raw data\n\t * and not processed during conversion from DOM to view elements.\n\t *\n\t * The raw data can be later accessed by {@link module:engine/view/element~Element#getCustomProperty view element custom property}\n\t * `\"$rawContent\"`.\n\t *\n\t * @param {module:engine/view/matcher~MatcherPattern} pattern Pattern matching all view elements whose content should\n\t * be treated as a raw data.\n\t */\n\tregisterRawContentMatcher( pattern ) {\n\t\t// No need to register the pattern if both `htmlProcessor` and `processor` are the same instances.\n\t\tif ( this.processor && this.processor !== this.htmlProcessor ) {\n\t\t\tthis.processor.registerRawContentMatcher( pattern );\n\t\t}\n\n\t\tthis.htmlProcessor.registerRawContentMatcher( pattern );\n\t}\n\n\t/**\n\t * Removes all event listeners set by the DataController.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks if all provided root names are existing editor roots.\n\t *\n\t * @private\n\t * @param {Array.<String>} rootNames Root names to check.\n\t * @returns {Boolean} Whether all provided root names are existing editor roots.\n\t */\n\t_checkIfRootsExists( rootNames ) {\n\t\tfor ( const rootName of rootNames ) {\n\t\t\tif ( !this.model.document.getRootNames().includes( rootName ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Event fired once the data initialization has finished.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Event fired after the {@link #init `init()` method} was run. It can be {@link #listenTo listened to} in order to adjust or modify\n\t * the initialization flow. However, if the `init` event is stopped or prevented, the {@link #event:ready `ready` event}\n\t * should be fired manually.\n\t *\n\t * The `init` event is fired by the decorated {@link #init} method.\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event init\n\t */\n\n\t/**\n\t * Event fired after {@link #set set() method} has been run.\n\t *\n\t * The `set` event is fired by decorated {@link #set} method.\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event set\n\t */\n}\n\nmix( DataController, ObservableMixin );\n\n// Helper function for downcast conversion.\n//\n// Takes a document element (element that is added to a model document) and checks which markers are inside it\n// and which markers are containing it. If the marker is intersecting with element, the intersection is returned.\nfunction _getMarkersRelativeToElement( element ) {\n\tconst result = [];\n\tconst doc = element.root.document;\n\n\tif ( !doc ) {\n\t\treturn [];\n\t}\n\n\tconst elementRange = ModelRange._createIn( element );\n\n\tfor ( const marker of doc.model.markers ) {\n\t\tconst intersection = elementRange.getIntersection( marker.getRange() );\n\n\t\tif ( intersection ) {\n\t\t\tresult.push( [ marker.name, intersection ] );\n\t\t}\n\t}\n\n\treturn result;\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/conversion/conversion\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport UpcastHelpers from './upcasthelpers';\nimport DowncastHelpers from './downcasthelpers';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\n/**\n * A utility class that helps add converters to upcast and downcast dispatchers.\n *\n * We recommend reading the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide first to\n * understand the core concepts of the conversion mechanisms.\n *\n * An instance of the conversion manager is available in the\n * {@link module:core/editor/editor~Editor#conversion `editor.conversion`} property\n * and by default has the following groups of dispatchers (i.e. directions of conversion):\n *\n * * `downcast` (editing and data downcasts)\n * * `editingDowncast`\n * * `dataDowncast`\n * * `upcast`\n *\n * # One-way converters\n *\n * To add a converter to a specific group, use the {@link module:engine/conversion/conversion~Conversion#for `for()`}\n * method:\n *\n *\t\t// Add a converter to editing downcast and data downcast.\n *\t\teditor.conversion.for( 'downcast' ).elementToElement( config ) );\n *\n *\t\t// Add a converter to the data pipepline only:\n *\t\teditor.conversion.for( 'dataDowncast' ).elementToElement( dataConversionConfig ) );\n *\n *\t\t// And a slightly different one for the editing pipeline:\n *\t\teditor.conversion.for( 'editingDowncast' ).elementToElement( editingConversionConfig ) );\n *\n * See {@link module:engine/conversion/conversion~Conversion#for `for()`} method documentation to learn more about\n * available conversion helpers and how to use your custom ones.\n *\n * # Two-way converters\n *\n * Besides using one-way converters via the `for()` method, you can also use other methods available in this\n * class to add two-way converters (upcast and downcast):\n *\n * * {@link module:engine/conversion/conversion~Conversion#elementToElement `elementToElement()`} &ndash;\n * Model element to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement()`} &ndash;\n * Model attribute to view element and vice versa.\n * * {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `attributeToAttribute()`} &ndash;\n * Model attribute to view element and vice versa.\n */\nexport default class Conversion {\n\t/**\n\t * Creates a new conversion instance.\n\t *\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher>} downcastDispatchers\n\t * @param {module:engine/conversion/upcastdispatcher~UpcastDispatcher|\n\t * Array.<module:engine/conversion/upcastdispatcher~UpcastDispatcher>} upcastDispatchers\n\t */\n\tconstructor( downcastDispatchers, upcastDispatchers ) {\n\t\t/**\n\t\t * Maps dispatchers group name to ConversionHelpers instances.\n\t\t *\n\t\t * @private\n\t\t * @member {Map.<String,module:engine/conversion/conversionhelpers~ConversionHelpers>}\n\t\t */\n\t\tthis._helpers = new Map();\n\n\t\t// Define default 'downcast' & 'upcast' dispatchers groups. Those groups are always available as two-way converters needs them.\n\t\tthis._downcast = toArray( downcastDispatchers );\n\t\tthis._createConversionHelpers( { name: 'downcast', dispatchers: this._downcast, isDowncast: true } );\n\n\t\tthis._upcast = toArray( upcastDispatchers );\n\t\tthis._createConversionHelpers( { name: 'upcast', dispatchers: this._upcast, isDowncast: false } );\n\t}\n\n\t/**\n\t * Define an alias for registered dispatcher.\n\t *\n\t *\t\tconst conversion = new Conversion(\n\t *\t\t\t[ dataDowncastDispatcher, editingDowncastDispatcher ],\n\t *\t\t\tupcastDispatcher\n\t *\t\t);\n\t *\n\t *\t\tconversion.addAlias( 'dataDowncast', dataDowncastDispatcher );\n\t *\n\t * @param {String} alias An alias of a dispatcher.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher} dispatcher Dispatcher which should have an alias.\n\t */\n\taddAlias( alias, dispatcher ) {\n\t\tconst isDowncast = this._downcast.includes( dispatcher );\n\t\tconst isUpcast = this._upcast.includes( dispatcher );\n\n\t\tif ( !isUpcast && !isDowncast ) {\n\t\t\t/**\n\t\t\t * Trying to register and alias for a dispatcher that nas not been registered.\n\t\t\t *\n\t\t\t * @error conversion-add-alias-dispatcher-not-registered\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'conversion-add-alias-dispatcher-not-registered',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tthis._createConversionHelpers( { name: alias, dispatchers: [ dispatcher ], isDowncast } );\n\t}\n\n\t/**\n\t * Provides a chainable API to assign converters to conversion dispatchers group.\n\t *\n\t * If the given group name has not been registered, the\n\t * {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown.\n\t *\n\t * You can use conversion helpers available directly in the `for()` chain or your custom ones via\n\t * the {@link module:engine/conversion/conversionhelpers~ConversionHelpers#add `add()`} method.\n\t *\n\t * # Using bulit-in conversion helpers\n\t *\n\t * The `for()` chain comes with a set of conversion helpers which you can use like this:\n\t *\n\t *\t\teditor.conversion.for( 'downcast' )\n\t *\t\t\t.elementToElement( config1 ) // Adds an element-to-element downcast converter.\n\t *\t\t\t.attributeToElement( config2 ); // Adds an attribute-to-element downcast converter.\n\t *\n\t *\t\teditor.conversion.for( 'upcast' )\n\t *\t\t\t.elementToAttribute( config3 ); // Adds an element-to-attribute upcast converter.\n\t *\n\t * Refer to the documentation of built-in conversion helpers to learn about their configuration options.\n\t *\n\t * * downcast (model-to-view) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement `attributeToElement()`},\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToElement `markerToElement()`}.\n\t *\t* {@link module:engine/conversion/downcasthelpers~DowncastHelpers#markerToHighlight `markerToHighlight()`}.\n\t *\n\t * * upcast (view-to-model) conversion helpers:\n\t *\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement `elementToElement()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToAttribute `elementToAttribute()`},\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#attributeToAttribute `attributeToAttribute()`}.\n\t *\t* {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToMarker `elementToMarker()`}.\n\t *\n\t * # Using custom conversion helpers\n\t *\n\t * If you need to implement a nontypical converter, you can do so by calling:\n\t *\n\t *\t\teditor.conversion.for( direction ).add( customHelper );\n\t *\n\t * The `.add()` method takes exactly one parameter, which is a function. This function should accept one parameter that\n\t * is a dispatcher instance. The function should add an actual converter to the passed dispatcher instance.\n\t *\n\t * Example:\n\t *\n\t *\t\teditor.conversion.for( 'upcast' ).add( dispatcher => {\n\t *\t\t\tdispatcher.on( 'element:a', ( evt, data, conversionApi ) => {\n\t *\t\t\t\t// Do something with a view <a> element.\n\t *\t\t\t} );\n\t *\t\t} );\n\t *\n\t * Refer to the documentation of {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}\n\t * and {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} to learn how to write\n\t * custom converters.\n\t *\n\t * @param {String} groupName The name of dispatchers group to add the converters to.\n\t * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers}\n\t */\n\tfor( groupName ) {\n\t\tif ( !this._helpers.has( groupName ) ) {\n\t\t\t/**\n\t\t\t * Trying to add a converter to an unknown dispatchers group.\n\t\t\t *\n\t\t\t * @error conversion-for-unknown-group\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-for-unknown-group', this );\n\t\t}\n\n\t\treturn this._helpers.get( groupName );\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model element to a view element (and vice versa).\n\t * For example, the model `<paragraph>Foo</paragraph>` is `<p>Foo</p>` in the view.\n\t *\n\t *\t\t// A simple conversion from the `paragraph` model element to the `<p>` view element (and vice versa).\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'div', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'fancyParagraph',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'p',\n\t *\t\t\t\tclasses: 'fancy'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to a `paragraph` element.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'paragraph',\n\t *\t\t\tview: 'p',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'div',\n\t *\t\t\t\t{\n\t *\t\t\t\t\t// Any element with the `display: block` style.\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\tdisplay: 'block'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.elementToElement( {\n\t *\t\t\tmodel: 'heading',\n\t *\t\t\tview: 'h2',\n\t *\t\t\t// Convert \"heading-like\" paragraphs to headings.\n\t *\t\t\tupcastAlso: viewElement => {\n\t *\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\tif ( size > 26 ) {\n\t *\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t}\n\t *\n\t *\t\t\t\treturn null;\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * `definition.model` is a `String` with a model element name to convert from or to.\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\telementToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).elementToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToElement( {\n\t\t\t\t\tmodel,\n\t\t\t\t\tview,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view element (and vice versa).\n\t * For example, a model text node with `\"Foo\"` as data and the `bold` attribute is `<strong>Foo</strong>` in the view.\n\t *\n\t *\t\t// A simple conversion from the `bold=true` attribute to the `<strong>` view element (and vice versa).\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'strong' } );\n\t *\n\t *\t\t// Override other converters by specifying a converter definition with a higher priority.\n\t *\t\teditor.conversion.attributeToElement( { model: 'bold', view: 'b', converterPriority: 'high' } );\n\t *\n\t *\t\t// View specified as an object instead of a string.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: {\n\t *\t\t\t\tname: 'span',\n\t *\t\t\t\tclasses: 'bold'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `config.model.name` to define the conversion only from a given node type, `$text` in this case.\n\t *\t\t// The same attribute on different elements may then be handled by a different converter.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'textDecoration',\n\t *\t\t\t\tvalues: [ 'underline', 'lineThrough' ],\n\t *\t\t\t\tname: '$text'\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tunderline: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'underline'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tlineThrough: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-decoration': 'line-through'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to the `bold` attribute.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: 'bold',\n\t *\t\t\tview: 'strong',\n\t *\t\t\tupcastAlso: [\n\t *\t\t\t\t'b',\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tclasses: 'bold'\n\t *\t\t\t\t},\n\t *\t\t\t\t{\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-weight': 'bold'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tviewElement => {\n\t *\t\t\t\t\tconst fontWeight = viewElement.getStyle( 'font-weight' );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && fontWeight && /\\d+/.test() && Number( fontWeight ) > 500 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn {\n\t *\t\t\t\t\t\t\tname: true,\n\t *\t\t\t\t\t\t\tstyles: [ 'font-weight' ]\n\t *\t\t\t\t\t\t};\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Conversion from and to a model attribute key whose value is an enum (`fontSize=big|small`).\n\t *\t\t// `upcastAlso` set as callback enables a conversion of a wide range of different view elements.\n\t *\t\teditor.conversion.attributeToElement( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'fontSize',\n\t *\t\t\t\tvalues: [ 'big', 'small' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tbig: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '1.2em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: {\n\t *\t\t\t\t\tname: 'span',\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'font-size': '0.8em'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tupcastAlso: {\n\t *\t\t\t\tbig: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && size > 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t},\n\t *\t\t\t\tsmall: viewElement => {\n\t *\t\t\t\t\tconst fontSize = viewElement.getStyle( 'font-size' );\n\t *\n\t *\t\t\t\t\tif ( !fontSize ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst match = fontSize.match( /(\\d+)\\s*px/ );\n\t *\n\t *\t\t\t\t\tif ( !match ) {\n\t *\t\t\t\t\t\treturn null;\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\tconst size = Number( match[ 1 ] );\n\t *\n\t *\t\t\t\t\tif ( viewElement.is( 'element', 'span' ) && size < 10 ) {\n\t *\t\t\t\t\t\t// Returned value can be an object with the matched properties.\n\t *\t\t\t\t\t\t// These properties will be \"consumed\" during the conversion.\n\t *\t\t\t\t\t\t// See `engine.view.Matcher~MatcherPattern` and `engine.view.Matcher#match` for more details.\n\t *\n\t *\t\t\t\t\t\treturn { name: true, styles: [ 'font-size' ] };\n\t *\t\t\t\t\t}\n\t *\n\t *\t\t\t\t\treturn null;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The `definition.model` parameter specifies which model attribute should be converted from or to. It can be a `{ key, value }` object\n\t * describing the attribute key and value to convert or a `String` specifying just the attribute key (then `value` is set to `true`).\n\t * See {@link module:engine/conversion/conversion~ConverterDefinition} to learn about other parameters.\n\t *\n\t * @param {module:engine/conversion/conversion~ConverterDefinition} definition The converter definition.\n\t */\n\tattributeToElement( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToElement( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.elementToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel,\n\t\t\t\t\tconverterPriority: definition.converterPriority\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up converters between the model and the view that convert a model attribute to a view attribute (and vice versa).\n\t * For example, `<image src='foo.jpg'></image>` is converted to `<img src='foo.jpg'></img>` (the same attribute key and value).\n\t * This type of converters is intended to be used with {@link module:engine/model/element~Element model element} nodes.\n\t * To convert text attributes {@link module:engine/conversion/conversion~Conversion#attributeToElement `attributeToElement converter`}\n\t * should be set up.\n\t *\n\t *\t\t// A simple conversion from the `source` model attribute to the `src` view attribute (and vice versa).\n\t *\t\teditor.conversion.attributeToAttribute( { model: 'source', view: 'src' } );\n\t *\n\t *\t\t// Attribute values are strictly specified.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: [ 'aside', 'half-size' ]\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Set the style attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tname: 'image',\n\t *\t\t\t\tkey: 'aside',\n\t *\t\t\t\tvalues: [ 'aside' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\taside: {\n\t *\t\t\t\t\tname: 'img',\n\t *\t\t\t\t\tkey: 'style',\n\t *\t\t\t\t\tvalue: {\n\t *\t\t\t\t\t\tfloat: 'right',\n\t *\t\t\t\t\t\twidth: '50%',\n\t *\t\t\t\t\t\tmargin: '5px'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Conversion from and to a model attribute key whose value is an enum (`align=right|center`).\n\t *\t\t// Use `upcastAlso` to define other view elements that should also be converted to the `align=right` attribute.\n\t *\t\teditor.conversion.attributeToAttribute( {\n\t *\t\t\tmodel: {\n\t *\t\t\t\tkey: 'align',\n\t *\t\t\t\tvalues: [ 'right', 'center' ]\n\t *\t\t\t},\n\t *\t\t\tview: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-right'\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tkey: 'class',\n\t *\t\t\t\t\tvalue: 'align-center'\n\t *\t\t\t\t}\n\t *\t\t\t},\n\t *\t\t\tupcastAlso: {\n\t *\t\t\t\tright: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'right'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t},\n\t *\t\t\t\tcenter: {\n\t *\t\t\t\t\tstyles: {\n\t *\t\t\t\t\t\t'text-align': 'center'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * The `definition.model` parameter specifies which model attribute should be converted from and to.\n\t * It can be a `{ key, [ values ], [ name ] }` object or a `String`, which will be treated like `{ key: definition.model }`.\n\t * The `key` property is the model attribute key to convert from and to.\n\t * The `values` are the possible model attribute values. If `values` is not set, the model attribute value will be the same as the\n\t * view attribute value.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t *\n\t * The `definition.view` parameter specifies which view attribute should be converted from and to.\n\t * It can be a `{ key, value, [ name ] }` object or a `String`, which will be treated like `{ key: definition.view }`.\n\t * The `key` property is the view attribute key to convert from and to.\n\t * The `value` is the view attribute value to convert from and to. If `definition.value` is not set, the view attribute value will be\n\t * the same as the model attribute value.\n\t * If `key` is `'class'`, `value` can be a `String` or an array of `String`s.\n\t * If `key` is `'style'`, `value` is an object with key-value pairs.\n\t * In other cases, `value` is a `String`.\n\t * If `name` is set, the conversion will be set up only for model elements with the given name.\n\t * If `definition.model.values` is set, `definition.view` is an object that assigns values from `definition.model.values`\n\t * to `{ key, value, [ name ] }` objects.\n\t *\n\t * `definition.upcastAlso` specifies which other matching view elements should also be upcast to the given model configuration.\n\t * If `definition.model.values` is set, `definition.upcastAlso` should be an object assigning values from `definition.model.values`\n\t * to {@link module:engine/view/matcher~MatcherPattern}s or arrays of {@link module:engine/view/matcher~MatcherPattern}s.\n\t *\n\t * **Note:** `definition.model` and `definition.view` form should be mirrored, so the same types of parameters should\n\t * be given in both parameters.\n\t *\n\t * @param {Object} definition The converter definition.\n\t * @param {String|Object} definition.model The model attribute to convert from and to.\n\t * @param {String|Object} definition.view The view attribute to convert from and to.\n\t * @param {module:engine/view/matcher~MatcherPattern|Array.<module:engine/view/matcher~MatcherPattern>} [definition.upcastAlso]\n\t * Any view element matching `definition.upcastAlso` will also be converted to the given model attribute. `definition.upcastAlso`\n\t * is used only if `config.model.values` is specified.\n\t */\n\tattributeToAttribute( definition ) {\n\t\t// Set up downcast converter.\n\t\tthis.for( 'downcast' ).attributeToAttribute( definition );\n\n\t\t// Set up upcast converter.\n\t\tfor ( const { model, view } of _getAllUpcastDefinitions( definition ) ) {\n\t\t\tthis.for( 'upcast' )\n\t\t\t\t.attributeToAttribute( {\n\t\t\t\t\tview,\n\t\t\t\t\tmodel\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Creates and caches conversion helpers for given dispatchers group.\n\t *\n\t * @private\n\t * @param {Object} options\n\t * @param {String} options.name Group name.\n\t * @param {Array.<module:engine/conversion/downcastdispatcher~DowncastDispatcher|\n\t * module:engine/conversion/upcastdispatcher~UpcastDispatcher>} options.dispatchers\n\t * @param {Boolean} options.isDowncast\n\t */\n\t_createConversionHelpers( { name, dispatchers, isDowncast } ) {\n\t\tif ( this._helpers.has( name ) ) {\n\t\t\t/**\n\t\t\t * Trying to register a group name that has already been registered.\n\t\t\t *\n\t\t\t * @error conversion-group-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'conversion-group-exists', this );\n\t\t}\n\n\t\tconst helpers = isDowncast ? new DowncastHelpers( dispatchers ) : new UpcastHelpers( dispatchers );\n\n\t\tthis._helpers.set( name, helpers );\n\t}\n}\n\n/**\n * Defines how the model should be converted from and to the view.\n *\n * @typedef {Object} module:engine/conversion/conversion~ConverterDefinition\n *\n * @property {*} [model] The model conversion definition. Describes the model element or model attribute to convert. This parameter differs\n * for different functions that accept `ConverterDefinition`. See the description of the function to learn how to set it.\n * @property {module:engine/view/elementdefinition~ElementDefinition|Object} view The definition of the view element to convert from and\n * to. If `model` describes multiple values, `view` is an object that assigns these values (`view` object keys) to view element definitions\n * (`view` object values).\n * @property {module:engine/view/matcher~MatcherPattern|Array.<module:engine/view/matcher~MatcherPattern>} [upcastAlso]\n * Any view element matching `upcastAlso` will also be converted to the model. If `model` describes multiple values, `upcastAlso`\n * is an object that assigns these values (`upcastAlso` object keys) to {@link module:engine/view/matcher~MatcherPattern}s\n * (`upcastAlso` object values).\n * @property {module:utils/priorities~PriorityString} [converterPriority] The converter priority.\n */\n\n// Helper function that creates a joint array out of an item passed in `definition.view` and items passed in\n// `definition.upcastAlso`.\n//\n// @param {module:engine/conversion/conversion~ConverterDefinition} definition\n// @returns {Array} Array containing view definitions.\nfunction* _getAllUpcastDefinitions( definition ) {\n\tif ( definition.model.values ) {\n\t\tfor ( const value of definition.model.values ) {\n\t\t\tconst model = { key: definition.model.key, value };\n\t\t\tconst view = definition.view[ value ];\n\t\t\tconst upcastAlso = definition.upcastAlso ? definition.upcastAlso[ value ] : undefined;\n\n\t\t\tyield* _getUpcastDefinition( model, view, upcastAlso );\n\t\t}\n\t} else {\n\t\tyield* _getUpcastDefinition( definition.model, definition.view, definition.upcastAlso );\n\t}\n}\n\nfunction* _getUpcastDefinition( model, view, upcastAlso ) {\n\tyield { model, view };\n\n\tif ( upcastAlso ) {\n\t\tfor ( const upcastAlsoItem of toArray( upcastAlso ) ) {\n\t\t\tyield { model, view: upcastAlsoItem };\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/batch\n */\n\n/**\n * A batch instance groups model changes ({@link module:engine/model/operation/operation~Operation operations}). All operations\n * grouped in a single batch can be reverted together, so you can also think about a batch as of a single undo step. If you want\n * to extend a given undo step, you can add more changes to the batch using {@link module:engine/model/model~Model#enqueueChange}:\n *\n *\t\tmodel.enqueueChange( batch, writer => {\n *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n *\t\t} );\n *\n * @see module:engine/model/model~Model#enqueueChange\n * @see module:engine/model/model~Model#change\n */\nexport default class Batch {\n\t/**\n\t * Creates a batch instance.\n\t *\n\t * @see module:engine/model/model~Model#enqueueChange\n\t * @see module:engine/model/model~Model#change\n\t * @param {'transparent'|'default'} [type='default'] The type of the batch.\n\t */\n\tconstructor( type = 'default' ) {\n\t\t/**\n\t\t * An array of operations that compose this batch.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Array.<module:engine/model/operation/operation~Operation>}\n\t\t */\n\t\tthis.operations = [];\n\n\t\t/**\n\t\t * The type of the batch.\n\t\t *\n\t\t * It can be one of the following values:\n\t\t * * `'default'` &ndash; All \"normal\" batches. This is the most commonly used type.\n\t\t * * `'transparent'` &ndash; A batch that should be ignored by other features, i.e. an initial batch or collaborative editing\n\t\t * changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {'transparent'|'default'}\n\t\t */\n\t\tthis.type = type;\n\t}\n\n\t/**\n\t * Returns the base version of this batch, which is equal to the base version of the first operation in the batch.\n\t * If there are no operations in the batch or neither operation has the base version set, it returns `null`.\n\t *\n\t * @readonly\n\t * @type {Number|null}\n\t */\n\tget baseVersion() {\n\t\tfor ( const op of this.operations ) {\n\t\t\tif ( op.baseVersion !== null ) {\n\t\t\t\treturn op.baseVersion;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Adds an operation to the batch instance.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation An operation to add.\n\t * @returns {module:engine/model/operation/operation~Operation} The added operation.\n\t */\n\taddOperation( operation ) {\n\t\toperation.batch = this;\n\t\tthis.operations.push( operation );\n\n\t\treturn operation;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/operation\n */\n\n/**\n * Abstract base operation class.\n *\n * @abstract\n */\nexport default class Operation {\n\t/**\n\t * Base operation constructor.\n\t *\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( baseVersion ) {\n\t\t/**\n\t\t * {@link module:engine/model/document~Document#version} on which operation can be applied. If you try to\n\t\t * {@link module:engine/model/model~Model#applyOperation apply} operation with different base version than the\n\t\t * {@link module:engine/model/document~Document#version document version} the\n\t\t * {@link module:utils/ckeditorerror~CKEditorError model-document-applyOperation-wrong-version} error is thrown.\n\t\t *\n\t\t * @member {Number}\n\t\t */\n\t\tthis.baseVersion = baseVersion;\n\n\t\t/**\n\t\t * Defines whether operation is executed on attached or detached {@link module:engine/model/item~Item items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isDocumentOperation\n\t\t */\n\t\tthis.isDocumentOperation = this.baseVersion !== null;\n\n\t\t/**\n\t\t * {@link module:engine/model/batch~Batch Batch} to which the operation is added or `null` if the operation is not\n\t\t * added to any batch yet.\n\t\t *\n\t\t * @member {module:engine/model/batch~Batch|null} #batch\n\t\t */\n\t\tthis.batch = null;\n\n\t\t/**\n\t\t * Operation type.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #type\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns an operation that has the same parameters as this operation.\n\t\t *\n\t\t * @method #clone\n\t\t * @returns {module:engine/model/operation/operation~Operation} Clone of this operation.\n\t\t */\n\n\t\t/**\n\t\t * Creates and returns a reverse operation. Reverse operation when executed right after\n\t\t * the original operation will bring back tree model state to the point before the original\n\t\t * operation execution. In other words, it reverses changes done by the original operation.\n\t\t *\n\t\t * Keep in mind that tree model state may change since executing the original operation,\n\t\t * so reverse operation will be \"outdated\". In that case you will need to transform it by\n\t\t * all operations that were executed after the original operation.\n\t\t *\n\t\t * @method #getReversed\n\t\t * @returns {module:engine/model/operation/operation~Operation} Reversed operation.\n\t\t */\n\n\t\t/**\n\t\t * Executes the operation - modifications described by the operation properties will be applied to the model tree.\n\t\t *\n\t\t * @protected\n\t\t * @method #_execute\n\t\t */\n\t}\n\n\t/**\n\t * Checks whether the operation's parameters are correct and the operation can be correctly executed. Throws\n\t * an error if operation is not valid.\n\t *\n\t * @protected\n\t * @method #_validate\n\t */\n\t_validate() {\n\t}\n\n\t/**\n\t * Custom toJSON method to solve child-parent circular dependencies.\n\t *\n\t * @method #toJSON\n\t * @returns {Object} Clone of this object with the operation property replaced with string.\n\t */\n\ttoJSON() {\n\t\t// This method creates only a shallow copy, all nested objects should be defined separately.\n\t\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1477.\n\t\tconst json = Object.assign( {}, this );\n\n\t\tjson.__className = this.constructor.className;\n\n\t\t// Remove reference to the parent `Batch` to avoid circular dependencies.\n\t\tdelete json.batch;\n\n\t\t// Only document operations are shared with other clients so it is not necessary to keep this information.\n\t\tdelete json.isDocumentOperation;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Name of the operation class used for serialization.\n\t *\n\t * @type {String}\n\t */\n\tstatic get className() {\n\t\treturn 'Operation';\n\t}\n\n\t/**\n\t * Creates Operation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} doc Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json ) {\n\t\treturn new this( json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.toString() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module module:engine/model/documentfragment\n */\n\nimport NodeList from './nodelist';\nimport Element from './element';\nimport Text from './text';\nimport TextProxy from './textproxy';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\n// @if CK_DEBUG_ENGINE // const { stringifyMap } = require( '../dev-utils/utils' );\n\n/**\n * DocumentFragment represents a part of model which does not have a common root but its top-level nodes\n * can be seen as siblings. In other words, it is a detached part of model tree, without a root.\n *\n * DocumentFragment has own {@link module:engine/model/markercollection~MarkerCollection}. Markers from this collection\n * will be set to the {@link module:engine/model/model~Model#markers model markers} by a\n * {@link module:engine/model/writer~Writer#insert} function.\n */\nexport default class DocumentFragment {\n\t/**\n\t * Creates an empty `DocumentFragment`.\n\t *\n\t * **Note:** Constructor of this class shouldn't be used directly in the code.\n\t * Use the {@link module:engine/model/writer~Writer#createDocumentFragment} method instead.\n\t *\n\t * @protected\n\t * @param {module:engine/model/node~Node|Iterable.<module:engine/model/node~Node>} [children]\n\t * Nodes to be contained inside the `DocumentFragment`.\n\t */\n\tconstructor( children ) {\n\t\t/**\n\t\t * DocumentFragment static markers map. This is a list of names and {@link module:engine/model/range~Range ranges}\n\t\t * which will be set as Markers to {@link module:engine/model/model~Model#markers model markers collection}\n\t\t * when DocumentFragment will be inserted to the document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Map<String,module:engine/model/range~Range>} module:engine/model/documentfragment~DocumentFragment#markers\n\t\t */\n\t\tthis.markers = new Map();\n\n\t\t/**\n\t\t * List of nodes contained inside the document fragment.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/documentfragment~DocumentFragment#_children\n\t\t */\n\t\tthis._children = new NodeList();\n\n\t\tif ( children ) {\n\t\t\tthis._insertChild( 0, children );\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all nodes contained inside this document fragment.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this.getChildren();\n\t}\n\n\t/**\n\t * Number of this document fragment's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget childCount() {\n\t\treturn this._children.length;\n\t}\n\n\t/**\n\t * Sum of {@link module:engine/model/node~Node#offsetSize offset sizes} of all of this document fragment's children.\n\t *\n\t * @readonly\n\t * @type {Number}\n\t */\n\tget maxOffset() {\n\t\treturn this._children.maxOffset;\n\t}\n\n\t/**\n\t * Is `true` if there are no nodes inside this document fragment, `false` otherwise.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this.childCount === 0;\n\t}\n\n\t/**\n\t * Artificial root of `DocumentFragment`. Returns itself. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tget root() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Artificial parent of `DocumentFragment`. Returns `null`. Added for compatibility reasons.\n\t *\n\t * @readonly\n\t * @type {null}\n\t */\n\tget parent() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given type.\n\t *\n\t *\t\tdocFrag.is( 'documentFragment' ); // -> true\n\t *\t\tdocFrag.is( 'model:documentFragment' ); // -> true\n\t *\n\t *\t\tdocFrag.is( 'view:documentFragment' ); // -> false\n\t *\t\tdocFrag.is( 'element' ); // -> false\n\t *\t\tdocFrag.is( 'node' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'documentFragment' || type === 'model:documentFragment';\n\t}\n\n\t/**\n\t * Gets the child at the given index. Returns `null` if incorrect index was passed.\n\t *\n\t * @param {Number} index Index of child.\n\t * @returns {module:engine/model/node~Node|null} Child node.\n\t */\n\tgetChild( index ) {\n\t\treturn this._children.getNode( index );\n\t}\n\n\t/**\n\t * Returns an iterator that iterates over all of this document fragment's children.\n\t *\n\t * @returns {Iterable.<module:engine/model/node~Node>}\n\t */\n\tgetChildren() {\n\t\treturn this._children[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Returns an index of the given child node. Returns `null` if given node is not a child of this document fragment.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's index.\n\t */\n\tgetChildIndex( node ) {\n\t\treturn this._children.getNodeIndex( node );\n\t}\n\n\t/**\n\t * Returns the starting offset of given child. Starting offset is equal to the sum of\n\t * {@link module:engine/model/node~Node#offsetSize offset sizes} of all node's siblings that are before it. Returns `null` if\n\t * given node is not a child of this document fragment.\n\t *\n\t * @param {module:engine/model/node~Node} node Child node to look for.\n\t * @returns {Number|null} Child node's starting offset.\n\t */\n\tgetChildStartOffset( node ) {\n\t\treturn this._children.getNodeStartOffset( node );\n\t}\n\n\t/**\n\t * Returns path to a `DocumentFragment`, which is an empty array. Added for compatibility reasons.\n\t *\n\t * @returns {Array}\n\t */\n\tgetPath() {\n\t\treturn [];\n\t}\n\n\t/**\n\t * Returns a descendant node by its path relative to this element.\n\t *\n\t *\t\t// <this>a<b>c</b></this>\n\t *\t\tthis.getNodeByPath( [ 0 ] ); // -> \"a\"\n\t *\t\tthis.getNodeByPath( [ 1 ] ); // -> <b>\n\t *\t\tthis.getNodeByPath( [ 1, 0 ] ); // -> \"c\"\n\t *\n\t * @param {Array.<Number>} relativePath Path of the node to find, relative to this element.\n\t * @returns {module:engine/model/node~Node|module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tgetNodeByPath( relativePath ) {\n\t\tlet node = this; // eslint-disable-line consistent-this\n\n\t\tfor ( const index of relativePath ) {\n\t\t\tnode = node.getChild( node.offsetToIndex( index ) );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Converts offset \"position\" to index \"position\".\n\t *\n\t * Returns index of a node that occupies given offset. If given offset is too low, returns `0`. If given offset is\n\t * too high, returns index after last child}.\n\t *\n\t *\t\tconst textNode = new Text( 'foo' );\n\t *\t\tconst pElement = new Element( 'p' );\n\t *\t\tconst docFrag = new DocumentFragment( [ textNode, pElement ] );\n\t *\t\tdocFrag.offsetToIndex( -1 ); // Returns 0, because offset is too low.\n\t *\t\tdocFrag.offsetToIndex( 0 ); // Returns 0, because offset 0 is taken by `textNode` which is at index 0.\n\t *\t\tdocFrag.offsetToIndex( 1 ); // Returns 0, because `textNode` has `offsetSize` equal to 3, so it occupies offset 1 too.\n\t *\t\tdocFrag.offsetToIndex( 2 ); // Returns 0.\n\t *\t\tdocFrag.offsetToIndex( 3 ); // Returns 1.\n\t *\t\tdocFrag.offsetToIndex( 4 ); // Returns 2. There are no nodes at offset 4, so last available index is returned.\n\t *\n\t * @param {Number} offset Offset to look for.\n\t * @returns {Number} Index of a node that occupies given offset.\n\t */\n\toffsetToIndex( offset ) {\n\t\treturn this._children.offsetToIndex( offset );\n\t}\n\n\t/**\n\t * Converts `DocumentFragment` instance to plain object and returns it.\n\t * Takes care of converting all of this document fragment's children.\n\t *\n\t * @returns {Object} `DocumentFragment` instance converted to plain object.\n\t */\n\ttoJSON() {\n\t\tconst json = [];\n\n\t\tfor ( const node of this._children ) {\n\t\t\tjson.push( node.toJSON() );\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Creates a `DocumentFragment` instance from given plain object (i.e. parsed JSON string).\n\t * Converts `DocumentFragment` children to proper nodes.\n\t *\n\t * @param {Object} json Plain object to be converted to `DocumentFragment`.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment} `DocumentFragment` instance created using given plain object.\n\t */\n\tstatic fromJSON( json ) {\n\t\tconst children = [];\n\n\t\tfor ( const child of json ) {\n\t\t\tif ( child.name ) {\n\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t} else {\n\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t}\n\t\t}\n\n\t\treturn new DocumentFragment( children );\n\t}\n\n\t/**\n\t * {@link #_insertChild Inserts} one or more nodes at the end of this document fragment.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_appendChild( items ) {\n\t\tthis._insertChild( this.childCount, items );\n\t}\n\n\t/**\n\t * Inserts one or more nodes at the given index and sets {@link module:engine/model/node~Node#parent parent} of these nodes\n\t * to this document fragment.\n\t *\n\t * @protected\n\t * @param {Number} index Index at which nodes should be inserted.\n\t * @param {module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>} items Items to be inserted.\n\t */\n\t_insertChild( index, items ) {\n\t\tconst nodes = normalize( items );\n\n\t\tfor ( const node of nodes ) {\n\t\t\t// If node that is being added to this element is already inside another element, first remove it from the old parent.\n\t\t\tif ( node.parent !== null ) {\n\t\t\t\tnode._remove();\n\t\t\t}\n\n\t\t\tnode.parent = this;\n\t\t}\n\n\t\tthis._children._insertNodes( index, nodes );\n\t}\n\n\t/**\n\t * Removes one or more nodes starting at the given index\n\t * and sets {@link module:engine/model/node~Node#parent parent} of these nodes to `null`.\n\t *\n\t * @protected\n\t * @param {Number} index Index of the first node to remove.\n\t * @param {Number} [howMany=1] Number of nodes to remove.\n\t * @returns {Array.<module:engine/model/node~Node>} Array containing removed nodes.\n\t */\n\t_removeChildren( index, howMany = 1 ) {\n\t\tconst nodes = this._children._removeNodes( index, howMany );\n\n\t\tfor ( const node of nodes ) {\n\t\t\tnode.parent = null;\n\t\t}\n\n\t\treturn nodes;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn 'documentFragment';\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelDocumentFragment: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // printTree() {\n\t// @if CK_DEBUG_ENGINE //\tlet string = 'ModelDocumentFragment: [';\n\n\t// @if CK_DEBUG_ENGINE //\tfor ( const child of this.getChildren() ) {\n\t// @if CK_DEBUG_ENGINE //\t\tstring += '\\n';\n\n\t// @if CK_DEBUG_ENGINE //\t\tif ( child.is( '$text' ) ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\tconst textAttrs = stringifyMap( child._attrs );\n\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += '\\t'.repeat( 1 );\n\n\t// @if CK_DEBUG_ENGINE //\t\t\tif ( textAttrs !== '' ) {\n\t// @if CK_DEBUG_ENGINE //\t\t\t\tstring += `<$text${ textAttrs }>` + child.data + '</$text>';\n\t// @if CK_DEBUG_ENGINE //\t\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\t\tstring += child.data;\n\t// @if CK_DEBUG_ENGINE //\t\t\t}\n\t// @if CK_DEBUG_ENGINE //\t\t} else {\n\t// @if CK_DEBUG_ENGINE //\t\t\tstring += child.printTree( 1 );\n\t// @if CK_DEBUG_ENGINE //\t\t}\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\tstring += '\\n]';\n\n\t// @if CK_DEBUG_ENGINE //\treturn string;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // logTree() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( this.printTree() );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\n// Converts strings to Text and non-iterables to arrays.\n//\n// @param {String|module:engine/model/item~Item|Iterable.<module:engine/model/item~Item>}\n// @returns {Iterable.<module:engine/model/node~Node>}\nfunction normalize( nodes ) {\n\t// Separate condition because string is iterable.\n\tif ( typeof nodes == 'string' ) {\n\t\treturn [ new Text( nodes ) ];\n\t}\n\n\tif ( !isIterable( nodes ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Array.from to enable .map() on non-arrays.\n\treturn Array.from( nodes )\n\t\t.map( node => {\n\t\t\tif ( typeof node == 'string' ) {\n\t\t\t\treturn new Text( node );\n\t\t\t}\n\n\t\t\tif ( node instanceof TextProxy ) {\n\t\t\t\treturn new Text( node.data, node.getAttributes() );\n\t\t\t}\n\n\t\t\treturn node;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/utils\n */\n\nimport Node from '../node';\nimport Text from '../text';\nimport TextProxy from '../textproxy';\nimport Range from '../range';\nimport DocumentFragment from '../documentfragment';\nimport NodeList from '../nodelist';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Contains functions used for composing model tree by {@link module:engine/model/operation/operation~Operation operations}.\n * Those functions are built on top of {@link module:engine/model/node~Node node}, and it's child classes', APIs.\n *\n * @protected\n * @namespace utils\n */\n\n/**\n * Inserts given nodes at given position.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.insert\n * @param {module:engine/model/position~Position} position Position at which nodes should be inserted.\n * @param {module:engine/model/node~NodeSet} nodes Nodes to insert.\n * @returns {module:engine/model/range~Range} Range spanning over inserted elements.\n */\nexport function _insert( position, nodes ) {\n\tnodes = _normalizeNodes( nodes );\n\n\t// We have to count offset before inserting nodes because they can get merged and we would get wrong offsets.\n\tconst offset = nodes.reduce( ( sum, node ) => sum + node.offsetSize, 0 );\n\tconst parent = position.parent;\n\n\t// Insertion might be in a text node, we should split it if that's the case.\n\t_splitNodeAtPosition( position );\n\tconst index = position.index;\n\n\t// Insert nodes at given index. After splitting we have a proper index and insertion is between nodes,\n\t// using basic `Element` API.\n\tparent._insertChild( index, nodes );\n\n\t// Merge text nodes, if possible. Merging is needed only at points where inserted nodes \"touch\" \"old\" nodes.\n\t_mergeNodesAtIndex( parent, index + nodes.length );\n\t_mergeNodesAtIndex( parent, index );\n\n\treturn new Range( position, position.getShiftedBy( offset ) );\n}\n\n/**\n * Removed nodes in given range. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._remove\n * @param {module:engine/model/range~Range} range Range containing nodes to remove.\n * @returns {Array.<module:engine/model/node~Node>}\n */\nexport function _remove( range ) {\n\tif ( !range.isFlat ) {\n\t\t/**\n\t\t * Trying to remove a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-remove-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-remove-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst parent = range.start.parent;\n\n\t// Range may be inside text nodes, we have to split them if that's the case.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Remove the text nodes using basic `Element` API.\n\tconst removed = parent._removeChildren( range.start.index, range.end.index - range.start.index );\n\n\t// Merge text nodes, if possible. After some nodes were removed, node before and after removed range will be\n\t// touching at the position equal to the removed range beginning. We check merging possibility there.\n\t_mergeNodesAtIndex( parent, range.start.index );\n\n\treturn removed;\n}\n\n/**\n * Moves nodes in given range to given target position. Only {@link module:engine/model/range~Range#isFlat flat} ranges are accepted.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.move\n * @param {module:engine/model/range~Range} sourceRange Range containing nodes to move.\n * @param {module:engine/model/position~Position} targetPosition Position to which nodes should be moved.\n * @returns {module:engine/model/range~Range} Range containing moved nodes.\n */\nexport function _move( sourceRange, targetPosition ) {\n\tif ( !sourceRange.isFlat ) {\n\t\t/**\n\t\t * Trying to move a range which starts and ends in different element.\n\t\t *\n\t\t * @error operation-utils-move-range-not-flat\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'operation-utils-move-range-not-flat',\n\t\t\tthis\n\t\t);\n\t}\n\n\tconst nodes = _remove( sourceRange );\n\n\t// We have to fix `targetPosition` because model changed after nodes from `sourceRange` got removed and\n\t// that change might have an impact on `targetPosition`.\n\ttargetPosition = targetPosition._getTransformedByDeletion( sourceRange.start, sourceRange.end.offset - sourceRange.start.offset );\n\n\treturn _insert( targetPosition, nodes );\n}\n\n/**\n * Sets given attribute on nodes in given range. The attributes are only set on top-level nodes of the range, not on its children.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils._setAttribute\n * @param {module:engine/model/range~Range} range Range containing nodes that should have the attribute set. Must be a flat range.\n * @param {String} key Key of attribute to set.\n * @param {*} value Attribute value.\n */\nexport function _setAttribute( range, key, value ) {\n\t// Range might start or end in text nodes, so we have to split them.\n\t_splitNodeAtPosition( range.start );\n\t_splitNodeAtPosition( range.end );\n\n\t// Iterate over all items in the range.\n\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t// Iterator will return `TextProxy` instances but we know that those text proxies will\n\t\t// always represent full text nodes (this is guaranteed thanks to splitting we did before).\n\t\t// So, we can operate on those text proxies' text nodes.\n\t\tconst node = item.is( '$textProxy' ) ? item.textNode : item;\n\n\t\tif ( value !== null ) {\n\t\t\tnode._setAttribute( key, value );\n\t\t} else {\n\t\t\tnode._removeAttribute( key );\n\t\t}\n\n\t\t// After attributes changing it may happen that some text nodes can be merged. Try to merge with previous node.\n\t\t_mergeNodesAtIndex( node.parent, node.index );\n\t}\n\n\t// Try to merge last changed node with it's previous sibling (not covered by the loop above).\n\t_mergeNodesAtIndex( range.end.parent, range.end.index );\n}\n\n/**\n * Normalizes given object or an array of objects to an array of {@link module:engine/model/node~Node nodes}. See\n * {@link module:engine/model/node~NodeSet NodeSet} for details on how normalization is performed.\n *\n * @protected\n * @function module:engine/model/operation/utils~utils.normalizeNodes\n * @param {module:engine/model/node~NodeSet} nodes Objects to normalize.\n * @returns {Array.<module:engine/model/node~Node>} Normalized nodes.\n */\nexport function _normalizeNodes( nodes ) {\n\tconst normalized = [];\n\n\tif ( !( nodes instanceof Array ) ) {\n\t\tnodes = [ nodes ];\n\t}\n\n\t// Convert instances of classes other than Node.\n\tfor ( let i = 0; i < nodes.length; i++ ) {\n\t\tif ( typeof nodes[ i ] == 'string' ) {\n\t\t\tnormalized.push( new Text( nodes[ i ] ) );\n\t\t} else if ( nodes[ i ] instanceof TextProxy ) {\n\t\t\tnormalized.push( new Text( nodes[ i ].data, nodes[ i ].getAttributes() ) );\n\t\t} else if ( nodes[ i ] instanceof DocumentFragment || nodes[ i ] instanceof NodeList ) {\n\t\t\tfor ( const child of nodes[ i ] ) {\n\t\t\t\tnormalized.push( child );\n\t\t\t}\n\t\t} else if ( nodes[ i ] instanceof Node ) {\n\t\t\tnormalized.push( nodes[ i ] );\n\t\t}\n\t\t// Skip unrecognized type.\n\t}\n\n\t// Merge text nodes.\n\tfor ( let i = 1; i < normalized.length; i++ ) {\n\t\tconst node = normalized[ i ];\n\t\tconst prev = normalized[ i - 1 ];\n\n\t\tif ( node instanceof Text && prev instanceof Text && _haveSameAttributes( node, prev ) ) {\n\t\t\t// Doing this instead changing `prev.data` because `data` is readonly.\n\t\t\tnormalized.splice( i - 1, 2, new Text( prev.data + node.data, prev.getAttributes() ) );\n\t\t\ti--;\n\t\t}\n\t}\n\n\treturn normalized;\n}\n\n// Checks if nodes before and after given index in given element are {@link module:engine/model/text~Text text nodes} and\n// merges them into one node if they have same attributes.\n//\n// Merging is done by removing two text nodes and inserting a new text node containing data from both merged text nodes.\n//\n// @private\n// @param {module:engine/model/element~Element} element Parent element of nodes to merge.\n// @param {Number} index Index between nodes to merge.\nfunction _mergeNodesAtIndex( element, index ) {\n\tconst nodeBefore = element.getChild( index - 1 );\n\tconst nodeAfter = element.getChild( index );\n\n\t// Check if both of those nodes are text objects with same attributes.\n\tif ( nodeBefore && nodeAfter && nodeBefore.is( '$text' ) && nodeAfter.is( '$text' ) && _haveSameAttributes( nodeBefore, nodeAfter ) ) {\n\t\t// Append text of text node after index to the before one.\n\t\tconst mergedNode = new Text( nodeBefore.data + nodeAfter.data, nodeBefore.getAttributes() );\n\n\t\t// Remove separate text nodes.\n\t\telement._removeChildren( index - 1, 2 );\n\n\t\t// Insert merged text node.\n\t\telement._insertChild( index - 1, mergedNode );\n\t}\n}\n\n// Checks if given position is in a text node, and if so, splits the text node in two text nodes, each of them\n// containing a part of original text node.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position at which node should be split.\nfunction _splitNodeAtPosition( position ) {\n\tconst textNode = position.textNode;\n\tconst element = position.parent;\n\n\tif ( textNode ) {\n\t\tconst offsetDiff = position.offset - textNode.startOffset;\n\t\tconst index = textNode.index;\n\n\t\telement._removeChildren( index, 1 );\n\n\t\tconst firstPart = new Text( textNode.data.substr( 0, offsetDiff ), textNode.getAttributes() );\n\t\tconst secondPart = new Text( textNode.data.substr( offsetDiff ), textNode.getAttributes() );\n\n\t\telement._insertChild( index, [ firstPart, secondPart ] );\n\t}\n}\n\n// Checks whether two given nodes have same attributes.\n//\n// @private\n// @param {module:engine/model/node~Node} nodeA Node to check.\n// @param {module:engine/model/node~Node} nodeB Node to check.\n// @returns {Boolean} `true` if nodes have same attributes, `false` otherwise.\nfunction _haveSameAttributes( nodeA, nodeB ) {\n\tconst iteratorA = nodeA.getAttributes();\n\tconst iteratorB = nodeB.getAttributes();\n\n\tfor ( const attr of iteratorA ) {\n\t\tif ( attr[ 1 ] !== nodeB.getAttribute( attr[ 0 ] ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\titeratorB.next();\n\t}\n\n\treturn iteratorB.next().done;\n}\n\n/**\n * Value that can be normalized to an array of {@link module:engine/model/node~Node nodes}.\n *\n * Non-arrays are normalized as follows:\n * * {@link module:engine/model/node~Node Node} is left as is,\n * * {@link module:engine/model/textproxy~TextProxy TextProxy} and `String` are normalized to {@link module:engine/model/text~Text Text},\n * * {@link module:engine/model/nodelist~NodeList NodeList} is normalized to an array containing all nodes that are in that node list,\n * * {@link module:engine/model/documentfragment~DocumentFragment DocumentFragment} is normalized to an array containing all of it's\n * * children.\n *\n * Arrays are processed item by item like non-array values and flattened to one array. Normalization always results in\n * a flat array of {@link module:engine/model/node~Node nodes}. Consecutive text nodes (or items normalized to text nodes) will be\n * merged if they have same attributes.\n *\n * @typedef {module:engine/model/node~Node|module:engine/model/textproxy~TextProxy|String|\n * module:engine/model/nodelist~NodeList|module:engine/model/documentfragment~DocumentFragment|Iterable}\n * module:engine/model/node~NodeSet\n */\n","import baseIsEqual from './_baseIsEqual.js';\n\n/**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, `Object` objects, regexes,\n * sets, strings, symbols, and typed arrays. `Object` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. `===`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\nfunction isEqual(value, other) {\n return baseIsEqual(value, other);\n}\n\nexport default isEqual;\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/operation/attributeoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport { _setAttribute } from './utils';\nimport { isEqual } from 'lodash-es';\n\n/**\n * Operation to change nodes' attribute.\n *\n * Using this class you can add, remove or change value of the attribute.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class AttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes.\n\t *\n\t * If only `newValue` is set, attribute will be added on a node. Note that all nodes in operation's range must not\n\t * have an attribute with the same key as the added attribute.\n\t *\n\t * If only `oldValue` is set, then attribute with given key will be removed. Note that all nodes in operation's range\n\t * must have an attribute with that key added.\n\t *\n\t * If both `newValue` and `oldValue` are set, then the operation will change the attribute value. Note that all nodes in\n\t * operation's ranges must already have an attribute with given key and `oldValue` as value\n\t *\n\t * @param {module:engine/model/range~Range} range Range on which the operation should be applied. Must be a flat range.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null`, if attribute was not set before.\n\t * @param {*} newValue New value of the attribute with given key or `null`, if operation should remove attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( range, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Range on which operation should be applied.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.range = range.clone();\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null`, if attribute was not set before.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue === undefined ? null : oldValue;\n\n\t\t/**\n\t\t * New value of the attribute with given key or `null`, if operation should remove attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue === undefined ? null : newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeAttribute';\n\t\t} else {\n\t\t\treturn 'changeAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new AttributeOperation( this.range, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new AttributeOperation( this.range, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.range = this.range.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( !this.range.isFlat ) {\n\t\t\t/**\n\t\t\t * The range to change is not flat.\n\t\t\t *\n\t\t\t * @error attribute-operation-range-not-flat\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'attribute-operation-range-not-flat', this );\n\t\t}\n\n\t\tfor ( const item of this.range.getItems( { shallow: true } ) ) {\n\t\t\tif ( this.oldValue !== null && !isEqual( item.getAttribute( this.key ), this.oldValue ) ) {\n\t\t\t\t/**\n\t\t\t\t * Changed node has different attribute value than operation's old attribute value.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-wrong-old-value\n\t\t\t\t * @param {module:engine/model/item~Item} item\n\t\t\t\t * @param {String} key\n\t\t\t\t * @param {*} value\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-wrong-old-value',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ item, key: this.key, value: this.oldValue }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( this.oldValue === null && this.newValue !== null && item.hasAttribute( this.key ) ) {\n\t\t\t\t/**\n\t\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t\t *\n\t\t\t\t * @error attribute-operation-attribute-exists\n\t\t\t\t * @param {module:engine/model/node~Node} node\n\t\t\t\t * @param {String} key\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'attribute-operation-attribute-exists',\n\t\t\t\t\tthis,\n\t\t\t\t\t{ node: item, key: this.key }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// If value to set is same as old value, don't do anything.\n\t\tif ( !isEqual( this.oldValue, this.newValue ) ) {\n\t\t\t// Execution.\n\t\t\t_setAttribute( this.range, this.key, this.newValue );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'AttributeOperation';\n\t}\n\n\t/**\n\t * Creates `AttributeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new AttributeOperation( Range.fromJSON( json.range, document ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `AttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/detachoperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\nimport { _remove } from './utils';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to permanently remove node from detached root.\n * Note this operation is only a local operation and won't be send to the other clients.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class DetachOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t */\n\tconstructor( sourcePosition, howMany ) {\n\t\tsuper( null );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to detach.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} #sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} #howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'detach';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.sourcePosition.root.document ) {\n\t\t\t/**\n\t\t\t * Cannot detach document node.\n\t\t\t *\n\t\t\t * @error detach-operation-on-document-node\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'detach-operation-on-document-node', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_remove( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'DetachOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // const range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\t// @if CK_DEBUG_ENGINE //\tconst nodes = Array.from( range.getItems() );\n\t// @if CK_DEBUG_ENGINE //\tconst nodeString = nodes.length > 1 ? `[ ${ nodes.length } ]` : nodes[ 0 ];\n\n\t// @if CK_DEBUG_ENGINE //\treturn `DetachOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ range }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/moveoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport Range from '../range';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\nimport { _move } from './utils';\n\n// @if CK_DEBUG_ENGINE // const ModelRange = require( '../range' ).default;\n\n/**\n * Operation to move a range of {@link module:engine/model/item~Item model items}\n * to given {@link module:engine/model/position~Position target position}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MoveOperation extends Operation {\n\t/**\n\t * Creates a move operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition\n\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t * @param {Number} howMany Offset size of moved range. Moved range will start from `sourcePosition` and end at\n\t * `sourcePosition` with offset shifted by `howMany`.\n\t * @param {module:engine/model/position~Position} targetPosition Position at which moved nodes will be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before the first {@link module:engine/model/item~Item model item} to move.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// `'toNext'` because `sourcePosition` is a bit like a start of the moved range.\n\t\tthis.sourcePosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Offset size of moved range.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/moveoperation~MoveOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which moved nodes will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/moveoperation~MoveOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\tthis.targetPosition.stickiness = 'toNone';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.targetPosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'remove';\n\t\t} else if ( this.sourcePosition.root.rootName == '$graveyard' ) {\n\t\t\treturn 'reinsert';\n\t\t}\n\n\t\treturn 'move';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * Returns the start position of the moved range after it got moved. This may be different than\n\t * {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition} in some cases, i.e. when a range is moved\n\t * inside the same parent but {@link module:engine/model/operation/moveoperation~MoveOperation#targetPosition targetPosition}\n\t * is after {@link module:engine/model/operation/moveoperation~MoveOperation#sourcePosition sourcePosition}.\n\t *\n\t *\t\t vv vv\n\t *\t\tabcdefg ===> adefbcg\n\t *\t\t ^ ^\n\t *\t\t targetPos\tmovedRangeStart\n\t *\t\t offset 6\toffset 4\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetMovedRangeStart() {\n\t\treturn this.targetPosition._getTransformedByDeletion( this.sourcePosition, this.howMany );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst newTargetPosition = this.sourcePosition._getTransformedByInsertion( this.targetPosition, this.howMany );\n\n\t\treturn new this.constructor( this.getMovedRangeStart(), this.howMany, newTargetPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\t\tconst sourceOffset = this.sourcePosition.offset;\n\t\tconst targetOffset = this.targetPosition.offset;\n\n\t\t// Validate whether move operation has correct parameters.\n\t\t// Validation is pretty complex but move operation is one of the core ways to manipulate the document state.\n\t\t// We expect that many errors might be connected with one of scenarios described below.\n\t\tif ( sourceOffset + this.howMany > sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * The nodes which should be moved do not exist.\n\t\t\t *\n\t\t\t * @error move-operation-nodes-do-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-nodes-do-not-exist', this\n\t\t\t);\n\t\t} else if ( sourceElement === targetElement && sourceOffset < targetOffset && targetOffset < sourceOffset + this.howMany ) {\n\t\t\t/**\n\t\t\t * Trying to move a range of nodes into the middle of that range.\n\t\t\t *\n\t\t\t * @error move-operation-range-into-itself\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'move-operation-range-into-itself', this\n\t\t\t);\n\t\t} else if ( this.sourcePosition.root == this.targetPosition.root ) {\n\t\t\tif ( compareArrays( this.sourcePosition.getParentPath(), this.targetPosition.getParentPath() ) == 'prefix' ) {\n\t\t\t\tconst i = this.sourcePosition.path.length - 1;\n\n\t\t\t\tif ( this.targetPosition.path[ i ] >= sourceOffset && this.targetPosition.path[ i ] < sourceOffset + this.howMany ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Trying to move a range of nodes into one of nodes from that range.\n\t\t\t\t\t *\n\t\t\t\t\t * @error move-operation-node-into-itself\n\t\t\t\t\t */\n\t\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t\t'move-operation-node-into-itself', this\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t_move( Range._createFromPositionAndShift( this.sourcePosition, this.howMany ), this.targetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = this.sourcePosition.toJSON();\n\t\tjson.targetPosition = this.targetPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MoveOperation';\n\t}\n\n\t/**\n\t * Creates `MoveOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst range = ModelRange._createFromPositionAndShift( this.sourcePosition, this.howMany );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `MoveOperation( ${ this.baseVersion } ): ${ range } -> ${ this.targetPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/insertoperation\n */\n\nimport Operation from './operation';\nimport Position from '../position';\nimport NodeList from '../nodelist';\nimport MoveOperation from './moveoperation';\nimport { _insert, _normalizeNodes } from './utils';\nimport Text from '../text';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to insert one or more nodes at given position in the model.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class InsertOperation extends Operation {\n\t/**\n\t * Creates an insert operation.\n\t *\n\t * @param {module:engine/model/position~Position} position Position of insertion.\n\t * @param {module:engine/model/node~NodeSet} nodes The list of nodes to be inserted.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, nodes, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position of insertion.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/insertoperation~InsertOperation#position\n\t\t */\n\t\tthis.position = position.clone();\n\t\tthis.position.stickiness = 'toNone';\n\n\t\t/**\n\t\t * List of nodes to insert.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/nodelist~NodeList} module:engine/model/operation/insertoperation~InsertOperation#nodeList\n\t\t */\n\t\tthis.nodes = new NodeList( _normalizeNodes( nodes ) );\n\n\t\t/**\n\t\t * Flag deciding how the operation should be transformed. If set to `true`, nodes might get additional attributes\n\t\t * during operational transformation. This happens when the operation insertion position is inside of a range\n\t\t * where attributes have changed.\n\t\t *\n\t\t * @member {Boolean} module:engine/model/operation/insertoperation~InsertOperation#shouldReceiveAttributes\n\t\t */\n\t\tthis.shouldReceiveAttributes = false;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'insert';\n\t}\n\n\t/**\n\t * Total offset size of inserted nodes.\n\t *\n\t * @returns {Number}\n\t */\n\tget howMany() {\n\t\treturn this.nodes.maxOffset;\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\tconst nodes = new NodeList( [ ...this.nodes ].map( node => node._clone( true ) ) );\n\t\tconst insert = new InsertOperation( this.position, nodes, this.baseVersion );\n\n\t\tinsert.shouldReceiveAttributes = this.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/moveoperation~MoveOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.position.root.document.graveyard;\n\t\tconst gyPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MoveOperation( this.position, this.nodes.maxOffset, gyPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst targetElement = this.position.parent;\n\n\t\tif ( !targetElement || targetElement.maxOffset < this.position.offset ) {\n\t\t\t/**\n\t\t\t * Insertion position is invalid.\n\t\t\t *\n\t\t\t * @error insert-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'insert-operation-position-invalid',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\t// What happens here is that we want original nodes be passed to writer because we want original nodes\n\t\t// to be inserted to the model. But in InsertOperation, we want to keep those nodes as they were added\n\t\t// to the operation, not modified. For example, text nodes can get merged or cropped while Elements can\n\t\t// get children. It is important that InsertOperation has the copy of original nodes in intact state.\n\t\tconst originalNodes = this.nodes;\n\t\tthis.nodes = new NodeList( [ ...originalNodes ].map( node => node._clone( true ) ) );\n\n\t\t_insert( this.position, originalNodes );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\t\tjson.nodes = this.nodes.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'InsertOperation';\n\t}\n\n\t/**\n\t * Creates `InsertOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/insertoperation~InsertOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst children = [];\n\n\t\tfor ( const child of json.nodes ) {\n\t\t\tif ( child.name ) {\n\t\t\t\t// If child has name property, it is an Element.\n\t\t\t\tchildren.push( Element.fromJSON( child ) );\n\t\t\t} else {\n\t\t\t\t// Otherwise, it is a Text node.\n\t\t\t\tchildren.push( Text.fromJSON( child ) );\n\t\t\t}\n\t\t}\n\n\t\tconst insert = new InsertOperation( Position.fromJSON( json.position, document ), children, json.baseVersion );\n\t\tinsert.shouldReceiveAttributes = json.shouldReceiveAttributes;\n\n\t\treturn insert;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \tconst nodeString = this.nodes.length > 1 ? `[ ${ this.nodes.length } ]` : this.nodes.getNode( 0 );\n\n\t// @if CK_DEBUG_ENGINE //\treturn `InsertOperation( ${ this.baseVersion } ): ${ nodeString } -> ${ this.position }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/markeroperation\n */\n\nimport Operation from './operation';\nimport Range from '../range';\n\n/**\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MarkerOperation extends Operation {\n\t/**\n\t * @param {String} name Marker name.\n\t * @param {module:engine/model/range~Range} oldRange Marker range before the change.\n\t * @param {module:engine/model/range~Range} newRange Marker range after the change.\n\t * @param {module:engine/model/markercollection~MarkerCollection} markers Marker collection on which change should be executed.\n\t * @param {Boolean} affectsData Specifies whether the marker operation affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( name, oldRange, newRange, markers, affectsData, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Marker name.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Marker range before the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.oldRange = oldRange ? oldRange.clone() : null;\n\n\t\t/**\n\t\t * Marker range after the change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/range~Range}\n\t\t */\n\t\tthis.newRange = newRange ? newRange.clone() : null;\n\n\t\t/**\n\t\t * Specifies whether the marker operation affects the data produced by the data pipeline\n\t\t * (is persisted in the editor's data).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.affectsData = affectsData;\n\n\t\t/**\n\t\t * Marker collection on which change should be executed.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis._markers = markers;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'marker';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new MarkerOperation( this.name, this.oldRange, this.newRange, this._markers, this.affectsData, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tgetReversed() {\n\t\treturn new MarkerOperation( this.name, this.newRange, this.oldRange, this._markers, this.affectsData, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst type = this.newRange ? '_set' : '_remove';\n\n\t\tthis._markers[ type ]( this.name, this.newRange, true, this.affectsData );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tif ( this.oldRange ) {\n\t\t\tjson.oldRange = this.oldRange.toJSON();\n\t\t}\n\n\t\tif ( this.newRange ) {\n\t\t\tjson.newRange = this.newRange.toJSON();\n\t\t}\n\n\t\tdelete json._markers;\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MarkerOperation';\n\t}\n\n\t/**\n\t * Creates `MarkerOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/markeroperation~MarkerOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new MarkerOperation(\n\t\t\tjson.name,\n\t\t\tjson.oldRange ? Range.fromJSON( json.oldRange, document ) : null,\n\t\t\tjson.newRange ? Range.fromJSON( json.newRange, document ) : null,\n\t\t\tdocument.model.markers,\n\t\t\tjson.affectsData,\n\t\t\tjson.baseVersion\n\t\t);\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MarkerOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.name }\": ${ this.oldRange } -> ${ this.newRange }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/renameoperation\n */\n\nimport Operation from './operation';\nimport Element from '../element';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Position from '../position';\n\n/**\n * Operation to change element's name.\n *\n * Using this class you can change element's name.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RenameOperation extends Operation {\n\t/**\n\t * Creates an operation that changes element's name.\n\t *\n\t * @param {module:engine/model/position~Position} position Position before an element to change.\n\t * @param {String} oldName Current name of the element.\n\t * @param {String} newName New name for the element.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( position, oldName, newName, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position before an element to change.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/renameoperation~RenameOperation#position\n\t\t */\n\t\tthis.position = position;\n\t\t// This position sticks to the next node because it is a position before the node that we want to change.\n\t\tthis.position.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Current name of the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#oldName\n\t\t */\n\t\tthis.oldName = oldName;\n\n\t\t/**\n\t\t * New name for the element.\n\t\t *\n\t\t * @member {String} module:engine/model/operation/renameoperation~RenameOperation#newName\n\t\t */\n\t\tthis.newName = newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'rename';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RenameOperation( this.position.clone(), this.oldName, this.newName, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/renameoperation~RenameOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RenameOperation( this.position.clone(), this.newName, this.oldName, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\tif ( !( element instanceof Element ) ) {\n\t\t\t/**\n\t\t\t * Given position is invalid or node after it is not instance of Element.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-position\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-position',\n\t\t\t\tthis\n\t\t\t);\n\t\t} else if ( element.name !== this.oldName ) {\n\t\t\t/**\n\t\t\t * Element to change has different name than operation's old name.\n\t\t\t *\n\t\t\t * @error rename-operation-wrong-name\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rename-operation-wrong-name',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst element = this.position.nodeAfter;\n\n\t\telement.name = this.newName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.position = this.position.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RenameOperation';\n\t}\n\n\t/**\n\t * Creates `RenameOperation` object from deserialized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/attributeoperation~AttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn new RenameOperation( Position.fromJSON( json.position, document ), json.oldName, json.newName, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RenameOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.position }: \"${ this.oldName }\" -> \"${ this.newName }\"`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/rootattributeoperation\n */\n\nimport Operation from './operation';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to change root element's attribute. Using this class you can add, remove or change value of the attribute.\n *\n * This operation is needed, because root elements can't be changed through\n * @link module:engine/model/operation/attributeoperation~AttributeOperation}.\n * It is because {@link module:engine/model/operation/attributeoperation~AttributeOperation}\n * requires a range to change and root element can't\n * be a part of range because every {@link module:engine/model/position~Position} has to be inside a root.\n * {@link module:engine/model/position~Position} can't be created before a root element.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class RootAttributeOperation extends Operation {\n\t/**\n\t * Creates an operation that changes, removes or adds attributes on root element.\n\t *\n\t * @see module:engine/model/operation/attributeoperation~AttributeOperation\n\t * @param {module:engine/model/rootelement~RootElement} root Root element to change.\n\t * @param {String} key Key of an attribute to change or remove.\n\t * @param {*} oldValue Old value of the attribute with given key or `null` if adding a new attribute.\n\t * @param {*} newValue New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( root, key, oldValue, newValue, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Root element to change.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/rootelement~RootElement}\n\t\t */\n\t\tthis.root = root;\n\n\t\t/**\n\t\t * Key of an attribute to change or remove.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.key = key;\n\n\t\t/**\n\t\t * Old value of the attribute with given key or `null` if adding a new attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.oldValue = oldValue;\n\n\t\t/**\n\t\t * New value to set for the attribute. If `null`, then the operation just removes the attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @member {*}\n\t\t */\n\t\tthis.newValue = newValue;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\tif ( this.oldValue === null ) {\n\t\t\treturn 'addRootAttribute';\n\t\t} else if ( this.newValue === null ) {\n\t\t\treturn 'removeRootAttribute';\n\t\t} else {\n\t\t\treturn 'changeRootAttribute';\n\t\t}\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.oldValue, this.newValue, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tgetReversed() {\n\t\treturn new RootAttributeOperation( this.root, this.key, this.newValue, this.oldValue, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tif ( this.root != this.root.root || this.root.is( 'documentFragment' ) ) {\n\t\t\t/**\n\t\t\t * The element to change is not a root element.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-not-a-root\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-not-a-root',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue !== null && this.root.getAttribute( this.key ) !== this.oldValue ) {\n\t\t\t/**\n\t\t\t * The attribute which should be removed does not exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-wrong-old-value\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t * @param {*} value\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-wrong-old-value',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\n\t\tif ( this.oldValue === null && this.newValue !== null && this.root.hasAttribute( this.key ) ) {\n\t\t\t/**\n\t\t\t * The attribute with given key already exists for the given node.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-attribute-exists\n\t\t\t * @param {module:engine/model/rootelement~RootElement} root\n\t\t\t * @param {String} key\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'rootattribute-operation-attribute-exists',\n\t\t\t\tthis,\n\t\t\t\t{ root: this.root, key: this.key }\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tif ( this.newValue !== null ) {\n\t\t\tthis.root._setAttribute( this.key, this.newValue );\n\t\t} else {\n\t\t\tthis.root._removeAttribute( this.key );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.root = this.root.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'RootAttributeOperation';\n\t}\n\n\t/**\n\t * Creates RootAttributeOperation object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/rootattributeoperation~RootAttributeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tif ( !document.getRoot( json.root ) ) {\n\t\t\t/**\n\t\t\t * Cannot create RootAttributeOperation for document. Root with specified name does not exist.\n\t\t\t *\n\t\t\t * @error rootattribute-operation-fromjson-no-root\n\t\t\t * @param {String} rootName\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'rootattribute-operation-fromjson-no-root', this, { rootName: json.root } );\n\t\t}\n\n\t\treturn new RootAttributeOperation( document.getRoot( json.root ), json.key, json.oldValue, json.newValue, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `RootAttributeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`\"${ this.key }\": ${ JSON.stringify( this.oldValue ) }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` -> ${ JSON.stringify( this.newValue ) }, ${ this.root.rootName }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/mergeoperation\n */\n\nimport Operation from './operation';\nimport SplitOperation from './splitoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to merge two {@link module:engine/model/element~Element elements}.\n *\n * The merged element is the parent of {@link ~MergeOperation#sourcePosition} and it is merged into the parent of\n * {@link ~MergeOperation#targetPosition}. All nodes from the merged element are moved to {@link ~MergeOperation#targetPosition}.\n *\n * The merged element is moved to the graveyard at {@link ~MergeOperation#graveyardPosition}.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class MergeOperation extends Operation {\n\t/**\n\t * Creates a merge operation.\n\t *\n\t * @param {module:engine/model/position~Position} sourcePosition Position inside the merged element. All nodes from that\n\t * element after that position will be moved to {@link ~#targetPosition}.\n\t * @param {Number} howMany Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t * @param {module:engine/model/position~Position} targetPosition Position which the nodes from the merged elements will be moved to.\n\t * @param {module:engine/model/position~Position} graveyardPosition Position in graveyard to which the merged element will be moved.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( sourcePosition, howMany, targetPosition, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position inside the merged element. All nodes from that element after that position will be moved to {@link ~#targetPosition}.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#sourcePosition\n\t\t */\n\t\tthis.sourcePosition = sourcePosition.clone();\n\t\t// This is, and should always remain, the first position in its parent.\n\t\tthis.sourcePosition.stickiness = 'toPrevious';\n\n\t\t/**\n\t\t * Summary offset size of nodes which will be moved from the merged element to the new parent.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/mergeoperation~MergeOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position which the nodes from the merged elements will be moved to.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#targetPosition\n\t\t */\n\t\tthis.targetPosition = targetPosition.clone();\n\t\t// Except of a rare scenario in `MergeOperation` x `MergeOperation` transformation,\n\t\t// this is, and should always remain, the last position in its parent.\n\t\tthis.targetPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Position in graveyard to which the merged element will be moved.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/mergeoperation~MergeOperation#graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition.clone();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'merge';\n\t}\n\n\t/**\n\t * Position before the merged element (which will be deleted).\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget deletionPosition() {\n\t\treturn new Position( this.sourcePosition.root, this.sourcePosition.path.slice( 0, -1 ) );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the merged element that will be moved to {@link ~MergeOperation#sourcePosition}.\n\t * The range starts at {@link ~MergeOperation#sourcePosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.sourcePosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.sourcePosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.sourcePosition, this.howMany, this.targetPosition, this.graveyardPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tgetReversed() {\n\t\t// Positions in this method are transformed by this merge operation because the split operation bases on\n\t\t// the context after this merge operation happened (because split operation reverses it).\n\t\t// So we need to acknowledge that the merge operation happened and those positions changed a little.\n\t\tconst targetPosition = this.targetPosition._getTransformedByMergeOperation( this );\n\n\t\tconst path = this.sourcePosition.path.slice( 0, -1 );\n\t\tconst insertionPosition = new Position( this.sourcePosition.root, path )._getTransformedByMergeOperation( this );\n\n\t\treturn new SplitOperation( targetPosition, this.howMany, insertionPosition, this.graveyardPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst sourceElement = this.sourcePosition.parent;\n\t\tconst targetElement = this.targetPosition.parent;\n\n\t\t// Validate whether merge operation has correct parameters.\n\t\tif ( !sourceElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge source position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-source-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-source-position-invalid', this );\n\t\t} else if ( !targetElement.parent ) {\n\t\t\t/**\n\t\t\t * Merge target position is invalid. The element to be merged must have a parent node.\n\t\t\t *\n\t\t\t * @error merge-operation-target-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-target-position-invalid', this );\n\t\t} else if ( this.howMany != sourceElement.maxOffset ) {\n\t\t\t/**\n\t\t\t * Merge operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error merge-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'merge-operation-how-many-invalid', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst mergedElement = this.sourcePosition.parent;\n\t\tconst sourceRange = Range._createIn( mergedElement );\n\n\t\t_move( sourceRange, this.targetPosition );\n\t\t_move( Range._createOn( mergedElement ), this.graveyardPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.sourcePosition = json.sourcePosition.toJSON();\n\t\tjson.targetPosition = json.targetPosition.toJSON();\n\t\tjson.graveyardPosition = json.graveyardPosition.toJSON();\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'MergeOperation';\n\t}\n\n\t/**\n\t * Creates `MergeOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst sourcePosition = Position.fromJSON( json.sourcePosition, document );\n\t\tconst targetPosition = Position.fromJSON( json.targetPosition, document );\n\t\tconst graveyardPosition = Position.fromJSON( json.graveyardPosition, document );\n\n\t\treturn new this( sourcePosition, json.howMany, targetPosition, graveyardPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `MergeOperation( ${ this.baseVersion } ): ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.sourcePosition } -> ${ this.targetPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t` ( ${ this.howMany } ), ${ this.graveyardPosition }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/splitoperation\n */\n\nimport Operation from './operation';\nimport MergeOperation from './mergeoperation';\nimport Position from '../position';\nimport Range from '../range';\nimport { _insert, _move } from './utils';\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Operation to split {@link module:engine/model/element~Element an element} at given\n * {@link module:engine/model/operation/splitoperation~SplitOperation#splitPosition split position} into two elements,\n * both containing a part of the element's original content.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class SplitOperation extends Operation {\n\t/**\n\t * Creates a split operation.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition Position at which an element should be split.\n\t * @param {Number} howMany Total offset size of elements that are in the split element after `position`.\n\t * @param {module:engine/model/position~Position} insertionPosition Position at which the clone of split element\n\t * (or element from graveyard) will be inserted.\n\t * @param {module:engine/model/position~Position|null} graveyardPosition Position in the graveyard root before the element which\n\t * should be used as a parent of the nodes after `position`. If it is not set, a copy of the the `position` parent will be used.\n\t * @param {Number|null} baseVersion Document {@link module:engine/model/document~Document#version} on which operation\n\t * can be applied or `null` if the operation operates on detached (non-document) tree.\n\t */\n\tconstructor( splitPosition, howMany, insertionPosition, graveyardPosition, baseVersion ) {\n\t\tsuper( baseVersion );\n\n\t\t/**\n\t\t * Position at which an element should be split.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#splitPosition\n\t\t */\n\t\tthis.splitPosition = splitPosition.clone();\n\t\t// Keep position sticking to the next node. This way any new content added at the place where the element is split\n\t\t// will be left in the original element.\n\t\tthis.splitPosition.stickiness = 'toNext';\n\n\t\t/**\n\t\t * Total offset size of elements that are in the split element after `position`.\n\t\t *\n\t\t * @member {Number} module:engine/model/operation/splitoperation~SplitOperation#howMany\n\t\t */\n\t\tthis.howMany = howMany;\n\n\t\t/**\n\t\t * Position at which the clone of split element (or element from graveyard) will be inserted.\n\t\t *\n\t\t * @member {module:engine/model/position~Position} module:engine/model/operation/splitoperation~SplitOperation#insertionPosition\n\t\t */\n\t\tthis.insertionPosition = insertionPosition;\n\n\t\t/**\n\t\t * Position in the graveyard root before the element which should be used as a parent of the nodes after `position`.\n\t\t * If it is not set, a copy of the the `position` parent will be used.\n\t\t *\n\t\t * The default behavior is to clone the split element. Element from graveyard is used during undo.\n\t\t *\n\t\t * @member {module:engine/model/position~Position|null} #graveyardPosition\n\t\t */\n\t\tthis.graveyardPosition = graveyardPosition ? graveyardPosition.clone() : null;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tthis.graveyardPosition.stickiness = 'toNext';\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget type() {\n\t\treturn 'split';\n\t}\n\n\t/**\n\t * Position inside the new clone of a split element.\n\t *\n\t * This is a position where nodes that are after the split position will be moved to.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/position~Position}\n\t */\n\tget moveTargetPosition() {\n\t\tconst path = this.insertionPosition.path.slice();\n\t\tpath.push( 0 );\n\n\t\treturn new Position( this.insertionPosition.root, path );\n\t}\n\n\t/**\n\t * Artificial range that contains all the nodes from the split element that will be moved to the new element.\n\t * The range starts at {@link ~#splitPosition} and ends in the same parent, at `POSITIVE_INFINITY` offset.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/range~Range}\n\t */\n\tget movedRange() {\n\t\tconst end = this.splitPosition.getShiftedBy( Number.POSITIVE_INFINITY );\n\n\t\treturn new Range( this.splitPosition, end );\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new this.constructor( this.splitPosition, this.howMany, this.insertionPosition, this.graveyardPosition, this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/mergeoperation~MergeOperation}\n\t */\n\tgetReversed() {\n\t\tconst graveyard = this.splitPosition.root.document.graveyard;\n\t\tconst graveyardPosition = new Position( graveyard, [ 0 ] );\n\n\t\treturn new MergeOperation( this.moveTargetPosition, this.howMany, this.splitPosition, graveyardPosition, this.baseVersion + 1 );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_validate() {\n\t\tconst element = this.splitPosition.parent;\n\t\tconst offset = this.splitPosition.offset;\n\n\t\t// Validate whether split operation has correct parameters.\n\t\tif ( !element || element.maxOffset < offset ) {\n\t\t\t/**\n\t\t\t * Split position is invalid.\n\t\t\t *\n\t\t\t * @error split-operation-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-position-invalid', this );\n\t\t} else if ( !element.parent ) {\n\t\t\t/**\n\t\t\t * Cannot split root element.\n\t\t\t *\n\t\t\t * @error split-operation-split-in-root\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-split-in-root', this );\n\t\t} else if ( this.howMany != element.maxOffset - this.splitPosition.offset ) {\n\t\t\t/**\n\t\t\t * Split operation specifies wrong number of nodes to move.\n\t\t\t *\n\t\t\t * @error split-operation-how-many-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-how-many-invalid', this );\n\t\t} else if ( this.graveyardPosition && !this.graveyardPosition.nodeAfter ) {\n\t\t\t/**\n\t\t\t * Graveyard position invalid.\n\t\t\t *\n\t\t\t * @error split-operation-graveyard-position-invalid\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'split-operation-graveyard-position-invalid', this );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_execute() {\n\t\tconst splitElement = this.splitPosition.parent;\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\t_move( Range._createFromPositionAndShift( this.graveyardPosition, 1 ), this.insertionPosition );\n\t\t} else {\n\t\t\tconst newElement = splitElement._clone();\n\n\t\t\t_insert( this.insertionPosition, newElement );\n\t\t}\n\n\t\tconst sourceRange = new Range(\n\t\t\tPosition._createAt( splitElement, this.splitPosition.offset ),\n\t\t\tPosition._createAt( splitElement, splitElement.maxOffset )\n\t\t);\n\n\t\t_move( sourceRange, this.moveTargetPosition );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\ttoJSON() {\n\t\tconst json = super.toJSON();\n\n\t\tjson.splitPosition = this.splitPosition.toJSON();\n\t\tjson.insertionPosition = this.insertionPosition.toJSON();\n\n\t\tif ( this.graveyardPosition ) {\n\t\t\tjson.graveyardPosition = this.graveyardPosition.toJSON();\n\t\t}\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'SplitOperation';\n\t}\n\n\t/**\n\t * Helper function that returns a default insertion position basing on given `splitPosition`. The default insertion\n\t * position is after the split element.\n\t *\n\t * @param {module:engine/model/position~Position} splitPosition\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tstatic getInsertionPosition( splitPosition ) {\n\t\tconst path = splitPosition.path.slice( 0, -1 );\n\t\tpath[ path.length - 1 ]++;\n\n\t\treturn new Position( splitPosition.root, path, 'toPrevious' );\n\t}\n\n\t/**\n\t * Creates `SplitOperation` object from deserilized object, i.e. from parsed JSON string.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/splitoperation~SplitOperation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\tconst splitPosition = Position.fromJSON( json.splitPosition, document );\n\t\tconst insertionPosition = Position.fromJSON( json.insertionPosition, document );\n\t\tconst graveyardPosition = json.graveyardPosition ? Position.fromJSON( json.graveyardPosition, document ) : null;\n\n\t\treturn new this( splitPosition, json.howMany, insertionPosition, graveyardPosition, json.baseVersion );\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `SplitOperation( ${ this.baseVersion } ): ${ this.splitPosition } ` +\n\t// @if CK_DEBUG_ENGINE //\t\t`( ${ this.howMany } ) -> ${ this.insertionPosition }` +\n\t// @if CK_DEBUG_ENGINE //\t\t`${ this.graveyardPosition ? ' with ' + this.graveyardPosition : '' }`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/rootelement\n */\n\nimport Element from './element';\n\n/**\n * Type of {@link module:engine/model/element~Element} that is a root of a model tree.\n * @extends module:engine/model/element~Element\n */\nexport default class RootElement extends Element {\n\t/**\n\t * Creates root element.\n\t *\n\t * @param {module:engine/model/document~Document} document Document that is an owner of this root.\n\t * @param {String} name Node name.\n\t * @param {String} [rootName='main'] Unique root name used to identify this root\n\t * element by {@link module:engine/model/document~Document}.\n\t */\n\tconstructor( document, name, rootName = 'main' ) {\n\t\tsuper( name );\n\n\t\t/**\n\t\t * Document that is an owner of this root.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/document~Document}\n\t\t */\n\t\tthis._document = document;\n\n\t\t/**\n\t\t * Unique root name used to identify this root element by {@link module:engine/model/document~Document}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.rootName = rootName;\n\t}\n\n\t/**\n\t * {@link module:engine/model/document~Document Document} that owns this root element.\n\t *\n\t * @readonly\n\t * @type {module:engine/model/document~Document|null}\n\t */\n\tget document() {\n\t\treturn this._document;\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\trootElement.is( 'rootElement' ); // -> true\n\t *\t\trootElement.is( 'element' ); // -> true\n\t *\t\trootElement.is( 'node' ); // -> true\n\t *\t\trootElement.is( 'model:rootElement' ); // -> true\n\t *\t\trootElement.is( 'model:element' ); // -> true\n\t *\t\trootElement.is( 'model:node' ); // -> true\n\t *\n\t *\t\trootElement.is( 'view:element' ); // -> false\n\t *\t\trootElement.is( 'documentFragment' ); // -> false\n\t *\n\t * Assuming that the object being checked is an element, you can also check its\n\t * {@link module:engine/model/element~Element#name name}:\n\t *\n\t *\t\trootElement.is( 'rootElement', '$root' ); // -> same as above\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type Type to check.\n\t * @param {String} [name] Element name.\n\t * @returns {Boolean}\n\t */\n\tis( type, name ) {\n\t\tif ( !name ) {\n\t\t\treturn type === 'rootElement' || type === 'model:rootElement' ||\n\t\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\t\ttype === 'element' || type === 'model:element' ||\n\t\t\t\ttype === 'node' || type === 'model:node';\n\t\t}\n\n\t\treturn name === this.name && (\n\t\t\ttype === 'rootElement' || type === 'model:rootElement' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype === 'element' || type === 'model:element'\n\t\t);\n\t}\n\n\t/**\n\t * Converts `RootElement` instance to `String` containing it's name.\n\t *\n\t * @returns {String} `RootElement` instance converted to `String`.\n\t */\n\ttoJSON() {\n\t\treturn this.rootName;\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn this.rootName;\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // log() {\n\t// @if CK_DEBUG_ENGINE // \tconsole.log( 'ModelRootElement: ' + this );\n\t// @if CK_DEBUG_ENGINE // }\n}\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/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.<Number>} 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.<String>} 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><$text bold=\"true\">biz</$text>\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: <p>Foo[</p><p>Bar]</p>\n\t\t\t\t// After merge: <p>Foo[Bar]</p>\n\t\t\t\t// After undoing split: <p>Foo</p><p>[Bar]</p> <-- 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: <p>[Foo</p><p>]Bar</p>\n\t\t\t\t// After merge: <p>[Foo]Bar</p>\n\t\t\t\t// After undoing split: <p>[Foo]</p><p>Bar</p> <-- 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: <p>[Foo</p>]<p>Bar</p>\n\t\t\t\t// After merge: <p>[Foo]Bar</p>\n\t\t\t\t// After undoing split: <p>[Foo]</p><p>Bar</p> <-- 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: <p>Foo</p>[<p>Bar]</p>\n\t\t\t\t// After merge: <p>Foo[Bar]</p>\n\t\t\t\t// After undoing split: <p>Foo</p><p>[Bar]</p> <-- incorrect, needs remembering for undo.\n\t\t\t\t//\n\t\t\t\tconst affectedBeforeRightElement = markerRange.start.nodeAfter == elementAfter;\n\n\t\t\t\tisAffected = affectedInLeftElement || affectedInRightElement || affectedAfterLeftElement || affectedBeforeRightElement;\n\t\t\t}\n\n\t\t\tif ( isAffected ) {\n\t\t\t\tthis.updateMarker( marker.name, { range: markerRange } );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Sets given attribute to each node in given range. When attribute value is null then attribute will be removed.\n//\n// Because attribute operation needs to have the same attribute value on the whole range, this function splits\n// the range into smaller parts.\n//\n// Given `range` must be flat.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/range~Range} range Model range on which the attribute will be set.\nfunction setAttributeOnRange( writer, key, value, range ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\t// Position of the last split, the beginning of the new range.\n\tlet lastSplitPosition = range.start;\n\n\t// Currently position in the scanning range. Because we need value after the position, it is not a current\n\t// position of the iterator but the previous one (we need to iterate one more time to get the value after).\n\tlet position;\n\n\t// Value before the currently position.\n\tlet valueBefore;\n\n\t// Value after the currently position.\n\tlet valueAfter;\n\n\tfor ( const val of range.getWalker( { shallow: true } ) ) {\n\t\tvalueAfter = val.item.getAttribute( key );\n\n\t\t// At the first run of the iterator the position in undefined. We also do not have a valueBefore, but\n\t\t// because valueAfter may be null, valueBefore may be equal valueAfter ( undefined == null ).\n\t\tif ( position && valueBefore != valueAfter ) {\n\t\t\t// if valueBefore == value there is nothing to change, so we add operation only if these values are different.\n\t\t\tif ( valueBefore != value ) {\n\t\t\t\taddOperation();\n\t\t\t}\n\n\t\t\tlastSplitPosition = position;\n\t\t}\n\n\t\tposition = val.nextPosition;\n\t\tvalueBefore = valueAfter;\n\t}\n\n\t// Because position in the loop is not the iterator position (see let position comment), the last position in\n\t// the while loop will be last but one position in the range. We need to check the last position manually.\n\tif ( position instanceof Position && position != lastSplitPosition && valueBefore != value ) {\n\t\taddOperation();\n\t}\n\n\tfunction addOperation() {\n\t\tconst range = new Range( lastSplitPosition, position );\n\t\tconst version = range.root.document ? doc.version : null;\n\t\tconst operation = new AttributeOperation( range, key, valueBefore, value, version );\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Sets given attribute to the given node. When attribute value is null then attribute will be removed.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} key Attribute key.\n// @param {*} value Attribute new value.\n// @param {module:engine/model/item~Item} item Model item on which the attribute will be set.\nfunction setAttributeOnItem( writer, key, value, item ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\tconst previousValue = item.getAttribute( key );\n\tlet range, operation;\n\n\tif ( previousValue != value ) {\n\t\tconst isRootChanged = item.root === item;\n\n\t\tif ( isRootChanged ) {\n\t\t\t// If we change attributes of root element, we have to use `RootAttributeOperation`.\n\t\t\tconst version = item.document ? doc.version : null;\n\n\t\t\toperation = new RootAttributeOperation( item, key, previousValue, value, version );\n\t\t} else {\n\t\t\trange = new Range( Position._createBefore( item ), writer.createPositionAfter( item ) );\n\n\t\t\tconst version = range.root.document ? doc.version : null;\n\n\t\t\toperation = new AttributeOperation( range, key, previousValue, value, version );\n\t\t}\n\n\t\twriter.batch.addOperation( operation );\n\t\tmodel.applyOperation( operation );\n\t}\n}\n\n// Creates and applies marker operation to {@link module:engine/model/operation/operation~Operation operation}.\n//\n// @private\n// @param {module:engine/model/writer~Writer} writer\n// @param {String} name Marker name.\n// @param {module:engine/model/range~Range} oldRange Marker range before the change.\n// @param {module:engine/model/range~Range} newRange Marker range after the change.\n// @param {Boolean} affectsData\nfunction applyMarkerOperation( writer, name, oldRange, newRange, affectsData ) {\n\tconst model = writer.model;\n\tconst doc = model.document;\n\n\tconst operation = new MarkerOperation( name, oldRange, newRange, model.markers, affectsData, doc.version );\n\n\twriter.batch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Creates `MoveOperation` or `DetachOperation` that removes `howMany` nodes starting from `position`.\n// The operation will be applied on given model instance and added to given operation instance.\n//\n// @private\n// @param {module:engine/model/position~Position} position Position from which nodes are removed.\n// @param {Number} howMany Number of nodes to remove.\n// @param {Batch} batch Batch to which the operation will be added.\n// @param {module:engine/model/model~Model} model Model instance on which operation will be applied.\nfunction applyRemoveOperation( position, howMany, batch, model ) {\n\tlet operation;\n\n\tif ( position.root.document ) {\n\t\tconst doc = model.document;\n\t\tconst graveyardPosition = new Position( doc.graveyard, [ 0 ] );\n\n\t\toperation = new MoveOperation( position, howMany, graveyardPosition, doc.version );\n\t} else {\n\t\toperation = new DetachOperation( position, howMany );\n\t}\n\n\tbatch.addOperation( operation );\n\tmodel.applyOperation( operation );\n}\n\n// Returns `true` if both root elements are the same element or both are documents root elements.\n//\n// Elements in the same tree can be moved (for instance you can move element form one documents root to another, or\n// within the same document fragment), but when element supposed to be moved from document fragment to the document, or\n// to another document it should be removed and inserted to avoid problems with OT. This is because features like undo or\n// collaboration may track changes on the document but ignore changes on detached fragments and should not get\n// unexpected `move` operation.\nfunction isSameTree( rootA, rootB ) {\n\t// If it is the same root this is the same tree.\n\tif ( rootA === rootB ) {\n\t\treturn true;\n\t}\n\n\t// If both roots are documents root it is operation within the document what we still treat as the same tree.\n\tif ( rootA instanceof RootElement && rootB instanceof RootElement ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/differ\n */\n\nimport Position from './position';\nimport Range from './range';\n\n/**\n * Calculates the difference between two model states.\n *\n * Receives operations that are to be applied on the model document. Marks parts of the model document tree which\n * are changed and saves the state of these elements before the change. Then, it compares saved elements with the\n * changed elements, after all changes are applied on the model document. Calculates the diff between saved\n * elements and new ones and returns a change set.\n */\nexport default class Differ {\n\t/**\n\t * Creates a `Differ` instance.\n\t *\n\t * @param {module:engine/model/markercollection~MarkerCollection} markerCollection Model's marker collection.\n\t */\n\tconstructor( markerCollection ) {\n\t\t/**\n\t\t * Reference to the model's marker collection.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis._markerCollection = markerCollection;\n\n\t\t/**\n\t\t * A map that stores changes that happened in a given element.\n\t\t *\n\t\t * The keys of the map are references to the model elements.\n\t\t * The values of the map are arrays with changes that were done on this element.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._changesInElement = new Map();\n\n\t\t/**\n\t\t * A map that stores \"element's children snapshots\". A snapshot is representing children of a given element before\n\t\t * the first change was applied on that element. Snapshot items are objects with two properties: `name`,\n\t\t * containing the element name (or `'$text'` for a text node) and `attributes` which is a map of the node's attributes.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._elementSnapshots = new Map();\n\n\t\t/**\n\t\t * A map that stores all changed markers.\n\t\t *\n\t\t * The keys of the map are marker names.\n\t\t * The values of the map are objects with the `oldRange` and `newRange` properties. They store the marker range\n\t\t * state before and after the change.\n\t\t *\n\t\t * @private\n\t\t * @type {Map}\n\t\t */\n\t\tthis._changedMarkers = new Map();\n\n\t\t/**\n\t\t * Stores the number of changes that were processed. Used to order the changes chronologically. It is important\n\t\t * when changes are sorted.\n\t\t *\n\t\t * @private\n\t\t * @type {Number}\n\t\t */\n\t\tthis._changeCount = 0;\n\n\t\t/**\n\t\t * For efficiency purposes, `Differ` stores the change set returned by the differ after {@link #getChanges} call.\n\t\t * Cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will\n\t\t * return the cached value instead of calculating it again.\n\t\t *\n\t\t * This property stores those changes that did not take place in graveyard root.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Object>|null}\n\t\t */\n\t\tthis._cachedChanges = null;\n\n\t\t/**\n\t\t * For efficiency purposes, `Differ` stores the change set returned by the differ after the {@link #getChanges} call.\n\t\t * The cache is reset each time a new operation is buffered. If the cache has not been reset, {@link #getChanges} will\n\t\t * return the cached value instead of calculating it again.\n\t\t *\n\t\t * This property stores all changes evaluated by `Differ`, including those that took place in the graveyard.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Object>|null}\n\t\t */\n\t\tthis._cachedChangesWithGraveyard = null;\n\t}\n\n\t/**\n\t * Informs whether there are any changes buffered in `Differ`.\n\t *\n\t * @readonly\n\t * @type {Boolean}\n\t */\n\tget isEmpty() {\n\t\treturn this._changesInElement.size == 0 && this._changedMarkers.size == 0;\n\t}\n\n\t/**\n\t * Marks given `item` in differ to be \"refreshed\". It means that the item will be marked as removed and inserted in the differ changes\n\t * set, so it will be effectively re-converted when differ changes will be handled by a dispatcher.\n\t *\n\t * @param {module:engine/model/item~Item} item Item to refresh.\n\t */\n\trefreshItem( item ) {\n\t\tif ( this._isInInsertedElement( item.parent ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._markRemove( item.parent, item.startOffset, item.offsetSize );\n\t\tthis._markInsert( item.parent, item.startOffset, item.offsetSize );\n\n\t\tconst range = Range._createOn( item );\n\n\t\tfor ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {\n\t\t\tconst markerRange = marker.getRange();\n\n\t\t\tthis.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );\n\t\t}\n\n\t\t// Clear cache after each buffered operation as it is no longer valid.\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Buffers the given operation. An operation has to be buffered before it is executed.\n\t *\n\t * Operation type is checked and it is checked which nodes it will affect. These nodes are then stored in `Differ`\n\t * in the state before the operation is executed.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation An operation to buffer.\n\t */\n\tbufferOperation( operation ) {\n\t\t// Below we take an operation, check its type, then use its parameters in marking (private) methods.\n\t\t// The general rule is to not mark elements inside inserted element. All inserted elements are re-rendered.\n\t\t// Marking changes in them would cause a \"double\" changing then.\n\t\t//\n\t\tswitch ( operation.type ) {\n\t\t\tcase 'insert': {\n\t\t\t\tif ( this._isInInsertedElement( operation.position.parent ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._markInsert( operation.position.parent, operation.position.offset, operation.nodes.maxOffset );\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'addAttribute':\n\t\t\tcase 'removeAttribute':\n\t\t\tcase 'changeAttribute': {\n\t\t\t\tfor ( const item of operation.range.getItems( { shallow: true } ) ) {\n\t\t\t\t\tif ( this._isInInsertedElement( item.parent ) ) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._markAttribute( item );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'remove':\n\t\t\tcase 'move':\n\t\t\tcase 'reinsert': {\n\t\t\t\t// When range is moved to the same position then not mark it as a change.\n\t\t\t\t// See: https://github.com/ckeditor/ckeditor5-engine/issues/1664.\n\t\t\t\tif (\n\t\t\t\t\toperation.sourcePosition.isEqual( operation.targetPosition ) ||\n\t\t\t\t\toperation.sourcePosition.getShiftedBy( operation.howMany ).isEqual( operation.targetPosition )\n\t\t\t\t) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst sourceParentInserted = this._isInInsertedElement( operation.sourcePosition.parent );\n\t\t\t\tconst targetParentInserted = this._isInInsertedElement( operation.targetPosition.parent );\n\n\t\t\t\tif ( !sourceParentInserted ) {\n\t\t\t\t\tthis._markRemove( operation.sourcePosition.parent, operation.sourcePosition.offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\tif ( !targetParentInserted ) {\n\t\t\t\t\tthis._markInsert( operation.targetPosition.parent, operation.getMovedRangeStart().offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'rename': {\n\t\t\t\tif ( this._isInInsertedElement( operation.position.parent ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._markRemove( operation.position.parent, operation.position.offset, 1 );\n\t\t\t\tthis._markInsert( operation.position.parent, operation.position.offset, 1 );\n\n\t\t\t\tconst range = Range._createFromPositionAndShift( operation.position, 1 );\n\n\t\t\t\tfor ( const marker of this._markerCollection.getMarkersIntersectingRange( range ) ) {\n\t\t\t\t\tconst markerRange = marker.getRange();\n\n\t\t\t\t\tthis.bufferMarkerChange( marker.name, markerRange, markerRange, marker.affectsData );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'split': {\n\t\t\t\tconst splitElement = operation.splitPosition.parent;\n\n\t\t\t\t// Mark that children of the split element were removed.\n\t\t\t\tif ( !this._isInInsertedElement( splitElement ) ) {\n\t\t\t\t\tthis._markRemove( splitElement, operation.splitPosition.offset, operation.howMany );\n\t\t\t\t}\n\n\t\t\t\t// Mark that the new element (split copy) was inserted.\n\t\t\t\tif ( !this._isInInsertedElement( operation.insertionPosition.parent ) ) {\n\t\t\t\t\tthis._markInsert( operation.insertionPosition.parent, operation.insertionPosition.offset, 1 );\n\t\t\t\t}\n\n\t\t\t\t// If the split took the element from the graveyard, mark that the element from the graveyard was removed.\n\t\t\t\tif ( operation.graveyardPosition ) {\n\t\t\t\t\tthis._markRemove( operation.graveyardPosition.parent, operation.graveyardPosition.offset, 1 );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'merge': {\n\t\t\t\t// Mark that the merged element was removed.\n\t\t\t\tconst mergedElement = operation.sourcePosition.parent;\n\n\t\t\t\tif ( !this._isInInsertedElement( mergedElement.parent ) ) {\n\t\t\t\t\tthis._markRemove( mergedElement.parent, mergedElement.startOffset, 1 );\n\t\t\t\t}\n\n\t\t\t\t// Mark that the merged element was inserted into graveyard.\n\t\t\t\tconst graveyardParent = operation.graveyardPosition.parent;\n\n\t\t\t\tthis._markInsert( graveyardParent, operation.graveyardPosition.offset, 1 );\n\n\t\t\t\t// Mark that children of merged element were inserted at new parent.\n\t\t\t\tconst mergedIntoElement = operation.targetPosition.parent;\n\n\t\t\t\tif ( !this._isInInsertedElement( mergedIntoElement ) ) {\n\t\t\t\t\tthis._markInsert( mergedIntoElement, operation.targetPosition.offset, mergedElement.maxOffset );\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Clear cache after each buffered operation as it is no longer valid.\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Buffers a marker change.\n\t *\n\t * @param {String} markerName The name of the marker that changed.\n\t * @param {module:engine/model/range~Range|null} oldRange Marker range before the change or `null` if the marker has just\n\t * been created.\n\t * @param {module:engine/model/range~Range|null} newRange Marker range after the change or `null` if the marker was removed.\n\t * @param {Boolean} affectsData Flag indicating whether marker affects the editor data.\n\t */\n\tbufferMarkerChange( markerName, oldRange, newRange, affectsData ) {\n\t\tconst buffered = this._changedMarkers.get( markerName );\n\n\t\tif ( !buffered ) {\n\t\t\tthis._changedMarkers.set( markerName, {\n\t\t\t\toldRange,\n\t\t\t\tnewRange,\n\t\t\t\taffectsData\n\t\t\t} );\n\t\t} else {\n\t\t\tbuffered.newRange = newRange;\n\t\t\tbuffered.affectsData = affectsData;\n\n\t\t\tif ( buffered.oldRange == null && buffered.newRange == null ) {\n\t\t\t\t// The marker is going to be removed (`newRange == null`) but it did not exist before the first buffered change\n\t\t\t\t// (`buffered.oldRange == null`). In this case, do not keep the marker in buffer at all.\n\t\t\t\tthis._changedMarkers.delete( markerName );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns all markers that should be removed as a result of buffered changes.\n\t *\n\t * @returns {Array.<Object>} Markers to remove. Each array item is an object containing the `name` and `range` properties.\n\t */\n\tgetMarkersToRemove() {\n\t\tconst result = [];\n\n\t\tfor ( const [ name, change ] of this._changedMarkers ) {\n\t\t\tif ( change.oldRange != null ) {\n\t\t\t\tresult.push( { name, range: change.oldRange } );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns all markers which should be added as a result of buffered changes.\n\t *\n\t * @returns {Array.<Object>} Markers to add. Each array item is an object containing the `name` and `range` properties.\n\t */\n\tgetMarkersToAdd() {\n\t\tconst result = [];\n\n\t\tfor ( const [ name, change ] of this._changedMarkers ) {\n\t\t\tif ( change.newRange != null ) {\n\t\t\t\tresult.push( { name, range: change.newRange } );\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns all markers which changed.\n\t *\n\t * @returns {Array.<Object>}\n\t */\n\tgetChangedMarkers() {\n\t\treturn Array.from( this._changedMarkers ).map( item => (\n\t\t\t{\n\t\t\t\tname: item[ 0 ],\n\t\t\t\tdata: {\n\t\t\t\t\toldRange: item[ 1 ].oldRange,\n\t\t\t\t\tnewRange: item[ 1 ].newRange\n\t\t\t\t}\n\t\t\t}\n\t\t) );\n\t}\n\n\t/**\n\t * Checks whether some of the buffered changes affect the editor data.\n\t *\n\t * Types of changes which affect the editor data:\n\t *\n\t * * model structure changes,\n\t * * attribute changes,\n\t * * changes of markers which were defined as `affectingData`.\n\t *\n\t * @returns {Boolean}\n\t */\n\thasDataChanges() {\n\t\tfor ( const [ , change ] of this._changedMarkers ) {\n\t\t\tif ( change.affectsData ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// If markers do not affect the data, check whether there are some changes in elements.\n\t\treturn this._changesInElement.size > 0;\n\t}\n\n\t/**\n\t * Calculates the diff between the old model tree state (the state before the first buffered operations since the last {@link #reset}\n\t * call) and the new model tree state (actual one). It should be called after all buffered operations are executed.\n\t *\n\t * The diff set is returned as an array of {@link module:engine/model/differ~DiffItem diff items}, each describing a change done\n\t * on the model. The items are sorted by the position on which the change happened. If a position\n\t * {@link module:engine/model/position~Position#isBefore is before} another one, it will be on an earlier index in the diff set.\n\t *\n\t * **Note**: Elements inside inserted element will not have a separate diff item, only the top most element change will be reported.\n\t *\n\t * Because calculating the diff is a costly operation, the result is cached. If no new operation was buffered since the\n\t * previous {@link #getChanges} call, the next call will return the cached value.\n\t *\n\t * @param {Object} options Additional options.\n\t * @param {Boolean} [options.includeChangesInGraveyard=false] If set to `true`, also changes that happened\n\t * in the graveyard root will be returned. By default, changes in the graveyard root are not returned.\n\t * @returns {Array.<module:engine/model/differ~DiffItem>} Diff between the old and the new model tree state.\n\t */\n\tgetChanges( options = { includeChangesInGraveyard: false } ) {\n\t\t// If there are cached changes, just return them instead of calculating changes again.\n\t\tif ( this._cachedChanges ) {\n\t\t\tif ( options.includeChangesInGraveyard ) {\n\t\t\t\treturn this._cachedChangesWithGraveyard.slice();\n\t\t\t} else {\n\t\t\t\treturn this._cachedChanges.slice();\n\t\t\t}\n\t\t}\n\n\t\t// Will contain returned results.\n\t\tlet diffSet = [];\n\n\t\t// Check all changed elements.\n\t\tfor ( const element of this._changesInElement.keys() ) {\n\t\t\t// Get changes for this element and sort them.\n\t\t\tconst changes = this._changesInElement.get( element ).sort( ( a, b ) => {\n\t\t\t\tif ( a.offset === b.offset ) {\n\t\t\t\t\tif ( a.type != b.type ) {\n\t\t\t\t\t\t// If there are multiple changes at the same position, \"remove\" change should be first.\n\t\t\t\t\t\t// If the order is different, for example, we would first add some nodes and then removed them\n\t\t\t\t\t\t// (instead of the nodes that we should remove).\n\t\t\t\t\t\treturn a.type == 'remove' ? -1 : 1;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn a.offset < b.offset ? -1 : 1;\n\t\t\t} );\n\n\t\t\t// Get children of this element before any change was applied on it.\n\t\t\tconst snapshotChildren = this._elementSnapshots.get( element );\n\t\t\t// Get snapshot of current element's children.\n\t\t\tconst elementChildren = _getChildrenSnapshot( element.getChildren() );\n\n\t\t\t// Generate actions basing on changes done on element.\n\t\t\tconst actions = _generateActionsFromChanges( snapshotChildren.length, changes );\n\n\t\t\tlet i = 0; // Iterator in `elementChildren` array -- iterates through current children of element.\n\t\t\tlet j = 0; // Iterator in `snapshotChildren` array -- iterates through old children of element.\n\n\t\t\t// Process every action.\n\t\t\tfor ( const action of actions ) {\n\t\t\t\tif ( action === 'i' ) {\n\t\t\t\t\t// Generate diff item for this element and insert it into the diff set.\n\t\t\t\t\tdiffSet.push( this._getInsertDiff( element, i, elementChildren[ i ].name ) );\n\n\t\t\t\t\ti++;\n\t\t\t\t} else if ( action === 'r' ) {\n\t\t\t\t\t// Generate diff item for this element and insert it into the diff set.\n\t\t\t\t\tdiffSet.push( this._getRemoveDiff( element, i, snapshotChildren[ j ].name ) );\n\n\t\t\t\t\tj++;\n\t\t\t\t} else if ( action === 'a' ) {\n\t\t\t\t\t// Take attributes from saved and current children.\n\t\t\t\t\tconst elementAttributes = elementChildren[ i ].attributes;\n\t\t\t\t\tconst snapshotAttributes = snapshotChildren[ j ].attributes;\n\t\t\t\t\tlet range;\n\n\t\t\t\t\tif ( elementChildren[ i ].name == '$text' ) {\n\t\t\t\t\t\trange = new Range( Position._createAt( element, i ), Position._createAt( element, i + 1 ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst index = element.offsetToIndex( i );\n\t\t\t\t\t\trange = new Range( Position._createAt( element, i ), Position._createAt( element.getChild( index ), 0 ) );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Generate diff items for this change (there might be multiple attributes changed and\n\t\t\t\t\t// there is a single diff for each of them) and insert them into the diff set.\n\t\t\t\t\tdiffSet.push( ...this._getAttributesDiff( range, snapshotAttributes, elementAttributes ) );\n\n\t\t\t\t\ti++;\n\t\t\t\t\tj++;\n\t\t\t\t} else {\n\t\t\t\t\t// `action` is 'equal'. Child not changed.\n\t\t\t\t\ti++;\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Then, sort the changes by the position (change at position before other changes is first).\n\t\tdiffSet.sort( ( a, b ) => {\n\t\t\t// If the change is in different root, we don't care much, but we'd like to have all changes in given\n\t\t\t// root \"together\" in the array. So let's just sort them by the root name. It does not matter which root\n\t\t\t// will be processed first.\n\t\t\tif ( a.position.root != b.position.root ) {\n\t\t\t\treturn a.position.root.rootName < b.position.root.rootName ? -1 : 1;\n\t\t\t}\n\n\t\t\t// If change happens at the same position...\n\t\t\tif ( a.position.isEqual( b.position ) ) {\n\t\t\t\t// Keep chronological order of operations.\n\t\t\t\treturn a.changeCount - b.changeCount;\n\t\t\t}\n\n\t\t\t// If positions differ, position \"on the left\" should be earlier in the result.\n\t\t\treturn a.position.isBefore( b.position ) ? -1 : 1;\n\t\t} );\n\n\t\t// Glue together multiple changes (mostly on text nodes).\n\t\tfor ( let i = 1, prevIndex = 0; i < diffSet.length; i++ ) {\n\t\t\tconst prevDiff = diffSet[ prevIndex ];\n\t\t\tconst thisDiff = diffSet[ i ];\n\n\t\t\t// Glue remove changes if they happen on text on same position.\n\t\t\tconst isConsecutiveTextRemove =\n\t\t\t\tprevDiff.type == 'remove' && thisDiff.type == 'remove' &&\n\t\t\t\tprevDiff.name == '$text' && thisDiff.name == '$text' &&\n\t\t\t\tprevDiff.position.isEqual( thisDiff.position );\n\n\t\t\t// Glue insert changes if they happen on text on consecutive fragments.\n\t\t\tconst isConsecutiveTextAdd =\n\t\t\t\tprevDiff.type == 'insert' && thisDiff.type == 'insert' &&\n\t\t\t\tprevDiff.name == '$text' && thisDiff.name == '$text' &&\n\t\t\t\tprevDiff.position.parent == thisDiff.position.parent &&\n\t\t\t\tprevDiff.position.offset + prevDiff.length == thisDiff.position.offset;\n\n\t\t\t// Glue attribute changes if they happen on consecutive fragments and have same key, old value and new value.\n\t\t\tconst isConsecutiveAttributeChange =\n\t\t\t\tprevDiff.type == 'attribute' && thisDiff.type == 'attribute' &&\n\t\t\t\tprevDiff.position.parent == thisDiff.position.parent &&\n\t\t\t\tprevDiff.range.isFlat && thisDiff.range.isFlat &&\n\t\t\t\tprevDiff.position.offset + prevDiff.length == thisDiff.position.offset &&\n\t\t\t\tprevDiff.attributeKey == thisDiff.attributeKey &&\n\t\t\t\tprevDiff.attributeOldValue == thisDiff.attributeOldValue &&\n\t\t\t\tprevDiff.attributeNewValue == thisDiff.attributeNewValue;\n\n\t\t\tif ( isConsecutiveTextRemove || isConsecutiveTextAdd || isConsecutiveAttributeChange ) {\n\t\t\t\tprevDiff.length++;\n\n\t\t\t\tif ( isConsecutiveAttributeChange ) {\n\t\t\t\t\tprevDiff.range.end = prevDiff.range.end.getShiftedBy( 1 );\n\t\t\t\t}\n\n\t\t\t\tdiffSet[ i ] = null;\n\t\t\t} else {\n\t\t\t\tprevIndex = i;\n\t\t\t}\n\t\t}\n\n\t\tdiffSet = diffSet.filter( v => v );\n\n\t\t// Remove `changeCount` property from diff items. It is used only for sorting and is internal thing.\n\t\tfor ( const item of diffSet ) {\n\t\t\tdelete item.changeCount;\n\n\t\t\tif ( item.type == 'attribute' ) {\n\t\t\t\tdelete item.position;\n\t\t\t\tdelete item.length;\n\t\t\t}\n\t\t}\n\n\t\tthis._changeCount = 0;\n\n\t\t// Cache changes.\n\t\tthis._cachedChangesWithGraveyard = diffSet.slice();\n\t\tthis._cachedChanges = diffSet.filter( _changesInGraveyardFilter );\n\n\t\tif ( options.includeChangesInGraveyard ) {\n\t\t\treturn this._cachedChangesWithGraveyard;\n\t\t} else {\n\t\t\treturn this._cachedChanges;\n\t\t}\n\t}\n\n\t/**\n\t * Resets `Differ`. Removes all buffered changes.\n\t */\n\treset() {\n\t\tthis._changesInElement.clear();\n\t\tthis._elementSnapshots.clear();\n\t\tthis._changedMarkers.clear();\n\t\tthis._cachedChanges = null;\n\t}\n\n\t/**\n\t * Saves and handles an insert change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_markInsert( parent, offset, howMany ) {\n\t\tconst changeItem = { type: 'insert', offset, howMany, count: this._changeCount++ };\n\n\t\tthis._markChange( parent, changeItem );\n\t}\n\n\t/**\n\t * Saves and handles a remove change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_markRemove( parent, offset, howMany ) {\n\t\tconst changeItem = { type: 'remove', offset, howMany, count: this._changeCount++ };\n\n\t\tthis._markChange( parent, changeItem );\n\n\t\tthis._removeAllNestedChanges( parent, offset, howMany );\n\t}\n\n\t/**\n\t * Saves and handles an attribute change.\n\t *\n\t * @private\n\t * @param {module:engine/model/item~Item} item\n\t */\n\t_markAttribute( item ) {\n\t\tconst changeItem = { type: 'attribute', offset: item.startOffset, howMany: item.offsetSize, count: this._changeCount++ };\n\n\t\tthis._markChange( item.parent, changeItem );\n\t}\n\n\t/**\n\t * Saves and handles a model change.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Object} changeItem\n\t */\n\t_markChange( parent, changeItem ) {\n\t\t// First, make a snapshot of this parent's children (it will be made only if it was not made before).\n\t\tthis._makeSnapshot( parent );\n\n\t\t// Then, get all changes that already were done on the element (empty array if this is the first change).\n\t\tconst changes = this._getChangesForElement( parent );\n\n\t\t// Then, look through all the changes, and transform them or the new change.\n\t\tthis._handleChange( changeItem, changes );\n\n\t\t// Add the new change.\n\t\tchanges.push( changeItem );\n\n\t\t// Remove incorrect changes. During transformation some change might be, for example, included in another.\n\t\t// In that case, the change will have `howMany` property set to `0` or less. We need to remove those changes.\n\t\tfor ( let i = 0; i < changes.length; i++ ) {\n\t\t\tif ( changes[ i ].howMany < 1 ) {\n\t\t\t\tchanges.splice( i, 1 );\n\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Gets an array of changes that have already been saved for a given element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element\n\t * @returns {Array.<Object>}\n\t */\n\t_getChangesForElement( element ) {\n\t\tlet changes;\n\n\t\tif ( this._changesInElement.has( element ) ) {\n\t\t\tchanges = this._changesInElement.get( element );\n\t\t} else {\n\t\t\tchanges = [];\n\n\t\t\tthis._changesInElement.set( element, changes );\n\t\t}\n\n\t\treturn changes;\n\t}\n\n\t/**\n\t * Saves a children snapshot for a given element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element\n\t */\n\t_makeSnapshot( element ) {\n\t\tif ( !this._elementSnapshots.has( element ) ) {\n\t\t\tthis._elementSnapshots.set( element, _getChildrenSnapshot( element.getChildren() ) );\n\t\t}\n\t}\n\n\t/**\n\t * For a given newly saved change, compares it with a change already done on the element and modifies the incoming\n\t * change and/or the old change.\n\t *\n\t * @private\n\t * @param {Object} inc Incoming (new) change.\n\t * @param {Array.<Object>} changes An array containing all the changes done on that element.\n\t */\n\t_handleChange( inc, changes ) {\n\t\t// We need a helper variable that will store how many nodes are to be still handled for this change item.\n\t\t// `nodesToHandle` (how many nodes still need to be handled) and `howMany` (how many nodes were affected)\n\t\t// needs to be differentiated.\n\t\t//\n\t\t// This comes up when there are multiple changes that are affected by `inc` change item.\n\t\t//\n\t\t// For example: assume two insert changes: `{ offset: 2, howMany: 1 }` and `{ offset: 5, howMany: 1 }`.\n\t\t// Assume that `inc` change is remove `{ offset: 2, howMany: 2, nodesToHandle: 2 }`.\n\t\t//\n\t\t// Then, we:\n\t\t// - \"forget\" about first insert change (it is \"eaten\" by remove),\n\t\t// - because of that, at the end we will want to remove only one node (`nodesToHandle = 1`),\n\t\t// - but still we have to change offset of the second insert change from `5` to `3`!\n\t\t//\n\t\t// So, `howMany` does not change throughout items transformation and keeps information about how many nodes were affected,\n\t\t// while `nodesToHandle` means how many nodes need to be handled after the change item is transformed by other changes.\n\t\tinc.nodesToHandle = inc.howMany;\n\n\t\tfor ( const old of changes ) {\n\t\t\tconst incEnd = inc.offset + inc.howMany;\n\t\t\tconst oldEnd = old.offset + old.howMany;\n\n\t\t\tif ( inc.type == 'insert' ) {\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\told.howMany += inc.nodesToHandle;\n\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\tif ( inc.offset < old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\told.offset += inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\t// This case is more complicated, because attribute change has to be split into two.\n\t\t\t\t\t\t// Example (assume that uppercase and lowercase letters mean different attributes):\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// initial state:\t\tabcxyz\n\t\t\t\t\t\t// attribute change:\taBCXYz\n\t\t\t\t\t\t// incoming insert:\t\taBCfooXYz\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// Change ranges cannot intersect because each item has to be described exactly (it was either\n\t\t\t\t\t\t// not changed, inserted, removed, or its attribute was changed). That's why old attribute\n\t\t\t\t\t\t// change has to be split and both parts has to be handled separately from now on.\n\t\t\t\t\t\tconst howMany = old.howMany;\n\n\t\t\t\t\t\told.howMany = inc.offset - old.offset;\n\n\t\t\t\t\t\t// Add the second part of attribute change to the beginning of processed array so it won't\n\t\t\t\t\t\t// be processed again in this loop.\n\t\t\t\t\t\tchanges.unshift( {\n\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\toffset: incEnd,\n\t\t\t\t\t\t\thowMany: howMany - old.howMany,\n\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( inc.type == 'remove' ) {\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( incEnd <= oldEnd ) {\n\t\t\t\t\t\tif ( inc.offset < old.offset ) {\n\t\t\t\t\t\t\tconst intersectionLength = incEnd - old.offset;\n\n\t\t\t\t\t\t\told.offset = inc.offset;\n\n\t\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t\t\tinc.nodesToHandle -= intersectionLength;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\told.howMany -= inc.nodesToHandle;\n\t\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif ( inc.offset <= old.offset ) {\n\t\t\t\t\t\t\tinc.nodesToHandle -= old.howMany;\n\t\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\t\tconst intersectionLength = oldEnd - inc.offset;\n\n\t\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t\t\tinc.nodesToHandle -= intersectionLength;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < old.offset ) {\n\t\t\t\t\t\tinc.nodesToHandle += old.howMany;\n\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\tif ( incEnd <= old.offset ) {\n\t\t\t\t\t\told.offset -= inc.howMany;\n\t\t\t\t\t} else if ( inc.offset < old.offset ) {\n\t\t\t\t\t\tconst intersectionLength = incEnd - old.offset;\n\n\t\t\t\t\t\told.offset = inc.offset;\n\t\t\t\t\t\told.howMany -= intersectionLength;\n\t\t\t\t\t} else if ( inc.offset < oldEnd ) {\n\t\t\t\t\t\tif ( incEnd <= oldEnd ) {\n\t\t\t\t\t\t\t// On first sight in this case we don't need to split attribute operation into two.\n\t\t\t\t\t\t\t// However the changes set is later converted to actions (see `_generateActionsFromChanges`).\n\t\t\t\t\t\t\t// For that reason, no two changes may intersect.\n\t\t\t\t\t\t\t// So we cannot have an attribute change that \"contains\" remove change.\n\t\t\t\t\t\t\t// Attribute change needs to be split.\n\t\t\t\t\t\t\tconst howMany = old.howMany;\n\n\t\t\t\t\t\t\told.howMany = inc.offset - old.offset;\n\n\t\t\t\t\t\t\tconst howManyAfter = howMany - old.howMany - inc.nodesToHandle;\n\n\t\t\t\t\t\t\t// Add the second part of attribute change to the beginning of processed array so it won't\n\t\t\t\t\t\t\t// be processed again in this loop.\n\t\t\t\t\t\t\tchanges.unshift( {\n\t\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\t\toffset: inc.offset,\n\t\t\t\t\t\t\t\thowMany: howManyAfter,\n\t\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\told.howMany -= oldEnd - inc.offset;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( inc.type == 'attribute' ) {\n\t\t\t\t// In case of attribute change, `howMany` should be kept same as `nodesToHandle`. It's not an error.\n\t\t\t\tif ( old.type == 'insert' ) {\n\t\t\t\t\tif ( inc.offset < old.offset && incEnd > old.offset ) {\n\t\t\t\t\t\tif ( incEnd > oldEnd ) {\n\t\t\t\t\t\t\t// This case is similar to a case described when incoming change was insert and old change was attribute.\n\t\t\t\t\t\t\t// See comment above.\n\t\t\t\t\t\t\t//\n\t\t\t\t\t\t\t// This time incoming change is attribute. We need to split incoming change in this case too.\n\t\t\t\t\t\t\t// However this time, the second part of the attribute change needs to be processed further\n\t\t\t\t\t\t\t// because there might be other changes that it collides with.\n\t\t\t\t\t\t\tconst attributePart = {\n\t\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\t\toffset: oldEnd,\n\t\t\t\t\t\t\t\thowMany: incEnd - oldEnd,\n\t\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tthis._handleChange( attributePart, changes );\n\n\t\t\t\t\t\t\tchanges.push( attributePart );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tinc.nodesToHandle = old.offset - inc.offset;\n\t\t\t\t\t\tinc.howMany = inc.nodesToHandle;\n\t\t\t\t\t} else if ( inc.offset >= old.offset && inc.offset < oldEnd ) {\n\t\t\t\t\t\tif ( incEnd > oldEnd ) {\n\t\t\t\t\t\t\tinc.nodesToHandle = incEnd - oldEnd;\n\t\t\t\t\t\t\tinc.offset = oldEnd;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'remove' ) {\n\t\t\t\t\t// This is a case when attribute change \"contains\" remove change.\n\t\t\t\t\t// The attribute change needs to be split into two because changes cannot intersect.\n\t\t\t\t\tif ( inc.offset < old.offset && incEnd > old.offset ) {\n\t\t\t\t\t\tconst attributePart = {\n\t\t\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\t\t\toffset: old.offset,\n\t\t\t\t\t\t\thowMany: incEnd - old.offset,\n\t\t\t\t\t\t\tcount: this._changeCount++\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tthis._handleChange( attributePart, changes );\n\n\t\t\t\t\t\tchanges.push( attributePart );\n\n\t\t\t\t\t\tinc.nodesToHandle = old.offset - inc.offset;\n\t\t\t\t\t\tinc.howMany = inc.nodesToHandle;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( old.type == 'attribute' ) {\n\t\t\t\t\t// There are only two conflicting scenarios possible here:\n\t\t\t\t\tif ( inc.offset >= old.offset && incEnd <= oldEnd ) {\n\t\t\t\t\t\t// `old` change includes `inc` change, or they are the same.\n\t\t\t\t\t\tinc.nodesToHandle = 0;\n\t\t\t\t\t\tinc.howMany = 0;\n\t\t\t\t\t\tinc.offset = 0;\n\t\t\t\t\t} else if ( inc.offset <= old.offset && incEnd >= oldEnd ) {\n\t\t\t\t\t\t// `inc` change includes `old` change.\n\t\t\t\t\t\told.howMany = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tinc.howMany = inc.nodesToHandle;\n\t\tdelete inc.nodesToHandle;\n\t}\n\n\t/**\n\t * Returns an object with a single insert change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent The element in which the change happened.\n\t * @param {Number} offset The offset at which change happened.\n\t * @param {String} name The name of the removed element or `'$text'` for a character.\n\t * @returns {Object} The diff item.\n\t */\n\t_getInsertDiff( parent, offset, name ) {\n\t\treturn {\n\t\t\ttype: 'insert',\n\t\t\tposition: Position._createAt( parent, offset ),\n\t\t\tname,\n\t\t\tlength: 1,\n\t\t\tchangeCount: this._changeCount++\n\t\t};\n\t}\n\n\t/**\n\t * Returns an object with a single remove change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent The element in which change happened.\n\t * @param {Number} offset The offset at which change happened.\n\t * @param {String} name The name of the removed element or `'$text'` for a character.\n\t * @returns {Object} The diff item.\n\t */\n\t_getRemoveDiff( parent, offset, name ) {\n\t\treturn {\n\t\t\ttype: 'remove',\n\t\t\tposition: Position._createAt( parent, offset ),\n\t\t\tname,\n\t\t\tlength: 1,\n\t\t\tchangeCount: this._changeCount++\n\t\t};\n\t}\n\n\t/**\n\t * Returns an array of objects where each one is a single attribute change description.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range The range where the change happened.\n\t * @param {Map} oldAttributes A map, map iterator or compatible object that contains attributes before the change.\n\t * @param {Map} newAttributes A map, map iterator or compatible object that contains attributes after the change.\n\t * @returns {Array.<Object>} An array containing one or more diff items.\n\t */\n\t_getAttributesDiff( range, oldAttributes, newAttributes ) {\n\t\t// Results holder.\n\t\tconst diffs = [];\n\n\t\t// Clone new attributes as we will be performing changes on this object.\n\t\tnewAttributes = new Map( newAttributes );\n\n\t\t// Look through old attributes.\n\t\tfor ( const [ key, oldValue ] of oldAttributes ) {\n\t\t\t// Check what is the new value of the attribute (or if it was removed).\n\t\t\tconst newValue = newAttributes.has( key ) ? newAttributes.get( key ) : null;\n\n\t\t\t// If values are different (or attribute was removed)...\n\t\t\tif ( newValue !== oldValue ) {\n\t\t\t\t// Add diff item.\n\t\t\t\tdiffs.push( {\n\t\t\t\t\ttype: 'attribute',\n\t\t\t\t\tposition: range.start,\n\t\t\t\t\trange: range.clone(),\n\t\t\t\t\tlength: 1,\n\t\t\t\t\tattributeKey: key,\n\t\t\t\t\tattributeOldValue: oldValue,\n\t\t\t\t\tattributeNewValue: newValue,\n\t\t\t\t\tchangeCount: this._changeCount++\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Prevent returning two diff items for the same change.\n\t\t\tnewAttributes.delete( key );\n\t\t}\n\n\t\t// Look through new attributes that weren't handled above.\n\t\tfor ( const [ key, newValue ] of newAttributes ) {\n\t\t\t// Each of them is a new attribute. Add diff item.\n\t\t\tdiffs.push( {\n\t\t\t\ttype: 'attribute',\n\t\t\t\tposition: range.start,\n\t\t\t\trange: range.clone(),\n\t\t\t\tlength: 1,\n\t\t\t\tattributeKey: key,\n\t\t\t\tattributeOldValue: null,\n\t\t\t\tattributeNewValue: newValue,\n\t\t\t\tchangeCount: this._changeCount++\n\t\t\t} );\n\t\t}\n\n\t\treturn diffs;\n\t}\n\n\t/**\n\t * Checks whether given element or any of its parents is an element that is buffered as an inserted element.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} element Element to check.\n\t * @returns {Boolean}\n\t */\n\t_isInInsertedElement( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( !parent ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst changes = this._changesInElement.get( parent );\n\t\tconst offset = element.startOffset;\n\n\t\tif ( changes ) {\n\t\t\tfor ( const change of changes ) {\n\t\t\t\tif ( change.type == 'insert' && offset >= change.offset && offset < change.offset + change.howMany ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this._isInInsertedElement( parent );\n\t}\n\n\t/**\n\t * Removes deeply all buffered changes that are registered in elements from range specified by `parent`, `offset`\n\t * and `howMany`.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} parent\n\t * @param {Number} offset\n\t * @param {Number} howMany\n\t */\n\t_removeAllNestedChanges( parent, offset, howMany ) {\n\t\tconst range = new Range( Position._createAt( parent, offset ), Position._createAt( parent, offset + howMany ) );\n\n\t\tfor ( const item of range.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( 'element' ) ) {\n\t\t\t\tthis._elementSnapshots.delete( item );\n\t\t\t\tthis._changesInElement.delete( item );\n\n\t\t\t\tthis._removeAllNestedChanges( item, 0, item.maxOffset );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Returns an array that is a copy of passed child list with the exception that text nodes are split to one or more\n// objects, each representing one character and attributes set on that character.\nfunction _getChildrenSnapshot( children ) {\n\tconst snapshot = [];\n\n\tfor ( const child of children ) {\n\t\tif ( child.is( '$text' ) ) {\n\t\t\tfor ( let i = 0; i < child.data.length; i++ ) {\n\t\t\t\tsnapshot.push( {\n\t\t\t\t\tname: '$text',\n\t\t\t\t\tattributes: new Map( child.getAttributes() )\n\t\t\t\t} );\n\t\t\t}\n\t\t} else {\n\t\t\tsnapshot.push( {\n\t\t\t\tname: child.name,\n\t\t\t\tattributes: new Map( child.getAttributes() )\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn snapshot;\n}\n\n// Generates array of actions for given changes set.\n// It simulates what `diff` function does.\n// Generated actions are:\n// - 'e' for 'equal' - when item at that position did not change,\n// - 'i' for 'insert' - when item at that position was inserted,\n// - 'r' for 'remove' - when item at that position was removed,\n// - 'a' for 'attribute' - when item at that position has it attributes changed.\n//\n// Example (assume that uppercase letters have bold attribute, compare with function code):\n//\n// children before:\tfooBAR\n// children after:\tfoxybAR\n//\n// changes: type: remove, offset: 1, howMany: 1\n//\t\t\ttype: insert, offset: 2, howMany: 2\n//\t\t\ttype: attribute, offset: 4, howMany: 1\n//\n// expected actions: equal (f), remove (o), equal (o), insert (x), insert (y), attribute (b), equal (A), equal (R)\n//\n// steps taken by th script:\n//\n// 1. change = \"type: remove, offset: 1, howMany: 1\"; offset = 0; oldChildrenHandled = 0\n// 1.1 between this change and the beginning is one not-changed node, fill with one equal action, one old child has been handled\n// 1.2 this change removes one node, add one remove action\n// 1.3 change last visited `offset` to 1\n// 1.4 since an old child has been removed, one more old child has been handled\n// 1.5 actions at this point are: equal, remove\n//\n// 2. change = \"type: insert, offset: 2, howMany: 2\"; offset = 1; oldChildrenHandled = 2\n// 2.1 between this change and previous change is one not-changed node, add equal action, another one old children has been handled\n// 2.2 this change inserts two nodes, add two insert actions\n// 2.3 change last visited offset to the end of the inserted range, that is 4\n// 2.4 actions at this point are: equal, remove, equal, insert, insert\n//\n// 3. change = \"type: attribute, offset: 4, howMany: 1\"; offset = 4, oldChildrenHandled = 3\n// 3.1 between this change and previous change are no not-changed nodes\n// 3.2 this change changes one node, add one attribute action\n// 3.3 change last visited `offset` to the end of change range, that is 5\n// 3.4 since an old child has been changed, one more old child has been handled\n// 3.5 actions at this point are: equal, remove, equal, insert, insert, attribute\n//\n// 4. after loop oldChildrenHandled = 4, oldChildrenLength = 6 (fooBAR is 6 characters)\n// 4.1 fill up with two equal actions\n//\n// The result actions are: equal, remove, equal, insert, insert, attribute, equal, equal.\nfunction _generateActionsFromChanges( oldChildrenLength, changes ) {\n\tconst actions = [];\n\n\tlet offset = 0;\n\tlet oldChildrenHandled = 0;\n\n\t// Go through all buffered changes.\n\tfor ( const change of changes ) {\n\t\t// First, fill \"holes\" between changes with \"equal\" actions.\n\t\tif ( change.offset > offset ) {\n\t\t\tfor ( let i = 0; i < change.offset - offset; i++ ) {\n\t\t\t\tactions.push( 'e' );\n\t\t\t}\n\n\t\t\toldChildrenHandled += change.offset - offset;\n\t\t}\n\n\t\t// Then, fill up actions accordingly to change type.\n\t\tif ( change.type == 'insert' ) {\n\t\t\tfor ( let i = 0; i < change.howMany; i++ ) {\n\t\t\t\tactions.push( 'i' );\n\t\t\t}\n\n\t\t\t// The last handled offset is after inserted range.\n\t\t\toffset = change.offset + change.howMany;\n\t\t} else if ( change.type == 'remove' ) {\n\t\t\tfor ( let i = 0; i < change.howMany; i++ ) {\n\t\t\t\tactions.push( 'r' );\n\t\t\t}\n\n\t\t\t// The last handled offset is at the position where the nodes were removed.\n\t\t\toffset = change.offset;\n\t\t\t// We removed `howMany` old nodes, update `oldChildrenHandled`.\n\t\t\toldChildrenHandled += change.howMany;\n\t\t} else {\n\t\t\tactions.push( ...'a'.repeat( change.howMany ).split( '' ) );\n\n\t\t\t// The last handled offset is at the position after the changed range.\n\t\t\toffset = change.offset + change.howMany;\n\t\t\t// We changed `howMany` old nodes, update `oldChildrenHandled`.\n\t\t\toldChildrenHandled += change.howMany;\n\t\t}\n\t}\n\n\t// Fill \"equal\" actions at the end of actions set. Use `oldChildrenHandled` to see how many children\n\t// has not been changed / removed at the end of their parent.\n\tif ( oldChildrenHandled < oldChildrenLength ) {\n\t\tfor ( let i = 0; i < oldChildrenLength - oldChildrenHandled - offset; i++ ) {\n\t\t\tactions.push( 'e' );\n\t\t}\n\t}\n\n\treturn actions;\n}\n\n// Filter callback for Array.filter that filters out change entries that are in graveyard.\nfunction _changesInGraveyardFilter( entry ) {\n\tconst posInGy = entry.position && entry.position.root.rootName == '$graveyard';\n\tconst rangeInGy = entry.range && entry.range.root.rootName == '$graveyard';\n\n\treturn !posInGy && !rangeInGy;\n}\n\n/**\n * The single diff item.\n *\n * Could be one of:\n *\n * * {@link module:engine/model/differ~DiffItemInsert `DiffItemInsert`},\n * * {@link module:engine/model/differ~DiffItemRemove `DiffItemRemove`},\n * * {@link module:engine/model/differ~DiffItemAttribute `DiffItemAttribute`}.\n *\n * @interface DiffItem\n */\n\n/**\n * The single diff item for inserted nodes.\n *\n * @class DiffItemInsert\n * @implements module:engine/model/differ~DiffItem\n */\n\n/**\n * The type of diff item.\n *\n * @member {'insert'} module:engine/model/differ~DiffItemInsert#type\n */\n\n/**\n * The name of the inserted elements or `'$text'` for a text node.\n *\n * @member {String} module:engine/model/differ~DiffItemInsert#name\n */\n\n/**\n * The position where the node was inserted.\n *\n * @member {module:engine/model/position~Position} module:engine/model/differ~DiffItemInsert#position\n */\n\n/**\n * The length of an inserted text node. For elements it is always 1 as each inserted element is counted as a one.\n *\n * @member {Number} module:engine/model/differ~DiffItemInsert#length\n */\n\n/**\n * The single diff item for removed nodes.\n *\n * @class DiffItemRemove\n * @implements module:engine/model/differ~DiffItem\n */\n\n/**\n * The type of diff item.\n *\n * @member {'remove'} module:engine/model/differ~DiffItemRemove#type\n */\n\n/**\n * The name of the removed element or `'$text'` for a text node.\n *\n * @member {String} module:engine/model/differ~DiffItemRemove#name\n */\n\n/**\n * The position where the node was removed.\n *\n * @member {module:engine/model/position~Position} module:engine/model/differ~DiffItemRemove#position\n */\n\n/**\n * The length of a removed text node. For elements it is always 1 as each removed element is counted as a one.\n *\n * @member {Number} module:engine/model/differ~DiffItemRemove#length\n */\n\n/**\n * The single diff item for attribute change.\n *\n * @class DiffItemAttribute\n * @implements module:engine/model/differ~DiffItem\n */\n\n/**\n * The type of diff item.\n *\n * @member {'attribute'} module:engine/model/differ~DiffItemAttribute#type\n */\n\n/**\n * The name of the changed attribute.\n *\n * @member {String} module:engine/model/differ~DiffItemAttribute#attributeKey\n */\n\n/**\n * An attribute previous value (before change).\n *\n * @member {String} module:engine/model/differ~DiffItemAttribute#attributeOldValue\n */\n\n/**\n * An attribute new value (after change).\n *\n * @member {String} module:engine/model/differ~DiffItemAttribute#attributeNewValue\n */\n\n/**\n * The range where the change happened.\n *\n * @member {module:engine/model/range~Range} module:engine/model/differ~DiffItemAttribute#range\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/history\n */\n\n/**\n * `History` keeps the track of all the operations applied to the {@link module:engine/model/document~Document document}.\n */\nexport default class History {\n\t/**\n\t * Creates an empty History instance.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Operations added to the history.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array.<module:engine/model/operation/operation~Operation>} module:engine/model/history~History#_operations\n\t\t */\n\t\tthis._operations = [];\n\n\t\t/**\n\t\t * Holds an information which {@link module:engine/model/operation/operation~Operation operation} undoes which\n\t\t * {@link module:engine/model/operation/operation~Operation operation}.\n\t\t *\n\t\t * Keys of the map are \"undoing operations\", that is operations that undone some other operations. For each key, the\n\t\t * value is an operation that has been undone by the \"undoing operation\".\n\t\t *\n\t\t * @private\n\t\t * @member {Map} module:engine/model/history~History#_undoPairs\n\t\t */\n\t\tthis._undoPairs = new Map();\n\n\t\t/**\n\t\t * Holds all undone operations.\n\t\t *\n\t\t * @private\n\t\t * @member {Set.<module:engine/model/operation/operation~Operation>} module:engine/model/history~History#_undoneOperations\n\t\t */\n\t\tthis._undoneOperations = new Set();\n\t}\n\n\t/**\n\t * Adds an operation to the history.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to add.\n\t */\n\taddOperation( operation ) {\n\t\tif ( this._operations.includes( operation ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._operations.push( operation );\n\t}\n\n\t/**\n\t * Returns operations added to the history.\n\t *\n\t * @param {Number} [from=Number.NEGATIVE_INFINITY] Base version from which operations should be returned (inclusive).\n\t * Defaults to `Number.NEGATIVE_INFINITY`, which means that operations from the first one will be returned.\n\t * @param {Number} [to=Number.POSITIVE_INFINITY] Base version up to which operations should be returned (exclusive).\n\t * Defaults to `Number.POSITIVE_INFINITY` which means that operations up to the last one will be returned.\n\t * @returns {Array.<module:engine/model/operation/operation~Operation>} Operations added to the history.\n\t */\n\tgetOperations( from = Number.NEGATIVE_INFINITY, to = Number.POSITIVE_INFINITY ) {\n\t\tconst operations = [];\n\n\t\tfor ( const operation of this._operations ) {\n\t\t\tif ( operation.baseVersion >= from && operation.baseVersion < to ) {\n\t\t\t\toperations.push( operation );\n\t\t\t}\n\t\t}\n\n\t\treturn operations;\n\t}\n\n\t/**\n\t * Returns operation from the history that bases on given `baseVersion`.\n\t *\n\t * @param {Number} baseVersion Base version of the operation to get.\n\t * @returns {module:engine/model/operation/operation~Operation|undefined} Operation with given base version or `undefined` if\n\t * there is no such operation in history.\n\t */\n\tgetOperation( baseVersion ) {\n\t\tfor ( const operation of this._operations ) {\n\t\t\tif ( operation.baseVersion == baseVersion ) {\n\t\t\t\treturn operation;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Marks in history that one operation is an operation that is undoing the other operation. By marking operation this way,\n\t * history is keeping more context information about operations, which helps in operational transformation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} undoneOperation Operation which is undone by `undoingOperation`.\n\t * @param {module:engine/model/operation/operation~Operation} undoingOperation Operation which undoes `undoneOperation`.\n\t */\n\tsetOperationAsUndone( undoneOperation, undoingOperation ) {\n\t\tthis._undoPairs.set( undoingOperation, undoneOperation );\n\t\tthis._undoneOperations.add( undoneOperation );\n\t}\n\n\t/**\n\t * Checks whether given `operation` is undoing any other operation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to check.\n\t * @returns {Boolean} `true` if given `operation` is undoing any other operation, `false` otherwise.\n\t */\n\tisUndoingOperation( operation ) {\n\t\treturn this._undoPairs.has( operation );\n\t}\n\n\t/**\n\t * Checks whether given `operation` has been undone by any other operation.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation Operation to check.\n\t * @returns {Boolean} `true` if given `operation` has been undone any other operation, `false` otherwise.\n\t */\n\tisUndoneOperation( operation ) {\n\t\treturn this._undoneOperations.has( operation );\n\t}\n\n\t/**\n\t * For given `undoingOperation`, returns the operation which has been undone by it.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} undoingOperation\n\t * @returns {module:engine/model/operation/operation~Operation|undefined} Operation that has been undone by given\n\t * `undoingOperation` or `undefined` if given `undoingOperation` is not undoing any other operation.\n\t */\n\tgetUndoneOperation( undoingOperation ) {\n\t\treturn this._undoPairs.get( undoingOperation );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * Set of utils to handle unicode characters.\n *\n * @module utils/unicode\n */\n\n/**\n * Checks whether given `character` is a combining mark.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isCombiningMark( character ) {\n\t// eslint-disable-next-line no-misleading-character-class\n\treturn !!character && character.length == 1 && /[\\u0300-\\u036f\\u1ab0-\\u1aff\\u1dc0-\\u1dff\\u20d0-\\u20ff\\ufe20-\\ufe2f]/.test( character );\n}\n\n/**\n * Checks whether given `character` is a high half of surrogate pair.\n *\n * Using UTF-16 terminology, a surrogate pair denotes UTF-16 character using two UTF-8 characters. The surrogate pair\n * consist of high surrogate pair character followed by low surrogate pair character.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isHighSurrogateHalf( character ) {\n\treturn !!character && character.length == 1 && /[\\ud800-\\udbff]/.test( character );\n}\n\n/**\n * Checks whether given `character` is a low half of surrogate pair.\n *\n * Using UTF-16 terminology, a surrogate pair denotes UTF-16 character using two UTF-8 characters. The surrogate pair\n * consist of high surrogate pair character followed by low surrogate pair character.\n *\n * @param {String} character Character to check.\n * @returns {Boolean}\n */\nexport function isLowSurrogateHalf( character ) {\n\treturn !!character && character.length == 1 && /[\\udc00-\\udfff]/.test( character );\n}\n\n/**\n * Checks whether given offset in a string is inside a surrogate pair (between two surrogate halves).\n *\n * @param {String} string String to check.\n * @param {Number} offset Offset to check.\n * @returns {Boolean}\n */\nexport function isInsideSurrogatePair( string, offset ) {\n\treturn isHighSurrogateHalf( string.charAt( offset - 1 ) ) && isLowSurrogateHalf( string.charAt( offset ) );\n}\n\n/**\n * Checks whether given offset in a string is between base character and combining mark or between two combining marks.\n *\n * @param {String} string String to check.\n * @param {Number} offset Offset to check.\n * @returns {Boolean}\n */\nexport function isInsideCombinedSymbol( string, offset ) {\n\treturn isCombiningMark( string.charAt( offset ) );\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/document\n */\n\nimport Differ from './differ';\nimport RootElement from './rootelement';\nimport History from './history';\nimport DocumentSelection from './documentselection';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { isInsideSurrogatePair, isInsideCombinedSymbol } from '@ckeditor/ckeditor5-utils/src/unicode';\nimport { clone } from 'lodash-es';\n\n// @if CK_DEBUG_ENGINE // const { logDocument } = require( '../dev-utils/utils' );\n\nconst graveyardName = '$graveyard';\n\n/**\n * Data model's document. It contains the model's structure, its selection and the history of changes.\n *\n * Read more about working with the model in\n * {@glink framework/guides/architecture/editing-engine#model introduction to the the editing engine's architecture}.\n *\n * Usually, the document contains just one {@link module:engine/model/document~Document#roots root element}, so\n * you can retrieve it by just calling {@link module:engine/model/document~Document#getRoot} without specifying its name:\n *\n *\t\tmodel.document.getRoot(); // -> returns the main root\n *\n * However, the document may contain multiple roots e.g. when the editor has multiple editable areas\n * (e.g. a title and a body of a message).\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Document {\n\t/**\n\t * Creates an empty document instance with no {@link #roots} (other than\n\t * the {@link #graveyard graveyard root}).\n\t */\n\tconstructor( model ) {\n\t\t/**\n\t\t * The {@link module:engine/model/model~Model model} that the document is a part of.\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 document version. It starts from `0` and every operation increases the version number. It is used to ensure that\n\t\t * operations are applied on a proper document version.\n\t\t *\n\t\t * If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,\n\t\t * a {@link module:utils/ckeditorerror~CKEditorError model-document-applyoperation-wrong-version} error is thrown.\n\t\t *\n\t\t * @type {Number}\n\t\t */\n\t\tthis.version = 0;\n\n\t\t/**\n\t\t * The document's history.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/history~History}\n\t\t */\n\t\tthis.history = new History( this );\n\n\t\t/**\n\t\t * The selection in this document.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/documentselection~DocumentSelection}\n\t\t */\n\t\tthis.selection = new DocumentSelection( this );\n\n\t\t/**\n\t\t * A list of roots that are owned and managed by this document. Use {@link #createRoot} and\n\t\t * {@link #getRoot} to manipulate it.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.roots = new Collection( { idProperty: 'rootName' } );\n\n\t\t/**\n\t\t * The model differ object. Its role is to buffer changes done on the model document and then calculate a diff of those changes.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/model/differ~Differ}\n\t\t */\n\t\tthis.differ = new Differ( model.markers );\n\n\t\t/**\n\t\t * Post-fixer callbacks registered to the model document.\n\t\t *\n\t\t * @private\n\t\t * @type {Set.<Function>}\n\t\t */\n\t\tthis._postFixers = new Set();\n\n\t\t/**\n\t\t * A boolean indicates whether the selection has changed until\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasSelectionChangedFromTheLastChangeBlock = false;\n\n\t\t// Graveyard tree root. Document always have a graveyard root, which stores removed nodes.\n\t\tthis.createRoot( '$root', graveyardName );\n\n\t\t// First, if the operation is a document operation check if it's base version is correct.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation && operation.baseVersion !== this.version ) {\n\t\t\t\t/**\n\t\t\t\t * Only operations with matching versions can be applied.\n\t\t\t\t *\n\t\t\t\t * @error model-document-applyoperation-wrong-version\n\t\t\t\t * @param {module:engine/model/operation/operation~Operation} operation\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'model-document-applyoperation-wrong-version', this, { operation } );\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\n\t\t// Then, still before an operation is applied on model, buffer the change in differ.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation ) {\n\t\t\t\tthis.differ.bufferOperation( operation );\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// After the operation is applied, bump document's version and add the operation to the history.\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.isDocumentOperation ) {\n\t\t\t\tthis.version++;\n\t\t\t\tthis.history.addOperation( operation );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// Listen to selection changes. If selection changed, mark it.\n\t\tthis.listenTo( this.selection, 'change', () => {\n\t\t\tthis._hasSelectionChangedFromTheLastChangeBlock = true;\n\t\t} );\n\n\t\t// Buffer marker changes.\n\t\t// This is not covered in buffering operations because markers may change outside of them (when they\n\t\t// are modified using `model.markers` collection, not through `MarkerOperation`).\n\t\tthis.listenTo( model.markers, 'update', ( evt, marker, oldRange, newRange ) => {\n\t\t\t// Whenever marker is updated, buffer that change.\n\t\t\tthis.differ.bufferMarkerChange( marker.name, oldRange, newRange, marker.affectsData );\n\n\t\t\tif ( oldRange === null ) {\n\t\t\t\t// If this is a new marker, add a listener that will buffer change whenever marker changes.\n\t\t\t\tmarker.on( 'change', ( evt, oldRange ) => {\n\t\t\t\t\tthis.differ.bufferMarkerChange( marker.name, oldRange, marker.getRange(), marker.affectsData );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * The graveyard tree root. A document always has a graveyard root that stores removed nodes.\n\t *\n\t * @readonly\n\t * @member {module:engine/model/rootelement~RootElement}\n\t */\n\tget graveyard() {\n\t\treturn this.getRoot( graveyardName );\n\t}\n\n\t/**\n\t * Creates a new root.\n\t *\n\t * @param {String} [elementName='$root'] The element name. Defaults to `'$root'` which also has some basic schema defined\n\t * (`$block`s are allowed inside the `$root`). Make sure to define a proper schema if you use a different name.\n\t * @param {String} [rootName='main'] A unique root name.\n\t * @returns {module:engine/model/rootelement~RootElement} The created root.\n\t */\n\tcreateRoot( elementName = '$root', rootName = 'main' ) {\n\t\tif ( this.roots.get( rootName ) ) {\n\t\t\t/**\n\t\t\t * A root with the specified name already exists.\n\t\t\t *\n\t\t\t * @error model-document-createroot-name-exists\n\t\t\t * @param {module:engine/model/document~Document} doc\n\t\t\t * @param {String} name\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-document-createroot-name-exists', this, { name: rootName } );\n\t\t}\n\n\t\tconst root = new RootElement( this, elementName, rootName );\n\t\tthis.roots.add( root );\n\n\t\treturn root;\n\t}\n\n\t/**\n\t * Removes all event listeners set by the document instance.\n\t */\n\tdestroy() {\n\t\tthis.selection.destroy();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Returns a root by its name.\n\t *\n\t * @param {String} [name='main'] A unique root name.\n\t * @returns {module:engine/model/rootelement~RootElement|null} The root registered under a given name or `null` when\n\t * there is no root with the given name.\n\t */\n\tgetRoot( name = 'main' ) {\n\t\treturn this.roots.get( name );\n\t}\n\n\t/**\n\t * Returns an array with names of all roots (without the {@link #graveyard}) added to the document.\n\t *\n\t * @returns {Array.<String>} Roots names.\n\t */\n\tgetRootNames() {\n\t\treturn Array.from( this.roots, root => root.rootName ).filter( name => name != graveyardName );\n\t}\n\n\t/**\n\t * Used to register a post-fixer callback. A post-fixer mechanism guarantees that the features\n\t * will operate on a correct model state.\n\t *\n\t * An execution of a feature may lead to an incorrect document tree state. The callbacks are used to fix the document tree after\n\t * it has changed. Post-fixers are fired just after all changes from the outermost change block were applied but\n\t * before the {@link module:engine/model/document~Document#event:change change event} is fired. If a post-fixer callback made\n\t * a change, it should return `true`. When this happens, all post-fixers are fired again to check if something else should\n\t * not be fixed in the new document tree state.\n\t *\n\t * As a parameter, a post-fixer callback receives a {@link module:engine/model/writer~Writer writer} instance connected with the\n\t * executed changes block. Thanks to that, all changes done by the callback will be added to the same\n\t * {@link module:engine/model/batch~Batch batch} (and undo step) as the original changes. This makes post-fixer changes transparent\n\t * for the user.\n\t *\n\t * An example of a post-fixer is a callback that checks if all the data were removed from the editor. If so, the\n\t * callback should add an empty paragraph so that the editor is never empty:\n\t *\n\t *\t\tdocument.registerPostFixer( writer => {\n\t *\t\t\tconst changes = document.differ.getChanges();\n\t *\n\t *\t\t\t// Check if the changes lead to an empty root in the editor.\n\t *\t\t\tfor ( const entry of changes ) {\n\t *\t\t\t\tif ( entry.type == 'remove' && entry.position.root.isEmpty ) {\n\t *\t\t\t\t\twriter.insertElement( 'paragraph', entry.position.root, 0 );\n\t *\n\t *\t\t\t\t\t// It is fine to return early, even if multiple roots would need to be fixed.\n\t *\t\t\t\t\t// All post-fixers will be fired again, so if there are more empty roots, those will be fixed, too.\n\t *\t\t\t\t\treturn true;\n\t *\t\t\t\t}\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @param {Function} postFixer\n\t */\n\tregisterPostFixer( postFixer ) {\n\t\tthis._postFixers.add( postFixer );\n\t}\n\n\t/**\n\t * A custom `toJSON()` method to solve child-parent circular dependencies.\n\t *\n\t * @returns {Object} A clone of this object with the document property changed to a string.\n\t */\n\ttoJSON() {\n\t\tconst json = clone( this );\n\n\t\t// Due to circular references we need to remove parent reference.\n\t\tjson.selection = '[engine.model.DocumentSelection]';\n\t\tjson.model = '[engine.model.Model]';\n\n\t\treturn json;\n\t}\n\n\t/**\n\t * Check if there were any changes done on document, and if so, call post-fixers,\n\t * fire `change` event for features and conversion and then reset the differ.\n\t * Fire `change:data` event when at least one operation or buffered marker changes the data.\n\t *\n\t * @protected\n\t * @fires change\n\t * @fires change:data\n\t * @param {module:engine/model/writer~Writer} writer The writer on which post-fixers will be called.\n\t */\n\t_handleChangeBlock( writer ) {\n\t\tif ( this._hasDocumentChangedFromTheLastChangeBlock() ) {\n\t\t\tthis._callPostFixers( writer );\n\n\t\t\t// Refresh selection attributes according to the final position in the model after the change.\n\t\t\tthis.selection.refresh();\n\n\t\t\tif ( this.differ.hasDataChanges() ) {\n\t\t\t\tthis.fire( 'change:data', writer.batch );\n\t\t\t} else {\n\t\t\t\tthis.fire( 'change', writer.batch );\n\t\t\t}\n\n\t\t\t// Theoretically, it is not necessary to refresh selection after change event because\n\t\t\t// post-fixers are the last who should change the model, but just in case...\n\t\t\tthis.selection.refresh();\n\n\t\t\tthis.differ.reset();\n\t\t}\n\n\t\tthis._hasSelectionChangedFromTheLastChangeBlock = false;\n\t}\n\n\t/**\n\t * Returns whether there is a buffered change or if the selection has changed from the last\n\t * {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block}\n\t * or {@link module:engine/model/model~Model#change `change()` block}.\n\t *\n\t * @protected\n\t * @returns {Boolean} Returns `true` if document has changed from the last `change()` or `enqueueChange()` block.\n\t */\n\t_hasDocumentChangedFromTheLastChangeBlock() {\n\t\treturn !this.differ.isEmpty || this._hasSelectionChangedFromTheLastChangeBlock;\n\t}\n\n\t/**\n\t * Returns the default root for this document which is either the first root that was added to the document using\n\t * {@link #createRoot} or the {@link #graveyard graveyard root} if no other roots were created.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/rootelement~RootElement} The default root for this document.\n\t */\n\t_getDefaultRoot() {\n\t\tfor ( const root of this.roots ) {\n\t\t\tif ( root !== this.graveyard ) {\n\t\t\t\treturn root;\n\t\t\t}\n\t\t}\n\n\t\treturn this.graveyard;\n\t}\n\n\t/**\n\t * Returns the default range for this selection. The default range is a collapsed range that starts and ends\n\t * at the beginning of this selection's document {@link #_getDefaultRoot default root}.\n\t *\n\t * @protected\n\t * @returns {module:engine/model/range~Range}\n\t */\n\t_getDefaultRange() {\n\t\tconst defaultRoot = this._getDefaultRoot();\n\t\tconst model = this.model;\n\t\tconst schema = model.schema;\n\n\t\t// Find the first position where the selection can be put.\n\t\tconst position = model.createPositionFromPath( defaultRoot, [ 0 ] );\n\t\tconst nearestRange = schema.getNearestSelectionRange( position );\n\n\t\t// If valid selection range is not found - return range collapsed at the beginning of the root.\n\t\treturn nearestRange || model.createRange( position );\n\t}\n\n\t/**\n\t * Checks whether a given {@link module:engine/model/range~Range range} is a valid range for\n\t * the {@link #selection document's selection}.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} range A range to check.\n\t * @returns {Boolean} `true` if `range` is valid, `false` otherwise.\n\t */\n\t_validateSelectionRange( range ) {\n\t\treturn validateTextNodePosition( range.start ) && validateTextNodePosition( range.end );\n\t}\n\n\t/**\n\t * Performs post-fixer loops. Executes post-fixer callbacks as long as none of them has done any changes to the model.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The writer on which post-fixer callbacks will be called.\n\t */\n\t_callPostFixers( writer ) {\n\t\tlet wasFixed = false;\n\n\t\tdo {\n\t\t\tfor ( const callback of this._postFixers ) {\n\t\t\t\t// Ensure selection attributes are up to date before each post-fixer.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-engine/issues/1673.\n\t\t\t\t//\n\t\t\t\t// It might be good to refresh the selection after each operation but at the moment it leads\n\t\t\t\t// to losing attributes for composition or and spell checking\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-typing/issues/188\n\t\t\t\tthis.selection.refresh();\n\n\t\t\t\twasFixed = callback( writer );\n\n\t\t\t\tif ( wasFixed ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} while ( wasFixed );\n\t}\n\n\t/**\n\t * Fired after each {@link module:engine/model/model~Model#enqueueChange `enqueueChange()` block} or the outermost\n\t * {@link module:engine/model/model~Model#change `change()` block} was executed and the document was changed\n\t * during that block's execution.\n\t *\n\t * The changes which this event will cover include:\n\t *\n\t * * document structure changes,\n\t * * selection changes,\n\t * * marker changes.\n\t *\n\t * If you want to be notified about all these changes, then simply listen to this event like this:\n\t *\n\t *\t\tmodel.document.on( 'change', () => {\n\t *\t\t\tconsole.log( 'The document has changed!' );\n\t *\t\t} );\n\t *\n\t * If, however, you only want to be notified about the data changes, then use the\n\t * {@link module:engine/model/document~Document#event:change:data change:data} event,\n\t * which is fired for document structure changes and marker changes (which affects the data).\n\t *\n\t *\t\tmodel.document.on( 'change:data', () => {\n\t *\t\t\tconsole.log( 'The data has changed!' );\n\t *\t\t} );\n\t *\n\t * @event change\n\t * @param {module:engine/model/batch~Batch} batch The batch that was used in the executed changes block.\n\t */\n\n\t/**\n\t * It is a narrower version of the {@link #event:change} event. It is fired for changes which\n\t * affect the editor data. This is:\n\t *\n\t * * document structure changes,\n\t * * marker changes (which affects the data).\n\t *\n\t * If you want to be notified about the data changes, then listen to this event:\n\t *\n\t *\t\tmodel.document.on( 'change:data', () => {\n\t *\t\t\tconsole.log( 'The data has changed!' );\n\t *\t\t} );\n\t *\n\t * If you would like to listen to all document changes, then check out the\n\t * {@link module:engine/model/document~Document#event:change change} event.\n\t *\n\t * @event change:data\n\t * @param {module:engine/model/batch~Batch} batch The batch that was used in the executed changes block.\n\t */\n\n\t// @if CK_DEBUG_ENGINE // log( version = null ) {\n\t// @if CK_DEBUG_ENGINE // \tversion = version === null ? this.version : version;\n\t// @if CK_DEBUG_ENGINE // \tlogDocument( this, version );\n\t// @if CK_DEBUG_ENGINE // }\n}\n\nmix( Document, EmitterMixin );\n\n// Checks whether given range boundary position is valid for document selection, meaning that is not between\n// unicode surrogate pairs or base character and combining marks.\nfunction validateTextNodePosition( rangeBoundary ) {\n\tconst textNode = rangeBoundary.textNode;\n\n\tif ( textNode ) {\n\t\tconst data = textNode.data;\n\t\tconst offset = rangeBoundary.offset - textNode.startOffset;\n\n\t\treturn !isInsideSurrogatePair( data, offset ) && !isInsideCombinedSymbol( data, offset );\n\t}\n\n\treturn true;\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/markercollection\n */\n\nimport LiveRange from './liverange';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * The collection of all {@link module:engine/model/markercollection~Marker markers} attached to the document.\n * It lets you {@link module:engine/model/markercollection~MarkerCollection#get get} markers or track them using\n * {@link module:engine/model/markercollection~MarkerCollection#event:update} event.\n *\n * To create, change or remove makers use {@link module:engine/model/writer~Writer model writers'} methods:\n * {@link module:engine/model/writer~Writer#addMarker} or {@link module:engine/model/writer~Writer#removeMarker}. Since\n * the writer is the only proper way to change the data model it is not possible to change markers directly using this\n * collection. All markers created by the writer will be automatically added to this collection.\n *\n * By default there is one marker collection available as {@link module:engine/model/model~Model#markers model property}.\n *\n * @see module:engine/model/markercollection~Marker\n */\nexport default class MarkerCollection {\n\t/**\n\t * Creates a markers collection.\n\t */\n\tconstructor() {\n\t\t/**\n\t\t * Stores {@link ~Marker markers} added to the collection.\n\t\t *\n\t\t * @private\n\t\t * @member {Map} #_markers\n\t\t */\n\t\tthis._markers = new Map();\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * Iterates over all {@link ~Marker markers} added to the collection.\n\t *\n\t * @returns {Iterable}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._markers.values();\n\t}\n\n\t/**\n\t * Checks if marker with given `markerName` is in the collection.\n\t *\n\t * @param {String} markerName Marker name.\n\t * @returns {Boolean} `true` if marker with given `markerName` is in the collection, `false` otherwise.\n\t */\n\thas( markerName ) {\n\t\treturn this._markers.has( markerName );\n\t}\n\n\t/**\n\t * Returns {@link ~Marker marker} with given `markerName`.\n\t *\n\t * @param {String} markerName Name of marker to get.\n\t * @returns {module:engine/model/markercollection~Marker|null} Marker with given name or `null` if such marker was\n\t * not added to the collection.\n\t */\n\tget( markerName ) {\n\t\treturn this._markers.get( markerName ) || null;\n\t}\n\n\t/**\n\t * Creates and adds a {@link ~Marker marker} to the `MarkerCollection` with given name on given\n\t * {@link module:engine/model/range~Range range}.\n\t *\n\t * If `MarkerCollection` already had a marker with given name (or {@link ~Marker marker} was passed), the marker in\n\t * collection is updated and {@link module:engine/model/markercollection~MarkerCollection#event:update} event is fired\n\t * but only if there was a change (marker range or {@link module:engine/model/markercollection~Marker#managedUsingOperations}\n\t * flag has changed.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String|module:engine/model/markercollection~Marker} markerOrName Name of marker to set or marker instance to update.\n\t * @param {module:engine/model/range~Range} range Marker range.\n\t * @param {Boolean} [managedUsingOperations=false] Specifies whether the marker is managed using operations.\n\t * @param {Boolean} [affectsData=false] Specifies whether the marker affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t * @returns {module:engine/model/markercollection~Marker} `Marker` instance which was added or updated.\n\t */\n\t_set( markerOrName, range, managedUsingOperations = false, affectsData = false ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\n\t\tif ( markerName.includes( ',' ) ) {\n\t\t\t/**\n\t\t\t * Marker name cannot contain the \",\" character.\n\t\t\t *\n\t\t\t * @error markercollection-incorrect-marker-name\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'markercollection-incorrect-marker-name', this );\n\t\t}\n\n\t\tconst oldMarker = this._markers.get( markerName );\n\n\t\tif ( oldMarker ) {\n\t\t\tconst oldRange = oldMarker.getRange();\n\t\t\tlet hasChanged = false;\n\n\t\t\tif ( !oldRange.isEqual( range ) ) {\n\t\t\t\toldMarker._attachLiveRange( LiveRange.fromRange( range ) );\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( managedUsingOperations != oldMarker.managedUsingOperations ) {\n\t\t\t\toldMarker._managedUsingOperations = managedUsingOperations;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( typeof affectsData === 'boolean' && affectsData != oldMarker.affectsData ) {\n\t\t\t\toldMarker._affectsData = affectsData;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tif ( hasChanged ) {\n\t\t\t\tthis.fire( 'update:' + markerName, oldMarker, oldRange, range );\n\t\t\t}\n\n\t\t\treturn oldMarker;\n\t\t}\n\n\t\tconst liveRange = LiveRange.fromRange( range );\n\t\tconst marker = new Marker( markerName, liveRange, managedUsingOperations, affectsData );\n\n\t\tthis._markers.set( markerName, marker );\n\t\tthis.fire( 'update:' + markerName, marker, null, range );\n\n\t\treturn marker;\n\t}\n\n\t/**\n\t * Removes given {@link ~Marker marker} or a marker with given name from the `MarkerCollection`.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String} markerOrName Marker or name of a marker to remove.\n\t * @returns {Boolean} `true` if marker was found and removed, `false` otherwise.\n\t */\n\t_remove( markerOrName ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\t\tconst oldMarker = this._markers.get( markerName );\n\n\t\tif ( oldMarker ) {\n\t\t\tthis._markers.delete( markerName );\n\t\t\tthis.fire( 'update:' + markerName, oldMarker, oldMarker.getRange(), null );\n\n\t\t\tthis._destroyMarker( oldMarker );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Fires an {@link module:engine/model/markercollection~MarkerCollection#event:update} event for the given {@link ~Marker marker}\n\t * but does not change the marker. Useful to force {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast\n\t * conversion} for the marker.\n\t *\n\t * @protected\n\t * @fires module:engine/model/markercollection~MarkerCollection#event:update\n\t * @param {String} markerOrName Marker or name of a marker to refresh.\n\t */\n\t_refresh( markerOrName ) {\n\t\tconst markerName = markerOrName instanceof Marker ? markerOrName.name : markerOrName;\n\t\tconst marker = this._markers.get( markerName );\n\n\t\tif ( !marker ) {\n\t\t\t/**\n\t\t\t * Marker with provided name does not exists.\n\t\t\t *\n\t\t\t * @error markercollection-refresh-marker-not-exists\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'markercollection-refresh-marker-not-exists', this );\n\t\t}\n\n\t\tconst range = marker.getRange();\n\n\t\tthis.fire( 'update:' + markerName, marker, range, range, marker.managedUsingOperations, marker.affectsData );\n\t}\n\n\t/**\n\t * Returns iterator that iterates over all markers, which ranges contain given {@link module:engine/model/position~Position position}.\n\t *\n\t * @param {module:engine/model/position~Position} position\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersAtPosition( position ) {\n\t\tfor ( const marker of this ) {\n\t\t\tif ( marker.getRange().containsPosition( position ) ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns iterator that iterates over all markers, which intersects with given {@link module:engine/model/range~Range range}.\n\t *\n\t * @param {module:engine/model/range~Range} range\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersIntersectingRange( range ) {\n\t\tfor ( const marker of this ) {\n\t\t\tif ( marker.getRange().getIntersection( range ) !== null ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys marker collection and all markers inside it.\n\t */\n\tdestroy() {\n\t\tfor ( const marker of this._markers.values() ) {\n\t\t\tthis._destroyMarker( marker );\n\t\t}\n\n\t\tthis._markers = null;\n\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Iterates over all markers that starts with given `prefix`.\n\t *\n\t *\t\tconst markerFooA = markersCollection.set( 'foo:a', rangeFooA );\n\t *\t\tconst markerFooB = markersCollection.set( 'foo:b', rangeFooB );\n\t *\t\tconst markerBarA = markersCollection.set( 'bar:a', rangeBarA );\n\t *\t\tconst markerFooBarA = markersCollection.set( 'foobar:a', rangeFooBarA );\n\t *\t\tArray.from( markersCollection.getMarkersGroup( 'foo' ) ); // [ markerFooA, markerFooB ]\n\t *\t\tArray.from( markersCollection.getMarkersGroup( 'a' ) ); // []\n\t *\n\t * @param prefix\n\t * @returns {Iterable.<module:engine/model/markercollection~Marker>}\n\t */\n\t* getMarkersGroup( prefix ) {\n\t\tfor ( const marker of this._markers.values() ) {\n\t\t\tif ( marker.name.startsWith( prefix + ':' ) ) {\n\t\t\t\tyield marker;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Destroys the marker.\n\t *\n\t * @private\n\t * @param {module:engine/model/markercollection~Marker} marker Marker to destroy.\n\t */\n\t_destroyMarker( marker ) {\n\t\tmarker.stopListening();\n\t\tmarker._detachLiveRange();\n\t}\n\n\t/**\n\t * Fired whenever marker is added, updated or removed from `MarkerCollection`.\n\t *\n\t * @event update\n\t * @param {module:engine/model/markercollection~Marker} marker Updated Marker.\n\t * @param {module:engine/model/range~Range|null} oldRange Marker range before the update. When is not defined it\n\t * means that marker is just added.\n\t * @param {module:engine/model/range~Range|null} newRange Marker range after update. When is not defined it\n\t * means that marker is just removed.\n\t */\n}\n\nmix( MarkerCollection, EmitterMixin );\n\n/**\n * `Marker` is a continuous parts of model (like a range), is named and represent some kind of information about marked\n * part of model document. In contrary to {@link module:engine/model/node~Node nodes}, which are building blocks of\n * model document tree, markers are not stored directly in document tree but in\n * {@link module:engine/model/model~Model#markers model markers' collection}. Still, they are document data, by giving\n * additional meaning to the part of a model document between marker start and marker end.\n *\n * In this sense, markers are similar to adding and converting attributes on nodes. The difference is that attribute is\n * connected with a given node (e.g. a character is bold no matter if it gets moved or content around it changes).\n * Markers on the other hand are continuous ranges and are characterized by their start and end position. This means that\n * any character in the marker is marked by the marker. For example, if a character is moved outside of marker it stops being\n * \"special\" and the marker is shrunk. Similarly, when a character is moved into the marker from other place in document\n * model, it starts being \"special\" and the marker is enlarged.\n *\n * Another upside of markers is that finding marked part of document is fast and easy. Using attributes to mark some nodes\n * and then trying to find that part of document would require traversing whole document tree. Marker gives instant access\n * to the range which it is marking at the moment.\n *\n * Markers are built from a name and a range.\n *\n * Range of the marker is updated automatically when document changes, using\n * {@link module:engine/model/liverange~LiveRange live range} mechanism.\n *\n * Name is used to group and identify markers. Names have to be unique, but markers can be grouped by\n * using common prefixes, separated with `:`, for example: `user:john` or `search:3`. That's useful in term of creating\n * namespaces for custom elements (e.g. comments, highlights). You can use this prefixes in\n * {@link module:engine/model/markercollection~MarkerCollection#event:update} listeners to listen on changes in a group of markers.\n * For instance: `model.markers.on( 'update:user', callback );` will be called whenever any `user:*` markers changes.\n *\n * There are two types of markers.\n *\n * 1. Markers managed directly, without using operations. They are added directly by {@link module:engine/model/writer~Writer}\n * to the {@link module:engine/model/markercollection~MarkerCollection} without any additional mechanism. They can be used\n * as bookmarks or visual markers. They are great for showing results of the find, or select link when the focus is in the input.\n *\n * 1. Markers managed using operations. These markers are also stored in {@link module:engine/model/markercollection~MarkerCollection}\n * but changes in these markers is managed the same way all other changes in the model structure - using operations.\n * Therefore, they are handled in the undo stack and synchronized between clients if the collaboration plugin is enabled.\n * This type of markers is useful for solutions like spell checking or comments.\n *\n * Both type of them should be added / updated by {@link module:engine/model/writer~Writer#addMarker}\n * and removed by {@link module:engine/model/writer~Writer#removeMarker} methods.\n *\n *\t\tmodel.change( ( writer ) => {\n * \t\t\tconst marker = writer.addMarker( name, { range, usingOperation: true } );\n *\n * \t\t\t// ...\n *\n * \t\t\twriter.removeMarker( marker );\n *\t\t} );\n *\n * See {@link module:engine/model/writer~Writer} to find more examples.\n *\n * Since markers need to track change in the document, for efficiency reasons, it is best to create and keep as little\n * markers as possible and remove them as soon as they are not needed anymore.\n *\n * Markers can be downcasted and upcasted.\n *\n * Markers downcast happens on {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:addMarker} and\n * {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:removeMarker} events.\n * Use {@link module:engine/conversion/downcasthelpers downcast converters} or attach a custom converter to mentioned events.\n * For {@link module:engine/controller/datacontroller~DataController data pipeline}, marker should be downcasted to an element.\n * Then, it can be upcasted back to a marker. Again, use {@link module:engine/conversion/upcasthelpers upcast converters} or\n * attach a custom converter to {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element}.\n *\n * `Marker` instances are created and destroyed only by {@link ~MarkerCollection MarkerCollection}.\n */\nclass Marker {\n\t/**\n\t * Creates a marker instance.\n\t *\n\t * @param {String} name Marker name.\n\t * @param {module:engine/model/liverange~LiveRange} liveRange Range marked by the marker.\n\t * @param {Boolean} managedUsingOperations Specifies whether the marker is managed using operations.\n\t * @param {Boolean} affectsData Specifies whether the marker affects the data produced by the data pipeline\n\t * (is persisted in the editor's data).\n\t */\n\tconstructor( name, liveRange, managedUsingOperations, affectsData ) {\n\t\t/**\n\t\t * Marker's name.\n\t\t *\n\t\t * @readonly\n\t\t * @type {String}\n\t\t */\n\t\tthis.name = name;\n\n\t\t/**\n\t\t * Range marked by the marker.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/model/liverange~LiveRange}\n\t\t */\n\t\tthis._liveRange = this._attachLiveRange( liveRange );\n\n\t\t/**\n\t\t * Flag indicates if the marker is managed using operations or not.\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._managedUsingOperations = managedUsingOperations;\n\n\t\t/**\n\t\t * Specifies whether the marker affects the data produced by the data pipeline\n\t\t * (is persisted in the editor's data).\n\t\t *\n\t\t * @private\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._affectsData = affectsData;\n\t}\n\n\t/**\n\t * A value indicating if the marker is managed using operations.\n\t * See {@link ~Marker marker class description} to learn more about marker types.\n\t * See {@link module:engine/model/writer~Writer#addMarker}.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget managedUsingOperations() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._managedUsingOperations;\n\t}\n\n\t/**\n\t * A value indicating if the marker changes the data.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget affectsData() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._affectsData;\n\t}\n\n\t/**\n\t * Returns current marker start position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetStart() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._liveRange.start.clone();\n\t}\n\n\t/**\n\t * Returns current marker end position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetEnd() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._liveRange.end.clone();\n\t}\n\n\t/**\n\t * Returns a range that represents the current state of the marker.\n\t *\n\t * Keep in mind that returned value is a {@link module:engine/model/range~Range Range}, not a\n\t * {@link module:engine/model/liverange~LiveRange LiveRange}. This means that it is up-to-date and relevant only\n\t * until next model document change. Do not store values returned by this method. Instead, store {@link ~Marker#name}\n\t * and get `Marker` instance from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection} every\n\t * time there is a need to read marker properties. This will guarantee that the marker has not been removed and\n\t * that it's data is up-to-date.\n\t *\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tgetRange() {\n\t\tif ( !this._liveRange ) {\n\t\t\tthrow new CKEditorError( 'marker-destroyed', this );\n\t\t}\n\n\t\treturn this._liveRange.toRange();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tmarker.is( 'marker' ); // -> true\n\t *\t\tmarker.is( 'model:marker' ); // -> true\n\t *\n\t *\t\tmarker.is( 'view:element' ); // -> false\n\t *\t\tmarker.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'marker' || type === 'model:marker';\n\t}\n\n\t/**\n\t * Binds new live range to the marker and detach the old one if is attached.\n\t *\n\t * @protected\n\t * @param {module:engine/model/liverange~LiveRange} liveRange Live range to attach\n\t * @returns {module:engine/model/liverange~LiveRange} Attached live range.\n\t */\n\t_attachLiveRange( liveRange ) {\n\t\tif ( this._liveRange ) {\n\t\t\tthis._detachLiveRange();\n\t\t}\n\n\t\t// Delegating does not work with namespaces. Alternatively, we could delegate all events (using `*`).\n\t\tliveRange.delegate( 'change:range' ).to( this );\n\t\tliveRange.delegate( 'change:content' ).to( this );\n\n\t\tthis._liveRange = liveRange;\n\n\t\treturn liveRange;\n\t}\n\n\t/**\n\t * Unbinds and destroys currently attached live range.\n\t *\n\t * @protected\n\t */\n\t_detachLiveRange() {\n\t\tthis._liveRange.stopDelegating( 'change:range', this );\n\t\tthis._liveRange.stopDelegating( 'change:content', this );\n\t\tthis._liveRange.detach();\n\t\tthis._liveRange = null;\n\t}\n\n\t/**\n\t * Fired whenever {@link ~Marker#_liveRange marker range} is changed due to changes on {@link module:engine/model/document~Document}.\n\t * This is a delegated {@link module:engine/model/liverange~LiveRange#event:change:range LiveRange change:range event}.\n\t *\n\t * When marker is removed from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection},\n\t * all event listeners listening to it should be removed. It is best to do it on\n\t * {@link module:engine/model/markercollection~MarkerCollection#event:update MarkerCollection update event}.\n\t *\n\t * @see module:engine/model/liverange~LiveRange#event:change:range\n\t * @event change:range\n\t * @param {module:engine/model/range~Range} oldRange\n\t * @param {Object} data\n\t */\n\n\t/**\n\t * Fired whenever change on {@link module:engine/model/document~Document} is done inside {@link ~Marker#_liveRange marker range}.\n\t * This is a delegated {@link module:engine/model/liverange~LiveRange#event:change:content LiveRange change:content event}.\n\t *\n\t * When marker is removed from {@link module:engine/model/markercollection~MarkerCollection MarkerCollection},\n\t * all event listeners listening to it should be removed. It is best to do it on\n\t * {@link module:engine/model/markercollection~MarkerCollection#event:update MarkerCollection update event}.\n\t *\n\t * @see module:engine/model/liverange~LiveRange#event:change:content\n\t * @event change:content\n\t * @param {module:engine/model/range~Range} oldRange\n\t * @param {Object} data\n\t */\n}\n\nmix( Marker, EmitterMixin );\n\n/**\n * Cannot use a {@link module:engine/model/markercollection~MarkerCollection#destroy destroyed marker} instance.\n *\n * @error marker-destroyed\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/operation/nooperation\n */\n\nimport Operation from './operation';\n\n/**\n * Operation which is doing nothing (\"empty operation\", \"do-nothing operation\", \"noop\"). This is an operation,\n * which when executed does not change the tree model. It still has some parameters defined for transformation purposes.\n *\n * In most cases this operation is a result of transforming operations. When transformation returns\n * {@link module:engine/model/operation/nooperation~NoOperation} it means that changes done by the transformed operation\n * have already been applied.\n *\n * @extends module:engine/model/operation/operation~Operation\n */\nexport default class NoOperation extends Operation {\n\tget type() {\n\t\treturn 'noop';\n\t}\n\n\t/**\n\t * Creates and returns an operation that has the same parameters as this operation.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation} Clone of this operation.\n\t */\n\tclone() {\n\t\treturn new NoOperation( this.baseVersion );\n\t}\n\n\t/**\n\t * See {@link module:engine/model/operation/operation~Operation#getReversed `Operation#getReversed()`}.\n\t *\n\t * @returns {module:engine/model/operation/nooperation~NoOperation}\n\t */\n\tgetReversed() {\n\t\treturn new NoOperation( this.baseVersion + 1 );\n\t}\n\n\t_execute() {\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get className() {\n\t\treturn 'NoOperation';\n\t}\n\n\t// @if CK_DEBUG_ENGINE // toString() {\n\t// @if CK_DEBUG_ENGINE // \treturn `NoOperation( ${ this.baseVersion } )`;\n\t// @if CK_DEBUG_ENGINE // }\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/operation/operationfactory\n */\n\nimport AttributeOperation from '../operation/attributeoperation';\nimport InsertOperation from '../operation/insertoperation';\nimport MarkerOperation from '../operation/markeroperation';\nimport MoveOperation from '../operation/moveoperation';\nimport NoOperation from '../operation/nooperation';\nimport Operation from '../operation/operation';\nimport RenameOperation from '../operation/renameoperation';\nimport RootAttributeOperation from '../operation/rootattributeoperation';\nimport SplitOperation from '../operation/splitoperation';\nimport MergeOperation from '../operation/mergeoperation';\n\nconst operations = {};\noperations[ AttributeOperation.className ] = AttributeOperation;\noperations[ InsertOperation.className ] = InsertOperation;\noperations[ MarkerOperation.className ] = MarkerOperation;\noperations[ MoveOperation.className ] = MoveOperation;\noperations[ NoOperation.className ] = NoOperation;\noperations[ Operation.className ] = Operation;\noperations[ RenameOperation.className ] = RenameOperation;\noperations[ RootAttributeOperation.className ] = RootAttributeOperation;\noperations[ SplitOperation.className ] = SplitOperation;\noperations[ MergeOperation.className ] = MergeOperation;\n\n/**\n * A factory class for creating operations.\n *\n * @abstract\n */\nexport default class OperationFactory {\n\t/**\n\t * Creates an operation instance from a JSON object (parsed JSON string).\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @param {module:engine/model/document~Document} document Document on which this operation will be applied.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tstatic fromJSON( json, document ) {\n\t\treturn operations[ json.__className ].fromJSON( json, document );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/liveposition\n */\n\nimport Position from './position';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * `LivePosition` is a type of {@link module:engine/model/position~Position Position}\n * that updates itself as {@link module:engine/model/document~Document document}\n * is changed through operations. It may be used as a bookmark.\n *\n * **Note:** Contrary to {@link module:engine/model/position~Position}, `LivePosition` works only in roots that are\n * {@link module:engine/model/rootelement~RootElement}.\n * If {@link module:engine/model/documentfragment~DocumentFragment} is passed, error will be thrown.\n *\n * **Note:** Be very careful when dealing with `LivePosition`. Each `LivePosition` instance bind events that might\n * have to be unbound.\n * Use {@link module:engine/model/liveposition~LivePosition#detach} whenever you don't need `LivePosition` anymore.\n *\n * @extends module:engine/model/position~Position\n */\nexport default class LivePosition extends Position {\n\t/**\n\t * Creates a live position.\n\t *\n\t * @see module:engine/model/position~Position\n\t * @param {module:engine/model/rootelement~RootElement} root\n\t * @param {Array.<Number>} path\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness]\n\t */\n\tconstructor( root, path, stickiness = 'toNone' ) {\n\t\tsuper( root, path, stickiness );\n\n\t\tif ( !this.root.is( 'rootElement' ) ) {\n\t\t\t/**\n\t\t\t * LivePosition's root has to be an instance of RootElement.\n\t\t\t *\n\t\t\t * @error model-liveposition-root-not-rootelement\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'model-liveposition-root-not-rootelement', root );\n\t\t}\n\n\t\tbindWithDocument.call( this );\n\t}\n\n\t/**\n\t * Unbinds all events previously bound by `LivePosition`. Use it whenever you don't need `LivePosition` instance\n\t * anymore (i.e. when leaving scope in which it was declared or before re-assigning variable that was\n\t * referring to it).\n\t */\n\tdetach() {\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Checks whether this object is of the given.\n\t *\n\t *\t\tlivePosition.is( 'position' ); // -> true\n\t *\t\tlivePosition.is( 'model:position' ); // -> true\n\t *\t\tlivePosition.is( 'liveposition' ); // -> true\n\t *\t\tlivePosition.is( 'model:livePosition' ); // -> true\n\t *\n\t *\t\tlivePosition.is( 'view:position' ); // -> false\n\t *\t\tlivePosition.is( 'documentSelection' ); // -> false\n\t *\n\t * {@link module:engine/model/node~Node#is Check the entire list of model objects} which implement the `is()` method.\n\t *\n\t * @param {String} type\n\t * @returns {Boolean}\n\t */\n\tis( type ) {\n\t\treturn type === 'livePosition' || type === 'model:livePosition' ||\n\t\t\t// From super.is(). This is highly utilised method and cannot call super. See ckeditor/ckeditor5#6529.\n\t\t\ttype == 'position' || type === 'model:position';\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/position~Position position instance}, which is equal to this live position.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\ttoPosition() {\n\t\treturn new Position( this.root, this.path.slice(), this.stickiness );\n\t}\n\n\t/**\n\t * Creates a `LivePosition` instance that is equal to position.\n\t *\n\t * @param {module:engine/model/position~Position} position\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness]\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tstatic fromPosition( position, stickiness ) {\n\t\treturn new this( position.root, position.path.slice(), stickiness ? stickiness : position.stickiness );\n\t}\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createAfter\n\t * @see module:engine/model/position~Position._createAfter\n\t * @param {module:engine/model/node~Node} node\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createBefore\n\t * @see module:engine/model/position~Position._createBefore\n\t * @param {module:engine/model/node~Node} node\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * @static\n\t * @protected\n\t * @method module:engine/model/liveposition~LivePosition._createAt\n\t * @see module:engine/model/position~Position._createAt\n\t * @param {module:engine/model/item~Item|module:engine/model/position~Position} itemOrPosition\n\t * @param {Number|'end'|'before'|'after'} [offset]\n\t * @param {module:engine/model/position~PositionStickiness} [stickiness='toNone']\n\t * @returns {module:engine/model/liveposition~LivePosition}\n\t */\n\n\t/**\n\t * Fired when `LivePosition` instance is changed due to changes on {@link module:engine/model/document~Document}.\n\t *\n\t * @event module:engine/model/liveposition~LivePosition#change\n\t * @param {module:engine/model/position~Position} oldPosition Position equal to this live position before it got changed.\n\t */\n}\n\n// Binds this `LivePosition` to the {@link module:engine/model/document~Document document} that owns\n// this position's {@link module:engine/model/position~Position#root root}.\n//\n// @private\nfunction bindWithDocument() {\n\tthis.listenTo(\n\t\tthis.root.document.model,\n\t\t'applyOperation',\n\t\t( event, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttransform.call( this, operation );\n\t\t},\n\t\t{ priority: 'low' }\n\t);\n}\n\n// Updates this position accordingly to the updates applied to the model. Bases on change events.\n//\n// @private\n// @param {module:engine/model/operation/operation~Operation} operation Executed operation.\nfunction transform( operation ) {\n\tconst result = this.getTransformedByOperation( operation );\n\n\tif ( !this.isEqual( result ) ) {\n\t\tconst oldPosition = this.toPosition();\n\n\t\tthis.path = result.path;\n\t\tthis.root = result.root;\n\n\t\tthis.fire( 'change', oldPosition );\n\t}\n}\n\nmix( LivePosition, EmitterMixin );\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<p>x^</p> + <p>y</p> => <p>x</p><p>y</p> => <p>xy[]</p>\n * \t\t<p>x^y</p> + <p>z</p> => <p>x</p>^<p>y</p> + <p>z</p> => <p>x</p><p>z</p><p>y</p> => <p>xz[]y</p>\n * \t\t<p>x^y</p> + <img /> => <p>x</p>^<p>y</p> + <img /> => <p>x</p><img /><p>y</p>\n * \t\t<p>x</p><p>^</p><p>z</p> + <p>y</p> => <p>x</p><p>y[]</p><p>z</p> (no merging)\n * \t\t<p>x</p>[<img />]<p>z</p> + <p>y</p> => <p>x</p>^<p>z</p> + <p>y</p> => <p>x</p><p>y[]</p><p>z</p>\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<p>x^</p><p>y</p> + <p>z</p> (can merge to <p>x</p>)\n\t\t *\t\t<p>x</p><p>^y</p> + <p>z</p> (can merge to <p>y</p>)\n\t\t *\t\t<p>x^y</p> + <p>z</p> (can merge to <p>xy</p> 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.<module:engine/model/node~Node>}\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.<module:engine/model/node~Node>} 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// <paragraph>Foo][bar</paragraph> -> <paragraph>Foo]xx[bar</paragraph>\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) <paragraph>Foo][</paragraph> -> <paragraph>Foo]xx[</paragraph>\n\t\t// (2) <paragraph>Foo]xx[</paragraph> -> <paragraph>Foo]xx</paragraph><widget></widget>[\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 `<paragraph>Abc</paragraph><paragraph>Xyz</paragraph>` at the end of `<paragraph>Foo^</paragraph>`:\n\t\t//\n\t\t// <paragraph>Foo</paragraph><paragraph>Bar</paragraph> -->\n\t\t// <paragraph>Foo</paragraph>]<paragraph>Abc</paragraph><paragraph>Xyz</paragraph>[<paragraph>Bar</paragraph> -->\n\t\t// <paragraph>Foo]Abc</paragraph><paragraph>Xyz</paragraph>[<paragraph>Bar</paragraph>\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// <p>A^A</p> + <p>X</p>\n\t\t//\n\t\t// <p>A</p>^<p>A</p>\n\t\t// <p>A</p><p>X</p><p>A</p>\n\t\t// <p>AX</p><p>A</p>\n\t\t// <p>AXA</p>\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 `<paragraph>Abc</paragraph>` at the of `<paragraph>Foo^</paragraph>`:\n\t\t//\n\t\t// <paragraph>Foo</paragraph><paragraph>Bar</paragraph> -->\n\t\t// <paragraph>Foo</paragraph>]<paragraph>Abc</paragraph>[<paragraph>Bar</paragraph> -->\n\t\t// <paragraph>Foo]Abc</paragraph>[<paragraph>Bar</paragraph> -->\n\t\t// <paragraph>Foo]Abc[</paragraph><paragraph>Bar</paragraph>\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// <p>x</p>[]<p>y</p> => <p>x[]</p><p>y</p>\n\t\tthis.position = Position._createAt( mergePosRight.nodeBefore, 'end' );\n\n\t\t// Explanation of setting position stickiness to `'toPrevious'`:\n\t\t// OK: <p>xx[]</p> + <p>yy</p> => <p>xx[]yy</p> (when sticks to previous)\n\t\t// NOK: <p>xx[]</p> + <p>yy</p> => <p>xxyy[]</p> (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// <p>A^A</p> + <p>X</p>\n\t\t//\n\t\t// <p>A</p>^<p>A</p>\n\t\t// <p>A</p><p>X</p><p>A</p>\n\t\t// <p>AX</p><p>A</p>\n\t\t// <p>AXA</p>\n\t\tif ( this._firstNode === this._lastNode ) {\n\t\t\tthis._firstNode = mergePosRight.nodeBefore;\n\t\t\tthis._lastNode = mergePosRight.nodeBefore;\n\t\t}\n\n\t\tthis.writer.merge( mergePosRight );\n\n\t\t// See comment in `_mergeOnLeft()` on moving `_affectedStart`.\n\t\tif ( mergePosRight.getShiftedBy( -1 ).isEqual( this._affectedStart ) && this._firstNode === this._lastNode ) {\n\t\t\tthis._affectedStart.detach();\n\t\t\tthis._affectedStart = LivePosition._createAt( mergePosRight.nodeBefore, 0, 'toPrevious' );\n\t\t}\n\n\t\tthis.position = livePosition.toPosition();\n\t\tlivePosition.detach();\n\n\t\t// After merge elements that were marked by _insert() to be filtered might be gone so\n\t\t// we need to mark the new container.\n\t\tthis._filterAttributesOf.push( this.position.parent );\n\n\t\tmergePosRight.detach();\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with previous sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @returns {Boolean}\n\t */\n\t_canMergeLeft( node ) {\n\t\tconst previousSibling = node.previousSibling;\n\n\t\treturn ( previousSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( previousSibling ) &&\n\t\t\tthis.model.schema.checkMerge( previousSibling, node );\n\t}\n\n\t/**\n\t * Checks whether specified node can be merged with next sibling element.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which could potentially be merged.\n\t * @returns {Boolean}\n\t */\n\t_canMergeRight( node ) {\n\t\tconst nextSibling = node.nextSibling;\n\n\t\treturn ( nextSibling instanceof Element ) &&\n\t\t\tthis.canMergeWith.has( nextSibling ) &&\n\t\t\tthis.model.schema.checkMerge( node, nextSibling );\n\t}\n\n\t/**\n\t * Tries wrapping the node in a new paragraph and inserting it this way.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node which needs to be autoparagraphed.\n\t */\n\t_tryAutoparagraphing( node ) {\n\t\tconst paragraph = this.writer.createElement( 'paragraph' );\n\n\t\t// Do not autoparagraph if the paragraph won't be allowed there,\n\t\t// cause that would lead to an infinite loop. The paragraph would be rejected in\n\t\t// the next _handleNode() call and we'd be here again.\n\t\tif ( this._getAllowedIn( paragraph, this.position.parent ) && this.schema.checkChild( paragraph, node ) ) {\n\t\t\tparagraph._appendChild( node );\n\t\t\tthis._handleNode( paragraph );\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a node can be inserted in the given position or it would be accepted if a paragraph would be inserted.\n\t * It also handles inserting the paragraph.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node.\n\t * @returns {Boolean} Whether an allowed position was found.\n\t * `false` is returned if the node isn't allowed at the current position or in auto paragraph, `true` if was.\n\t */\n\t_checkAndAutoParagraphToAllowedPosition( node ) {\n\t\tif ( this.schema.checkChild( this.position.parent, node ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Do not auto paragraph if the paragraph won't be allowed there,\n\t\t// cause that would lead to an infinite loop. The paragraph would be rejected in\n\t\t// the next _handleNode() call and we'd be here again.\n\t\tif ( !this.schema.checkChild( this.position.parent, 'paragraph' ) || !this.schema.checkChild( 'paragraph', node ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Insert nodes collected in temporary DocumentFragment if the position parent needs change to process further nodes.\n\t\tthis._insertPartialFragment();\n\n\t\t// Insert a paragraph and move insertion position to it.\n\t\tconst paragraph = this.writer.createElement( 'paragraph' );\n\n\t\tthis.writer.insert( paragraph, this.position );\n\t\tthis._setAffectedBoundaries( this.position );\n\n\t\tthis._lastAutoParagraph = paragraph;\n\t\tthis.position = this.writer.createPositionAt( paragraph, 0 );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/node~Node} node\n\t * @returns {Boolean} Whether an allowed position was found.\n\t * `false` is returned if the node isn't allowed at any position up in the tree, `true` if was.\n\t */\n\t_checkAndSplitToAllowedPosition( node ) {\n\t\tconst allowedIn = this._getAllowedIn( node, this.position.parent );\n\n\t\tif ( !allowedIn ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Insert nodes collected in temporary DocumentFragment if the position parent needs change to process further nodes.\n\t\tif ( allowedIn != this.position.parent ) {\n\t\t\tthis._insertPartialFragment();\n\t\t}\n\n\t\twhile ( allowedIn != this.position.parent ) {\n\t\t\t// If a parent which we'd need to leave is a limit element, break.\n\t\t\tif ( this.schema.isLimit( this.position.parent ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif ( this.position.isAtStart ) {\n\t\t\t\t// If insertion position is at the beginning of the parent, move it out instead of splitting.\n\t\t\t\t// <p>^Foo</p> -> ^<p>Foo</p>\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 (<p>^</p>).\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// <p>Foo^</p> -> <p>Foo</p>^\n\t\t\t\tthis.position = this.writer.createPositionAfter( this.position.parent );\n\t\t\t} else {\n\t\t\t\tconst tempPos = this.writer.createPositionAfter( this.position.parent );\n\n\t\t\t\tthis._setAffectedBoundaries( this.position );\n\t\t\t\tthis.writer.split( this.position );\n\n\t\t\t\tthis.position = tempPos;\n\n\t\t\t\tthis.canMergeWith.add( this.position.nodeAfter );\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Gets the element in which the given node is allowed. It checks the passed element and all its ancestors.\n\t *\n\t * @private\n\t * @param {module:engine/model/node~Node} node The node to check.\n\t * @param {module:engine/model/element~Element} element The element in which the node's correctness should be checked.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getAllowedIn( node, element ) {\n\t\tif ( this.schema.checkChild( element, node ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\tif ( element.parent ) {\n\t\t\treturn this._getAllowedIn( node, element.parent );\n\t\t}\n\n\t\treturn null;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/deletecontent\n */\n\nimport LivePosition from '../liveposition';\nimport Range from '../range';\nimport DocumentSelection from '../documentselection';\n\n/**\n * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.\n *\n * **Note:** Use {@link module:engine/model/model~Model#deleteContent} instead of this function.\n * This function is only exposed to be reusable in algorithms\n * which change the {@link module:engine/model/model~Model#deleteContent}\n * method's behavior.\n *\n * @param {module:engine/model/model~Model} model The model in context of which the insertion\n * should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * Selection of which the content should be deleted.\n * @param {Object} [options]\n * @param {Boolean} [options.leaveUnmerged=false] Whether to merge elements after removing the content of the selection.\n *\n * For example `<heading>x[x</heading><paragraph>y]y</paragraph>` will become:\n *\n * * `<heading>x^y</heading>` with the option disabled (`leaveUnmerged == false`)\n * * `<heading>x^</heading><paragraph>y</paragraph>` with enabled (`leaveUnmerged == true`).\n *\n * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}\n * elements will not be merged.\n *\n * @param {Boolean} [options.doNotResetEntireContent=false] Whether to skip replacing the entire content with a\n * paragraph when the entire content was selected.\n *\n * For example `<heading>[x</heading><paragraph>y]</paragraph>` will become:\n *\n * * `<paragraph>^</paragraph>` with the option disabled (`doNotResetEntireContent == false`)\n * * `<heading>^</heading>` with enabled (`doNotResetEntireContent == true`).\n *\n * @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved\n * to a place where text cannot be inserted.\n *\n * For example `<paragraph>x</paragraph>[<image src=\"foo.jpg\"></image>]` will become:\n *\n * * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)\n * * `<paragraph>x</paragraph>[]` with the option enabled (`doNotAutoparagraph == true`).\n *\n * If you use this option you need to make sure to handle invalid selections yourself or leave\n * them to the selection post-fixer (may not always work).\n *\n * **Note:** if there is no valid position for the selection, the paragraph will always be created:\n *\n * `[<image src=\"foo.jpg\"></image>]` -> `<paragraph>[]</paragraph>`.\n */\nexport default function deleteContent( model, selection, options = {} ) {\n\tif ( selection.isCollapsed ) {\n\t\treturn;\n\t}\n\n\tconst selRange = selection.getFirstRange();\n\n\t// If the selection is already removed, don't do anything.\n\tif ( selRange.root.rootName == '$graveyard' ) {\n\t\treturn;\n\t}\n\n\tconst schema = model.schema;\n\n\tmodel.change( writer => {\n\t\t// 1. Replace the entire content with paragraph.\n\t\t// See: https://github.com/ckeditor/ckeditor5-engine/issues/1012#issuecomment-315017594.\n\t\tif ( !options.doNotResetEntireContent && shouldEntireContentBeReplacedWithParagraph( schema, selection ) ) {\n\t\t\treplaceEntireContentWithParagraph( writer, selection, schema );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Get the live positions for the range adjusted to span only blocks selected from the user perspective.\n\t\tconst [ startPosition, endPosition ] = getLivePositionsForSelectedBlocks( selRange );\n\n\t\t// 2. Remove the content if there is any.\n\t\tif ( !startPosition.isTouching( endPosition ) ) {\n\t\t\twriter.remove( writer.createRange( startPosition, endPosition ) );\n\t\t}\n\n\t\t// 3. Merge elements in the right branch to the elements in the left branch.\n\t\t// The only reasonable (in terms of data and selection correctness) case in which we need to do that is:\n\t\t//\n\t\t// <heading type=1>Fo[</heading><paragraph>]ar</paragraph> => <heading type=1>Fo^ar</heading>\n\t\t//\n\t\t// However, the algorithm supports also merging deeper structures (up to the depth of the shallower branch),\n\t\t// as it's hard to imagine what should actually be the default behavior. Usually, specific features will\n\t\t// want to override that behavior anyway.\n\t\tif ( !options.leaveUnmerged ) {\n\t\t\tmergeBranches( writer, startPosition, endPosition );\n\n\t\t\t// TMP this will be replaced with a postfixer.\n\t\t\t// We need to check and strip disallowed attributes in all nested nodes because after merge\n\t\t\t// some attributes could end up in a path where are disallowed.\n\t\t\t//\n\t\t\t// e.g. bold is disallowed for <H1>\n\t\t\t// <h1>Fo{o</h1><p>b}a<b>r</b><p> -> <h1>Fo{}a<b>r</b><h1> -> <h1>Fo{}ar<h1>.\n\t\t\tschema.removeDisallowedAttributes( startPosition.parent.getChildren(), writer );\n\t\t}\n\n\t\tcollapseSelectionAt( writer, selection, startPosition );\n\n\t\t// 4. Add a paragraph to set selection in it.\n\t\t// Check if a text is allowed in the new container. If not, try to create a new paragraph (if it's allowed here).\n\t\t// If autoparagraphing is off, we assume that you know what you do so we leave the selection wherever it was.\n\t\tif ( !options.doNotAutoparagraph && shouldAutoparagraph( schema, startPosition ) ) {\n\t\t\tinsertParagraph( writer, startPosition, selection );\n\t\t}\n\n\t\tstartPosition.detach();\n\t\tendPosition.detach();\n\t} );\n}\n\n// Returns the live positions for the range adjusted to span only blocks selected from the user perspective. Example:\n//\n// <heading1>[foo</heading1>\n// <paragraph>bar</paragraph>\n// <heading1>]abc</heading1> <-- this block is not considered as selected\n//\n// This is the same behavior as in Selection#getSelectedBlocks() \"special case\".\nfunction getLivePositionsForSelectedBlocks( range ) {\n\tconst model = range.root.document.model;\n\n\tconst startPosition = range.start;\n\tlet endPosition = range.end;\n\n\t// If the end of selection is at the start position of last block in the selection, then\n\t// shrink it to not include that trailing block. Note that this should happen only for not empty selection.\n\tif ( model.hasContent( range, { ignoreMarkers: true } ) ) {\n\t\tconst endBlock = getParentBlock( endPosition );\n\n\t\tif ( endBlock && endPosition.isTouching( model.createPositionAt( endBlock, 0 ) ) ) {\n\t\t\t// Create forward selection as a probe to find a valid position after excluding last block from the range.\n\t\t\tconst selection = model.createSelection( range );\n\n\t\t\t// Modify the forward selection in backward direction to shrink it and remove first position of following block from it.\n\t\t\t// This is how modifySelection works and here we are making use of it.\n\t\t\tmodel.modifySelection( selection, { direction: 'backward' } );\n\n\t\t\tendPosition = selection.getLastPosition();\n\t\t}\n\t}\n\n\treturn [\n\t\tLivePosition.fromPosition( startPosition, 'toPrevious' ),\n\t\tLivePosition.fromPosition( endPosition, 'toNext' )\n\t];\n}\n\n// Finds the lowest element in position's ancestors which is a block.\n// Returns null if a limit element is encountered before reaching a block element.\nfunction getParentBlock( position ) {\n\tconst element = position.parent;\n\tconst schema = element.root.document.model.schema;\n\tconst ancestors = element.getAncestors( { parentFirst: true, includeSelf: true } );\n\n\tfor ( const element of ancestors ) {\n\t\tif ( schema.isLimit( element ) ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif ( schema.isBlock( element ) ) {\n\t\t\treturn element;\n\t\t}\n\t}\n}\n\n// This function is a result of reaching the Ballmer's peak for just the right amount of time.\n// Even I had troubles documenting it after a while and after reading it again I couldn't believe that it really works.\nfunction mergeBranches( writer, startPosition, endPosition ) {\n\tconst model = writer.model;\n\n\t// Verify if there is a need and possibility to merge.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// If the start element on the common ancestor level is empty, and the end element on the same level is not empty\n\t// then merge those to the right element so that it's properties are preserved (name, attributes).\n\t// Because of OT merging is used instead of removing elements.\n\t//\n\t// Merge left:\n\t// <heading1>foo[</heading1> -> <heading1>foo[]bar</heading1>\n\t// <paragraph>]bar</paragraph> -> --^\n\t//\n\t// Merge right:\n\t// <heading1>[</heading1> ->\n\t// <paragraph>]bar</paragraph> -> <paragraph>[]bar</paragraph>\n\t//\n\t// Merge left:\n\t// <blockQuote> -> <blockQuote>\n\t// <heading1>foo[</heading1> -> <heading1>foo[]bar</heading1>\n\t// <paragraph>]bar</paragraph> -> --^\n\t// </blockQuote> -> </blockQuote>\n\t//\n\t// Merge right:\n\t// <blockQuote> -> <blockQuote>\n\t// <heading1>[</heading1> ->\n\t// <paragraph>]bar</paragraph> -> <paragraph>[]bar</paragraph>\n\t// </blockQuote> -> </blockQuote>\n\n\t// Merging should not go deeper than common ancestor.\n\tconst [ startAncestor, endAncestor ] = getAncestorsJustBelowCommonAncestor( startPosition, endPosition );\n\n\t// Branches can't be merged if one of the positions is directly inside a common ancestor.\n\t//\n\t// Example:\n\t// <blockQuote>\n\t// <paragraph>[foo</paragraph>]\n\t// <table> ... </table>\n\t// <blockQuote>\n\t//\n\tif ( !startAncestor || !endAncestor ) {\n\t\treturn;\n\t}\n\n\tif ( !model.hasContent( startAncestor, { ignoreMarkers: true } ) && model.hasContent( endAncestor, { ignoreMarkers: true } ) ) {\n\t\tmergeBranchesRight( writer, startPosition, endPosition, startAncestor.parent );\n\t} else {\n\t\tmergeBranchesLeft( writer, startPosition, endPosition, startAncestor.parent );\n\t}\n}\n\n// Merging blocks to the left (properties of the left block are preserved).\n// Simple example:\n// <heading1>foo[</heading1> -> <heading1>foo[bar</heading1>]\n// <paragraph>]bar</paragraph> -> --^\n//\n// Nested example:\n// <blockQuote> -> <blockQuote>\n// <heading1>foo[</heading1> -> <heading1>foo[bar</heading1>\n// </blockQuote> -> </blockQuote>] ^\n// <blockBlock> -> |\n// <paragraph>]bar</paragraph> -> ---\n// </blockBlock> ->\n//\nfunction mergeBranchesLeft( writer, startPosition, endPosition, commonAncestor ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// Merging reached the common ancestor element, stop here.\n\tif ( startElement == commonAncestor || endElement == commonAncestor ) {\n\t\treturn;\n\t}\n\n\t// Remember next positions to merge in next recursive step (also used as modification points pointers).\n\tstartPosition = writer.createPositionAfter( startElement );\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Move endElement just after startElement if they aren't siblings.\n\tif ( !endPosition.isEqual( startPosition ) ) {\n\t\t//\n\t\t// <blockQuote> -> <blockQuote>\n\t\t// <heading1>foo[</heading1> -> <heading1>foo</heading1>[<paragraph>bar</paragraph>\n\t\t// </blockQuote> -> </blockQuote> ^\n\t\t// <blockBlock> -> <blockBlock> |\n\t\t// <paragraph>]bar</paragraph> -> ] ---\n\t\t// </blockBlock> -> </blockBlock>\n\t\t//\n\t\twriter.insert( endElement, startPosition );\n\t}\n\n\t// Merge two siblings (nodes on sides of startPosition):\n\t//\n\t// <blockQuote> -> <blockQuote>\n\t// <heading1>foo</heading1>[<paragraph>bar</paragraph> -> <heading1>foo[bar</heading1>\n\t// </blockQuote> -> </blockQuote>\n\t// <blockBlock> -> <blockBlock>\n\t// ] -> ]\n\t// </blockBlock> -> </blockBlock>\n\t//\n\t// Or in simple case (without moving elements in above if):\n\t// <heading1>foo</heading1>[<paragraph>bar</paragraph>] -> <heading1>foo[bar</heading1>]\n\t//\n\twriter.merge( startPosition );\n\n\t// Remove empty end ancestors:\n\t//\n\t// <blockQuote> -> <blockQuote>\n\t// <heading1>foo[bar</heading1> -> <heading1>foo[bar</heading1>\n\t// </blockQuote> -> </blockQuote>\n\t// <blockBlock> ->\n\t// ] -> ]\n\t// </blockBlock> ->\n\t//\n\twhile ( endPosition.parent.isEmpty ) {\n\t\tconst parentToRemove = endPosition.parent;\n\n\t\tendPosition = writer.createPositionBefore( parentToRemove );\n\n\t\twriter.remove( parentToRemove );\n\t}\n\n\t// Verify if there is a need and possibility to merge next level.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// Continue merging next level (blockQuote with blockBlock in the examples above if it would not be empty and got removed).\n\tmergeBranchesLeft( writer, startPosition, endPosition, commonAncestor );\n}\n\n// Merging blocks to the right (properties of the right block are preserved).\n// Simple example:\n// <heading1>foo[</heading1> -> --v\n// <paragraph>]bar</paragraph> -> [<paragraph>foo]bar</paragraph>\n//\n// Nested example:\n// <blockQuote> ->\n// <heading1>foo[</heading1> -> ---\n// </blockQuote> -> |\n// <blockBlock> -> [<blockBlock> v\n// <paragraph>]bar</paragraph> -> <paragraph>foo]bar</paragraph>\n// </blockBlock> -> </blockBlock>\n//\nfunction mergeBranchesRight( writer, startPosition, endPosition, commonAncestor ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// Merging reached the common ancestor element, stop here.\n\tif ( startElement == commonAncestor || endElement == commonAncestor ) {\n\t\treturn;\n\t}\n\n\t// Remember next positions to merge in next recursive step (also used as modification points pointers).\n\tstartPosition = writer.createPositionAfter( startElement );\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Move startElement just before endElement if they aren't siblings.\n\tif ( !endPosition.isEqual( startPosition ) ) {\n\t\t//\n\t\t// <blockQuote> -> <blockQuote>\n\t\t// <heading1>foo[</heading1> -> [ ---\n\t\t// </blockQuote> -> </blockQuote> |\n\t\t// <blockBlock> -> <blockBlock> v\n\t\t// <paragraph>]bar</paragraph> -> <heading1>foo</heading1>]<paragraph>bar</paragraph>\n\t\t// </blockBlock> -> </blockBlock>\n\t\t//\n\t\twriter.insert( startElement, endPosition );\n\t}\n\n\t// Remove empty end ancestors:\n\t//\n\t// <blockQuote> ->\n\t// [ -> [\n\t// </blockQuote> ->\n\t// <blockBlock> -> <blockBlock>\n\t// <heading1>foo</heading1>]<paragraph>bar</paragraph> -> <heading1>foo</heading1>]<paragraph>bar</paragraph>\n\t// </blockBlock> -> </blockBlock>\n\t//\n\twhile ( startPosition.parent.isEmpty ) {\n\t\tconst parentToRemove = startPosition.parent;\n\n\t\tstartPosition = writer.createPositionBefore( parentToRemove );\n\n\t\twriter.remove( parentToRemove );\n\t}\n\n\t// Update endPosition after inserting and removing elements.\n\tendPosition = writer.createPositionBefore( endElement );\n\n\t// Merge right two siblings (nodes on sides of endPosition):\n\t// ->\n\t// [ -> [\n\t// ->\n\t// <blockBlock> -> <blockBlock>\n\t// <heading1>foo</heading1>]<paragraph>bar</paragraph> -> <paragraph>foo]bar</paragraph>\n\t// </blockBlock> -> </blockBlock>\n\t//\n\t// Or in simple case (without moving elements in above if):\n\t// [<heading1>foo</heading1>]<paragraph>bar</paragraph> -> [<heading1>foo]bar</heading1>\n\t//\n\tmergeRight( writer, endPosition );\n\n\t// Verify if there is a need and possibility to merge next level.\n\tif ( !checkShouldMerge( writer.model.schema, startPosition, endPosition ) ) {\n\t\treturn;\n\t}\n\n\t// Continue merging next level (blockQuote with blockBlock in the examples above if it would not be empty and got removed).\n\tmergeBranchesRight( writer, startPosition, endPosition, commonAncestor );\n}\n\n// There is no right merge operation so we need to simulate it.\nfunction mergeRight( writer, position ) {\n\tconst startElement = position.nodeBefore;\n\tconst endElement = position.nodeAfter;\n\n\tif ( startElement.name != endElement.name ) {\n\t\twriter.rename( startElement, endElement.name );\n\t}\n\n\twriter.clearAttributes( startElement );\n\twriter.setAttributes( Object.fromEntries( endElement.getAttributes() ), startElement );\n\n\twriter.merge( position );\n}\n\n// Verifies if merging is needed and possible. It's not needed if both positions are in the same element\n// and it's not possible if some element is a limit or the range crosses a limit element.\nfunction checkShouldMerge( schema, startPosition, endPosition ) {\n\tconst startElement = startPosition.parent;\n\tconst endElement = endPosition.parent;\n\n\t// If both positions ended up in the same parent, then there's nothing more to merge:\n\t// <$root><p>x[</p><p>]y</p></$root> => <$root><p>xy</p>[]</$root>\n\tif ( startElement == endElement ) {\n\t\treturn false;\n\t}\n\n\t// If one of the positions is a limit element, then there's nothing to merge because we don't want to cross the limit boundaries.\n\tif ( schema.isLimit( startElement ) || schema.isLimit( endElement ) ) {\n\t\treturn false;\n\t}\n\n\t// Check if operations we'll need to do won't need to cross object or limit boundaries.\n\t// E.g., we can't merge endElement into startElement in this case:\n\t// <limit><startElement>x[</startElement></limit><endElement>]</endElement>\n\treturn isCrossingLimitElement( startPosition, endPosition, schema );\n}\n\n// Returns the elements that are the ancestors of the provided positions that are direct children of the common ancestor.\nfunction getAncestorsJustBelowCommonAncestor( positionA, positionB ) {\n\tconst ancestorsA = positionA.getAncestors();\n\tconst ancestorsB = positionB.getAncestors();\n\n\tlet i = 0;\n\n\twhile ( ancestorsA[ i ] && ancestorsA[ i ] == ancestorsB[ i ] ) {\n\t\ti++;\n\t}\n\n\treturn [ ancestorsA[ i ], ancestorsB[ i ] ];\n}\n\nfunction shouldAutoparagraph( schema, position ) {\n\tconst isTextAllowed = schema.checkChild( position, '$text' );\n\tconst isParagraphAllowed = schema.checkChild( position, 'paragraph' );\n\n\treturn !isTextAllowed && isParagraphAllowed;\n}\n\n// Check if parents of two positions can be merged by checking if there are no limit/object\n// boundaries between those two positions.\n//\n// E.g. in <bQ><p>x[]</p></bQ><widget><caption>{}</caption></widget>\n// we'll check <p>, <bQ>, <widget> and <caption>.\n// Usually, widget and caption are marked as objects/limits in the schema, so in this case merging will be blocked.\nfunction isCrossingLimitElement( leftPos, rightPos, schema ) {\n\tconst rangeToCheck = new Range( leftPos, rightPos );\n\n\tfor ( const value of rangeToCheck.getWalker() ) {\n\t\tif ( schema.isLimit( value.item ) ) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction insertParagraph( writer, position, selection ) {\n\tconst paragraph = writer.createElement( 'paragraph' );\n\n\twriter.insert( paragraph, position );\n\n\tcollapseSelectionAt( writer, selection, writer.createPositionAt( paragraph, 0 ) );\n}\n\nfunction replaceEntireContentWithParagraph( writer, selection ) {\n\tconst limitElement = writer.model.schema.getLimitElement( selection );\n\n\twriter.remove( writer.createRangeIn( limitElement ) );\n\tinsertParagraph( writer, writer.createPositionAt( limitElement, 0 ), selection );\n}\n\n// We want to replace the entire content with a paragraph when:\n// * the entire content is selected,\n// * selection contains at least two elements,\n// * whether the paragraph is allowed in schema in the common ancestor.\nfunction shouldEntireContentBeReplacedWithParagraph( schema, selection ) {\n\tconst limitElement = schema.getLimitElement( selection );\n\n\tif ( !selection.containsEntireContent( limitElement ) ) {\n\t\treturn false;\n\t}\n\n\tconst range = selection.getFirstRange();\n\n\tif ( range.start.parent == range.end.parent ) {\n\t\treturn false;\n\t}\n\n\treturn schema.checkChild( limitElement, 'paragraph' );\n}\n\n// Helper function that sets the selection. Depending whether given `selection` is a document selection or not,\n// uses a different method to set it.\nfunction collapseSelectionAt( writer, selection, positionOrRange ) {\n\tif ( selection instanceof DocumentSelection ) {\n\t\twriter.setSelection( positionOrRange );\n\t} else {\n\t\tselection.setTo( positionOrRange );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/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</$text> bazbaz'\n\t\t\t// should expand to : 'foofoo [bar<$text bold=\"true\">bar</$text>] 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 `<softBreak>`).\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/getselectedcontent\n */\n\n/**\n * Gets a clone of the selected content.\n *\n * For example, for the following selection:\n *\n * ```html\n * <p>x</p><quote><p>y</p><h>fir[st</h></quote><p>se]cond</p><p>z</p>\n * ```\n *\n * It will return a document fragment with such a content:\n *\n * ```html\n * <quote><h>st</h></quote><p>se</p>\n * ```\n *\n * @param {module:engine/model/model~Model} model The model in context of which\n * the selection modification should be performed.\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection of which content will be returned.\n * @returns {module:engine/model/documentfragment~DocumentFragment}\n */\nexport default function getSelectedContent( model, selection ) {\n\treturn model.change( writer => {\n\t\tconst frag = writer.createDocumentFragment();\n\t\tconst range = selection.getFirstRange();\n\n\t\tif ( !range || range.isCollapsed ) {\n\t\t\treturn frag;\n\t\t}\n\n\t\tconst root = range.start.root;\n\t\tconst commonPath = range.start.getCommonPath( range.end );\n\t\tconst commonParent = root.getNodeByPath( commonPath );\n\n\t\t// ## 1st step\n\t\t//\n\t\t// First, we'll clone a fragment represented by a minimal flat range\n\t\t// containing the original range to be cloned.\n\t\t// E.g. let's consider such a range:\n\t\t//\n\t\t// <p>x</p><quote><p>y</p><h>fir[st</h></quote><p>se]cond</p><p>z</p>\n\t\t//\n\t\t// A minimal flat range containing this one is:\n\t\t//\n\t\t// <p>x</p>[<quote><p>y</p><h>first</h></quote><p>second</p>]<p>z</p>\n\t\t//\n\t\t// We can easily clone this structure, preserving e.g. the <quote> element.\n\t\tlet flatSubtreeRange;\n\n\t\tif ( range.start.parent == range.end.parent ) {\n\t\t\t// The original range is flat, so take it.\n\t\t\tflatSubtreeRange = range;\n\t\t} else {\n\t\t\tflatSubtreeRange = writer.createRange(\n\t\t\t\twriter.createPositionAt( commonParent, range.start.path[ commonPath.length ] ),\n\t\t\t\twriter.createPositionAt( commonParent, range.end.path[ commonPath.length ] + 1 )\n\t\t\t);\n\t\t}\n\n\t\tconst howMany = flatSubtreeRange.end.offset - flatSubtreeRange.start.offset;\n\n\t\t// Clone the whole contents.\n\t\tfor ( const item of flatSubtreeRange.getItems( { shallow: true } ) ) {\n\t\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\t\twriter.appendText( item.data, item.getAttributes(), frag );\n\t\t\t} else {\n\t\t\t\twriter.append( writer.cloneElement( item, true ), frag );\n\t\t\t}\n\t\t}\n\n\t\t// ## 2nd step\n\t\t//\n\t\t// If the original range wasn't flat, then we need to remove the excess nodes from the both ends of the cloned fragment.\n\t\t//\n\t\t// For example, for the range shown in the 1st step comment, we need to remove these pieces:\n\t\t//\n\t\t// <quote>[<p>y</p>]<h>[fir]st</h></quote><p>se[cond]</p>\n\t\t//\n\t\t// So this will be the final copied content:\n\t\t//\n\t\t// <quote><h>st</h></quote><p>se</p>\n\t\t//\n\t\t// In order to do that, we remove content from these two ranges:\n\t\t//\n\t\t// [<quote><p>y</p><h>fir]st</h></quote><p>se[cond</p>]\n\t\tif ( flatSubtreeRange != range ) {\n\t\t\t// Find the position of the original range in the cloned fragment.\n\t\t\tconst newRange = range._getTransformedByMove( flatSubtreeRange.start, writer.createPositionAt( frag, 0 ), howMany )[ 0 ];\n\n\t\t\tconst leftExcessRange = writer.createRange( writer.createPositionAt( frag, 0 ), newRange.start );\n\t\t\tconst rightExcessRange = writer.createRange( newRange.end, writer.createPositionAt( frag, 'end' ) );\n\n\t\t\tremoveRangeContent( rightExcessRange, writer );\n\t\t\tremoveRangeContent( leftExcessRange, writer );\n\t\t}\n\n\t\treturn frag;\n\t} );\n}\n\n// After https://github.com/ckeditor/ckeditor5-engine/issues/690 is fixed,\n// this function will, most likely, be able to rewritten using getMinimalFlatRanges().\nfunction removeRangeContent( range, writer ) {\n\tconst parentsToCheck = [];\n\n\tArray.from( range.getItems( { direction: 'backward' } ) )\n\t\t// We should better store ranges because text proxies will lose integrity\n\t\t// with the text nodes when we'll start removing content.\n\t\t.map( item => writer.createRangeOn( item ) )\n\t\t// Filter only these items which are fully contained in the passed range.\n\t\t//\n\t\t// E.g. for the following range: [<quote><p>y</p><h>fir]st</h>\n\t\t// the walker will return the entire <h> element, when only the \"fir\" item inside it is fully contained.\n\t\t.filter( itemRange => {\n\t\t\t// We should be able to use Range.containsRange, but https://github.com/ckeditor/ckeditor5-engine/issues/691.\n\t\t\tconst contained =\n\t\t\t\t( itemRange.start.isAfter( range.start ) || itemRange.start.isEqual( range.start ) ) &&\n\t\t\t\t( itemRange.end.isBefore( range.end ) || itemRange.end.isEqual( range.end ) );\n\n\t\t\treturn contained;\n\t\t} )\n\t\t.forEach( itemRange => {\n\t\t\tparentsToCheck.push( itemRange.start.parent );\n\n\t\t\twriter.remove( itemRange );\n\t\t} );\n\n\t// Remove ancestors of the removed items if they turned to be empty now\n\t// (their whole content was contained in the range).\n\tparentsToCheck.forEach( parentToCheck => {\n\t\tlet parent = parentToCheck;\n\n\t\twhile ( parent.parent && parent.isEmpty ) {\n\t\t\tconst removeRange = writer.createRangeOn( parent );\n\n\t\t\tparent = parent.parent;\n\n\t\t\twriter.remove( removeRange );\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/model/utils/selection-post-fixer\n */\n\nimport Range from '../range';\nimport Position from '../position';\n\n/**\n * Injects selection post-fixer to the model.\n *\n * The role of the selection post-fixer is to ensure that the selection is in a correct place\n * after a {@link module:engine/model/model~Model#change `change()`} block was executed.\n *\n * The correct position means that:\n *\n * * All collapsed selection ranges are in a place where the {@link module:engine/model/schema~Schema}\n * allows a `$text`.\n * * None of the selection's non-collapsed ranges crosses a {@link module:engine/model/schema~Schema#isLimit limit element}\n * boundary (a range must be rooted within one limit element).\n * * Only {@link module:engine/model/schema~Schema#isSelectable selectable elements} can be selected from the outside\n * (e.g. `[<paragraph>foo</paragraph>]` is invalid). This rule applies independently to both selection ends, so this\n * selection is correct: `<paragraph>f[oo</paragraph><image></image>]`.\n *\n * If the position is not correct, the post-fixer will automatically correct it.\n *\n * ## Fixing a non-collapsed selection\n *\n * See as an example a selection that starts in a P1 element and ends inside the text of a TD element\n * (`[` and `]` are range boundaries and `(l)` denotes an element defined as `isLimit=true`):\n *\n *\t\troot\n *\t\t |- element P1\n *\t\t | |- \"foo\" root\n *\t\t |- element TABLE (l) P1 TABLE P2\n *\t\t | |- element TR (l) f o[o TR TR b a r\n *\t\t | | |- element TD (l) TD TD\n *\t\t | | |- \"aaa\" a]a a b b b\n *\t\t | |- element TR (l)\n *\t\t | | |- element TD (l) ||\n *\t\t | | |- \"bbb\" ||\n *\t\t |- element P2 VV\n *\t\t | |- \"bar\"\n *\t\t root\n *\t\t P1 TABLE] P2\n *\t\t f o[o TR TR b a r\n *\t\t TD TD\n *\t\t a a a b b b\n *\n * In the example above, the TABLE, TR and TD are defined as `isLimit=true` in the schema. The range which is not contained within\n * a single limit element must be expanded to select the outermost limit element. The range end is inside the text node of the TD element.\n * As the TD element is a child of the TR and TABLE elements, where both are defined as `isLimit=true` in the schema, the range must be\n * expanded to select the whole TABLE element.\n *\n * **Note** If the selection contains multiple ranges, the method returns a minimal set of ranges that are not intersecting after expanding\n * them to select `isLimit=true` elements.\n *\n * @param {module:engine/model/model~Model} model\n */\nexport function injectSelectionPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => selectionPostFixer( writer, model ) );\n}\n\n// The selection post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction selectionPostFixer( writer, model ) {\n\tconst selection = model.document.selection;\n\tconst schema = model.schema;\n\n\tconst ranges = [];\n\n\tlet wasFixed = false;\n\n\tfor ( const modelRange of selection.getRanges() ) {\n\t\t// Go through all ranges in selection and try fixing each of them.\n\t\t// Those ranges might overlap but will be corrected later.\n\t\tconst correctedRange = tryFixingRange( modelRange, schema );\n\n\t\t// \"Selection fixing\" algorithms sometimes get lost. In consequence, it may happen\n\t\t// that a new range is returned but, in fact, it has the same positions as the original\n\t\t// range anyway. If this range is not discarded, a new selection will be set and that,\n\t\t// for instance, would destroy the selection attributes. Let's make sure that the post-fixer\n\t\t// actually worked first before setting a new selection.\n\t\t//\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6693\n\t\tif ( correctedRange && !correctedRange.isEqual( modelRange ) ) {\n\t\t\tranges.push( correctedRange );\n\t\t\twasFixed = true;\n\t\t} else {\n\t\t\tranges.push( modelRange );\n\t\t}\n\t}\n\n\t// If any of ranges were corrected update the selection.\n\tif ( wasFixed ) {\n\t\twriter.setSelection( mergeIntersectingRanges( ranges ), { backward: selection.isBackward } );\n\t}\n}\n\n// Tries fixing a range if it's incorrect.\n//\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingRange( range, schema ) {\n\tif ( range.isCollapsed ) {\n\t\treturn tryFixingCollapsedRange( range, schema );\n\t}\n\n\treturn tryFixingNonCollapsedRage( range, schema );\n}\n\n// Tries to fix collapsed ranges.\n//\n// * Fixes situation when a range is in a place where $text is not allowed\n//\n// @param {module:engine/model/range~Range} range Collapsed range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingCollapsedRange( range, schema ) {\n\tconst originalPosition = range.start;\n\n\tconst nearestSelectionRange = schema.getNearestSelectionRange( originalPosition );\n\n\t// This might be null ie when editor data is empty.\n\t// In such cases there is no need to fix the selection range.\n\tif ( !nearestSelectionRange ) {\n\t\treturn null;\n\t}\n\n\tif ( !nearestSelectionRange.isCollapsed ) {\n\t\treturn nearestSelectionRange;\n\t}\n\n\tconst fixedPosition = nearestSelectionRange.start;\n\n\t// Fixed position is the same as original - no need to return corrected range.\n\tif ( originalPosition.isEqual( fixedPosition ) ) {\n\t\treturn null;\n\t}\n\n\treturn new Range( fixedPosition );\n}\n\n// Tries to fix an expanded range.\n//\n// @param {module:engine/model/range~Range} range Expanded range to fix.\n// @param {module:engine/model/schema~Schema} schema\n// @returns {module:engine/model/range~Range|null} Returns fixed range or null if range is valid.\nfunction tryFixingNonCollapsedRage( range, schema ) {\n\tconst { start, end } = range;\n\n\tconst isTextAllowedOnStart = schema.checkChild( start, '$text' );\n\tconst isTextAllowedOnEnd = schema.checkChild( end, '$text' );\n\n\tconst startLimitElement = schema.getLimitElement( start );\n\tconst endLimitElement = schema.getLimitElement( end );\n\n\t// Ranges which both end are inside the same limit element (or root) might needs only minor fix.\n\tif ( startLimitElement === endLimitElement ) {\n\t\t// Range is valid when both position allows to place a text:\n\t\t// - <block>f[oobarba]z</block>\n\t\t// This would be \"fixed\" by a next check but as it will be the same it's better to return null so the selection stays the same.\n\t\tif ( isTextAllowedOnStart && isTextAllowedOnEnd ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Range that is on non-limit element (or is partially) must be fixed so it is placed inside the block around $text:\n\t\t// - [<block>foo</block>] -> <block>[foo]</block>\n\t\t// - [<block>foo]</block> -> <block>[foo]</block>\n\t\t// - <block>f[oo</block>] -> <block>f[oo]</block>\n\t\t// - [<block>foo</block><selectable></selectable>] -> <block>[foo</block><selectable></selectable>]\n\t\tif ( checkSelectionOnNonLimitElements( start, end, schema ) ) {\n\t\t\tconst isStartBeforeSelectable = start.nodeAfter && schema.isSelectable( start.nodeAfter );\n\t\t\tconst fixedStart = isStartBeforeSelectable ? null : schema.getNearestSelectionRange( start, 'forward' );\n\n\t\t\tconst isEndAfterSelectable = end.nodeBefore && schema.isSelectable( end.nodeBefore );\n\t\t\tconst fixedEnd = isEndAfterSelectable ? null : schema.getNearestSelectionRange( end, 'backward' );\n\n\t\t\t// The schema.getNearestSelectionRange might return null - if that happens use original position.\n\t\t\tconst rangeStart = fixedStart ? fixedStart.start : start;\n\t\t\tconst rangeEnd = fixedEnd ? fixedEnd.end : end;\n\n\t\t\treturn new Range( rangeStart, rangeEnd );\n\t\t}\n\t}\n\n\tconst isStartInLimit = startLimitElement && !startLimitElement.is( 'rootElement' );\n\tconst isEndInLimit = endLimitElement && !endLimitElement.is( 'rootElement' );\n\n\t// At this point we eliminated valid positions on text nodes so if one of range positions is placed inside a limit element\n\t// then the range crossed limit element boundaries and needs to be fixed.\n\tif ( isStartInLimit || isEndInLimit ) {\n\t\tconst bothInSameParent = ( start.nodeAfter && end.nodeBefore ) && start.nodeAfter.parent === end.nodeBefore.parent;\n\n\t\tconst expandStart = isStartInLimit && ( !bothInSameParent || !isSelectable( start.nodeAfter, schema ) );\n\t\tconst expandEnd = isEndInLimit && ( !bothInSameParent || !isSelectable( end.nodeBefore, schema ) );\n\n\t\t// Although we've already found limit element on start/end positions we must find the outer-most limit element.\n\t\t// as limit elements might be nested directly inside (ie table > tableRow > tableCell).\n\t\tlet fixedStart = start;\n\t\tlet fixedEnd = end;\n\n\t\tif ( expandStart ) {\n\t\t\tfixedStart = Position._createBefore( findOutermostLimitAncestor( startLimitElement, schema ) );\n\t\t}\n\n\t\tif ( expandEnd ) {\n\t\t\tfixedEnd = Position._createAfter( findOutermostLimitAncestor( endLimitElement, schema ) );\n\t\t}\n\n\t\treturn new Range( fixedStart, fixedEnd );\n\t}\n\n\t// Range was not fixed at this point so it is valid - ie it was placed around limit element already.\n\treturn null;\n}\n\n// Finds the outer-most ancestor.\n//\n// @param {module:engine/model/node~Node} startingNode\n// @param {module:engine/model/schema~Schema} schema\n// @param {String} expandToDirection Direction of expansion - either 'start' or 'end' of the range.\n// @returns {module:engine/model/node~Node}\nfunction findOutermostLimitAncestor( startingNode, schema ) {\n\tlet isLimitNode = startingNode;\n\tlet parent = isLimitNode;\n\n\t// Find outer most isLimit block as such blocks might be nested (ie. in tables).\n\twhile ( schema.isLimit( parent ) && parent.parent ) {\n\t\tisLimitNode = parent;\n\t\tparent = parent.parent;\n\t}\n\n\treturn isLimitNode;\n}\n\n// Checks whether any of range boundaries is placed around non-limit elements.\n//\n// @param {module:engine/model/position~Position} start\n// @param {module:engine/model/position~Position} end\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction checkSelectionOnNonLimitElements( start, end, schema ) {\n\tconst startIsOnBlock = ( start.nodeAfter && !schema.isLimit( start.nodeAfter ) ) || schema.checkChild( start, '$text' );\n\tconst endIsOnBlock = ( end.nodeBefore && !schema.isLimit( end.nodeBefore ) ) || schema.checkChild( end, '$text' );\n\n\t// We should fix such selection when one of those nodes needs fixing.\n\treturn startIsOnBlock || endIsOnBlock;\n}\n\n// Returns a minimal non-intersecting array of ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges\n// @returns {Array.<module:engine/model/range~Range>}\nfunction mergeIntersectingRanges( ranges ) {\n\tconst nonIntersectingRanges = [];\n\n\t// First range will always be fine.\n\tnonIntersectingRanges.push( ranges.shift() );\n\n\tfor ( const range of ranges ) {\n\t\tconst previousRange = nonIntersectingRanges.pop();\n\n\t\tif ( range.isEqual( previousRange ) ) {\n\t\t\t// Use only one of two identical ranges.\n\t\t\tnonIntersectingRanges.push( previousRange );\n\t\t} else if ( range.isIntersecting( previousRange ) ) {\n\t\t\t// Get the sum of two ranges.\n\t\t\tconst start = previousRange.start.isAfter( range.start ) ? range.start : previousRange.start;\n\t\t\tconst end = previousRange.end.isAfter( range.end ) ? previousRange.end : range.end;\n\n\t\t\tconst merged = new Range( start, end );\n\t\t\tnonIntersectingRanges.push( merged );\n\t\t} else {\n\t\t\tnonIntersectingRanges.push( previousRange );\n\t\t\tnonIntersectingRanges.push( range );\n\t\t}\n\t}\n\n\treturn nonIntersectingRanges;\n}\n\n// Checks if node exists and if it's a selectable.\n//\n// @param {module:engine/model/node~Node} node\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isSelectable( node, schema ) {\n\treturn node && schema.isSelectable( node );\n}\n","/**\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/model\n */\n\nimport Batch from './batch';\nimport Writer from './writer';\nimport Schema from './schema';\nimport Document from './document';\nimport MarkerCollection from './markercollection';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ModelElement from './element';\nimport ModelRange from './range';\nimport ModelPosition from './position';\nimport ModelSelection from './selection';\nimport OperationFactory from './operation/operationfactory';\n\nimport insertContent from './utils/insertcontent';\nimport deleteContent from './utils/deletecontent';\nimport modifySelection from './utils/modifyselection';\nimport getSelectedContent from './utils/getselectedcontent';\nimport { injectSelectionPostFixer } from './utils/selection-post-fixer';\nimport { autoParagraphEmptyRoots } from './utils/autoparagraphing';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n// @if CK_DEBUG_ENGINE // const { dumpTrees } = require( '../dev-utils/utils' );\n// @if CK_DEBUG_ENGINE // const { OperationReplayer } = require( '../dev-utils/operationreplayer' ).default;\n\n/**\n * Editor's data model. Read about the model in the\n * {@glink framework/guides/architecture/editing-engine engine architecture guide}.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Model {\n\tconstructor() {\n\t\t/**\n\t\t * Model's marker collection.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/markercollection~MarkerCollection}\n\t\t */\n\t\tthis.markers = new MarkerCollection();\n\n\t\t/**\n\t\t * Model's document.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/document~Document}\n\t\t */\n\t\tthis.document = new Document( this );\n\n\t\t/**\n\t\t * Model's schema.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/schema~Schema}\n\t\t */\n\t\tthis.schema = new Schema();\n\n\t\t/**\n\t\t * All callbacks added by {@link module:engine/model/model~Model#change} or\n\t\t * {@link module:engine/model/model~Model#enqueueChange} methods waiting to be executed.\n\t\t *\n\t\t * @private\n\t\t * @type {Array.<Function>}\n\t\t */\n\t\tthis._pendingChanges = [];\n\n\t\t/**\n\t\t * The last created and currently used writer instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/writer~Writer}\n\t\t */\n\t\tthis._currentWriter = null;\n\n\t\t[ 'insertContent', 'deleteContent', 'modifySelection', 'getSelectedContent', 'applyOperation' ]\n\t\t\t.forEach( methodName => this.decorate( methodName ) );\n\n\t\t// Adding operation validation with `highest` priority, so it is called before any other feature would like\n\t\t// to do anything with the operation. If the operation has incorrect parameters it should throw on the earliest occasion.\n\t\tthis.on( 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\toperation._validate();\n\t\t}, { priority: 'highest' } );\n\n\t\t// Register some default abstract entities.\n\t\tthis.schema.register( '$root', {\n\t\t\tisLimit: true\n\t\t} );\n\n\t\tthis.schema.register( '$block', {\n\t\t\tallowIn: '$root',\n\t\t\tisBlock: true\n\t\t} );\n\n\t\tthis.schema.register( '$text', {\n\t\t\tallowIn: '$block',\n\t\t\tisInline: true,\n\t\t\tisContent: true\n\t\t} );\n\n\t\tthis.schema.register( '$clipboardHolder', {\n\t\t\tallowContentOf: '$root',\n\t\t\tisLimit: true\n\t\t} );\n\t\tthis.schema.extend( '$text', { allowIn: '$clipboardHolder' } );\n\n\t\tthis.schema.register( '$documentFragment', {\n\t\t\tallowContentOf: '$root',\n\t\t\tisLimit: true\n\t\t} );\n\t\tthis.schema.extend( '$text', { allowIn: '$documentFragment' } );\n\n\t\t// An element needed by the `upcastElementToMarker` converter.\n\t\t// This element temporarily represents a marker boundary during the conversion process and is removed\n\t\t// at the end of the conversion. `UpcastDispatcher` or at least `Conversion` class looks like a\n\t\t// better place for this registration but both know nothing about `Schema`.\n\t\tthis.schema.register( '$marker' );\n\t\tthis.schema.addChildCheck( ( context, childDefinition ) => {\n\t\t\tif ( childDefinition.name === '$marker' ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} );\n\n\t\tinjectSelectionPostFixer( this );\n\n\t\t// Post-fixer which takes care of adding empty paragraph elements to the empty roots.\n\t\tthis.document.registerPostFixer( autoParagraphEmptyRoots );\n\n\t\t// @if CK_DEBUG_ENGINE // this.on( 'applyOperation', () => {\n\t\t// @if CK_DEBUG_ENGINE // \tdumpTrees( this.document, this.document.version );\n\t\t// @if CK_DEBUG_ENGINE // }, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * The `change()` method is the primary way of changing the model. You should use it to modify all document nodes\n\t * (including detached nodes i.e. nodes not added to the {@link module:engine/model/model~Model#document model document}),\n\t * the {@link module:engine/model/document~Document#selection document's selection}, and\n\t * {@link module:engine/model/model~Model#markers model markers}.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t} );\n\t *\n\t * All changes inside the change block use the same {@link module:engine/model/batch~Batch} so they are combined\n\t * into a single undo step.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' ); // foo.\n\t *\n\t *\t\t\tmodel.change( writer => {\n\t *\t\t\t\twriter.insertText( 'bar', paragraph, 'end' ); // foobar.\n\t *\t\t\t} );\n\t *\n\t * \t\t\twriter.insertText( 'bom', paragraph, 'end' ); // foobarbom.\n\t *\t\t} );\n\t *\n\t * The callback of the `change()` block is executed synchronously.\n\t *\n\t * You can also return a value from the change block.\n\t *\n\t *\t\tconst img = model.change( writer => {\n\t *\t\t\treturn writer.createElement( 'img' );\n\t *\t\t} );\n\t *\n\t * @see #enqueueChange\n\t * @param {Function} callback Callback function which may modify the model.\n\t * @returns {*} Value returned by the callback.\n\t */\n\tchange( callback ) {\n\t\ttry {\n\t\t\tif ( this._pendingChanges.length === 0 ) {\n\t\t\t\t// If this is the outermost block, create a new batch and start `_runPendingChanges` execution flow.\n\t\t\t\tthis._pendingChanges.push( { batch: new Batch(), callback } );\n\n\t\t\t\treturn this._runPendingChanges()[ 0 ];\n\t\t\t} else {\n\t\t\t\t// If this is not the outermost block, just execute the callback.\n\t\t\t\treturn callback( this._currentWriter );\n\t\t\t}\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * The `enqueueChange()` method performs similar task as the {@link #change `change()` method}, with two major differences.\n\t *\n\t * First, the callback of `enqueueChange()` is executed when all other enqueued changes are done. It might be executed\n\t * immediately if it is not nested in any other change block, but if it is nested in another (enqueue)change block,\n\t * it will be delayed and executed after the outermost block.\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconsole.log( 1 );\n\t *\n\t *\t\t\tmodel.enqueueChange( writer => {\n\t *\t\t\t\tconsole.log( 2 );\n\t *\t\t\t} );\n\t *\n\t * \t\t\tconsole.log( 3 );\n\t *\t\t} ); // Will log: 1, 3, 2.\n\t *\n\t * In addition to that, the changes enqueued with `enqueueChange()` will be converted separately from the changes\n\t * done in the outer `change()` block.\n\t *\n\t * Second, it lets you define the {@link module:engine/model/batch~Batch} into which you want to add your changes.\n\t * By default, a new batch is created. In the sample above, `change` and `enqueueChange` blocks use a different\n\t * batch (and different {@link module:engine/model/writer~Writer} since each of them operates on the separate batch).\n\t *\n\t * When using the `enqueueChange()` block you can also add some changes to the batch you used before.\n\t *\n\t *\t\tmodel.enqueueChange( batch, writer => {\n\t *\t\t\twriter.insertText( 'foo', paragraph, 'end' );\n\t *\t\t} );\n\t *\n\t * In order to make a nested `enqueueChange()` create a single undo step together with the changes done in the outer `change()`\n\t * block, you can obtain the batch instance from the {@link module:engine/model/writer~Writer#batch writer} of the outer block.\n\t *\n\t * @param {module:engine/model/batch~Batch|'transparent'|'default'} batchOrType Batch or batch type should be used in the callback.\n\t * If not defined, a new batch will be created.\n\t * @param {Function} callback Callback function which may modify the model.\n\t */\n\tenqueueChange( batchOrType, callback ) {\n\t\ttry {\n\t\t\tif ( typeof batchOrType === 'string' ) {\n\t\t\t\tbatchOrType = new Batch( batchOrType );\n\t\t\t} else if ( typeof batchOrType == 'function' ) {\n\t\t\t\tcallback = batchOrType;\n\t\t\t\tbatchOrType = new Batch();\n\t\t\t}\n\n\t\t\tthis._pendingChanges.push( { batch: batchOrType, callback } );\n\n\t\t\tif ( this._pendingChanges.length == 1 ) {\n\t\t\t\tthis._runPendingChanges();\n\t\t\t}\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * {@link module:utils/observablemixin~ObservableMixin#decorate Decorated} function for applying\n\t * {@link module:engine/model/operation/operation~Operation operations} to the model.\n\t *\n\t * This is a low-level way of changing the model. It is exposed for very specific use cases (like the undo feature).\n\t * Normally, to modify the model, you will want to use {@link module:engine/model/writer~Writer `Writer`}.\n\t * See also {@glink framework/guides/architecture/editing-engine#changing-the-model Changing the model} section\n\t * of the {@glink framework/guides/architecture/editing-engine Editing architecture} guide.\n\t *\n\t * @param {module:engine/model/operation/operation~Operation} operation The operation to apply.\n\t */\n\tapplyOperation( operation ) {\n\t\t// @if CK_DEBUG_ENGINE // console.log( 'Applying ' + operation );\n\n\t\t// @if CK_DEBUG_ENGINE // if ( !this._operationLogs ) {\n\t\t// @if CK_DEBUG_ENGINE //\tthis._operationLogs = [];\n\t\t// @if CK_DEBUG_ENGINE // }\n\n\t\t// @if CK_DEBUG_ENGINE // this._operationLogs.push( JSON.stringify( operation ) );\n\n\t\t// @if CK_DEBUG_ENGINE //if ( !this._appliedOperations ) {\n\t\t// @if CK_DEBUG_ENGINE //\tthis._appliedOperations = [];\n\t\t// @if CK_DEBUG_ENGINE //}\n\n\t\t// @if CK_DEBUG_ENGINE //this._appliedOperations.push( operation );\n\n\t\toperation._execute();\n\t}\n\n\t// @if CK_DEBUG_ENGINE // getAppliedOperation() {\n\t// @if CK_DEBUG_ENGINE //\tif ( !this._appliedOperations ) {\n\t// @if CK_DEBUG_ENGINE //\t\treturn '';\n\t// @if CK_DEBUG_ENGINE //\t}\n\n\t// @if CK_DEBUG_ENGINE //\treturn this._appliedOperations.map( JSON.stringify ).join( '-------' );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t// @if CK_DEBUG_ENGINE // createReplayer( stringifiedOperations ) {\n\t// @if CK_DEBUG_ENGINE //\treturn new OperationReplayer( this, '-------', stringifiedOperations );\n\t// @if CK_DEBUG_ENGINE // }\n\n\t/**\n\t * Inserts content at the position in the editor specified by the selection, as one would expect the paste\n\t * functionality to work.\n\t *\n\t * This is a high-level method. It takes the {@link #schema schema} into consideration when inserting\n\t * the content, clears the given selection's content before inserting nodes and moves the selection\n\t * to its target position at the end of the process.\n\t * It can split elements, merge them, wrap bare text nodes with paragraphs, etc. &mdash; just like the\n\t * pasting feature should do.\n\t *\n\t * For lower-level methods see {@link module:engine/model/writer~Writer `Writer`}.\n\t *\n\t * This method, unlike {@link module:engine/model/writer~Writer `Writer`}'s methods, does not have to be used\n\t * inside a {@link #change `change()` block}.\n\t *\n\t * # Conversion and schema\n\t *\n\t * Inserting elements and text nodes into the model is not enough to make CKEditor 5 render that content\n\t * to the user. CKEditor 5 implements a model-view-controller architecture and what `model.insertContent()` does\n\t * is only adding nodes to the model. Additionally, you need to define\n\t * {@glink framework/guides/architecture/editing-engine#conversion converters} between the model and view\n\t * and define those nodes in the {@glink framework/guides/architecture/editing-engine#schema schema}.\n\t *\n\t * So, while this method may seem similar to CKEditor 4 `editor.insertHtml()` (in fact, both methods\n\t * are used for paste-like content insertion), the CKEditor 5 method cannot be use to insert arbitrary HTML\n\t * unless converters are defined for all elements and attributes in that HTML.\n\t *\n\t * # Examples\n\t *\n\t * Using `insertContent()` with a manually created model structure:\n\t *\n\t *\t\t// Let's create a document fragment containing such content as:\n\t *\t\t//\n\t *\t\t// <paragraph>foo</paragraph>\n\t *\t\t// <blockQuote>\n\t *\t\t// <paragraph>bar</paragraph>\n\t *\t\t// </blockQuote>\n\t *\t\tconst docFrag = editor.model.change( writer => {\n\t *\t\t\tconst p1 = writer.createElement( 'paragraph' );\n\t *\t\t\tconst p2 = writer.createElement( 'paragraph' );\n\t *\t\t\tconst blockQuote = writer.createElement( 'blockQuote' );\n\t *\t\t\tconst docFrag = writer.createDocumentFragment();\n\t *\n\t *\t\t\twriter.append( p1, docFrag );\n\t *\t\t\twriter.append( blockQuote, docFrag );\n\t *\t\t\twriter.append( p2, blockQuote );\n\t *\t\t\twriter.insertText( 'foo', p1 );\n\t *\t\t\twriter.insertText( 'bar', p2 );\n\t *\n\t *\t\t\treturn docFrag;\n\t *\t\t} );\n\t *\n\t *\t\t// insertContent() does not have to be used in a change() block. It can, though,\n\t *\t\t// so this code could be moved to the callback defined above.\n\t *\t\teditor.model.insertContent( docFrag );\n\t *\n\t * Using `insertContent()` with an HTML string converted to a model document fragment (similar to the pasting mechanism):\n\t *\n\t *\t\t// You can create your own HtmlDataProcessor instance or use editor.data.processor\n\t *\t\t// if you have not overridden the default one (which is the HtmlDataProcessor instance).\n\t *\t\tconst htmlDP = new HtmlDataProcessor( viewDocument );\n\t *\n\t *\t\t// Convert an HTML string to a view document fragment:\n\t *\t\tconst viewFragment = htmlDP.toView( htmlString );\n\t *\n\t *\t\t// Convert the view document fragment to a model document fragment\n\t *\t\t// in the context of $root. This conversion takes the schema into\n\t *\t\t// account so if, for example, the view document fragment contained a bare text node,\n\t *\t\t// this text node cannot be a child of $root, so it will be automatically\n\t *\t\t// wrapped with a <paragraph>. You can define the context yourself (in the second parameter),\n\t *\t\t// and e.g. convert the content like it would happen in a <paragraph>.\n\t *\t\t// Note: The clipboard feature uses a custom context called $clipboardHolder\n\t *\t\t// which has a loosened schema.\n\t *\t\tconst modelFragment = editor.data.toModel( viewFragment );\n\t *\n\t *\t\teditor.model.insertContent( modelFragment );\n\t *\n\t * By default this method will use the document selection but it can also be used with a position, range or selection instance.\n\t *\n\t *\t\t// Insert text at the current document selection position.\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ) );\n\t *\t\t} );\n\t *\n\t *\t\t// Insert text at a given position - the document selection will not be modified.\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), doc.getRoot(), 2 );\n\t *\n\t *\t\t\t// Which is a shorthand for:\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), writer.createPositionAt( doc.getRoot(), 2 ) );\n\t *\t\t} );\n\t *\n\t * If you want the document selection to be moved to the inserted content, use the\n\t * {@link module:engine/model/writer~Writer#setSelection `setSelection()`} method of the writer after inserting\n\t * the content:\n\t *\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\n\t *\t\t\t// Insert an empty paragraph at the beginning of the root.\n\t *\t\t\teditor.model.insertContent( paragraph, writer.createPositionAt( editor.model.document.getRoot(), 0 ) );\n\t *\n\t *\t\t\t// Move the document selection to the inserted paragraph.\n\t *\t\t\twriter.setSelection( paragraph, 'in' );\n\t *\t\t} );\n\t *\n\t * If an instance of the {@link module:engine/model/selection~Selection model selection} is passed as `selectable`,\n\t * the new content will be inserted at the passed selection (instead of document selection):\n\t *\n\t *\t\teditor.model.change( writer => {\n\t *\t\t\t// Create a selection in a paragraph that will be used as a place of insertion.\n\t *\t\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t\t// Insert the new text at the created selection.\n\t *\t\t\teditor.model.insertContent( writer.createText( 'x' ), selection );\n\t *\n\t *\t\t\t// insertContent() modifies the passed selection instance so it can be used to set the document selection.\n\t *\t\t\t// Note: This is not necessary when you passed the document selection to insertContent().\n\t *\t\t\twriter.setSelection( selection );\n\t *\t\t} );\n\t *\n\t * @fires insertContent\n\t * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n\t * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n\t * The selection into which the content should be inserted. If not provided the current model document selection will be used.\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] To be used when a model item was passed as `selectable`.\n\t * This param defines a position in relation to that item.\n\t * @returns {module:engine/model/range~Range} Range which contains all the performed changes. This is a range that, if removed,\n\t * would return the model to the state before the insertion. If no changes were preformed by `insertContent`, returns a range collapsed\n\t * at the insertion position.\n\t */\n\tinsertContent( content, selectable, placeOrOffset ) {\n\t\treturn insertContent( this, content, selectable, placeOrOffset );\n\t}\n\n\t/**\n\t * Deletes content of the selection and merge siblings. The resulting selection is always collapsed.\n\t *\n\t * **Note:** For the sake of predictability, the resulting selection should always be collapsed.\n\t * In cases where a feature wants to modify deleting behavior so selection isn't collapsed\n\t * (e.g. a table feature may want to keep row selection after pressing <kbd>Backspace</kbd>),\n\t * then that behavior should be implemented in the view's listener. At the same time, the table feature\n\t * will need to modify this method's behavior too, e.g. to \"delete contents and then collapse\n\t * the selection inside the last selected cell\" or \"delete the row and collapse selection somewhere near\".\n\t * That needs to be done in order to ensure that other features which use `deleteContent()` will work well with tables.\n\t *\n\t * @fires deleteContent\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * Selection of which the content should be deleted.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.leaveUnmerged=false] Whether to merge elements after removing the content of the selection.\n\t *\n\t * For example `<heading1>x[x</heading1><paragraph>y]y</paragraph>` will become:\n\t *\n\t * * `<heading1>x^y</heading1>` with the option disabled (`leaveUnmerged == false`)\n\t * * `<heading1>x^</heading1><paragraph>y</paragraph>` with enabled (`leaveUnmerged == true`).\n\t *\n\t * Note: {@link module:engine/model/schema~Schema#isObject object} and {@link module:engine/model/schema~Schema#isLimit limit}\n\t * elements will not be merged.\n\t *\n\t * @param {Boolean} [options.doNotResetEntireContent=false] Whether to skip replacing the entire content with a\n\t * paragraph when the entire content was selected.\n\t *\n\t * For example `<heading1>[x</heading1><paragraph>y]</paragraph>` will become:\n\t *\n\t * * `<paragraph>^</paragraph>` with the option disabled (`doNotResetEntireContent == false`)\n\t * * `<heading1>^</heading1>` with enabled (`doNotResetEntireContent == true`)\n\t *\n\t * @param {Boolean} [options.doNotAutoparagraph=false] Whether to create a paragraph if after content deletion selection is moved\n\t * to a place where text cannot be inserted.\n\t *\n\t * For example `<paragraph>x</paragraph>[<image src=\"foo.jpg\"></image>]` will become:\n\t *\n\t * * `<paragraph>x</paragraph><paragraph>[]</paragraph>` with the option disabled (`doNotAutoparagraph == false`)\n\t * * `<paragraph>x[]</paragraph>` with the option enabled (`doNotAutoparagraph == true`).\n\t *\n\t * **Note:** if there is no valid position for the selection, the paragraph will always be created:\n\t *\n\t * `[<image src=\"foo.jpg\"></image>]` -> `<paragraph>[]</paragraph>`.\n\t *\n\t * @param {'forward'|'backward'} [options.direction='backward'] The direction in which the content is being consumed.\n\t * Deleting backward corresponds to using the <kbd>Backspace</kbd> key, while deleting content forward corresponds to\n\t * the <kbd>Shift</kbd>+<kbd>Backspace</kbd> keystroke.\n\t */\n\tdeleteContent( selection, options ) {\n\t\tdeleteContent( this, selection, options );\n\t}\n\n\t/**\n\t * Modifies the selection. Currently, the supported modifications are:\n\t *\n\t * * Extending. The selection focus is moved in the specified `options.direction` with a step specified in `options.unit`.\n\t * Possible values for `unit` are:\n\t * * `'character'` (default) - moves selection by one user-perceived character. In most cases this means moving by one\n\t * character in `String` sense. However, unicode also defines \"combing marks\". These are special symbols, that combines\n\t * with a symbol before it (\"base character\") to create one user-perceived character. For example, `q̣̇` is a normal\n\t * letter `q` with two \"combining marks\": upper dot (`Ux0307`) and lower dot (`Ux0323`). For most actions, i.e. extending\n\t * selection by one position, it is correct to include both \"base character\" and all of it's \"combining marks\". That is\n\t * why `'character'` value is most natural and common method of modifying selection.\n\t * * `'codePoint'` - moves selection by one unicode code point. In contrary to, `'character'` unit, this will insert\n\t * selection between \"base character\" and \"combining mark\", because \"combining marks\" have their own unicode code points.\n\t * However, for technical reasons, unicode code points with values above `UxFFFF` are represented in native `String` by\n\t * two characters, called \"surrogate pairs\". Halves of \"surrogate pairs\" have a meaning only when placed next to each other.\n\t * For example `𨭎` is represented in `String` by `\\uD862\\uDF4E`. Both `\\uD862` and `\\uDF4E` do not have any meaning\n\t * outside the pair (are rendered as ? when alone). Position between them would be incorrect. In this case, selection\n\t * extension will include whole \"surrogate pair\".\n\t * * `'word'` - moves selection by a whole word.\n\t *\n\t * **Note:** if you extend a forward selection in a backward direction you will in fact shrink it.\n\t *\n\t * @fires modifySelection\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * The selection to modify.\n\t * @param {Object} [options]\n\t * @param {'forward'|'backward'} [options.direction='forward'] The direction in which the selection should be modified.\n\t * @param {'character'|'codePoint'|'word'} [options.unit='character'] The unit by which selection should be modified.\n\t */\n\tmodifySelection( selection, options ) {\n\t\tmodifySelection( this, selection, options );\n\t}\n\n\t/**\n\t * Gets a clone of the selected content.\n\t *\n\t * For example, for the following selection:\n\t *\n\t * ```html\n\t * <paragraph>x</paragraph>\n\t * <blockQuote>\n\t *\t<paragraph>y</paragraph>\n\t *\t<heading1>fir[st</heading1>\n\t * </blockQuote>\n\t * <paragraph>se]cond</paragraph>\n\t * <paragraph>z</paragraph>\n\t * ```\n\t *\n\t * It will return a document fragment with such a content:\n\t *\n\t * ```html\n\t * <blockQuote>\n\t *\t<heading1>st</heading1>\n\t * </blockQuote>\n\t * <paragraph>se</paragraph>\n\t * ```\n\t *\n\t * @fires getSelectedContent\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n\t * The selection of which content will be returned.\n\t * @returns {module:engine/model/documentfragment~DocumentFragment}\n\t */\n\tgetSelectedContent( selection ) {\n\t\treturn getSelectedContent( this, selection );\n\t}\n\n\t/**\n\t * Checks whether the given {@link module:engine/model/range~Range range} or\n\t * {@link module:engine/model/element~Element element} has any meaningful content.\n\t *\n\t * Meaningful content is:\n\t *\n\t * * any text node (`options.ignoreWhitespaces` allows controlling whether this text node must also contain\n\t * any non-whitespace characters),\n\t * * or any {@link module:engine/model/schema~Schema#isContent content element},\n\t * * or any {@link module:engine/model/markercollection~Marker marker} which\n\t * {@link module:engine/model/markercollection~Marker#_affectsData affects data}.\n\t *\n\t * This means that a range containing an empty `<paragraph></paragraph>` is not considered to have a meaningful content.\n\t * However, a range containing an `<image></image>` (which would normally be marked in the schema as an object element)\n\t * is considered non-empty.\n\t *\n\t * @param {module:engine/model/range~Range|module:engine/model/element~Element} rangeOrElement Range or element to check.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.ignoreWhitespaces] Whether text node with whitespaces only should be considered empty.\n\t * @param {Boolean} [options.ignoreMarkers] Whether markers should be ignored.\n\t * @returns {Boolean}\n\t */\n\thasContent( rangeOrElement, options = {} ) {\n\t\tconst range = rangeOrElement instanceof ModelElement ? ModelRange._createIn( rangeOrElement ) : rangeOrElement;\n\n\t\tif ( range.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst { ignoreWhitespaces = false, ignoreMarkers = false } = options;\n\n\t\t// Check if there are any markers which affects data in this given range.\n\t\tif ( !ignoreMarkers ) {\n\t\t\tfor ( const intersectingMarker of this.markers.getMarkersIntersectingRange( range ) ) {\n\t\t\t\tif ( intersectingMarker.affectsData ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor ( const item of range.getItems() ) {\n\t\t\tif ( this.schema.isContent( item ) ) {\n\t\t\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\t\t\tif ( !ignoreWhitespaces ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( item.data.search( /\\S/ ) !== -1 ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Creates a position from the given root and path in that root.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionFromPath `Writer#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.<Number>} 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 new ModelPosition( root, path, stickiness );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/model/position~Position position},\n\t * * a parent element and offset in that element,\n\t * * a parent element and `'end'` (the position will be set at the end of that element),\n\t * * a {@link module:engine/model/item~Item model item} and `'before'` or `'after'`\n\t * (the position will be set before or after the given model item).\n\t *\n\t * This method is a shortcut to other factory methods such as:\n\t *\n\t * * {@link module:engine/model/model~Model#createPositionBefore `createPositionBefore()`},\n\t * * {@link module:engine/model/model~Model#createPositionAfter `createPositionAfter()`}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionAt `Writer#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 */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn ModelPosition._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionAfter `Writer#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 ModelPosition._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before the given {@link module:engine/model/item~Item model item}.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createPositionBefore `Writer#createPositionBefore()`}.\n\t *\n\t * @param {module:engine/model/item~Item} item Item before which the position should be placed.\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn ModelPosition._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from the `start` position to the `end` position.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createRange `Writer#createRange()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRange( start, end );\n\t *\t\t} );\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, the range will be collapsed\n\t * to the `start` position.\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new ModelRange( start, end );\n\t}\n\n\t/**\n\t * Creates a range inside the given 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 * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createRangeIn `Writer#createRangeIn()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRangeIn( paragraph );\n\t *\t\t} );\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 ModelRange._createIn( element );\n\t}\n\n\t/**\n\t * Creates a range that starts before the given {@link module:engine/model/item~Item model item} and ends after it.\n\t *\n\t * Note: This method is also available on `writer` instance as\n\t * {@link module:engine/model/writer~Writer#createRangeOn `Writer.createRangeOn()`}:\n\t *\n\t *\t\tmodel.change( writer => {\n\t *\t\t\tconst range = writer.createRangeOn( paragraph );\n\t *\t\t} );\n\t *\n\t * @param {module:engine/model/item~Item} item\n\t * @returns {module:engine/model/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn ModelRange._createOn( item );\n\t}\n\n\t/**\n\t * Creates a new selection instance based on the given {@link module:engine/model/selection~Selectable selectable}\n\t * or creates an empty selection if no arguments were passed.\n\t *\n\t * Note: This method is also available as\n\t * {@link module:engine/model/writer~Writer#createSelection `Writer#createSelection()`}.\n\t *\n\t *\t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t *\t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the given document selection.\n\t *\t\t// Note: It doesn't copies selection attributes.\n\t *\t\tconst documentSelection = model.document.selection;\n\t *\t\tconst selection = writer.createSelection( documentSelection );\n\t *\n\t *\t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates selection at the given offset in the given element.\n\t *\t\tconst paragraph = writer.createElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/model/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/model/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t *\t\t// Additional options (`'backward'`) can be specified as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\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 new ModelSelection( selectable, placeOrOffset, options );\n\t}\n\n\t/**\n\t * Creates a {@link module:engine/model/batch~Batch} instance.\n\t *\n\t * **Note:** In most cases creating a batch instance is not necessary as they are created when using:\n\t *\n\t * * {@link #change `change()`},\n\t * * {@link #enqueueChange `enqueueChange()`}.\n\t *\n\t * @param {'transparent'|'default'} [type='default'] The type of the batch.\n\t * @returns {module:engine/model/batch~Batch}\n\t */\n\tcreateBatch( type ) {\n\t\treturn new Batch( type );\n\t}\n\n\t/**\n\t * Creates an operation instance from a JSON object (parsed JSON string).\n\t *\n\t * This is an alias for {@link module:engine/model/operation/operationfactory~OperationFactory.fromJSON `OperationFactory.fromJSON()`}.\n\t *\n\t * @param {Object} json Deserialized JSON object.\n\t * @returns {module:engine/model/operation/operation~Operation}\n\t */\n\tcreateOperationFromJSON( json ) {\n\t\treturn OperationFactory.fromJSON( json, this.document );\n\t}\n\n\t/**\n\t * Removes all events listeners set by model instance and destroys {@link module:engine/model/document~Document}.\n\t */\n\tdestroy() {\n\t\tthis.document.destroy();\n\t\tthis.stopListening();\n\t}\n\n\t/**\n\t * Common part of {@link module:engine/model/model~Model#change} and {@link module:engine/model/model~Model#enqueueChange}\n\t * which calls callbacks and returns array of values returned by these callbacks.\n\t *\n\t * @private\n\t * @returns {Array.<*>} Array of values returned by callbacks.\n\t */\n\t_runPendingChanges() {\n\t\tconst ret = [];\n\n\t\tthis.fire( '_beforeChanges' );\n\n\t\twhile ( this._pendingChanges.length ) {\n\t\t\t// Create a new writer using batch instance created for this chain of changes.\n\t\t\tconst currentBatch = this._pendingChanges[ 0 ].batch;\n\t\t\tthis._currentWriter = new Writer( this, currentBatch );\n\n\t\t\t// Execute changes callback and gather the returned value.\n\t\t\tconst callbackReturnValue = this._pendingChanges[ 0 ].callback( this._currentWriter );\n\t\t\tret.push( callbackReturnValue );\n\n\t\t\tthis.document._handleChangeBlock( this._currentWriter );\n\n\t\t\tthis._pendingChanges.shift();\n\t\t\tthis._currentWriter = null;\n\t\t}\n\n\t\tthis.fire( '_afterChanges' );\n\n\t\treturn ret;\n\t}\n\n\t/**\n\t * Fired when entering the outermost {@link module:engine/model/model~Model#enqueueChange} or\n\t * {@link module:engine/model/model~Model#change} block.\n\t *\n\t * @protected\n\t * @event _beforeChanges\n\t */\n\n\t/**\n\t * Fired when leaving the outermost {@link module:engine/model/model~Model#enqueueChange} or\n\t * {@link module:engine/model/model~Model#change} block.\n\t *\n\t * @protected\n\t * @event _afterChanges\n\t */\n\n\t/**\n\t * Fired every time any {@link module:engine/model/operation/operation~Operation operation} is applied on the model\n\t * using {@link #applyOperation}.\n\t *\n\t * Note that this event is suitable only for very specific use-cases. Use it if you need to listen to every single operation\n\t * applied on the document. However, in most cases {@link module:engine/model/document~Document#event:change} should\n\t * be used.\n\t *\n\t * A few callbacks are already added to this event by engine internal classes:\n\t *\n\t * * with `highest` priority operation is validated,\n\t * * with `normal` priority operation is executed,\n\t * * with `low` priority the {@link module:engine/model/document~Document} updates its version,\n\t * * with `low` priority {@link module:engine/model/liveposition~LivePosition} and {@link module:engine/model/liverange~LiveRange}\n\t * update themselves.\n\t *\n\t * @event applyOperation\n\t * @param {Array} args Arguments of the `applyOperation` which is an array with a single element - applied\n\t * {@link module:engine/model/operation/operation~Operation operation}.\n\t */\n\n\t/**\n\t * Event fired when {@link #insertContent} method is called.\n\t *\n\t * The {@link #insertContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * **Note** The `selectable` parameter for the {@link #insertContent} is optional. When `undefined` value is passed the method uses\n\t * `model.document.selection`.\n\t *\n\t * @event insertContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #deleteContent} method is called.\n\t *\n\t * The {@link #deleteContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event deleteContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #modifySelection} method is called.\n\t *\n\t * The {@link #modifySelection default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event modifySelection\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n\n\t/**\n\t * Event fired when {@link #getSelectedContent} method is called.\n\t *\n\t * The {@link #getSelectedContent default action of that method} is implemented as a\n\t * listener to this event so it can be fully customized by the features.\n\t *\n\t * @event getSelectedContent\n\t * @param {Array} args The arguments passed to the original method.\n\t */\n}\n\nmix( Model, ObservableMixin );\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 core/editingkeystrokehandler\n */\n\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\n/**\n * A keystroke handler for editor editing. Its instance is available\n * in {@link module:core/editor/editor~Editor#keystrokes} so plugins\n * can register their keystrokes.\n *\n * E.g. an undo plugin would do this:\n *\n *\t\teditor.keystrokes.set( 'Ctrl+Z', 'undo' );\n *\t\teditor.keystrokes.set( 'Ctrl+Shift+Z', 'redo' );\n *\t\teditor.keystrokes.set( 'Ctrl+Y', 'redo' );\n *\n * @extends module:utils/keystrokehandler~KeystrokeHandler\n */\nexport default class EditingKeystrokeHandler extends KeystrokeHandler {\n\t/**\n\t * Creates an instance of the keystroke handler.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t */\n\tconstructor( editor ) {\n\t\tsuper();\n\n\t\t/**\n\t\t * The editor instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\t}\n\n\t/**\n\t * Registers a handler for the specified keystroke.\n\t *\n\t * The handler can be specified as a command name or a callback.\n\t *\n\t * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by\n\t * the {@link module:utils/keyboard~parseKeystroke} function.\n\t * @param {Function|String} callback If a string is passed, then the keystroke will\n\t * {@link module:core/editor/editor~Editor#execute execute a command}.\n\t * If a function, then it will be called with the\n\t * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and\n\t * a `cancel()` helper to both `preventDefault()` and `stopPropagation()` of the event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of the keystroke\n\t * callback. The higher the priority value the sooner the callback will be executed. Keystrokes having the same priority\n\t * are called in the order they were added.\n\t */\n\tset( keystroke, callback, options = {} ) {\n\t\tif ( typeof callback == 'string' ) {\n\t\t\tconst commandName = callback;\n\n\t\t\tcallback = ( evtData, cancel ) => {\n\t\t\t\tthis.editor.execute( commandName );\n\t\t\t\tcancel();\n\t\t\t};\n\t\t}\n\n\t\tsuper.set( keystroke, callback, options );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module core/editor/editor\n */\n\nimport Context from '../context';\nimport Config from '@ckeditor/ckeditor5-utils/src/config';\nimport EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';\nimport PluginCollection from '../plugincollection';\nimport CommandCollection from '../commandcollection';\nimport DataController from '@ckeditor/ckeditor5-engine/src/controller/datacontroller';\nimport Conversion from '@ckeditor/ckeditor5-engine/src/conversion/conversion';\nimport Model from '@ckeditor/ckeditor5-engine/src/model/model';\nimport EditingKeystrokeHandler from '../editingkeystrokehandler';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport { StylesProcessor } from '@ckeditor/ckeditor5-engine/src/view/stylesmap';\n\n/**\n * The class representing a basic, generic editor.\n *\n * Check out the list of its subclasses to learn about specific editor implementations.\n *\n * All editor implementations (like {@link module:editor-classic/classiceditor~ClassicEditor} or\n * {@link module:editor-inline/inlineeditor~InlineEditor}) should extend this class. They can add their\n * own methods and properties.\n *\n * When you are implementing a plugin, this editor represents the API\n * which your plugin can expect to get when using its {@link module:core/plugin~Plugin#editor} property.\n *\n * This API should be sufficient in order to implement the \"editing\" part of your feature\n * (schema definition, conversion, commands, keystrokes, etc.).\n * It does not define the editor UI, which is available only if\n * the specific editor implements also the {@link module:core/editor/editorwithui~EditorWithUI} interface\n * (as most editor implementations do).\n *\n * @abstract\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Editor {\n\t/**\n\t * Creates a new instance of the editor class.\n\t *\n\t * Usually, not to be used directly. See the static {@link module:core/editor/editor~Editor.create `create()`} method.\n\t *\n\t * @param {Object} [config={}] The editor configuration.\n\t */\n\tconstructor( config = {} ) {\n\t\t/**\n\t\t * The editor context.\n\t\t * When it is not provided through the configuration, the editor creates it.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:core/context~Context}\n\t\t */\n\t\tthis._context = config.context || new Context( { language: config.language } );\n\t\tthis._context._addEditor( this, !config.context );\n\n\t\t// Clone the plugins to make sure that the plugin array will not be shared\n\t\t// between editors and make the watchdog feature work correctly.\n\t\tconst availablePlugins = Array.from( this.constructor.builtinPlugins || [] );\n\n\t\t/**\n\t\t * Stores all configurations specific to this editor instance.\n\t\t *\n\t\t *\t\teditor.config.get( 'image.toolbar' );\n\t\t *\t\t// -> [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/config~Config}\n\t\t */\n\t\tthis.config = new Config( config, this.constructor.defaultConfig );\n\t\tthis.config.define( 'plugins', availablePlugins );\n\t\tthis.config.define( this._context._getEditorConfig() );\n\n\t\t/**\n\t\t * The plugins loaded and in use by this editor instance.\n\t\t *\n\t\t *\t\teditor.plugins.get( 'ClipboardPipeline' ); // -> An instance of the clipboard pipeline plugin.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/plugincollection~PluginCollection}\n\t\t */\n\t\tthis.plugins = new PluginCollection( this, availablePlugins, this._context.plugins );\n\n\t\t/**\n\t\t * The locale instance.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = this._context.locale;\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method #t\n\t\t */\n\t\tthis.t = this.locale.t;\n\n\t\t/**\n\t\t * Commands registered to the editor.\n\t\t *\n\t\t * Use the shorthand {@link #execute `editor.execute()`} method to execute commands:\n\t\t *\n\t\t *\t\t// Execute the bold command:\n\t\t *\t\teditor.execute( 'bold' );\n\t\t *\n\t\t *\t\t// Check the state of the bold command:\n\t\t *\t\teditor.commands.get( 'bold' ).value;\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/commandcollection~CommandCollection}\n\t\t */\n\t\tthis.commands = new CommandCollection();\n\n\t\t/**\n\t\t * Indicates the editor life-cycle state.\n\t\t *\n\t\t * The editor is in one of the following states:\n\t\t *\n\t\t * * `initializing` &ndash; During the editor initialization (before\n\t\t * {@link module:core/editor/editor~Editor.create `Editor.create()`}) finished its job.\n\t\t * * `ready` &ndash; After the promise returned by the {@link module:core/editor/editor~Editor.create `Editor.create()`}\n\t\t * method is resolved.\n\t\t * * `destroyed` &ndash; Once the {@link #destroy `editor.destroy()`} method was called.\n\t\t *\n\t\t * @observable\n\t\t * @member {'initializing'|'ready'|'destroyed'} #state\n\t\t */\n\t\tthis.set( 'state', 'initializing' );\n\t\tthis.once( 'ready', () => ( this.state = 'ready' ), { priority: 'high' } );\n\t\tthis.once( 'destroy', () => ( this.state = 'destroyed' ), { priority: 'high' } );\n\n\t\t/**\n\t\t * Defines whether this editor is in read-only mode.\n\t\t *\n\t\t * In read-only mode the editor {@link #commands commands} are disabled so it is not possible\n\t\t * to modify the document by using them. Also, the editable element(s) become non-editable.\n\t\t *\n\t\t * In order to make the editor read-only, you can set this value directly:\n\t\t *\n\t\t *\t\teditor.isReadOnly = true;\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * The editor's model.\n\t\t *\n\t\t * The central point of the editor's abstract data model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = new Model();\n\n\t\tconst stylesProcessor = new StylesProcessor();\n\n\t\t/**\n\t\t * The {@link module:engine/controller/datacontroller~DataController data controller}.\n\t\t * Used e.g. for setting and retrieving the editor data.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/datacontroller~DataController}\n\t\t */\n\t\tthis.data = new DataController( this.model, stylesProcessor );\n\n\t\t/**\n\t\t * The {@link module:engine/controller/editingcontroller~EditingController editing controller}.\n\t\t * Controls user input and rendering the content for editing.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/editingcontroller~EditingController}\n\t\t */\n\t\tthis.editing = new EditingController( this.model, stylesProcessor );\n\t\tthis.editing.view.document.bind( 'isReadOnly' ).to( this );\n\n\t\t/**\n\t\t * Conversion manager through which you can register model-to-view and view-to-model converters.\n\t\t *\n\t\t * See the {@link module:engine/conversion/conversion~Conversion} documentation to learn how to add converters.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/conversion/conversion~Conversion}\n\t\t */\n\t\tthis.conversion = new Conversion( [ this.editing.downcastDispatcher, this.data.downcastDispatcher ], this.data.upcastDispatcher );\n\t\tthis.conversion.addAlias( 'dataDowncast', this.data.downcastDispatcher );\n\t\tthis.conversion.addAlias( 'editingDowncast', this.editing.downcastDispatcher );\n\n\t\t/**\n\t\t * An instance of the {@link module:core/editingkeystrokehandler~EditingKeystrokeHandler}.\n\t\t *\n\t\t * It allows setting simple keystrokes:\n\t\t *\n\t\t *\t\t// Execute the bold command on Ctrl+E:\n\t\t *\t\teditor.keystrokes.set( 'Ctrl+E', 'bold' );\n\t\t *\n\t\t *\t\t// Execute your own callback:\n\t\t *\t\teditor.keystrokes.set( 'Ctrl+E', ( data, cancel ) => {\n\t\t *\t\t\tconsole.log( data.keyCode );\n\t\t *\n\t\t *\t\t\t// Prevent the default (native) action and stop the underlying keydown event\n\t\t *\t\t\t// so no other editor feature will interfere.\n\t\t *\t\t\tcancel();\n\t\t *\t\t} );\n\t\t *\n\t\t * Note: Certain typing-oriented keystrokes (like <kbd>Backspace</kbd> or <kbd>Enter</kbd>) are handled\n\t\t * by a low-level mechanism and trying to listen to them via the keystroke handler will not work reliably.\n\t\t * To handle these specific keystrokes, see the events fired by the\n\t\t * {@link module:engine/view/document~Document editing view document} (`editor.editing.view.document`).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editingkeystrokehandler~EditingKeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new EditingKeystrokeHandler( this );\n\t\tthis.keystrokes.listenTo( this.editing.view.document );\n\t}\n\n\t/**\n\t * Loads and initializes plugins specified in the configuration.\n\t *\n\t * @returns {Promise.<module:core/plugin~LoadedPlugins>} A promise which resolves\n\t * once the initialization is completed, providing an array of loaded plugins.\n\t */\n\tinitPlugins() {\n\t\tconst config = this.config;\n\t\tconst plugins = config.get( 'plugins' );\n\t\tconst removePlugins = config.get( 'removePlugins' ) || [];\n\t\tconst extraPlugins = config.get( 'extraPlugins' ) || [];\n\t\tconst substitutePlugins = config.get( 'substitutePlugins' ) || [];\n\n\t\treturn this.plugins.init( plugins.concat( extraPlugins ), removePlugins, substitutePlugins );\n\t}\n\n\t/**\n\t * Destroys the editor instance, releasing all resources used by it.\n\t *\n\t * **Note** The editor cannot be destroyed during the initialization phase so if it is called\n\t * while the editor {@link #state is being initialized}, it will wait for the editor initialization before destroying it.\n\t *\n\t * @fires destroy\n\t * @returns {Promise} A promise that resolves once the editor instance is fully destroyed.\n\t */\n\tdestroy() {\n\t\tlet readyPromise = Promise.resolve();\n\n\t\tif ( this.state == 'initializing' ) {\n\t\t\treadyPromise = new Promise( resolve => this.once( 'ready', resolve ) );\n\t\t}\n\n\t\treturn readyPromise\n\t\t\t.then( () => {\n\t\t\t\tthis.fire( 'destroy' );\n\t\t\t\tthis.stopListening();\n\t\t\t\tthis.commands.destroy();\n\t\t\t} )\n\t\t\t.then( () => this.plugins.destroy() )\n\t\t\t.then( () => {\n\t\t\t\tthis.model.destroy();\n\t\t\t\tthis.data.destroy();\n\t\t\t\tthis.editing.destroy();\n\t\t\t\tthis.keystrokes.destroy();\n\t\t\t} )\n\t\t\t// Remove the editor from the context.\n\t\t\t// When the context was created by this editor, the context will be destroyed.\n\t\t\t.then( () => this._context._removeEditor( this ) );\n\t}\n\n\t/**\n\t * Executes the specified command with given parameters.\n\t *\n\t * Shorthand for:\n\t *\n\t *\t\teditor.commands.get( commandName ).execute( ... );\n\t *\n\t * @param {String} commandName The name of the command to execute.\n\t * @param {*} [...commandParams] Command parameters.\n\t * @returns {*} The value returned by the {@link module:core/commandcollection~CommandCollection#execute `commands.execute()`}.\n\t */\n\texecute( ...args ) {\n\t\ttry {\n\t\t\treturn this.commands.execute( ...args );\n\t\t} catch ( err ) {\n\t\t\t// @if CK_DEBUG // throw err;\n\t\t\t/* istanbul ignore next */\n\t\t\tCKEditorError.rethrowUnexpectedError( err, this );\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the editor.\n\t *\n\t * **Note** To explicitly focus the editing area of the editor, use the\n\t * {@link module:engine/view/view~View#focus `editor.editing.view.focus()`} method of the editing view.\n\t *\n\t * Check out the {@glink framework/guides/deep-dive/ui/focus-tracking#focus-in-the-editor-ui Focus in the editor UI} section\n\t * of the {@glink framework/guides/deep-dive/ui/focus-tracking Deep dive into focus tracking} guide to learn more.\n\t */\n\tfocus() {\n\t\tthis.editing.view.focus();\n\t}\n\n\t/**\n\t * Creates and initializes a new editor instance.\n\t *\n\t * This is an abstract method. Every editor type needs to implement its own initialization logic.\n\t *\n\t * See the `create()` methods of the existing editor types to learn how to use them:\n\t *\n\t * * {@link module:editor-classic/classiceditor~ClassicEditor.create `ClassicEditor.create()`}\n\t * * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}\n\t * * {@link module:editor-decoupled/decouplededitor~DecoupledEditor.create `DecoupledEditor.create()`}\n\t * * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`}\n\t *\n\t * @abstract\n\t * @method module:core/editor/editor~Editor.create\n\t */\n}\n\nmix( Editor, ObservableMixin );\n\n/**\n * Fired when the {@link module:engine/controller/datacontroller~DataController#event:ready data} and all additional\n * editor components are ready.\n *\n * Note: This event is most useful for plugin developers. When integrating the editor with your website or\n * application, you do not have to listen to `editor#ready` because when the promise returned by the static\n * {@link module:core/editor/editor~Editor.create `Editor.create()`} event is resolved, the editor is already ready.\n * In fact, since the first moment when the editor instance is available to you is inside `then()`'s callback,\n * you cannot even add a listener to the `editor#ready` event.\n *\n * See also the {@link #state `editor.state`} property.\n *\n * @event ready\n */\n\n/**\n * Fired when this editor instance is destroyed. The editor at this point is not usable and this event should be used to\n * perform the clean-up in any plugin.\n *\n *\n * See also the {@link #state `editor.state`} property.\n *\n * @event destroy\n */\n\n/**\n * This error is thrown when trying to pass a `<textarea>` element to a `create()` function of an editor class.\n *\n * The only editor type which can be initialized on `<textarea>` elements is {@glink builds/guides/overview#classic-editor classic editor}.\n * This editor hides the passed element and inserts its own UI next to it. Other types of editors reuse the passed element as their root\n * editable element and therefore `<textarea>` is not appropriate for them. Use a `<div>` or another text container instead:\n *\n *\t\t<div id=\"editor\">\n *\t\t\t<p>Initial content.</p>\n *\t\t</div>\n *\n * @error editor-wrong-element\n */\n\n/**\n * An array of plugins built into this editor class.\n *\n * It is used in CKEditor 5 builds to provide a list of plugins which are later automatically initialized\n * during the editor initialization.\n *\n * They will be automatically initialized by the editor, unless listed in `config.removePlugins` and\n * unless `config.plugins` is passed.\n *\n *\t\t// Build some plugins into the editor class first.\n *\t\tClassicEditor.builtinPlugins = [ FooPlugin, BarPlugin ];\n *\n *\t\t// Normally, you need to define config.plugins, but since ClassicEditor.builtinPlugins was\n *\t\t// defined, now you can call create() without any configuration.\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\teditor.plugins.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, {\n *\t\t\t\t// Do not initialize these plugins (note: it is defined by a string):\n *\t\t\t\tremovePlugins: [ 'Foo' ]\n *\t\t\t} )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> Undefined.\n *\t\t\t\teditor.config.get( BarPlugin ); // -> An instance of the Bar plugin.\n *\t\t\t} );\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, {\n *\t\t\t\t// Load only this plugin. It can also be defined by a string if\n *\t\t\t\t// this plugin was built into the editor class.\n *\t\t\t\tplugins: [ FooPlugin ]\n *\t\t\t} )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.plugins.get( FooPlugin ); // -> An instance of the Foo plugin.\n *\t\t\t\teditor.config.get( BarPlugin ); // -> Undefined.\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.defaultConfig}.\n *\n * @static\n * @member {Array.<Function>} module:core/editor/editor~Editor.builtinPlugins\n */\n\n/**\n * The default configuration which is built into the editor class.\n *\n * It is used in CKEditor 5 builds to provide the default configuration options which are later used during the editor initialization.\n *\n *\t\tClassicEditor.defaultConfig = {\n *\t\t\tfoo: 1,\n *\t\t\tbar: 2\n *\t\t};\n *\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.config.get( 'foo' ); // -> 1\n *\t\t\t\teditor.config.get( 'bar' ); // -> 2\n *\t\t\t} );\n *\n *\t\t// The default options can be overridden by the configuration passed to create().\n *\t\tClassicEditor\n *\t\t\t.create( sourceElement, { bar: 3 } )\n *\t\t\t.then( editor => {\n *\t\t\t\teditor.config.get( 'foo' ); // -> 1\n *\t\t\t\teditor.config.get( 'bar' ); // -> 3\n *\t\t\t} );\n *\n * See also {@link module:core/editor/editor~Editor.builtinPlugins}.\n *\n * @static\n * @member {Object} module:core/editor/editor~Editor.defaultConfig\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 ui/componentfactory\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * A helper class implementing the UI component ({@link module:ui/view~View view}) factory.\n *\n * It allows functions producing specific UI components to be registered under their unique names\n * in the factory. A registered component can be then instantiated by providing its name.\n * Note that names are case insensitive.\n *\n *\t\t// The editor provides localization tools for the factory.\n *\t\tconst factory = new ComponentFactory( editor );\n *\n *\t\tfactory.add( 'foo', locale => new FooView( locale ) );\n *\t\tfactory.add( 'bar', locale => new BarView( locale ) );\n *\n *\t\t// An instance of FooView.\n *\t\tconst fooInstance = factory.create( 'foo' );\n *\n *\t\t// Names are case insensitive so this is also allowed:\n *\t\tconst barInstance = factory.create( 'Bar' );\n *\n * The {@link module:core/editor/editor~Editor#locale editor locale} is passed to the factory\n * function when {@link module:ui/componentfactory~ComponentFactory#create} is called.\n */\nexport default class ComponentFactory {\n\t/**\n\t * Creates an instance of the factory.\n\t *\n\t * @constructor\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor instance that the factory belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor}\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * Registered component factories.\n\t\t *\n\t\t * @private\n\t\t * @member {Map}\n\t\t */\n\t\tthis._components = new Map();\n\t}\n\n\t/**\n\t * Returns an iterator of registered component names. Names are returned in lower case.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\t* names() {\n\t\tfor ( const value of this._components.values() ) {\n\t\t\tyield value.originalName;\n\t\t}\n\t}\n\n\t/**\n\t * Registers a component factory function that will be used by the\n\t * {@link #create create} method and called with the\n\t * {@link module:core/editor/editor~Editor#locale editor locale} as an argument,\n\t * allowing localization of the {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @param {Function} callback The callback that returns the component.\n\t */\n\tadd( name, callback ) {\n\t\tthis._components.set( getNormalized( name ), { callback, originalName: name } );\n\t}\n\n\t/**\n\t * Creates an instance of a component registered in the factory under a specific name.\n\t *\n\t * When called, the {@link module:core/editor/editor~Editor#locale editor locale} is passed to\n\t * the previously {@link #add added} factory function, allowing localization of the\n\t * {@link module:ui/view~View view}.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {module:ui/view~View} The instantiated component view.\n\t */\n\tcreate( name ) {\n\t\tif ( !this.has( name ) ) {\n\t\t\t/**\n\t\t\t * The required component is not registered in the component factory. Please make sure\n\t\t\t * the provided name is correct and the component has been correctly\n\t\t\t * {@link #add added} to the factory.\n\t\t\t *\n\t\t\t * @error componentfactory-item-missing\n\t\t\t * @param {String} name The name of the missing component.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'componentfactory-item-missing',\n\t\t\t\tthis,\n\t\t\t\t{ name }\n\t\t\t);\n\t\t}\n\n\t\treturn this._components.get( getNormalized( name ) ).callback( this.editor.locale );\n\t}\n\n\t/**\n\t * Checks if a component of a given name is registered in the factory.\n\t *\n\t * @param {String} name The name of the component.\n\t * @returns {Boolean}\n\t */\n\thas( name ) {\n\t\treturn this._components.has( getNormalized( name ) );\n\t}\n}\n\n//\n// Ensures that the component name used as the key in the internal map is in lower case.\n//\n// @private\n// @param {String} name\n// @returns {String}\nfunction getNormalized( name ) {\n\treturn String( name ).toLowerCase();\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 core/editor/editorui\n */\n\n/* globals console */\n\nimport ComponentFactory from '@ckeditor/ckeditor5-ui/src/componentfactory';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * A class providing the minimal interface that is required to successfully bootstrap any editor UI.\n *\n * @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class EditorUI {\n\t/**\n\t * Creates an instance of the editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * The editor that the UI belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * An instance of the {@link module:ui/componentfactory~ComponentFactory}, a registry used by plugins\n\t\t * to register factories of specific UI components.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/componentfactory~ComponentFactory} #componentFactory\n\t\t */\n\t\tthis.componentFactory = new ComponentFactory( editor );\n\n\t\t/**\n\t\t * Stores the information about the editor UI focus and propagates it so various plugins and components\n\t\t * are unified as a focus group.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Stores all editable elements used by the editor instance.\n\t\t *\n\t\t * @private\n\t\t * @member {Map.<String,HTMLElement>}\n\t\t */\n\t\tthis._editableElementsMap = new Map();\n\n\t\t// Informs UI components that should be refreshed after layout change.\n\t\tthis.listenTo( editor.editing.view.document, 'layoutChanged', () => this.update() );\n\t}\n\n\t/**\n\t * The main (outermost) DOM element of the editor UI.\n\t *\n\t * For example, in {@link module:editor-classic/classiceditor~ClassicEditor} it is a `<div>` which\n\t * wraps the editable element and the toolbar. In {@link module:editor-inline/inlineeditor~InlineEditor}\n\t * it is the editable element itself (as there is no other wrapper). However, in\n\t * {@link module:editor-decoupled/decouplededitor~DecoupledEditor} it is set to `null` because this editor does not\n\t * come with a single \"main\" HTML element (its editable element and toolbar are separate).\n\t *\n\t * This property can be understood as a shorthand for retrieving the element that a specific editor integration\n\t * considers to be its main DOM element.\n\t *\n\t * @readonly\n\t * @member {HTMLElement|null} #element\n\t */\n\tget element() {\n\t\treturn null;\n\t}\n\n\t/**\n\t * Fires the {@link module:core/editor/editorui~EditorUI#event:update `update`} event.\n\t *\n\t * This method should be called when the editor UI (e.g. positions of its balloons) needs to be updated due to\n\t * some environmental change which CKEditor 5 is not aware of (e.g. resize of a container in which it is used).\n\t */\n\tupdate() {\n\t\tthis.fire( 'update' );\n\t}\n\n\t/**\n\t * Destroys the UI.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis.focusTracker.destroy();\n\n\t\t// Cleanup the references to the CKEditor instance stored in the native editable DOM elements.\n\t\tfor ( const domElement of this._editableElementsMap.values() ) {\n\t\t\tdomElement.ckeditorInstance = null;\n\t\t}\n\n\t\tthis._editableElementsMap = new Map();\n\t}\n\n\t/**\n\t * Store the native DOM editable element used by the editor under\n\t * a unique name.\n\t *\n\t * @param {String} rootName The unique name of the editable element.\n\t * @param {HTMLElement} domElement The native DOM editable element.\n\t */\n\tsetEditableElement( rootName, domElement ) {\n\t\tthis._editableElementsMap.set( rootName, domElement );\n\n\t\t// Put a reference to the CKEditor instance in the editable native DOM element.\n\t\t// It helps 3rdparty software (browser extensions, other libraries) access and recognize\n\t\t// CKEditor 5 instances (editing roots) and use their API (there is no global editor\n\t\t// instance registry).\n\t\tif ( !domElement.ckeditorInstance ) {\n\t\t\tdomElement.ckeditorInstance = this.editor;\n\t\t}\n\t}\n\n\t/**\n\t * Returns the editable editor element with the given name or null if editable does not exist.\n\t *\n\t * @param {String} [rootName=main] The editable name.\n\t * @returns {HTMLElement|undefined}\n\t */\n\tgetEditableElement( rootName = 'main' ) {\n\t\treturn this._editableElementsMap.get( rootName );\n\t}\n\n\t/**\n\t * Returns array of names of all editor editable elements.\n\t *\n\t * @returns {Iterable.<String>}\n\t */\n\tgetEditableElementsNames() {\n\t\treturn this._editableElementsMap.keys();\n\t}\n\n\t/**\n\t * Stores all editable elements used by the editor instance.\n\t *\n\t * @protected\n\t * @deprecated\n\t * @member {Map.<String,HTMLElement>}\n\t */\n\tget _editableElements() {\n\t\t/**\n\t\t * The {@link module:core/editor/editorui~EditorUI#_editableElements `EditorUI#_editableElements`} property has been\n\t\t * deprecated and will be removed in the near future. Please use {@link #setEditableElement `setEditableElement()`} and\n\t\t * {@link #getEditableElement `getEditableElement()`} methods instead.\n\t\t *\n\t\t * @error editor-ui-deprecated-editable-elements\n\t\t * @param {module:core/editor/editorui~EditorUI} editorUI Editor UI instance the deprecated property belongs to.\n\t\t */\n\t\tconsole.warn(\n\t\t\t'editor-ui-deprecated-editable-elements: ' +\n\t\t\t'The EditorUI#_editableElements property has been deprecated and will be removed in the near future.',\n\t\t\t{ editorUI: this } );\n\n\t\treturn this._editableElementsMap;\n\t}\n\n\t/**\n\t * Fired when the editor UI is ready.\n\t *\n\t * Fired before {@link module:engine/controller/datacontroller~DataController#event:ready}.\n\t *\n\t * @event ready\n\t */\n\n\t/**\n\t * Fired whenever the UI (all related components) should be refreshed.\n\t *\n\t * **Note:**: The event is fired after each {@link module:engine/view/document~Document#event:layoutChanged}.\n\t * It can also be fired manually via the {@link module:core/editor/editorui~EditorUI#update} method.\n\t *\n\t * @event update\n\t */\n}\n\nmix( EditorUI, EmitterMixin );\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 core/editor/utils/dataapimixin\n */\n\n/**\n * Implementation of the {@link module:core/editor/utils/dataapimixin~DataApi}.\n *\n * @mixin DataApiMixin\n * @implements module:core/editor/utils/dataapimixin~DataApi\n */\nconst DataApiMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tsetData( data ) {\n\t\tthis.data.set( data );\n\t},\n\n\t/**\n\t * @inheritDoc\n\t */\n\tgetData( options ) {\n\t\treturn this.data.get( options );\n\t}\n};\n\nexport default DataApiMixin;\n\n/**\n * Interface defining editor methods for setting and getting data to and from the editor's main root element\n * using the {@link module:core/editor/editor~Editor#data data pipeline}.\n *\n * This interface is not a part of the {@link module:core/editor/editor~Editor} class because one may want to implement\n * an editor with multiple root elements, in which case the methods for setting and getting data will need to be implemented\n * differently.\n *\n * @interface DataApi\n */\n\n/**\n * Sets the data in the editor.\n *\n *\t\teditor.setData( '<p>This is editor!</p>' );\n *\n * By default the editor accepts HTML. This can be controlled by injecting a different data processor.\n * See the {@glink features/markdown Markdown output} guide for more details.\n *\n * Note: Not only is the format of the data configurable, but the type of the `setData()`'s parameter does not\n * have to be a string either. You can e.g. accept an object or a DOM `DocumentFragment` if you consider this\n * the right format for you.\n *\n * @method #setData\n * @param {String} data Input data.\n */\n\n/**\n * Gets the data from the editor.\n *\n *\t\teditor.getData(); // -> '<p>This is editor!</p>'\n *\n * By default the editor outputs HTML. This can be controlled by injecting a different data processor.\n * See the {@glink features/markdown Markdown output} guide for more details.\n *\n * Note: Not only is the format of the data configurable, but the type of the `getData()`'s return value does not\n * have to be a string either. You can e.g. return an object or a DOM `DocumentFragment` if you consider this\n * the right format for you.\n *\n * @method #getData\n * @param {Object} [options] Additional configuration for the retrieved data.\n * Editor features may introduce more configuration options that can be set through this parameter.\n * @param {String} [options.rootName='main'] Root name.\n * @param {String} [options.trim='empty'] Whether returned data should be trimmed. This option is set to `'empty'` by default,\n * which means that whenever editor content is considered empty, an empty string is returned. To turn off trimming\n * use `'none'`. In such cases exact content will be returned (for example `'<p>&nbsp;</p>'` for an empty editor).\n * @returns {String} Output data.\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\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';\n\n/**\n * @module core/editor/utils/elementapimixin\n */\n\n/**\n * Implementation of the {@link module:core/editor/utils/elementapimixin~ElementApi}.\n *\n * @mixin ElementApiMixin\n * @implements module:core/editor/utils/elementapimixin~ElementApi\n */\nconst ElementApiMixin = {\n\t/**\n\t * @inheritDoc\n\t */\n\tupdateSourceElement() {\n\t\tif ( !this.sourceElement ) {\n\t\t\t/**\n\t\t\t * Cannot update the source element of a detached editor.\n\t\t\t *\n\t\t\t * The {@link ~ElementApi#updateSourceElement `updateSourceElement()`} method cannot be called if you did not\n\t\t\t * pass an element to `Editor.create()`.\n\t\t\t *\n\t\t\t * @error editor-missing-sourceelement\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'editor-missing-sourceelement',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tsetDataInElement( this.sourceElement, this.data.get() );\n\t}\n};\n\nexport default ElementApiMixin;\n\n/**\n * Interface describing an editor that replaced a DOM element (was \"initialized on an element\").\n *\n * Such an editor should provide a method to\n * {@link module:core/editor/utils/elementapimixin~ElementApi#updateSourceElement update the replaced element with the current data}.\n *\n * @interface ElementApi\n */\n\n/**\n * The element on which the editor has been initialized.\n *\n * @readonly\n * @member {HTMLElement} #sourceElement\n */\n\n/**\n * Updates the {@link #sourceElement editor source element}'s content with the data.\n *\n * @method #updateSourceElement\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 core/pendingactions\n */\n\nimport ContextPlugin from './contextplugin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * The list of pending editor actions.\n *\n * This plugin should be used to synchronise plugins that execute long-lasting actions\n * (e.g. file upload) with the editor integration. It gives the developer who integrates the editor\n * an easy way to check if there are any actions pending whenever such information is needed.\n * All plugins that register a pending action also provide a message about the action that is ongoing\n * which can be displayed to the user. This lets them decide if they want to interrupt the action or wait.\n *\n * Adding and updating a pending action:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n * \t\tconst action = pendingActions.add( 'Upload in progress: 0%.' );\n *\n *\t\t// You can update the message:\n * \t\taction.message = 'Upload in progress: 10%.';\n *\n * Removing a pending action:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n * \t\tconst action = pendingActions.add( 'Unsaved changes.' );\n *\n * \t\tpendingActions.remove( action );\n *\n * Getting pending actions:\n *\n * \t\tconst pendingActions = editor.plugins.get( 'PendingActions' );\n *\n * \t\tconst action1 = pendingActions.add( 'Action 1' );\n * \t\tconst action2 = pendingActions.add( 'Action 2' );\n *\n * \t\tpendingActions.first; // Returns action1\n * \t\tArray.from( pendingActions ); // Returns [ action1, action2 ]\n *\n * This plugin is used by features like {@link module:upload/filerepository~FileRepository} to register their ongoing actions\n * and by features like {@link module:autosave/autosave~Autosave} to detect whether there are any ongoing actions.\n * Read more about saving the data in the {@glink builds/guides/integration/saving-data Saving and getting data} guide.\n *\n * @extends module:core/contextplugin~ContextPlugin\n */\nexport default class PendingActions extends ContextPlugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PendingActions';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t/**\n\t\t * Defines whether there is any registered pending action.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #hasAny\n\t\t */\n\t\tthis.set( 'hasAny', false );\n\n\t\t/**\n\t\t * A list of pending actions.\n\t\t *\n\t\t * @private\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis._actions = new Collection( { idProperty: '_id' } );\n\t\tthis._actions.delegate( 'add', 'remove' ).to( this );\n\t}\n\n\t/**\n\t * Adds an action to the list of pending actions.\n\t *\n\t * This method returns an action object with an observable message property.\n\t * The action object can be later used in the {@link #remove} method. It also allows you to change the message.\n\t *\n\t * @param {String} message The action message.\n\t * @returns {Object} An observable object that represents a pending action.\n\t */\n\tadd( message ) {\n\t\tif ( typeof message !== 'string' ) {\n\t\t\t/**\n\t\t\t * The message must be a string.\n\t\t\t *\n\t\t\t * @error pendingactions-add-invalid-message\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'pendingactions-add-invalid-message', this );\n\t\t}\n\n\t\tconst action = Object.create( ObservableMixin );\n\n\t\taction.set( 'message', message );\n\t\tthis._actions.add( action );\n\t\tthis.hasAny = true;\n\n\t\treturn action;\n\t}\n\n\t/**\n\t * Removes an action from the list of pending actions.\n\t *\n\t * @param {Object} action An action object.\n\t */\n\tremove( action ) {\n\t\tthis._actions.remove( action );\n\t\tthis.hasAny = !!this._actions.length;\n\t}\n\n\t/**\n\t * Returns the first action from the list or null when list is empty\n\t *\n\t * returns {Object|null} The pending action object.\n\t */\n\tget first() {\n\t\treturn this._actions.get( 0 );\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<*>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this._actions[ Symbol.iterator ]();\n\t}\n\n\t/**\n\t * Fired when an action is added to the list.\n\t *\n\t * @event add\n\t * @param {Object} action The added action.\n\t */\n\n\t/**\n\t * Fired when an action is removed from the list.\n\t *\n\t * @event remove\n\t * @param {Object} action The removed action.\n\t */\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m11.591 10.177 4.243 4.242a1 1 0 0 1-1.415 1.415l-4.242-4.243-4.243 4.243a1 1 0 0 1-1.414-1.415l4.243-4.242L4.52 5.934A1 1 0 0 1 5.934 4.52l4.243 4.243 4.242-4.243a1 1 0 1 1 1.415 1.414l-4.243 4.243z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M6.972 16.615a.997.997 0 0 1-.744-.292l-4.596-4.596a1 1 0 1 1 1.414-1.414l3.926 3.926 9.937-9.937a1 1 0 0 1 1.414 1.415L7.717 16.323a.997.997 0 0 1-.745.292z\\\"/></svg>\";","/**\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 core\n */\n\nexport { default as Plugin } from './plugin';\nexport { default as Command } from './command';\nexport { default as MultiCommand } from './multicommand';\n\nexport { default as Context } from './context';\nexport { default as ContextPlugin } from './contextplugin';\n\nexport { default as Editor } from './editor/editor';\nexport { default as EditorUI } from './editor/editorui';\n\nexport { default as attachToForm } from './editor/utils/attachtoform';\nexport { default as DataApiMixin } from './editor/utils/dataapimixin';\nexport { default as ElementApiMixin } from './editor/utils/elementapimixin';\nexport { default as secureSourceElement } from './editor/utils/securesourceelement';\n\nexport { default as PendingActions } from './pendingactions';\n\nimport cancel from './../theme/icons/cancel.svg';\nimport caption from './../theme/icons/caption.svg';\nimport check from './../theme/icons/check.svg';\nimport eraser from './../theme/icons/eraser.svg';\nimport lowVision from './../theme/icons/low-vision.svg';\nimport image from './../theme/icons/image.svg';\nimport alignBottom from './../theme/icons/align-bottom.svg';\nimport alignMiddle from './../theme/icons/align-middle.svg';\nimport alignTop from './../theme/icons/align-top.svg';\nimport alignLeft from './../theme/icons/align-left.svg';\nimport alignCenter from './../theme/icons/align-center.svg';\nimport alignRight from './../theme/icons/align-right.svg';\nimport alignJustify from './../theme/icons/align-justify.svg';\nimport objectLeft from './../theme/icons/object-left.svg';\nimport objectCenter from './../theme/icons/object-center.svg';\nimport objectRight from './../theme/icons/object-right.svg';\nimport objectFullWidth from './../theme/icons/object-full-width.svg';\nimport objectSizeFull from './../theme/icons/object-size-full.svg';\nimport objectSizeLarge from './../theme/icons/object-size-large.svg';\nimport objectSizeSmall from './../theme/icons/object-size-small.svg';\nimport objectSizeMedium from './../theme/icons/object-size-medium.svg';\nimport pencil from './../theme/icons/pencil.svg';\nimport pilcrow from './../theme/icons/pilcrow.svg';\nimport quote from './../theme/icons/quote.svg';\nimport threeVerticalDots from './../theme/icons/three-vertical-dots.svg';\n\nexport const icons = {\n\tcancel,\n\tcaption,\n\tcheck,\n\teraser,\n\tlowVision,\n\timage,\n\talignBottom,\n\talignMiddle,\n\talignTop,\n\talignLeft,\n\talignCenter,\n\talignRight,\n\talignJustify,\n\tobjectLeft,\n\tobjectCenter,\n\tobjectRight,\n\tobjectFullWidth,\n\tobjectSizeFull,\n\tobjectSizeLarge,\n\tobjectSizeSmall,\n\tobjectSizeMedium,\n\tpencil,\n\tpilcrow,\n\tquote,\n\tthreeVerticalDots\n};\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m8.636 9.531-2.758 3.94a.5.5 0 0 0 .122.696l3.224 2.284h1.314l2.636-3.736L8.636 9.53zm.288 8.451L5.14 15.396a2 2 0 0 1-.491-2.786l6.673-9.53a2 2 0 0 1 2.785-.49l3.742 2.62a2 2 0 0 1 .491 2.785l-7.269 10.053-2.147-.066z\\\"/><path d=\\\"M4 18h5.523v-1H4zm-2 0h1v-1H2z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M5.085 6.22 2.943 4.078a.75.75 0 1 1 1.06-1.06l2.592 2.59A11.094 11.094 0 0 1 10 5.068c4.738 0 8.578 3.101 8.578 5.083 0 1.197-1.401 2.803-3.555 3.887l1.714 1.713a.75.75 0 0 1-.09 1.138.488.488 0 0 1-.15.084.75.75 0 0 1-.821-.16L6.17 7.304c-.258.11-.51.233-.757.365l6.239 6.24-.006.005.78.78c-.388.094-.78.166-1.174.215l-1.11-1.11h.011L4.55 8.197a7.2 7.2 0 0 0-.665.514l-.112.098 4.897 4.897-.005.006 1.276 1.276a10.164 10.164 0 0 1-1.477-.117l-.479-.479-.009.009-4.863-4.863-.022.031a2.563 2.563 0 0 0-.124.2c-.043.077-.08.158-.108.241a.534.534 0 0 0-.028.133.29.29 0 0 0 .008.072.927.927 0 0 0 .082.226c.067.133.145.26.234.379l3.242 3.365.025.01.59.623c-3.265-.918-5.59-3.155-5.59-4.668 0-1.194 1.448-2.838 3.663-3.93zm7.07.531a4.632 4.632 0 0 1 1.108 5.992l.345.344.046-.018a9.313 9.313 0 0 0 2-1.112c.256-.187.5-.392.727-.613.137-.134.27-.277.392-.431.072-.091.141-.185.203-.286.057-.093.107-.19.148-.292a.72.72 0 0 0 .036-.12.29.29 0 0 0 .008-.072.492.492 0 0 0-.028-.133.999.999 0 0 0-.036-.096 2.165 2.165 0 0 0-.071-.145 2.917 2.917 0 0 0-.125-.2 3.592 3.592 0 0 0-.263-.335 5.444 5.444 0 0 0-.53-.523 7.955 7.955 0 0 0-1.054-.768 9.766 9.766 0 0 0-1.879-.891c-.337-.118-.68-.219-1.027-.301zm-2.85.21-.069.002a.508.508 0 0 0-.254.097.496.496 0 0 0-.104.679.498.498 0 0 0 .326.199l.045.005c.091.003.181.003.272.012a2.45 2.45 0 0 1 2.017 1.513c.024.061.043.125.069.185a.494.494 0 0 0 .45.287h.008a.496.496 0 0 0 .35-.158.482.482 0 0 0 .13-.335.638.638 0 0 0-.048-.219 3.379 3.379 0 0 0-.36-.723 3.438 3.438 0 0 0-2.791-1.543l-.028-.001h-.013z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M6.91 10.54c.26-.23.64-.21.88.03l3.36 3.14 2.23-2.06a.64.64 0 0 1 .87 0l2.52 2.97V4.5H3.2v10.12l3.71-4.08zm10.27-7.51c.6 0 1.09.47 1.09 1.05v11.84c0 .59-.49 1.06-1.09 1.06H2.79c-.6 0-1.09-.47-1.09-1.06V4.08c0-.58.49-1.05 1.1-1.05h14.38zm-5.22 5.56a1.96 1.96 0 1 1 3.4-1.96 1.96 1.96 0 0 1-3.4 1.96z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m9.239 13.938-2.88-1.663a.75.75 0 0 1 .75-1.3L9 12.067V4.75a.75.75 0 1 1 1.5 0v7.318l1.89-1.093a.75.75 0 0 1 .75 1.3l-2.879 1.663a.752.752 0 0 1-.511.187.752.752 0 0 1-.511-.187zM4.25 17a.75.75 0 1 1 0-1.5h10.5a.75.75 0 0 1 0 1.5H4.25z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M9.75 11.875a.752.752 0 0 1 .508.184l2.883 1.666a.75.75 0 0 1-.659 1.344l-.091-.044-1.892-1.093.001 4.318a.75.75 0 1 1-1.5 0v-4.317l-1.89 1.092a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .51-.187zM15.25 9a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM9.75.375a.75.75 0 0 1 .75.75v4.318l1.89-1.093.092-.045a.75.75 0 0 1 .659 1.344l-2.883 1.667a.752.752 0 0 1-.508.184.752.752 0 0 1-.511-.187L6.359 5.65a.75.75 0 0 1 .75-1.299L9 5.442V1.125a.75.75 0 0 1 .75-.75z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m10.261 7.062 2.88 1.663a.75.75 0 0 1-.75 1.3L10.5 8.933v7.317a.75.75 0 1 1-1.5 0V8.932l-1.89 1.093a.75.75 0 0 1-.75-1.3l2.879-1.663a.752.752 0 0 1 .511-.187.752.752 0 0 1 .511.187zM15.25 4a.75.75 0 1 1 0 1.5H4.75a.75.75 0 0 1 0-1.5h10.5z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm2.286 4c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h9.928a.75.75 0 1 0 0-1.5H5.036a.75.75 0 0 0-.75.75z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M18 3.75a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 8a.75.75 0 0 1-.75.75H2.75a.75.75 0 1 1 0-1.5h14.5a.75.75 0 0 1 .75.75zm0 4a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75zm0-8a.75.75 0 0 1-.75.75H7.321a.75.75 0 1 1 0-1.5h9.929a.75.75 0 0 1 .75.75z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0 4c0 .414.336.75.75.75h9.929a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm0-8c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" clip-rule=\\\"evenodd\\\" stroke-linejoin=\\\"round\\\" stroke-miterlimit=\\\"1.414\\\"><path d=\\\"M18 4.5V3H2v1.5h16zm0 3V6h-5.674v1.5H18zm0 3V9h-5.674v1.5H18zm0 3V12h-5.674v1.5H18zm-8.5-6V12h-6V7.5h6zm.818-1.5H2.682C2.305 6 2 6.407 2 6.91v5.68c0 .503.305.91.682.91h7.636c.377 0 .682-.407.682-.91V6.91c0-.503-.305-.91-.682-.91zM18 16.5V15H2v1.5h16z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm4.5 3V12h7V7.5h-7zM5.758 6h8.484c.419 0 .758.407.758.91v5.681c0 .502-.34.909-.758.909H5.758c-.419 0-.758-.407-.758-.91V6.91c0-.503.34-.91.758-.91zM2 16.5V15h16v1.5z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm0 3V6h5.674v1.5zm0 3V9h5.674v1.5zm0 3V12h5.674v1.5zm8.5-6V12h6V7.5h-6zM9.682 6h7.636c.377 0 .682.407.682.91v5.68c0 .503-.305.91-.682.91H9.682c-.377 0-.682-.407-.682-.91V6.91c0-.503.305-.91.682-.91zM2 16.5V15h16v1.5z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 4.5V3h16v1.5zm2.5 3V12h11V7.5h-11zM4.061 6H15.94c.586 0 1.061.407 1.061.91v5.68c0 .503-.475.91-1.061.91H4.06c-.585 0-1.06-.407-1.06-.91V6.91C3 6.406 3.475 6 4.061 6zM2 16.5V15h16v1.5z\\\"/></svg>\";","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 20 20\\\"><path d=\\\"M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z\\\"/><path d=\\\"M18.095 2H1.905C.853 2 0 2.895 0 4v12c0 1.105.853 2 1.905 2h16.19C19.147 18 20 17.105 20 16V4c0-1.105-.853-2-1.905-2zm0 1.5c.263 0 .476.224.476.5v12c0 .276-.213.5-.476.5H1.905a.489.489 0 0 1-.476-.5V4c0-.276.213-.5.476-.5h16.19z\\\"/></svg>\";","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 20 20\\\"><path d=\\\"M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z\\\"/><path d=\\\"M13 6H2a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zm0 1.5a.5.5 0 0 1 .5.5v8a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5V8a.5.5 0 0 1 .5-.5h11z\\\"/></svg>\";","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 20 20\\\"><path d=\\\"M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z\\\"/><path d=\\\"M7 10H2a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2zm0 1.5a.5.5 0 0 1 .5.5v4a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-4a.5.5 0 0 1 .5-.5h5z\\\"/></svg>\";","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 20 20\\\"><path d=\\\"M2.5 17v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zm2 0v1h-1v-1h1zM1 15.5v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm-19-2v1H0v-1h1zm19 0v1h-1v-1h1zm0-2v1h-1v-1h1zm-19 0v1H0v-1h1zM14.5 2v1h-1V2h1zm2 0v1h-1V2h1zm2 0v1h-1V2h1zm-8 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm-2 0v1h-1V2h1zm8 0v1h-1V2h1zm-10 0v1h-1V2h1z\\\"/><path d=\\\"M10 8H2a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-6a2 2 0 0 0-2-2zm0 1.5a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-.5.5H2a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 .5-.5h8z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m7.3 17.37-.061.088a1.518 1.518 0 0 1-.934.535l-4.178.663-.806-4.153a1.495 1.495 0 0 1 .187-1.058l.056-.086L8.77 2.639c.958-1.351 2.803-1.076 4.296-.03 1.497 1.047 2.387 2.693 1.433 4.055L7.3 17.37zM9.14 4.728l-5.545 8.346 3.277 2.294 5.544-8.346L9.14 4.728zM6.07 16.512l-3.276-2.295.53 2.73 2.746-.435zM9.994 3.506 13.271 5.8c.316-.452-.16-1.333-1.065-1.966-.905-.634-1.895-.78-2.212-.328zM8 18.5 9.375 17H19v1.5H8z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M6.999 2H15a1 1 0 0 1 0 2h-1.004v13a1 1 0 1 1-2 0V4H8.999v13a1 1 0 1 1-2 0v-7A4 4 0 0 1 3 6a4 4 0 0 1 3.999-4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 10.423a6.5 6.5 0 0 1 6.056-6.408l.038.67C6.448 5.423 5.354 7.663 5.22 10H9c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574zm8 0a6.5 6.5 0 0 1 6.056-6.408l.038.67c-2.646.739-3.74 2.979-3.873 5.315H17c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.574z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><circle cx=\\\"9.5\\\" cy=\\\"4.5\\\" r=\\\"1.5\\\"/><circle cx=\\\"9.5\\\" cy=\\\"10.5\\\" r=\\\"1.5\\\"/><circle cx=\\\"9.5\\\" cy=\\\"16.5\\\" r=\\\"1.5\\\"/></svg>\";","/**\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 ui/bindings/clickoutsidehandler\n */\n\n/* global document */\n\n/**\n * Handles clicking **outside** of a specified set of elements, then fires an action.\n *\n * **Note**: Actually, the action is executed upon `mousedown`, not `click`. It prevents\n * certain issues when the user keeps holding the mouse button and the UI cannot react\n * properly.\n *\n * @param {Object} options Configuration options.\n * @param {module:utils/dom/emittermixin~Emitter} options.emitter The emitter to which this behavior\n * should be added.\n * @param {Function} options.activator Function returning a `Boolean`, to determine whether the handler is active.\n * @param {Array.<HTMLElement>} options.contextElements HTML elements that determine the scope of the\n * handler. Clicking any of them or their descendants will **not** fire the callback.\n * @param {Function} options.callback An action executed by the handler.\n */\nexport default function clickOutsideHandler( { emitter, activator, callback, contextElements } ) {\n\temitter.listenTo( document, 'mousedown', ( evt, domEvt ) => {\n\t\tif ( !activator() ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if `composedPath` is `undefined` in case the browser does not support native shadow DOM.\n\t\t// Can be removed when all supported browsers support native shadow DOM.\n\t\tconst path = typeof domEvt.composedPath == 'function' ? domEvt.composedPath() : [];\n\n\t\tfor ( const contextElement of contextElements ) {\n\t\t\tif ( contextElement.contains( domEvt.target ) || path.includes( contextElement ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tcallback();\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/bindings/injectcsstransitiondisabler\n */\n\n/**\n * A decorator that brings the possibility to temporarily disable CSS transitions using\n * {@link module:ui/view~View} methods. It is helpful when, for instance, the transitions should not happen\n * when the view is first displayed but they should work normal in other cases.\n *\n * The methods to control the CSS transitions are:\n * * `disableCssTransitions()` Adds the `.ck-transitions-disabled` class to the\n * {@link module:ui/view~View#element view element}.\n * * `enableCssTransitions()` Removes the `.ck-transitions-disabled` class from the\n * {@link module:ui/view~View#element view element}.\n *\n * **Note**: This helper extends the {@link module:ui/view~View#template template} and must be used **after**\n * {@link module:ui/view~View#setTemplate} is called:\n *\n *\t\timport injectCssTransitionDisabler from '@ckeditor/ckeditor5-ui/src/bindings/injectcsstransitiondisabler';\n *\n *\t\tclass MyView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tsuper();\n *\n *\t\t\t\t// ...\n *\n *\t\t\t\tthis.setTemplate( { ... } );\n *\n *\t\t\t\t// ...\n *\n *\t\t\t\tinjectCssTransitionDisabler( this );\n *\n *\t\t\t\t// ...\n *\t\t\t}\n *\t\t}\n *\n * The usage comes down to:\n *\n *\t\tconst view = new MyView();\n *\n *\t\t// ...\n *\n *\t\tview.disableCssTransitions();\n *\t\tview.show();\n *\t\tview.enableCssTransitions();\n *\n * @param {module:ui/view~View} view View instance that should get this functionality.\n */\nexport default function injectCssTransitionDisabler( view ) {\n\tview.set( '_isCssTransitionsDisabled', false );\n\n\tview.disableCssTransitions = () => {\n\t\tview._isCssTransitionsDisabled = true;\n\t};\n\n\tview.enableCssTransitions = () => {\n\t\tview._isCssTransitionsDisabled = false;\n\t};\n\n\tview.extendTemplate( {\n\t\tattributes: {\n\t\t\tclass: [\n\t\t\t\tview.bindTemplate.if( '_isCssTransitionsDisabled', 'ck-transitions-disabled' )\n\t\t\t]\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/bindings/submithandler\n */\n\n/**\n * A handler useful for {@link module:ui/view~View views} working as HTML forms. It intercepts a native DOM\n * `submit` event, prevents the default web browser behavior (navigation and page reload) and\n * fires the `submit` event on a view instead. Such a custom event can be then used by any\n * {@link module:utils/dom/emittermixin~Emitter emitter}, e.g. to serialize the form data.\n *\n *\t\timport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\n *\n *\t\t// ...\n *\n *\t\tclass AnyFormView extends View {\n *\t\t\tconstructor() {\n *\t\t\t\tsuper();\n *\n *\t\t\t\t// ...\n *\n *\t\t\t\tsubmitHandler( {\n *\t\t\t\t\tview: this\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n *\t\t// ...\n *\n *\t\tconst view = new AnyFormView();\n *\n *\t\t// A sample listener attached by an emitter working with the view.\n *\t\tthis.listenTo( view, 'submit', () => {\n *\t\t\tsaveTheFormData();\n *\t\t\thideTheForm();\n *\t\t} );\n *\n * @param {Object} [options] Configuration options.\n * @param {module:ui/view~View} options.view The view which DOM `submit` events should be handled.\n */\nexport default function submitHandler( { view } ) {\n\tview.listenTo( view.element, 'submit', ( evt, domEvt ) => {\n\t\tdomEvt.preventDefault();\n\t\tview.fire( 'submit' );\n\t}, { useCapture: true } );\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 ui/viewcollection\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\n\n/**\n * Collects {@link module:ui/view~View} instances.\n *\n *\t\tconst parentView = new ParentView( locale );\n *\t\tconst collection = new ViewCollection( locale );\n *\n *\t\tcollection.setParent( parentView.element );\n *\n *\t\tconst viewA = new ChildView( locale );\n *\t\tconst viewB = new ChildView( locale );\n *\n * View collection renders and manages view {@link module:ui/view~View#element elements}:\n *\n *\t\tcollection.add( viewA );\n *\t\tcollection.add( viewB );\n *\n *\t\tconsole.log( parentView.element.firsChild ); // -> viewA.element\n *\t\tconsole.log( parentView.element.lastChild ); // -> viewB.element\n *\n * It {@link module:ui/viewcollection~ViewCollection#delegate propagates} DOM events too:\n *\n *\t\t// Delegate #click and #keydown events from viewA and viewB to the parentView.\n *\t\tcollection.delegate( 'click' ).to( parentView );\n *\n *\t\tparentView.on( 'click', ( evt ) => {\n *\t\t\tconsole.log( `${ evt.source } has been clicked.` );\n *\t\t} );\n *\n *\t\t// This event will be delegated to the parentView.\n *\t\tviewB.fire( 'click' );\n *\n * **Note**: A view collection can be used directly in the {@link module:ui/template~TemplateDefinition definition}\n * of a {@link module:ui/template~Template template}.\n *\n * @extends module:utils/collection~Collection\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ViewCollection extends Collection {\n\t/**\n\t * Creates a new instance of the {@link module:ui/viewcollection~ViewCollection}.\n\t *\n\t * @param {Iterable.<module:ui/view~View>} [initialItems] The initial items of the collection.\n\t */\n\tconstructor( initialItems = [] ) {\n\t\tsuper( initialItems, {\n\t\t\t// An #id Number attribute should be legal and not break the `ViewCollection` instance.\n\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/93\n\t\t\tidProperty: 'viewUid'\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a new view is added to the collection.\n\t\tthis.on( 'add', ( evt, view, index ) => {\n\t\t\tthis._renderViewIntoCollectionParent( view, index );\n\t\t} );\n\n\t\t// Handle {@link module:ui/view~View#element} in DOM when a view is removed from the collection.\n\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\tif ( view.element && this._parentElement ) {\n\t\t\t\tview.element.remove();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A parent element within which child views are rendered and managed in DOM.\n\t\t *\n\t\t * @protected\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis._parentElement = null;\n\t}\n\n\t/**\n\t * Destroys the view collection along with child views.\n\t * See the view {@link module:ui/view~View#destroy} method.\n\t */\n\tdestroy() {\n\t\tthis.map( view => view.destroy() );\n\t}\n\n\t/**\n\t * Sets the parent HTML element of this collection. When parent is set, {@link #add adding} and\n\t * {@link #remove removing} views in the collection synchronizes their\n\t * {@link module:ui/view~View#element elements} in the parent element.\n\t *\n\t * @param {HTMLElement} element A new parent element.\n\t */\n\tsetParent( elementOrDocFragment ) {\n\t\tthis._parentElement = elementOrDocFragment;\n\n\t\t// Take care of the initial collection items passed to the constructor.\n\t\tfor ( const view of this ) {\n\t\t\tthis._renderViewIntoCollectionParent( view );\n\t\t}\n\t}\n\n\t/**\n\t * Delegates selected events coming from within views in the collection to any\n\t * {@link module:utils/emittermixin~Emitter}.\n\t *\n\t * For the following views and collection:\n\t *\n\t *\t\tconst viewA = new View();\n\t *\t\tconst viewB = new View();\n\t *\t\tconst viewC = new View();\n\t *\n\t *\t\tconst views = parentView.createCollection();\n\t *\n\t *\t\tviews.delegate( 'eventX' ).to( viewB );\n\t *\t\tviews.delegate( 'eventX', 'eventY' ).to( viewC );\n\t *\n\t *\t\tviews.add( viewA );\n\t *\n\t * the `eventX` is delegated (fired by) `viewB` and `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventX', customData );\n\t *\n\t * and `eventY` is delegated (fired by) `viewC` along with `customData`:\n\t *\n\t *\t\tviewA.fire( 'eventY', customData );\n\t *\n\t * See {@link module:utils/emittermixin~Emitter#delegate}.\n\t *\n\t * @param {...String} events {@link module:ui/view~View} event names to be delegated to another\n\t * {@link module:utils/emittermixin~Emitter}.\n\t * @returns {Object}\n\t * @returns {Function} return.to A function which accepts the destination of\n\t * {@link module:utils/emittermixin~Emitter#delegate delegated} events.\n\t */\n\tdelegate( ...events ) {\n\t\tif ( !events.length || !isStringArray( events ) ) {\n\t\t\t/**\n\t\t\t * All event names must be strings.\n\t\t\t *\n\t\t\t * @error ui-viewcollection-delegate-wrong-events\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-viewcollection-delegate-wrong-events',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Selects destination for {@link module:utils/emittermixin~Emitter#delegate} events.\n\t\t\t *\n\t\t\t * @memberOf module:ui/viewcollection~ViewCollection#delegate\n\t\t\t * @function module:ui/viewcollection~ViewCollection#delegate.to\n\t\t\t * @param {module:utils/emittermixin~Emitter} dest An `Emitter` instance which is\n\t\t\t * the destination for delegated events.\n\t\t\t */\n\t\t\tto: dest => {\n\t\t\t\t// Activate delegating on existing views in this collection.\n\t\t\t\tfor ( const view of this ) {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Activate delegating on future views in this collection.\n\t\t\t\tthis.on( 'add', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.delegate( evtName ).to( dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\t// Deactivate delegating when view is removed from this collection.\n\t\t\t\tthis.on( 'remove', ( evt, view ) => {\n\t\t\t\t\tfor ( const evtName of events ) {\n\t\t\t\t\t\tview.stopDelegating( evtName, dest );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * This method {@link module:ui/view~View#render renders} a new view added to the collection.\n\t *\n\t * If the {@link #_parentElement parent element} of the collection is set, this method also adds\n\t * the view's {@link module:ui/view~View#element} as a child of the parent in DOM at a specified index.\n\t *\n\t * **Note**: If index is not specified, the view's element is pushed as the last child\n\t * of the parent element.\n\t *\n\t * @private\n\t * @param {module:ui/view~View} view A new view added to the collection.\n\t * @param {Number} [index] An index the view holds in the collection. When not specified,\n\t * the view is added at the end.\n\t */\n\t_renderViewIntoCollectionParent( view, index ) {\n\t\tif ( !view.isRendered ) {\n\t\t\tview.render();\n\t\t}\n\n\t\tif ( view.element && this._parentElement ) {\n\t\t\tthis._parentElement.insertBefore( view.element, this._parentElement.children[ index ] );\n\t\t}\n\t}\n\n\t/**\n\t * Removes a child view from the collection. If the {@link #setParent parent element} of the\n\t * collection has been set, the {@link module:ui/view~View#element element} of the view is also removed\n\t * in DOM, reflecting the order of the collection.\n\t *\n\t * See the {@link #add} method.\n\t *\n\t * @method #remove\n\t * @param {module:ui/view~View|Number|String} subject The view to remove, its id or index in the collection.\n\t * @returns {Object} The removed view.\n\t */\n}\n\n// Check if all entries of the array are of `String` type.\n//\n// @private\n// @param {Array} arr An array to be checked.\n// @returns {Boolean}\nfunction isStringArray( arr ) {\n\treturn arr.every( a => typeof a == 'string' );\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 ui/view\n */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ViewCollection from './viewcollection';\nimport Template from './template';\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport isIterable from '@ckeditor/ckeditor5-utils/src/isiterable';\n\nimport '../theme/globals/globals.css';\n\n/**\n * The basic view class, which represents an HTML element created out of a\n * {@link module:ui/view~View#template}. Views are building blocks of the user interface and handle\n * interaction\n *\n * Views {@link module:ui/view~View#registerChild aggregate} children in\n * {@link module:ui/view~View#createCollection collections} and manage the life cycle of DOM\n * listeners e.g. by handling rendering and destruction.\n *\n * See the {@link module:ui/template~TemplateDefinition} syntax to learn more about shaping view\n * elements, attributes and listeners.\n *\n *\t\tclass SampleView extends View {\n *\t\t\tconstructor( locale ) {\n *\t\t\t\tsuper( locale );\n *\n *\t\t\t\tconst bind = this.bindTemplate;\n *\n *\t\t\t\t// Views define their interface (state) using observable attributes.\n *\t\t\t\tthis.set( 'elementClass', 'bar' );\n *\n *\t\t\t\tthis.setTemplate( {\n *\t\t\t\t\ttag: 'p',\n *\n *\t\t\t\t\t// The element of the view can be defined with its children.\n *\t\t\t\t\tchildren: [\n *\t\t\t\t\t\t'Hello',\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\ttag: 'b',\n *\t\t\t\t\t\t\tchildren: [ 'world!' ]\n *\t\t\t\t\t\t}\n *\t\t\t\t\t],\n *\t\t\t\t\tattributes: {\n *\t\t\t\t\t\tclass: [\n *\t\t\t\t\t\t\t'foo',\n *\n *\t\t\t\t\t\t\t// Observable attributes control the state of the view in DOM.\n *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n *\t\t\t\t\t\t]\n *\t\t\t\t\t},\n *\t\t\t\t\ton: {\n *\t\t\t\t\t\t// Views listen to DOM events and propagate them.\n *\t\t\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t\t\t}\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n *\n *\t\tconst view = new SampleView( locale );\n *\n *\t\tview.render();\n *\n *\t\t// Append <p class=\"foo bar\">Hello<b>world</b></p> to the <body>\n *\t\tdocument.body.appendChild( view.element );\n *\n *\t\t// Change the class attribute to <p class=\"foo baz\">Hello<b>world</b></p>\n *\t\tview.elementClass = 'baz';\n *\n *\t\t// Respond to the \"click\" event in DOM by executing a custom action.\n *\t\tview.on( 'clicked', () => {\n *\t\t\tconsole.log( 'The view has been clicked!' );\n *\t\t} );\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class View {\n\t/**\n\t * Creates an instance of the {@link module:ui/view~View} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t */\n\tconstructor( locale ) {\n\t\t/**\n\t\t * An HTML element of the view. `null` until {@link #render rendered}\n\t\t * from the {@link #template}.\n\t\t *\n\t\t *\t\tclass SampleView extends View {\n\t\t *\t\t\tconstructor() {\n\t\t *\t\t\t\tsuper();\n\t\t *\n\t\t *\t\t\t\t// A template instance the #element will be created from.\n\t\t *\t\t\t\tthis.setTemplate( {\n\t\t *\t\t\t\t\ttag: 'p'\n\t\t *\n\t\t *\t\t\t\t\t// ...\n\t\t *\t\t\t\t} );\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t *\t\tconst view = new SampleView();\n\t\t *\n\t\t *\t\t// Renders the #template.\n\t\t *\t\tview.render();\n\t\t *\n\t\t *\t\t// Append the HTML element of the view to <body>.\n\t\t *\t\tdocument.body.appendChild( view.element );\n\t\t *\n\t\t * **Note**: The element of the view can also be assigned directly:\n\t\t *\n\t\t *\t\tview.element = document.querySelector( '#my-container' );\n\t\t *\n\t\t * @member {HTMLElement}\n\t\t */\n\t\tthis.element = null;\n\n\t\t/**\n\t\t * Set `true` when the view has already been {@link module:ui/view~View#render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isRendered\n\t\t */\n\t\tthis.isRendered = false;\n\n\t\t/**\n\t\t * A set of tools to localize the user interface.\n\t\t *\n\t\t * Also see {@link module:core/editor/editor~Editor#locale}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\n\t\t/**\n\t\t * Shorthand for {@link module:utils/locale~Locale#t}.\n\t\t *\n\t\t * Note: If {@link #locale} instance hasn't been passed to the view this method may not\n\t\t * be available.\n\t\t *\n\t\t * @see module:utils/locale~Locale#t\n\t\t * @method\n\t\t */\n\t\tthis.t = locale && locale.t;\n\n\t\t/**\n\t\t * Collections registered with {@link #createCollection}.\n\t\t *\n\t\t * @protected\n\t\t * @member {Set.<module:ui/viewcollection~ViewCollection>}\n\t\t */\n\t\tthis._viewCollections = new Collection();\n\n\t\t/**\n\t\t * A collection of view instances, which have been added directly\n\t\t * into the {@link module:ui/template~Template#children}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._unboundChildren = this.createCollection();\n\n\t\t// Pass parent locale to its children.\n\t\tthis._viewCollections.on( 'add', ( evt, collection ) => {\n\t\t\tcollection.locale = locale;\n\t\t} );\n\n\t\t/**\n\t\t * Template of this view. It provides the {@link #element} representing\n\t\t * the view in DOM, which is {@link #render rendered}.\n\t\t *\n\t\t * @member {module:ui/template~Template} #template\n\t\t */\n\n\t\t/**\n\t\t * Cached {@link module:ui/template~BindChain bind chain} object created by the\n\t\t * {@link #template}. See {@link #bindTemplate}.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_bindTemplate\n\t\t */\n\n\t\tthis.decorate( 'render' );\n\t}\n\n\t/**\n\t * Shorthand for {@link module:ui/template~Template.bind}, a binding\n\t * {@link module:ui/template~BindChain interface} preconfigured for the view instance.\n\t *\n\t * It provides {@link module:ui/template~BindChain#to `to()`} and\n\t * {@link module:ui/template~BindChain#if `if()`} methods that initialize bindings with\n\t * observable attributes and attach DOM listeners.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tconst bind = this.bindTemplate;\n\t *\n\t *\t\t\t\t// These {@link module:utils/observablemixin~Observable observable} attributes will control\n\t *\t\t\t\t// the state of the view in DOM.\n\t *\t\t\t\tthis.set( {\n\t *\t\t\t\t\telementClass: 'foo',\n\t *\t\t\t\t \tisEnabled: true\n\t *\t\t\t\t } );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\t// The class HTML attribute will follow elementClass\n\t *\t\t\t\t\t\t// and isEnabled view attributes.\n\t *\t\t\t\t\t\tclass: [\n\t *\t\t\t\t\t\t\tbind.to( 'elementClass' )\n\t *\t\t\t\t\t\t\tbind.if( 'isEnabled', 'present-when-enabled' )\n\t *\t\t\t\t\t\t]\n\t *\t\t\t\t\t},\n\t *\n\t *\t\t\t\t\ton: {\n\t *\t\t\t\t\t\t// The view will fire the \"clicked\" event upon clicking <p> in DOM.\n\t *\t\t\t\t\t\tclick: bind.to( 'clicked' )\n\t *\t\t\t\t\t}\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * @method #bindTemplate\n\t */\n\tget bindTemplate() {\n\t\tif ( this._bindTemplate ) {\n\t\t\treturn this._bindTemplate;\n\t\t}\n\n\t\treturn ( this._bindTemplate = Template.bind( this, this ) );\n\t}\n\n\t/**\n\t * Creates a new collection of views, which can be used as\n\t * {@link module:ui/template~Template#children} of this view.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tconst child = new ChildView( locale );\n\t *\t\t\t\tthis.items = this.createCollection( [ child ] );\n \t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n\t *\t\t\t\t\t// `items` collection will render here.\n\t *\t\t\t\t\tchildren: this.items\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\t\tview.render();\n\t *\n\t *\t\t// It will append <p><child#element></p> to the <body>.\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t * @param {Iterable.<module:ui/view~View>} [views] Initial views of the collection.\n\t * @returns {module:ui/viewcollection~ViewCollection} A new collection of view instances.\n\t */\n\tcreateCollection( views ) {\n\t\tconst collection = new ViewCollection( views );\n\n\t\tthis._viewCollections.add( collection );\n\n\t\treturn collection;\n\t}\n\n\t/**\n\t * Registers a new child view under the view instance. Once registered, a child\n\t * view is managed by its parent, including {@link #render rendering}\n\t * and {@link #destroy destruction}.\n\t *\n\t * To revert this, use {@link #deregisterChild}.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( { tag: 'p' } );\n\t *\n\t *\t\t\t\t// Register the children.\n\t *\t\t\t\tthis.registerChild( [ this.childA, this.childB ] );\n\t *\t\t\t}\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\tthis.element.appendChild( this.childA.element );\n\t *\t\t\t\tthis.element.appendChild( this.childB.element );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView( locale );\n\t *\n\t *\t\tview.render();\n\t *\n\t *\t\t// Will append <p><childA#element><b></b><childB#element></p>.\n\t *\t\tdocument.body.appendChild( view.element );\n\t *\n\t * **Note**: There's no need to add child views if they're already referenced in the\n\t * {@link #template}:\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor( locale ) {\n\t *\t\t\t\tsuper( locale );\n\t *\n\t *\t\t\t\tthis.childA = new SomeChildView( locale );\n\t *\t\t\t\tthis.childB = new SomeChildView( locale );\n\t *\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\ttag: 'p',\n\t *\n \t *\t\t\t\t\t// These children will be added automatically. There's no\n \t *\t\t\t\t\t// need to call {@link #registerChild} for any of them.\n\t *\t\t\t\t\tchildren: [ this.childA, this.childB ]\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\n\t *\t\t\t// ...\n\t *\t\t}\n\t *\n\t * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Children views to be registered.\n\t */\n\tregisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.add( child );\n\t\t}\n\t}\n\n\t/**\n\t * The opposite of {@link #registerChild}. Removes a child view from this view instance.\n\t * Once removed, the child is no longer managed by its parent, e.g. it can safely\n\t * become a child of another parent view.\n\t *\n\t * @see #registerChild\n\t * @param {module:ui/view~View|Iterable.<module:ui/view~View>} children Child views to be removed.\n\t */\n\tderegisterChild( children ) {\n\t\tif ( !isIterable( children ) ) {\n\t\t\tchildren = [ children ];\n\t\t}\n\n\t\tfor ( const child of children ) {\n\t\t\tthis._unboundChildren.remove( child );\n\t\t}\n\t}\n\n\t/**\n\t * Sets the {@link #template} of the view with with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tview.setTemplate( definition );\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition of view's template.\n\t */\n\tsetTemplate( definition ) {\n\t\tthis.template = new Template( definition );\n\t}\n\n\t/**\n\t * {@link module:ui/template~Template.extend Extends} the {@link #template} of the view with\n\t * with given definition.\n\t *\n\t * A shorthand for:\n\t *\n\t *\t\tTemplate.extend( view.template, definition );\n\t *\n\t * **Note**: Is requires the {@link #template} to be already set. See {@link #setTemplate}.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} definition Definition which\n\t * extends the {@link #template}.\n\t */\n\textendTemplate( definition ) {\n\t\tTemplate.extend( this.template, definition );\n\t}\n\n\t/**\n\t * Recursively renders the view.\n\t *\n\t * Once the view is rendered:\n\t * * the {@link #element} becomes an HTML element out of {@link #template},\n\t * * the {@link #isRendered} flag is set `true`.\n\t *\n\t * **Note**: The children of the view:\n\t * * defined directly in the {@link #template}\n\t * * residing in collections created by the {@link #createCollection} method,\n\t * * and added by {@link #registerChild}\n\t * are also rendered in the process.\n\t *\n\t * In general, `render()` method is the right place to keep the code which refers to the\n\t * {@link #element} and should be executed at the very beginning of the view's life cycle.\n\t *\n\t * It is possible to {@link module:ui/template~Template.extend} the {@link #template} before\n\t * the view is rendered. To allow an early customization of the view (e.g. by its parent),\n\t * such references should be done in `render()`.\n\t *\n\t *\t\tclass SampleView extends View {\n\t *\t\t\tconstructor() {\n\t *\t\t\t\tthis.setTemplate( {\n\t *\t\t\t\t\t// ...\n\t *\t\t\t\t} );\n\t *\t\t\t},\n\t *\n\t *\t\t\trender() {\n\t *\t\t\t\t// View#element becomes available.\n\t *\t\t\t\tsuper.render();\n\t *\n\t *\t\t\t\t// The \"scroll\" listener depends on #element.\n\t *\t\t\t\tthis.listenTo( window, 'scroll', () => {\n\t *\t\t\t\t\t// A reference to #element would render the #template and make it non-extendable.\n\t *\t\t\t\t\tif ( window.scrollY > 0 ) {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 100;\n\t *\t\t\t\t\t} else {\n\t *\t\t\t\t\t\tthis.element.scrollLeft = 0;\n\t *\t\t\t\t\t}\n\t *\t\t\t\t} );\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t *\t\tconst view = new SampleView();\n\t *\n\t *\t\t// Let's customize the view before it gets rendered.\n\t *\t\tview.extendTemplate( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: [\n\t *\t\t\t\t\t'additional-class'\n\t *\t\t\t\t]\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t *\t\t// Late rendering allows customization of the view.\n\t *\t\tview.render();\n\t */\n\trender() {\n\t\tif ( this.isRendered ) {\n\t\t\t/**\n\t\t\t * This View has already been rendered.\n\t\t\t *\n\t\t\t * @error ui-view-render-already-rendered\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'ui-view-render-already-rendered', this );\n\t\t}\n\n\t\t// Render #element of the view.\n\t\tif ( this.template ) {\n\t\t\tthis.element = this.template.render();\n\n\t\t\t// Autoregister view children from #template.\n\t\t\tthis.registerChild( this.template.getViews() );\n\t\t}\n\n\t\tthis.isRendered = true;\n\t}\n\n\t/**\n\t * Recursively destroys the view instance and child views added by {@link #registerChild} and\n\t * residing in collections created by the {@link #createCollection}.\n\t *\n\t * Destruction disables all event listeners:\n\t * * created on the view, e.g. `view.on( 'event', () => {} )`,\n\t * * defined in the {@link #template} for DOM events.\n\t */\n\tdestroy() {\n\t\tthis.stopListening();\n\n\t\tthis._viewCollections.map( c => c.destroy() );\n\n\t\t// Template isn't obligatory for views.\n\t\tif ( this.template && this.template._revertData ) {\n\t\t\tthis.template.revert( this.element );\n\t\t}\n\t}\n\n\t/**\n\t * Event fired by the {@link #render} method. Actual rendering is executed as a listener to\n\t * this event with the default priority.\n\t *\n\t * See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.\n\t *\n\t * @event render\n\t */\n}\n\nmix( View, DomEmitterMixin );\nmix( View, ObservableMixin );\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 ui/template\n */\n\n/* global document */\n\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport View from './view';\nimport ViewCollection from './viewcollection';\nimport isNode from '@ckeditor/ckeditor5-utils/src/dom/isnode';\nimport { isObject, cloneDeepWith } from 'lodash-es';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\nconst xhtmlNs = 'http://www.w3.org/1999/xhtml';\n\n/**\n * A basic Template class. It renders a DOM HTML element or text from a\n * {@link module:ui/template~TemplateDefinition definition} and supports element attributes, children,\n * bindings to {@link module:utils/observablemixin~Observable observables} and DOM event propagation.\n *\n * A simple template can look like this:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\tclass: 'foo',\n *\t\t\t\tstyle: {\n *\t\t\t\t\tbackgroundColor: 'yellow'\n *\t\t\t\t}\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t'A paragraph.'\n *\t\t\t]\n *\t\t} ).render();\n *\n * and it will render the following HTML element:\n *\n *\t\t<p class=\"foo\" style=\"background-color: yellow;\">A paragraph.</p>\n *\n * Additionally, the `observable` will always fire `clicked` upon clicking `<p>` in the DOM.\n *\n * See {@link module:ui/template~TemplateDefinition} to know more about templates and complex\n * template definitions.\n *\n* @mixes module:utils/emittermixin~EmitterMixin\n */\nexport default class Template {\n\t/**\n\t * Creates an instance of the {@link ~Template} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the template.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, normalize( clone( def ) ) );\n\n\t\t/**\n\t\t * Indicates whether this particular Template instance has been\n\t\t * {@link #render rendered}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._isRendered = false;\n\n\t\t/**\n\t\t * The tag (`tagName`) of this template, e.g. `div`. It also indicates that the template\n\t\t * renders to an HTML element.\n\t\t *\n\t\t * @member {String} #tag\n\t\t */\n\n\t\t/**\n\t\t * The text of the template. It also indicates that the template renders to a DOM text node.\n\t\t *\n\t\t * @member {Array.<String|module:ui/template~TemplateValueSchema>} #text\n\t\t */\n\n\t\t/**\n\t\t * The attributes of the template, e.g. `{ id: [ 'ck-id' ] }`, corresponding with\n\t\t * the attributes of an HTML element.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Object} #attributes\n\t\t */\n\n\t\t/**\n\t\t * The children of the template. They can be either:\n\t\t * * independent instances of {@link ~Template} (subtemplates),\n\t\t * * native DOM Nodes.\n\t\t *\n\t\t * **Note**: This property only makes sense when {@link #tag} is defined.\n\t\t *\n\t\t * @member {Array.<module:ui/template~Template|Node>} #children\n\t\t */\n\n\t\t/**\n\t\t * The DOM event listeners of the template.\n\t\t *\n\t\t * @member {Object} #eventListeners\n\t\t */\n\n\t\t/**\n\t\t * The data used by the {@link #revert} method to restore a node to its original state.\n\t\t *\n\t\t * See: {@link #apply}.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/template~RenderData}\n\t\t */\n\t\tthis._revertData = null;\n\t}\n\n\t/**\n\t * Renders a DOM Node (an HTML element or text) out of the template.\n\t *\n\t *\t\tconst domNode = new Template( { ... } ).render();\n\t *\n\t * See: {@link #apply}.\n\t *\n\t * @returns {HTMLElement|Text}\n\t */\n\trender() {\n\t\tconst node = this._renderNode( {\n\t\t\tintoFragment: true\n\t\t} );\n\n\t\tthis._isRendered = true;\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Applies the template to an existing DOM Node, either HTML element or text.\n\t *\n\t * **Note:** No new DOM nodes will be created. Applying extends:\n\t *\n\t * {@link module:ui/template~TemplateDefinition attributes},\n\t * {@link module:ui/template~TemplateDefinition event listeners}, and\n\t * `textContent` of {@link module:ui/template~TemplateDefinition children} only.\n\t *\n\t * **Note:** Existing `class` and `style` attributes are extended when a template\n\t * is applied to an HTML element, while other attributes and `textContent` are overridden.\n\t *\n\t * **Note:** The process of applying a template can be easily reverted using the\n\t * {@link module:ui/template~Template#revert} method.\n\t *\n\t *\t\tconst element = document.createElement( 'div' );\n\t *\t\tconst observable = new Model( { divClass: 'my-div' } );\n\t *\t\tconst emitter = Object.create( EmitterMixin );\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tid: 'first-div',\n\t *\t\t\t\tclass: bind.to( 'divClass' )\n\t *\t\t\t},\n\t *\t\t\ton: {\n\t *\t\t\t\tclick: bind( 'elementClicked' ) // Will be fired by the observable.\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t'Div text.'\n\t *\t\t\t]\n\t *\t\t} ).apply( element );\n\t *\n\t *\t\tconsole.log( element.outerHTML ); // -> '<div id=\"first-div\" class=\"my-div\"></div>'\n\t *\n\t * @see module:ui/template~Template#render\n\t * @see module:ui/template~Template#revert\n\t * @param {Node} node Root node for the template to apply.\n\t */\n\tapply( node ) {\n\t\tthis._revertData = getEmptyRevertData();\n\n\t\tthis._renderNode( {\n\t\t\tnode,\n\t\t\tisApplying: true,\n\t\t\trevertData: this._revertData\n\t\t} );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Reverts a template {@link module:ui/template~Template#apply applied} to a DOM node.\n\t *\n\t * @param {Node} node The root node for the template to revert. In most of the cases, it is the\n\t * same node used by {@link module:ui/template~Template#apply}.\n\t */\n\trevert( node ) {\n\t\tif ( !this._revertData ) {\n\t\t\t/**\n\t\t\t * Attempting to revert a template which has not been applied yet.\n\t\t\t *\n\t\t\t * @error ui-template-revert-not-applied\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-revert-not-applied',\n\t\t\t\t[ this, node ]\n\t\t\t);\n\t\t}\n\n\t\tthis._revertTemplateFromNode( node, this._revertData );\n\t}\n\n\t/**\n\t * Returns an iterator which traverses the template in search of {@link module:ui/view~View}\n\t * instances and returns them one by one.\n\t *\n\t *\t\tconst viewFoo = new View();\n\t *\t\tconst viewBar = new View();\n\t *\t\tconst viewBaz = new View();\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'div',\n\t *\t\t\tchildren: [\n\t *\t\t\t\tviewFoo,\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'div',\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\tviewBar\n\t *\t\t\t\t\t]\n\t *\t\t\t\t},\n\t *\t\t\t\tviewBaz\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Logs: viewFoo, viewBar, viewBaz\n\t *\t\tfor ( const view of template.getViews() ) {\n\t *\t\t\tconsole.log( view );\n\t *\t\t}\n\t *\n\t * @returns {Iterable.<module:ui/view~View>}\n\t */\n\t* getViews() {\n\t\tfunction* search( def ) {\n\t\t\tif ( def.children ) {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isView( child ) ) {\n\t\t\t\t\t\tyield child;\n\t\t\t\t\t} else if ( isTemplate( child ) ) {\n\t\t\t\t\t\tyield* search( child );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tyield* search( this );\n\t}\n\n\t/**\n\t * An entry point to the interface which binds DOM nodes to\n\t * {@link module:utils/observablemixin~Observable observables}.\n\t * There are two types of bindings:\n\t *\n\t * * HTML element attributes or text `textContent` synchronized with attributes of an\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}\n\t * and {@link module:ui/template~BindChain#if}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\tattributes: {\n\t *\t\t\t\t// Binds the element \"class\" attribute to observable#classAttribute.\n\t *\t\t\t\tclass: bind.to( 'classAttribute' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * * DOM events fired on HTML element propagated through\n\t * {@link module:utils/observablemixin~Observable}. Learn more about {@link module:ui/template~BindChain#to}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tnew Template( {\n\t *\t\t\ton: {\n\t *\t\t\t\t// Will be fired by the observable.\n\t *\t\t\t\tclick: bind( 'elementClicked' )\n\t *\t\t\t}\n\t *\t\t} ).render();\n\t *\n\t * Also see {@link module:ui/view~View#bindTemplate}.\n\t *\n\t * @param {module:utils/observablemixin~Observable} observable An observable which provides boundable attributes.\n\t * @param {module:utils/emittermixin~Emitter} emitter An emitter that listens to observable attribute\n\t * changes or DOM Events (depending on the kind of the binding). Usually, a {@link module:ui/view~View} instance.\n\t * @returns {module:ui/template~BindChain}\n\t */\n\tstatic bind( observable, emitter ) {\n\t\treturn {\n\t\t\tto( eventNameOrFunctionOrAttribute, callback ) {\n\t\t\t\treturn new TemplateToBinding( {\n\t\t\t\t\teventNameOrFunction: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tattribute: eventNameOrFunctionOrAttribute,\n\t\t\t\t\tobservable, emitter, callback\n\t\t\t\t} );\n\t\t\t},\n\n\t\t\tif( attribute, valueIfTrue, callback ) {\n\t\t\t\treturn new TemplateIfBinding( {\n\t\t\t\t\tobservable, emitter, attribute, valueIfTrue, callback\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Extends an existing {@link module:ui/template~Template} instance with some additional content\n\t * from another {@link module:ui/template~TemplateDefinition}.\n\t *\n\t *\t\tconst bind = Template.bind( observable, emitter );\n\t *\n\t *\t\tconst template = new Template( {\n\t *\t\t\ttag: 'p',\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'a',\n\t *\t\t\t\tdata-x: bind.to( 'foo' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\ttag: 'span',\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'b'\n\t *\t\t\t\t\t},\n\t *\t\t\t\t\tchildren: [\n\t *\t\t\t\t\t\t'Span'\n\t *\t\t\t\t\t]\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t } );\n\t *\n\t *\t\t// Instance-level extension.\n\t *\t\tTemplate.extend( template, {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'b',\n\t *\t\t\t\tdata-x: bind.to( 'bar' )\n\t *\t\t\t},\n\t *\t\t\tchildren: [\n\t *\t\t\t\t{\n\t *\t\t\t\t\tattributes: {\n\t *\t\t\t\t\t\tclass: 'c'\n\t *\t\t\t\t\t}\n\t *\t\t\t\t}\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t *\t\t// Child extension.\n\t *\t\tTemplate.extend( template.children[ 0 ], {\n\t *\t\t\tattributes: {\n\t *\t\t\t\tclass: 'd'\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * the `outerHTML` of `template.render()` is:\n\t *\n\t *\t\t<p class=\"a b\" data-x=\"{ observable.foo } { observable.bar }\">\n\t *\t\t\t<span class=\"b c d\">Span</span>\n\t *\t\t</p>\n\t *\n\t * @param {module:ui/template~Template} template An existing template instance to be extended.\n\t * @param {module:ui/template~TemplateDefinition} def Additional definition to be applied to a template.\n\t */\n\tstatic extend( template, def ) {\n\t\tif ( template._isRendered ) {\n\t\t\t/**\n\t\t\t * Extending a template after rendering may not work as expected. To make sure\n\t\t\t * the {@link module:ui/template~Template.extend extending} works for an element,\n\t\t\t * make sure it happens before {@link #render} is called.\n\t\t\t *\n\t\t\t * @error template-extend-render\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'template-extend-render',\n\t\t\t\t[ this, template ]\n\t\t\t);\n\t\t}\n\n\t\textendTemplate( template, normalize( clone( def ) ) );\n\t}\n\n\t/**\n\t * Renders a DOM Node (either an HTML element or text) out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderNode( data ) {\n\t\tlet isInvalid;\n\n\t\tif ( data.node ) {\n\t\t\t// When applying, a definition cannot have \"tag\" and \"text\" at the same time.\n\t\t\tisInvalid = this.tag && this.text;\n\t\t} else {\n\t\t\t// When rendering, a definition must have either \"tag\" or \"text\": XOR( this.tag, this.text ).\n\t\t\tisInvalid = this.tag ? this.text : !this.text;\n\t\t}\n\n\t\tif ( isInvalid ) {\n\t\t\t/**\n\t\t\t * Node definition cannot have the \"tag\" and \"text\" properties at the same time.\n\t\t\t * Node definition must have either \"tag\" or \"text\" when rendering a new Node.\n\t\t\t *\n\t\t\t * @error ui-template-wrong-syntax\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-wrong-syntax',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( this.text ) {\n\t\t\treturn this._renderText( data );\n\t\t} else {\n\t\t\treturn this._renderElement( data );\n\t\t}\n\t}\n\n\t/**\n\t * Renders an HTML element out of the template.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElement( data ) {\n\t\tlet node = data.node;\n\n\t\tif ( !node ) {\n\t\t\tnode = data.node = document.createElementNS( this.ns || xhtmlNs, this.tag );\n\t\t}\n\n\t\tthis._renderAttributes( data );\n\t\tthis._renderElementChildren( data );\n\t\tthis._setUpListeners( data );\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders a text node out of {@link module:ui/template~Template#text}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderText( data ) {\n\t\tlet node = data.node;\n\n\t\t// Save the original textContent to revert it in #revert().\n\t\tif ( node ) {\n\t\t\tdata.revertData.text = node.textContent;\n\t\t} else {\n\t\t\tnode = data.node = document.createTextNode( '' );\n\t\t}\n\n\t\t// Check if this Text Node is bound to Observable. Cases:\n\t\t//\n\t\t//\t\ttext: [ Template.bind( ... ).to( ... ) ]\n\t\t//\n\t\t//\t\ttext: [\n\t\t//\t\t\t'foo',\n\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t//\t\t\t...\n\t\t//\t\t]\n\t\t//\n\t\tif ( hasTemplateBinding( this.text ) ) {\n\t\t\tthis._bindToObservable( {\n\t\t\t\tschema: this.text,\n\t\t\t\tupdater: getTextUpdater( node ),\n\t\t\t\tdata\n\t\t\t} );\n\t\t}\n\t\t// Simply set text. Cases:\n\t\t//\n\t\t//\t\ttext: [ 'all', 'are', 'static' ]\n\t\t//\n\t\t//\t\ttext: [ 'foo' ]\n\t\t//\n\t\telse {\n\t\t\tnode.textContent = this.text.join( '' );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\t/**\n\t * Renders HTML element attributes out of {@link module:ui/template~Template#attributes}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderAttributes( data ) {\n\t\tlet attrName, attrValue, domAttrValue, attrNs;\n\n\t\tif ( !this.attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = data.node;\n\t\tconst revertData = data.revertData;\n\n\t\tfor ( attrName in this.attributes ) {\n\t\t\t// Current attribute value in DOM.\n\t\t\tdomAttrValue = node.getAttribute( attrName );\n\n\t\t\t// The value to be set.\n\t\t\tattrValue = this.attributes[ attrName ];\n\n\t\t\t// Save revert data.\n\t\t\tif ( revertData ) {\n\t\t\t\trevertData.attributes[ attrName ] = domAttrValue;\n\t\t\t}\n\n\t\t\t// Detect custom namespace:\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tattrNs = ( isObject( attrValue[ 0 ] ) && attrValue[ 0 ].ns ) ? attrValue[ 0 ].ns : null;\n\n\t\t\t// Activate binding if one is found. Cases:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'bar',\n\t\t\t//\t\t\tTemplate.bind( ... ).to( ... ),\n\t\t\t//\t\t\t'baz'\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\t//\t\tclass: {\n\t\t\t//\t\t\tns: 'abc',\n\t\t\t//\t\t\tvalue: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( attrValue ) ) {\n\t\t\t\t// Normalize attributes with additional data like namespace:\n\t\t\t\t//\n\t\t\t\t//\t\tclass: {\n\t\t\t\t//\t\t\tns: 'abc',\n\t\t\t\t//\t\t\tvalue: [ ... ]\n\t\t\t\t//\t\t}\n\t\t\t\t//\n\t\t\t\tconst valueToBind = attrNs ? attrValue[ 0 ].value : attrValue;\n\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && shouldExtend( attrName ) ) {\n\t\t\t\t\tvalueToBind.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: valueToBind,\n\t\t\t\t\tupdater: getAttributeUpdater( node, attrName, attrNs ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Style attribute could be an Object so it needs to be parsed in a specific way.\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\twidth: '100px',\n\t\t\t//\t\t\theight: Template.bind( ... ).to( ... )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse if ( attrName == 'style' && typeof attrValue[ 0 ] !== 'string' ) {\n\t\t\t\tthis._renderStyleAttribute( attrValue[ 0 ], data );\n\t\t\t}\n\n\t\t\t// Otherwise simply set the static attribute:\n\t\t\t//\n\t\t\t//\t\tclass: [ 'foo' ]\n\t\t\t//\n\t\t\t//\t\tclass: [ 'all', 'are', 'static' ]\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t{\n\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t//\t\t\t\tvalue: [ 'foo' ]\n\t\t\t//\t\t\t}\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\telse {\n\t\t\t\t// Extend the original value of attributes like \"style\" and \"class\",\n\t\t\t\t// don't override them.\n\t\t\t\tif ( revertData && domAttrValue && shouldExtend( attrName ) ) {\n\t\t\t\t\tattrValue.unshift( domAttrValue );\n\t\t\t\t}\n\n\t\t\t\tattrValue = attrValue\n\t\t\t\t\t// Retrieve \"values\" from:\n\t\t\t\t\t//\n\t\t\t\t\t//\t\tclass: [\n\t\t\t\t\t//\t\t\t{\n\t\t\t\t\t//\t\t\t\tns: 'abc',\n\t\t\t\t\t//\t\t\t\tvalue: [ ... ]\n\t\t\t\t\t//\t\t\t}\n\t\t\t\t\t//\t\t]\n\t\t\t\t\t//\n\t\t\t\t\t.map( val => val ? ( val.value || val ) : val )\n\t\t\t\t\t// Flatten the array.\n\t\t\t\t\t.reduce( ( prev, next ) => prev.concat( next ), [] )\n\t\t\t\t\t// Convert into string.\n\t\t\t\t\t.reduce( arrayValueReducer, '' );\n\n\t\t\t\tif ( !isFalsy( attrValue ) ) {\n\t\t\t\t\tnode.setAttributeNS( attrNs, attrName, attrValue );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Renders the `style` attribute of an HTML element based on\n\t * {@link module:ui/template~Template#attributes}.\n\t *\n\t * A style attribute is an {Object} with static values:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: 'red'\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * or values bound to {@link module:ui/model~Model} properties:\n\t *\n\t *\t\tattributes: {\n\t *\t\t\tstyle: {\n\t *\t\t\t\tcolor: bind.to( ... )\n\t *\t\t\t}\n\t *\t\t}\n\t *\n\t * Note: The `style` attribute is rendered without setting the namespace. It does not seem to be\n\t * needed.\n\t *\n\t * @private\n\t * @param {Object} styles Styles located in `attributes.style` of {@link module:ui/template~TemplateDefinition}.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderStyleAttribute( styles, data ) {\n\t\tconst node = data.node;\n\n\t\tfor ( const styleName in styles ) {\n\t\t\tconst styleValue = styles[ styleName ];\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: bind.to( 'attribute' )\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\tif ( hasTemplateBinding( styleValue ) ) {\n\t\t\t\tthis._bindToObservable( {\n\t\t\t\t\tschema: [ styleValue ],\n\t\t\t\t\tupdater: getStyleUpdater( node, styleName ),\n\t\t\t\t\tdata\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t// Cases:\n\t\t\t//\n\t\t\t//\t\tstyle: {\n\t\t\t//\t\t\tcolor: 'red'\n\t\t\t//\t\t}\n\t\t\t//\n\t\t\telse {\n\t\t\t\tnode.style[ styleName ] = styleValue;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Recursively renders HTML element's children from {@link module:ui/template~Template#children}.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_renderElementChildren( data ) {\n\t\tconst node = data.node;\n\t\tconst container = data.intoFragment ? document.createDocumentFragment() : node;\n\t\tconst isApplying = data.isApplying;\n\t\tlet childIndex = 0;\n\n\t\tfor ( const child of this.children ) {\n\t\t\tif ( isViewCollection( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tchild.setParent( node );\n\n\t\t\t\t\t// Note: ViewCollection renders its children.\n\t\t\t\t\tfor ( const view of child ) {\n\t\t\t\t\t\tcontainer.appendChild( view.element );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if ( isView( child ) ) {\n\t\t\t\tif ( !isApplying ) {\n\t\t\t\t\tif ( !child.isRendered ) {\n\t\t\t\t\t\tchild.render();\n\t\t\t\t\t}\n\n\t\t\t\t\tcontainer.appendChild( child.element );\n\t\t\t\t}\n\t\t\t} else if ( isNode( child ) ) {\n\t\t\t\tcontainer.appendChild( child );\n\t\t\t} else {\n\t\t\t\tif ( isApplying ) {\n\t\t\t\t\tconst revertData = data.revertData;\n\t\t\t\t\tconst childRevertData = getEmptyRevertData();\n\n\t\t\t\t\trevertData.children.push( childRevertData );\n\n\t\t\t\t\tchild._renderNode( {\n\t\t\t\t\t\tnode: container.childNodes[ childIndex++ ],\n\t\t\t\t\t\tisApplying: true,\n\t\t\t\t\t\trevertData: childRevertData\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tcontainer.appendChild( child.render() );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( data.intoFragment ) {\n\t\t\tnode.appendChild( container );\n\t\t}\n\t}\n\n\t/**\n\t * Activates `on` event listeners from the {@link module:ui/template~TemplateDefinition}\n\t * on an HTML element.\n\t *\n\t * @protected\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t */\n\t_setUpListeners( data ) {\n\t\tif ( !this.eventListeners ) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const key in this.eventListeners ) {\n\t\t\tconst revertBindings = this.eventListeners[ key ].map( schemaItem => {\n\t\t\t\tconst [ domEvtName, domSelector ] = key.split( '@' );\n\n\t\t\t\treturn schemaItem.activateDomEventListener( domEvtName, domSelector, data );\n\t\t\t} );\n\n\t\t\tif ( data.revertData ) {\n\t\t\t\tdata.revertData.bindings.push( revertBindings );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * For a given {@link module:ui/template~TemplateValueSchema} containing {@link module:ui/template~TemplateBinding}\n\t * activates the binding and sets its initial value.\n\t *\n\t * Note: {@link module:ui/template~TemplateValueSchema} can be for HTML element attributes or\n\t * text node `textContent`.\n\t *\n\t * @protected\n\t * @param {Object} options Binding options.\n\t * @param {module:ui/template~TemplateValueSchema} options.schema\n\t * @param {Function} options.updater A function which updates the DOM (like attribute or text).\n\t * @param {module:ui/template~RenderData} options.data Rendering data.\n\t */\n\t_bindToObservable( { schema, updater, data } ) {\n\t\tconst revertData = data.revertData;\n\n\t\t// Set initial values.\n\t\tsyncValueSchemaValue( schema, updater, data );\n\n\t\tconst revertBindings = schema\n\t\t\t// Filter \"falsy\" (false, undefined, null, '') value schema components out.\n\t\t\t.filter( item => !isFalsy( item ) )\n\t\t\t// Filter inactive bindings from schema, like static strings ('foo'), numbers (42), etc.\n\t\t\t.filter( item => item.observable )\n\t\t\t// Once only the actual binding are left, let the emitter listen to observable change:attribute event.\n\t\t\t// TODO: Reduce the number of listeners attached as many bindings may listen\n\t\t\t// to the same observable attribute.\n\t\t\t.map( templateBinding => templateBinding.activateAttributeListener( schema, updater, data ) );\n\n\t\tif ( revertData ) {\n\t\t\trevertData.bindings.push( revertBindings );\n\t\t}\n\t}\n\n\t/**\n\t * Reverts {@link module:ui/template~RenderData#revertData template data} from a node to\n\t * return it to the original state.\n\t *\n\t * @protected\n\t * @param {HTMLElement|Text} node A node to be reverted.\n\t * @param {Object} revertData An object that stores information about what changes have been made by\n\t * {@link #apply} to the node. See {@link module:ui/template~RenderData#revertData} for more information.\n\t */\n\t_revertTemplateFromNode( node, revertData ) {\n\t\tfor ( const binding of revertData.bindings ) {\n\t\t\t// Each binding may consist of several observable+observable#attribute.\n\t\t\t// like the following has 2:\n\t\t\t//\n\t\t\t//\t\tclass: [\n\t\t\t//\t\t\t'x',\n\t\t\t//\t\t\tbind.to( 'foo' ),\n\t\t\t//\t\t\t'y',\n\t\t\t//\t\t\tbind.to( 'bar' )\n\t\t\t//\t\t]\n\t\t\t//\n\t\t\tfor ( const revertBinding of binding ) {\n\t\t\t\trevertBinding();\n\t\t\t}\n\t\t}\n\n\t\tif ( revertData.text ) {\n\t\t\tnode.textContent = revertData.text;\n\n\t\t\treturn;\n\t\t}\n\n\t\tfor ( const attrName in revertData.attributes ) {\n\t\t\tconst attrValue = revertData.attributes[ attrName ];\n\n\t\t\t// When the attribute has **not** been set before #apply().\n\t\t\tif ( attrValue === null ) {\n\t\t\t\tnode.removeAttribute( attrName );\n\t\t\t} else {\n\t\t\t\tnode.setAttribute( attrName, attrValue );\n\t\t\t}\n\t\t}\n\n\t\tfor ( let i = 0; i < revertData.children.length; ++i ) {\n\t\t\tthis._revertTemplateFromNode( node.childNodes[ i ], revertData.children[ i ] );\n\t\t}\n\t}\n}\n\nmix( Template, EmitterMixin );\n\n/**\n * Describes a binding created by the {@link module:ui/template~Template.bind} interface.\n *\n * @protected\n */\nexport class TemplateBinding {\n\t/**\n\t * Creates an instance of the {@link module:ui/template~TemplateBinding} class.\n\t *\n\t * @param {module:ui/template~TemplateDefinition} def The definition of the binding.\n\t */\n\tconstructor( def ) {\n\t\tObject.assign( this, def );\n\n\t\t/**\n\t\t * An observable instance of the binding. It either:\n\t\t *\n\t\t * * provides the attribute with the value,\n\t\t * * or passes the event when a corresponding DOM event is fired.\n\t\t *\n\t\t * @member {module:utils/observablemixin~ObservableMixin} module:ui/template~TemplateBinding#observable\n\t\t */\n\n\t\t/**\n\t\t * An {@link module:utils/emittermixin~Emitter} used by the binding to:\n\t\t *\n\t\t * * listen to the attribute change in the {@link module:ui/template~TemplateBinding#observable},\n\t\t * * or listen to the event in the DOM.\n\t\t *\n\t\t * @member {module:utils/emittermixin~EmitterMixin} module:ui/template~TemplateBinding#emitter\n\t\t */\n\n\t\t/**\n\t\t * The name of the {@link module:ui/template~TemplateBinding#observable observed attribute}.\n\t\t *\n\t\t * @member {String} module:ui/template~TemplateBinding#attribute\n\t\t */\n\n\t\t/**\n\t\t * A custom function to process the value of the {@link module:ui/template~TemplateBinding#attribute}.\n\t\t *\n\t\t * @member {Function} [module:ui/template~TemplateBinding#callback]\n\t\t */\n\t}\n\n\t/**\n\t * Returns the value of the binding. It is the value of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}. The value may be processed by the\n\t * {@link module:ui/template~TemplateBinding#callback}, if such has been passed to the binding.\n\t *\n\t * @param {Node} [node] A native DOM node, passed to the custom {@link module:ui/template~TemplateBinding#callback}.\n\t * @returns {*} The value of {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}.\n\t */\n\tgetValue( node ) {\n\t\tconst value = this.observable[ this.attribute ];\n\n\t\treturn this.callback ? this.callback( value, node ) : value;\n\t}\n\n\t/**\n\t * Activates the listener which waits for changes of the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable}, then updates the DOM with the aggregated\n\t * value of {@link module:ui/template~TemplateValueSchema}.\n\t *\n\t * @param {module:ui/template~TemplateValueSchema} schema A full schema to generate an attribute or text in the DOM.\n\t * @param {Function} updater A DOM updater function used to update the native DOM attribute or text.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateAttributeListener( schema, updater, data ) {\n\t\tconst callback = () => syncValueSchemaValue( schema, updater, data );\n\n\t\tthis.emitter.listenTo( this.observable, 'change:' + this.attribute, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( this.observable, 'change:' + this.attribute, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes either:\n *\n * * a binding to an {@link module:utils/observablemixin~Observable},\n * * or a native DOM event binding.\n *\n * It is created by the {@link module:ui/template~BindChain#to} method.\n *\n * @protected\n */\nexport class TemplateToBinding extends TemplateBinding {\n\t/**\n\t * Activates the listener for the native DOM event, which when fired, is propagated by\n\t * the {@link module:ui/template~TemplateBinding#emitter}.\n\t *\n\t * @param {String} domEvtName The name of the native DOM event.\n\t * @param {String} domSelector The selector in the DOM to filter delegated events.\n\t * @param {module:ui/template~RenderData} data Rendering data.\n\t * @returns {Function} A function to sever the listener binding.\n\t */\n\tactivateDomEventListener( domEvtName, domSelector, data ) {\n\t\tconst callback = ( evt, domEvt ) => {\n\t\t\tif ( !domSelector || domEvt.target.matches( domSelector ) ) {\n\t\t\t\tif ( typeof this.eventNameOrFunction == 'function' ) {\n\t\t\t\t\tthis.eventNameOrFunction( domEvt );\n\t\t\t\t} else {\n\t\t\t\t\tthis.observable.fire( this.eventNameOrFunction, domEvt );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.emitter.listenTo( data.node, domEvtName, callback );\n\n\t\t// Allows revert of the listener.\n\t\treturn () => {\n\t\t\tthis.emitter.stopListening( data.node, domEvtName, callback );\n\t\t};\n\t}\n}\n\n/**\n * Describes a binding to {@link module:utils/observablemixin~ObservableMixin} created by the {@link module:ui/template~BindChain#if}\n * method.\n *\n * @protected\n */\nexport class TemplateIfBinding extends TemplateBinding {\n\t/**\n\t * @inheritDoc\n\t */\n\tgetValue( node ) {\n\t\tconst value = super.getValue( node );\n\n\t\treturn isFalsy( value ) ? false : ( this.valueIfTrue || true );\n\t}\n\n\t/**\n\t * The value of the DOM attribute or text to be set if the {@link module:ui/template~TemplateBinding#attribute} in\n\t * {@link module:ui/template~TemplateBinding#observable} is `true`.\n\t *\n\t * @member {String} [module:ui/template~TemplateIfBinding#valueIfTrue]\n\t */\n}\n\n// Checks whether given {@link module:ui/template~TemplateValueSchema} contains a\n// {@link module:ui/template~TemplateBinding}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @returns {Boolean}\nfunction hasTemplateBinding( schema ) {\n\tif ( !schema ) {\n\t\treturn false;\n\t}\n\n\t// Normalize attributes with additional data like namespace:\n\t//\n\t//\t\tclass: {\n\t//\t\t\tns: 'abc',\n\t//\t\t\tvalue: [ ... ]\n\t//\t\t}\n\t//\n\tif ( schema.value ) {\n\t\tschema = schema.value;\n\t}\n\n\tif ( Array.isArray( schema ) ) {\n\t\treturn schema.some( hasTemplateBinding );\n\t} else if ( schema instanceof TemplateBinding ) {\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Assembles the value using {@link module:ui/template~TemplateValueSchema} and stores it in a form of\n// an Array. Each entry of the Array corresponds to one of {@link module:ui/template~TemplateValueSchema}\n// items.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\n// @returns {Array}\nfunction getValueSchemaValue( schema, node ) {\n\treturn schema.map( schemaItem => {\n\t\t// Process {@link module:ui/template~TemplateBinding} bindings.\n\t\tif ( schemaItem instanceof TemplateBinding ) {\n\t\t\treturn schemaItem.getValue( node );\n\t\t}\n\n\t\t// All static values like strings, numbers, and \"falsy\" values (false, null, undefined, '', etc.) just pass.\n\t\treturn schemaItem;\n\t} );\n}\n\n// A function executed each time the bound Observable attribute changes, which updates the DOM with a value\n// constructed from {@link module:ui/template~TemplateValueSchema}.\n//\n// @param {module:ui/template~TemplateValueSchema} schema\n// @param {Function} updater A function which updates the DOM (like attribute or text).\n// @param {Node} node DOM Node updated when {@link module:utils/observablemixin~ObservableMixin} changes.\nfunction syncValueSchemaValue( schema, updater, { node } ) {\n\tlet value = getValueSchemaValue( schema, node );\n\n\t// Check if schema is a single Template.bind.if, like:\n\t//\n\t//\t\tclass: Template.bind.if( 'foo' )\n\t//\n\tif ( schema.length == 1 && schema[ 0 ] instanceof TemplateIfBinding ) {\n\t\tvalue = value[ 0 ];\n\t} else {\n\t\tvalue = value.reduce( arrayValueReducer, '' );\n\t}\n\n\tif ( isFalsy( value ) ) {\n\t\tupdater.remove();\n\t} else {\n\t\tupdater.set( value );\n\t}\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset `textContent`.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @returns {Object}\nfunction getTextUpdater( node ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tnode.textContent = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tnode.textContent = '';\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of DOM Node to set or reset an attribute.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} attrName Name of the attribute to be modified.\n// @param {String} [ns=null] Namespace to use.\n// @returns {Object}\nfunction getAttributeUpdater( el, attrName, ns ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.setAttributeNS( ns, attrName, value );\n\t\t},\n\n\t\tremove() {\n\t\t\tel.removeAttributeNS( ns, attrName );\n\t\t}\n\t};\n}\n\n// Returns an object consisting of `set` and `remove` functions, which\n// can be used in the context of CSSStyleDeclaration to set or remove a style.\n// @see module:ui/view~View#_bindToObservable\n//\n// @param {Node} node DOM Node to be modified.\n// @param {String} styleName Name of the style to be modified.\n// @returns {Object}\nfunction getStyleUpdater( el, styleName ) {\n\treturn {\n\t\tset( value ) {\n\t\t\tel.style[ styleName ] = value;\n\t\t},\n\n\t\tremove() {\n\t\t\tel.style[ styleName ] = null;\n\t\t}\n\t};\n}\n\n// Clones definition of the template.\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition}\nfunction clone( def ) {\n\tconst clone = cloneDeepWith( def, value => {\n\t\t// Don't clone the `Template.bind`* bindings because of the references to Observable\n\t\t// and DomEmitterMixin instances inside, which would also be traversed and cloned by greedy\n\t\t// cloneDeepWith algorithm. There's no point in cloning Observable/DomEmitterMixins\n\t\t// along with the definition.\n\t\t//\n\t\t// Don't clone Template instances if provided as a child. They're simply #render()ed\n\t\t// and nothing should interfere.\n\t\t//\n\t\t// Also don't clone View instances if provided as a child of the Template. The template\n\t\t// instance will be extracted from the View during the normalization and there's no need\n\t\t// to clone it.\n\t\tif ( value && ( value instanceof TemplateBinding || isTemplate( value ) || isView( value ) || isViewCollection( value ) ) ) {\n\t\t\treturn value;\n\t\t}\n\t} );\n\n\treturn clone;\n}\n\n// Normalizes given {@link module:ui/template~TemplateDefinition}.\n//\n// See:\n// * {@link normalizeAttributes}\n// * {@link normalizeListeners}\n// * {@link normalizePlainTextDefinition}\n// * {@link normalizeTextDefinition}\n//\n// @param {module:ui/template~TemplateDefinition} def\n// @returns {module:ui/template~TemplateDefinition} Normalized definition.\nfunction normalize( def ) {\n\tif ( typeof def == 'string' ) {\n\t\tdef = normalizePlainTextDefinition( def );\n\t} else if ( def.text ) {\n\t\tnormalizeTextDefinition( def );\n\t}\n\n\tif ( def.on ) {\n\t\tdef.eventListeners = normalizeListeners( def.on );\n\n\t\t// Template mixes EmitterMixin, so delete #on to avoid collision.\n\t\tdelete def.on;\n\t}\n\n\tif ( !def.text ) {\n\t\tif ( def.attributes ) {\n\t\t\tnormalizeAttributes( def.attributes );\n\t\t}\n\n\t\tconst children = [];\n\n\t\tif ( def.children ) {\n\t\t\tif ( isViewCollection( def.children ) ) {\n\t\t\t\tchildren.push( def.children );\n\t\t\t} else {\n\t\t\t\tfor ( const child of def.children ) {\n\t\t\t\t\tif ( isTemplate( child ) || isView( child ) || isNode( child ) ) {\n\t\t\t\t\t\tchildren.push( child );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchildren.push( new Template( child ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tdef.children = children;\n\t}\n\n\treturn def;\n}\n\n// Normalizes \"attributes\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tattributes: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: {\n//\t\t\t\tvalue: 'bar'\n//\t\t\t}\n//\t\t}\n//\n// becomes\n//\n//\t\tattributes: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: {\n//\t\t\t\tvalue: [ 'bar' ]\n//\t\t\t}\n//\t\t}\n//\n// @param {Object} attributes\nfunction normalizeAttributes( attributes ) {\n\tfor ( const a in attributes ) {\n\t\tif ( attributes[ a ].value ) {\n\t\t\tattributes[ a ].value = toArray( attributes[ a ].value );\n\t\t}\n\n\t\tarrayify( attributes, a );\n\t}\n}\n\n// Normalizes \"on\" section of {@link module:ui/template~TemplateDefinition}.\n//\n//\t\ton: {\n//\t\t\ta: 'bar',\n//\t\t\tb: {@link module:ui/template~TemplateBinding},\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// becomes\n//\n//\t\ton: {\n//\t\t\ta: [ 'bar' ],\n//\t\t\tb: [ {@link module:ui/template~TemplateBinding} ],\n//\t\t\tc: [ {@link module:ui/template~TemplateBinding}, () => { ... } ]\n//\t\t}\n//\n// @param {Object} listeners\n// @returns {Object} Object containing normalized listeners.\nfunction normalizeListeners( listeners ) {\n\tfor ( const l in listeners ) {\n\t\tarrayify( listeners, l );\n\t}\n\n\treturn listeners;\n}\n\n// Normalizes \"string\" {@link module:ui/template~TemplateDefinition}.\n//\n//\t\t\"foo\"\n//\n// becomes\n//\n//\t\t{ text: [ 'foo' ] },\n//\n// @param {String} def\n// @returns {module:ui/template~TemplateDefinition} Normalized template definition.\nfunction normalizePlainTextDefinition( def ) {\n\treturn {\n\t\ttext: [ def ]\n\t};\n}\n\n// Normalizes text {@link module:ui/template~TemplateDefinition}.\n//\n//\t\tchildren: [\n//\t\t\t{ text: 'def' },\n//\t\t\t{ text: {@link module:ui/template~TemplateBinding} }\n//\t\t]\n//\n// becomes\n//\n//\t\tchildren: [\n//\t\t\t{ text: [ 'def' ] },\n//\t\t\t{ text: [ {@link module:ui/template~TemplateBinding} ] }\n//\t\t]\n//\n// @param {module:ui/template~TemplateDefinition} def\nfunction normalizeTextDefinition( def ) {\n\tdef.text = toArray( def.text );\n}\n\n// Wraps an entry in Object in an Array, if not already one.\n//\n//\t\t{\n//\t\t\tx: 'y',\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// becomes\n//\n//\t\t{\n//\t\t\tx: [ 'y' ],\n//\t\t\ta: [ 'b' ]\n//\t\t}\n//\n// @param {Object} obj\n// @param {String} key\nfunction arrayify( obj, key ) {\n\tobj[ key ] = toArray( obj[ key ] );\n}\n\n// A helper which concatenates the value avoiding unwanted\n// leading white spaces.\n//\n// @param {String} prev\n// @param {String} cur\n// @returns {String}\nfunction arrayValueReducer( prev, cur ) {\n\tif ( isFalsy( cur ) ) {\n\t\treturn prev;\n\t} else if ( isFalsy( prev ) ) {\n\t\treturn cur;\n\t} else {\n\t\treturn `${ prev } ${ cur }`;\n\t}\n}\n\n// Extends one object defined in the following format:\n//\n//\t\t{\n//\t\t\tkey1: [Array1],\n//\t\t\tkey2: [Array2],\n//\t\t\t...\n//\t\t\tkeyN: [ArrayN]\n//\t\t}\n//\n// with another object of the same data format.\n//\n// @param {Object} obj Base object.\n// @param {Object} ext Object extending base.\n// @returns {String}\nfunction extendObjectValueArray( obj, ext ) {\n\tfor ( const a in ext ) {\n\t\tif ( obj[ a ] ) {\n\t\t\tobj[ a ].push( ...ext[ a ] );\n\t\t} else {\n\t\t\tobj[ a ] = ext[ a ];\n\t\t}\n\t}\n}\n\n// A helper for {@link module:ui/template~Template#extend}. Recursively extends {@link module:ui/template~Template} instance\n// with content from {@link module:ui/template~TemplateDefinition}. See {@link module:ui/template~Template#extend} to learn more.\n//\n// @param {module:ui/template~Template} def A template instance to be extended.\n// @param {module:ui/template~TemplateDefinition} def A definition which is to extend the template instance.\n// @param {Object} Error context.\nfunction extendTemplate( template, def ) {\n\tif ( def.attributes ) {\n\t\tif ( !template.attributes ) {\n\t\t\ttemplate.attributes = {};\n\t\t}\n\n\t\textendObjectValueArray( template.attributes, def.attributes );\n\t}\n\n\tif ( def.eventListeners ) {\n\t\tif ( !template.eventListeners ) {\n\t\t\ttemplate.eventListeners = {};\n\t\t}\n\n\t\textendObjectValueArray( template.eventListeners, def.eventListeners );\n\t}\n\n\tif ( def.text ) {\n\t\ttemplate.text.push( ...def.text );\n\t}\n\n\tif ( def.children && def.children.length ) {\n\t\tif ( template.children.length != def.children.length ) {\n\t\t\t/**\n\t\t\t * The number of children in extended definition does not match.\n\t\t\t *\n\t\t\t * @error ui-template-extend-children-mismatch\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'ui-template-extend-children-mismatch',\n\t\t\t\ttemplate\n\t\t\t);\n\t\t}\n\n\t\tlet childIndex = 0;\n\n\t\tfor ( const childDef of def.children ) {\n\t\t\textendTemplate( template.children[ childIndex++ ], childDef );\n\t\t}\n\t}\n}\n\n// Checks if value is \"falsy\".\n// Note: 0 (Number) is not \"falsy\" in this context.\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isFalsy( value ) {\n\treturn !value && value !== 0;\n}\n\n// Checks if the item is an instance of {@link module:ui/view~View}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isView( item ) {\n\treturn item instanceof View;\n}\n\n// Checks if the item is an instance of {@link module:ui/template~Template}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isTemplate( item ) {\n\treturn item instanceof Template;\n}\n\n// Checks if the item is an instance of {@link module:ui/viewcollection~ViewCollection}\n//\n// @private\n// @param {*} value Value to be checked.\nfunction isViewCollection( item ) {\n\treturn item instanceof ViewCollection;\n}\n\n// Creates an empty skeleton for {@link module:ui/template~Template#revert}\n// data.\n//\n// @private\nfunction getEmptyRevertData() {\n\treturn {\n\t\tchildren: [],\n\t\tbindings: [],\n\t\tattributes: {}\n\t};\n}\n\n// Checks whether an attribute should be extended when\n// {@link module:ui/template~Template#apply} is called.\n//\n// @private\n// @param {String} attrName Attribute name to check.\nfunction shouldExtend( attrName ) {\n\treturn attrName == 'class' || attrName == 'style';\n}\n\n/**\n * A definition of the {@link module:ui/template~Template}. It describes what kind of\n * node a template will render (HTML element or text), attributes of an element, DOM event\n * listeners and children.\n *\n * Also see:\n * * {@link module:ui/template~TemplateValueSchema} to learn about HTML element attributes,\n * * {@link module:ui/template~TemplateListenerSchema} to learn about DOM event listeners.\n *\n * A sample definition on an HTML element can look like this:\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\ttag: 'span',\n *\t\t\t\t\tattributes: { ... },\n *\t\t\t\t\tchildren: [ ... ],\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\ttext: 'statictext'\n *\t\t\t\t},\n *\t\t\t\t'also-statictext',\n *\t\t\t],\n *\t\t\tattributes: {\n *\t\t\t\tclass: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tid: {@link module:ui/template~TemplateValueSchema},\n *\t\t\t\tstyle: {@link module:ui/template~TemplateValueSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t},\n *\t\t\ton: {\n *\t\t\t\t'click': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// Document.querySelector format is also accepted.\n *\t\t\t\t'keyup@a.some-class': {@link module:ui/template~TemplateListenerSchema}\n *\n *\t\t\t\t// ...\n *\t\t\t}\n *\t\t} );\n *\n * A {@link module:ui/view~View}, another {@link module:ui/template~Template} or a native DOM node\n * can also become a child of a template. When a view is passed, its {@link module:ui/view~View#element} is used:\n *\n *\t\tconst view = new SomeView();\n *\t\tconst childTemplate = new Template( { ... } );\n *\t\tconst childNode = document.createElement( 'b' );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: [\n *\t\t\t\t// view#element will be added as a child of this <p>.\n *\t\t\t\tview,\n *\n * \t\t\t\t// The output of childTemplate.render() will be added here.\n *\t\t\t\tchildTemplate,\n *\n *\t\t\t\t// Native DOM nodes are included directly in the rendered output.\n *\t\t\t\tchildNode\n *\t\t\t]\n *\t\t} );\n *\n * An entire {@link module:ui/viewcollection~ViewCollection} can be used as a child in the definition:\n *\n *\t\tconst collection = new ViewCollection();\n *\t\tcollection.add( someView );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\n *\t\t\tchildren: collection\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateDefinition\n * @type Object\n *\n * @property {String} tag See the template {@link module:ui/template~Template#tag} property.\n *\n * @property {Array.<module:ui/template~TemplateDefinition>} [children]\n * See the template {@link module:ui/template~Template#children} property.\n *\n * @property {Object.<String, module:ui/template~TemplateValueSchema>} [attributes]\n * See the template {@link module:ui/template~Template#attributes} property.\n *\n * @property {String|module:ui/template~TemplateValueSchema|Array.<String|module:ui/template~TemplateValueSchema>} [text]\n * See the template {@link module:ui/template~Template#text} property.\n *\n * @property {Object.<String, module:ui/template~TemplateListenerSchema>} [on]\n * See the template {@link module:ui/template~Template#eventListeners} property.\n */\n\n/**\n * Describes a value of an HTML element attribute or `textContent`. It allows combining multiple\n * data sources like static values and {@link module:utils/observablemixin~Observable} attributes.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn where to use it,\n * * {@link module:ui/template~Template.bind} to learn how to configure\n * {@link module:utils/observablemixin~Observable} attribute bindings,\n * * {@link module:ui/template~Template#render} to learn how to render a template,\n * * {@link module:ui/template~BindChain#to `to()`} and {@link module:ui/template~BindChain#if `if()`}\n * methods to learn more about bindings.\n *\n * Attribute values can be described in many different ways:\n *\n *\t\t// Bind helper will create bindings to attributes of the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// A plain string schema.\n *\t\t\t\t'class': 'static-text',\n *\n *\t\t\t\t// An object schema, binds to the \"foo\" attribute of the\n *\t\t\t\t// observable and follows its value.\n *\t\t\t\t'class': bind.to( 'foo' ),\n *\n *\t\t\t\t// An array schema, combines the above.\n *\t\t\t\t'class': [\n *\t\t\t\t\t'static-text',\n *\t\t\t\t\tbind.to( 'bar', () => { ... } ),\n *\n * \t\t\t\t\t// Bindings can also be conditional.\n *\t\t\t\t\tbind.if( 'baz', 'class-when-baz-is-true' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema, with a custom namespace, e.g. useful for creating SVGs.\n *\t\t\t\t'class': {\n *\t\t\t\t\tns: 'http://ns.url',\n *\t\t\t\t\tvalue: [\n *\t\t\t\t\t\tbind.if( 'baz', 'value-when-true' ),\n *\t\t\t\t\t\t'static-text'\n *\t\t\t\t\t]\n *\t\t\t\t},\n *\n *\t\t\t\t// An object schema, specific for styles.\n *\t\t\t\tstyle: {\n *\t\t\t\t\tcolor: 'red',\n *\t\t\t\t\tbackgroundColor: bind.to( 'qux', () => { ... } )\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * Text nodes can also have complex values:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\t// Will render a \"foo\" text node.\n *\t\tnew Template( {\n *\t\t\ttext: 'foo'\n *\t\t} );\n *\n *\t\t// Will render a \"static text: {observable.foo}\" text node.\n *\t\t// The text of the node will be updated as the \"foo\" attribute changes.\n *\t\tnew Template( {\n *\t\t\ttext: [\n *\t\t\t\t'static text: ',\n *\t\t\t\tbind.to( 'foo', () => { ... } )\n *\t\t\t]\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateValueSchema\n * @type {Object|String|Array}\n */\n\n/**\n * Describes an event listener attached to an HTML element. Such listener can propagate DOM events\n * through an {@link module:utils/observablemixin~Observable} instance, execute custom callbacks\n * or both, if necessary.\n *\n * Also see:\n * * {@link module:ui/template~TemplateDefinition} to learn more about template definitions,\n * * {@link module:ui/template~BindChain#to `to()`} method to learn more about bindings.\n *\n * Check out different ways of attaching event listeners below:\n *\n *\t\t// Bind helper will propagate events through the observable.\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\ton: {\n *\t\t\t\t// An object schema. The observable will fire the \"clicked\" event upon DOM \"click\".\n *\t\t\t\tclick: bind.to( 'clicked' )\n *\n *\t\t\t\t// An object schema. It will work for \"click\" event on \"a.foo\" children only.\n *\t\t\t\t'click@a.foo': bind.to( 'clicked' )\n *\n *\t\t\t\t// An array schema, makes the observable propagate multiple events.\n *\t\t\t\tclick: [\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( 'executed' )\n *\t\t\t\t],\n *\n *\t\t\t\t// An array schema with a custom callback.\n *\t\t\t\t'click@a.foo': {\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\t\t\t\t\tbind.to( evt => {\n *\t\t\t\t\t\tconsole.log( `${ evt.target } has been clicked!` );\n *\t\t\t\t\t} }\n *\t\t\t\t}\n *\t\t\t}\n *\t\t} );\n *\n * @typedef module:ui/template~TemplateListenerSchema\n * @type {Object|String|Array}\n */\n\n/**\n * The return value of {@link ~Template.bind `Template.bind()`}. It provides `to()` and `if()`\n * methods to create the {@link module:utils/observablemixin~Observable observable} attribute and event bindings.\n *\n * @interface module:ui/template~BindChain\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to either:\n *\n * * an HTML element attribute or a text node `textContent`, so it remains in sync with the observable\n * attribute as it changes,\n * * or an HTML element DOM event, so the DOM events are propagated through an observable.\n *\n * Some common use cases of `to()` bindings are presented below:\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'p',\n *\t\t\tattributes: {\n *\t\t\t\t// class=\"...\" attribute gets bound to `observable#a`\n *\t\t\t\tclass: bind.to( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t// <p>...</p> gets bound to observable#b; always `toUpperCase()`.\n *\t\t\t\t{\n *\t\t\t\t\ttext: bind.to( 'b', ( value, node ) => value.toUpperCase() )\n *\t\t\t\t}\n *\t\t\t],\n *\t\t\ton: {\n *\t\t\t\tclick: [\n *\t\t\t\t\t// An observable will fire \"clicked\" upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( 'clicked' ),\n *\n *\t\t\t\t\t// A custom callback will be executed upon \"click\" in the DOM.\n *\t\t\t\t\tbind.to( () => {\n *\t\t\t\t\t\t...\n *\t\t\t\t\t} )\n *\t\t\t\t]\n *\t\t\t}\n *\t\t} ).render();\n *\n * Learn more about using `to()` in the {@link module:ui/template~TemplateValueSchema} and\n * {@link module:ui/template~TemplateListenerSchema}.\n *\n * @method #to\n * @param {String|Function} eventNameOrFunctionOrAttribute An attribute name of\n * {@link module:utils/observablemixin~Observable} or a DOM event name or an event callback.\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * Binds an {@link module:utils/observablemixin~Observable observable} to an HTML element attribute or a text\n * node `textContent` so it remains in sync with the observable attribute as it changes.\n *\n * Unlike {@link module:ui/template~BindChain#to}, it controls the presence of the attribute or `textContent`\n * depending on the \"falseness\" of an {@link module:utils/observablemixin~Observable} attribute.\n *\n *\t\tconst bind = Template.bind( observable, emitter );\n *\n *\t\tnew Template( {\n *\t\t\ttag: 'input',\n *\t\t\tattributes: {\n *\t\t\t\t// <input checked> when `observable#a` is not undefined/null/false/''\n *\t\t\t\t// <input> when `observable#a` is undefined/null/false\n *\t\t\t\tchecked: bind.if( 'a' )\n *\t\t\t},\n *\t\t\tchildren: [\n *\t\t\t\t{\n *\t\t\t\t\t// <input>\"b-is-not-set\"</input> when `observable#b` is undefined/null/false/''\n *\t\t\t\t\t// <input></input> when `observable#b` is not \"falsy\"\n *\t\t\t\t\ttext: bind.if( 'b', 'b-is-not-set', ( value, node ) => !value )\n *\t\t\t\t}\n *\t\t\t]\n *\t\t} ).render();\n *\n * Learn more about using `if()` in the {@link module:ui/template~TemplateValueSchema}.\n *\n * @method #if\n * @param {String} attribute An attribute name of {@link module:utils/observablemixin~Observable} used in the binding.\n * @param {String} [valueIfTrue] Value set when the {@link module:utils/observablemixin~Observable} attribute is not\n * undefined/null/false/'' (empty string).\n * @param {Function} [callback] Allows for processing of the value. Accepts `Node` and `value` as arguments.\n * @returns {module:ui/template~TemplateBinding}\n */\n\n/**\n * The {@link module:ui/template~Template#_renderNode} configuration.\n *\n * @private\n * @interface module:ui/template~RenderData\n */\n\n/**\n * Tells {@link module:ui/template~Template#_renderNode} to render\n * children into `DocumentFragment` first and then append the fragment\n * to the parent element. It is a speed optimization.\n *\n * @member {Boolean} #intoFragment\n */\n\n/**\n * A node which is being rendered.\n *\n * @member {HTMLElement|Text} #node\n */\n\n/**\n * Indicates whether the {@module:ui/template~RenderNodeOptions#node} has\n * been provided by {@module:ui/template~Template#apply}.\n *\n * @member {Boolean} #isApplying\n */\n\n/**\n * An object storing the data that helps {@module:ui/template~Template#revert}\n * bringing back an element to its initial state, i.e. before\n * {@module:ui/template~Template#apply} was called.\n *\n * @member {Object} #revertData\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 ui/editorui/bodycollection\n */\n\n/* globals document */\n\nimport Template from '../template';\nimport ViewCollection from '../viewcollection';\n\nimport createElement from '@ckeditor/ckeditor5-utils/src/dom/createelement';\n\n/**\n * This is a special {@link module:ui/viewcollection~ViewCollection} dedicated to elements that are detached\n * from the DOM structure of the editor, like panels, icons, etc.\n *\n * The body collection is available in the {@link module:ui/editorui/editoruiview~EditorUIView#body `editor.ui.view.body`} property.\n * Any plugin can add a {@link module:ui/view~View view} to this collection.\n * These views will render in a container placed directly in the `<body>` element.\n * The editor will detach and destroy this collection when the editor will be {@link module:core/editor/editor~Editor#destroy destroyed}.\n *\n * If you need to control the life cycle of the body collection on your own, you can create your own instance of this class.\n *\n * A body collection will render itself automatically in the DOM body element as soon as you call {@link ~BodyCollection#attachToDom}.\n * If you create multiple body collections, this class will create a special wrapper element in the DOM to limit the number of\n * elements created directly in the body and remove it when the last body collection will be\n * {@link ~BodyCollection#detachFromDom detached}.\n *\n * @extends module:ui/viewcollection~ViewCollection\n */\nexport default class BodyCollection extends ViewCollection {\n\t/**\n\t * Creates a new instance of the {@link module:ui/editorui/bodycollection~BodyCollection}.\n\t *\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor editor's locale} instance.\n\t * @param {Iterable.<module:ui/view~View>} [initialItems] The initial items of the collection.\n\t */\n\tconstructor( locale, initialItems = [] ) {\n\t\tsuper( initialItems );\n\n\t\t/**\n\t\t * The {@link module:core/editor/editor~Editor#locale editor's locale} instance.\n\t\t * See the view {@link module:ui/view~View#locale locale} property.\n\t\t *\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.locale = locale;\n\t}\n\n\t/**\n\t * Attaches the body collection to the DOM body element. You need to execute this method to render the content of\n\t * the body collection.\n\t */\n\tattachToDom() {\n\t\t/**\n\t\t * The element holding elements of the body region.\n\t\t *\n\t\t * @protected\n\t\t * @member {HTMLElement} #_bodyCollectionContainer\n\t\t */\n\t\tthis._bodyCollectionContainer = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset_all',\n\t\t\t\t\t'ck-body',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t],\n\t\t\t\tdir: this.locale.uiLanguageDirection\n\t\t\t},\n\t\t\tchildren: this\n\t\t} ).render();\n\n\t\tlet wrapper = document.querySelector( '.ck-body-wrapper' );\n\n\t\tif ( !wrapper ) {\n\t\t\twrapper = createElement( document, 'div', { class: 'ck-body-wrapper' } );\n\t\t\tdocument.body.appendChild( wrapper );\n\t\t}\n\n\t\twrapper.appendChild( this._bodyCollectionContainer );\n\t}\n\n\t/**\n\t * Detaches the collection from the DOM structure. Use this method when you do not need to use the body collection\n\t * anymore to clean-up the DOM structure.\n\t */\n\tdetachFromDom() {\n\t\tsuper.destroy();\n\n\t\tif ( this._bodyCollectionContainer ) {\n\t\t\tthis._bodyCollectionContainer.remove();\n\t\t}\n\n\t\tconst wrapper = document.querySelector( '.ck-body-wrapper' );\n\n\t\tif ( wrapper && wrapper.childElementCount == 0 ) {\n\t\t\twrapper.remove();\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* global DOMParser */\n\n/**\n * @module ui/icon/iconview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/icon/icon.css';\n\n/**\n * The icon view class.\n *\n * @extends module:ui/view~View\n */\nexport default class IconView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor() {\n\t\tsuper();\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The SVG source of the icon.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #content\n\t\t */\n\t\tthis.set( 'content', '' );\n\n\t\t/**\n\t\t * This attribute specifies the boundaries to which the\n\t\t * icon content should stretch.\n\t\t *\n\t\t * @observable\n\t\t * @default '0 0 20 20'\n\t\t * @member {String} #viewBox\n\t\t */\n\t\tthis.set( 'viewBox', '0 0 20 20' );\n\n\t\t/**\n\t\t * The fill color of the child `path.ck-icon__fill`.\n\t\t *\n\t\t * @observable\n\t\t * @default ''\n\t\t * @member {String} #fillColor\n\t\t */\n\t\tthis.set( 'fillColor', '' );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'svg',\n\t\t\tns: 'http://www.w3.org/2000/svg',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-icon'\n\t\t\t\t],\n\t\t\t\tviewBox: bind.to( 'viewBox' )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis._updateXMLContent();\n\t\tthis._colorFillPaths();\n\n\t\t// This is a hack for lack of innerHTML binding.\n\t\t// See: https://github.com/ckeditor/ckeditor5-ui/issues/99.\n\t\tthis.on( 'change:content', () => {\n\t\t\tthis._updateXMLContent();\n\t\t\tthis._colorFillPaths();\n\t\t} );\n\n\t\tthis.on( 'change:fillColor', () => {\n\t\t\tthis._colorFillPaths();\n\t\t} );\n\t}\n\n\t/**\n\t * Updates the {@link #element} with the value of {@link #content}.\n\t *\n\t * @private\n\t */\n\t_updateXMLContent() {\n\t\tif ( this.content ) {\n\t\t\tconst parsed = new DOMParser().parseFromString( this.content.trim(), 'image/svg+xml' );\n\t\t\tconst svg = parsed.querySelector( 'svg' );\n\t\t\tconst viewBox = svg.getAttribute( 'viewBox' );\n\n\t\t\tif ( viewBox ) {\n\t\t\t\tthis.viewBox = viewBox;\n\t\t\t}\n\n\t\t\tthis.element.innerHTML = '';\n\n\t\t\twhile ( svg.childNodes.length > 0 ) {\n\t\t\t\tthis.element.appendChild( svg.childNodes[ 0 ] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Fills all child `path.ck-icon__fill` with the `#fillColor`.\n\t *\n\t * @private\n\t */\n\t_colorFillPaths() {\n\t\tif ( this.fillColor ) {\n\t\t\tthis.element.querySelectorAll( '.ck-icon__fill' ).forEach( path => {\n\t\t\t\tpath.style.fill = this.fillColor;\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/tooltip/tooltipview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/tooltip/tooltip.css';\n\n/**\n * The tooltip view class.\n *\n * @extends module:ui/view~View\n */\nexport default class TooltipView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The text of the tooltip visible to the user.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #text\n\t\t */\n\t\tthis.set( 'text', '' );\n\n\t\t/**\n\t\t * The position of the tooltip (south, south-west, south-east, or north).\n\t\t *\n\t\t *\t\t+-----------+\n\t\t *\t\t| north |\n\t\t *\t\t+-----------+\n\t\t *\t\t V\n\t\t *\t\t [element]\n\t\t *\n\t\t *\t\t [element]\n\t\t *\t\t ^\n\t\t *\t\t+-----------+\n\t\t *\t\t| south |\n\t\t *\t\t+-----------+\n\t\t *\n\t\t * +----------+\n\t\t * [element] < | east |\n\t\t * +----------+\n\t\t *\n\t\t * +----------+\n\t\t * | west | > [element]\n\t\t * +----------+\n\t\t *\n\t\t *\t\t [element]\n\t\t *\t\t ^\n\t\t *\t\t+--------------+\n\t\t *\t\t| south west |\n\t\t *\t\t+--------------+\n\t\t *\n\t\t *\t [element]\n\t\t *\t\t ^\n\t\t *\t\t+--------------+\n\t\t *\t\t| south east |\n\t\t *\t\t+--------------+\n\n\t\t * @observable\n\t\t * @default 's'\n\t\t * @member {'s'|'n'|'e'|'w'|'sw'|'se'} #position\n\t\t */\n\t\tthis.set( 'position', 's' );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-tooltip',\n\t\t\t\t\tbind.to( 'position', position => 'ck-tooltip_' + position ),\n\t\t\t\t\tbind.if( 'text', 'ck-hidden', value => !value.trim() )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-tooltip__text'\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: bind.to( 'text' )\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/button/buttonview\n */\n\nimport View from '../view';\nimport IconView from '../icon/iconview';\nimport TooltipView from '../tooltip/tooltipview';\n\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport { getEnvKeystrokeText } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\nimport '../../theme/components/button/button.css';\n\n/**\n * The button view class.\n *\n *\t\tconst view = new ButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true,\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * @extends module:ui/view~View\n * @implements module:ui/button/button~Button\n */\nexport default class ButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\t\tconst ariaLabelUid = uid();\n\n\t\t// Implement the Button interface.\n\t\tthis.set( 'class' );\n\t\tthis.set( 'labelStyle' );\n\t\tthis.set( 'icon' );\n\t\tthis.set( 'isEnabled', true );\n\t\tthis.set( 'isOn', false );\n\t\tthis.set( 'isVisible', true );\n\t\tthis.set( 'isToggleable', false );\n\t\tthis.set( 'keystroke' );\n\t\tthis.set( 'label' );\n\t\tthis.set( 'tabindex', -1 );\n\t\tthis.set( 'tooltip' );\n\t\tthis.set( 'tooltipPosition', 's' );\n\t\tthis.set( 'type', 'button' );\n\t\tthis.set( 'withText', false );\n\t\tthis.set( 'withKeystroke', false );\n\n\t\t/**\n\t\t * Collection of the child views inside of the button {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * Tooltip of the button view. It is configurable using the {@link #tooltip tooltip attribute}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/tooltip/tooltipview~TooltipView} #tooltipView\n\t\t */\n\t\tthis.tooltipView = this._createTooltipView();\n\n\t\t/**\n\t\t * Label of the button view. It is configurable using the {@link #label label attribute}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #labelView\n\t\t */\n\t\tthis.labelView = this._createLabelView( ariaLabelUid );\n\n\t\t/**\n\t\t * The icon view of the button. Will be added to {@link #children} when the\n\t\t * {@link #icon icon attribute} is defined.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/icon/iconview~IconView} #iconView\n\t\t */\n\t\tthis.iconView = new IconView();\n\n\t\tthis.iconView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-button__icon'\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A view displaying the keystroke of the button next to the {@link #labelView label}.\n\t\t * Added to {@link #children} when the {@link #withKeystroke `withKeystroke` attribute}\n\t\t * is defined.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view/view~View} #keystrokeView\n\t\t */\n\t\tthis.keystrokeView = this._createKeystrokeView();\n\n\t\t/**\n\t\t * Tooltip of the button bound to the template.\n\t\t *\n\t\t * @see #tooltip\n\t\t * @see #_getTooltipString\n\t\t * @private\n\t\t * @observable\n\t\t * @member {Boolean} #_tooltipString\n\t\t */\n\t\tthis.bind( '_tooltipString' ).to(\n\t\t\tthis, 'tooltip',\n\t\t\tthis, 'label',\n\t\t\tthis, 'keystroke',\n\t\t\tthis._getTooltipString.bind( this )\n\t\t);\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'button',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-hidden', value => !value ),\n\t\t\t\t\tbind.to( 'isOn', value => value ? 'ck-on' : 'ck-off' ),\n\t\t\t\t\tbind.if( 'withText', 'ck-button_with-text' ),\n\t\t\t\t\tbind.if( 'withKeystroke', 'ck-button_with-keystroke' )\n\t\t\t\t],\n\t\t\t\ttype: bind.to( 'type', value => value ? value : 'button' ),\n\t\t\t\ttabindex: bind.to( 'tabindex' ),\n\t\t\t\t'aria-labelledby': `ck-editor__aria-label_${ ariaLabelUid }`,\n\t\t\t\t'aria-disabled': bind.if( 'isEnabled', true, value => !value ),\n\t\t\t\t'aria-pressed': bind.to( 'isOn', value => this.isToggleable ? String( value ) : false )\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\tmousedown: bind.to( evt => {\n\t\t\t\t\tevt.preventDefault();\n\t\t\t\t} ),\n\n\t\t\t\tclick: bind.to( evt => {\n\t\t\t\t\t// We can't make the button disabled using the disabled attribute, because it won't be focusable.\n\t\t\t\t\t// Though, shouldn't this condition be moved to the button controller?\n\t\t\t\t\tif ( this.isEnabled ) {\n\t\t\t\t\t\tthis.fire( 'execute' );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Prevent the default when button is disabled, to block e.g.\n\t\t\t\t\t\t// automatic form submitting. See ckeditor/ckeditor5-link#74.\n\t\t\t\t\t\tevt.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tif ( this.icon ) {\n\t\t\tthis.iconView.bind( 'content' ).to( this, 'icon' );\n\t\t\tthis.children.add( this.iconView );\n\t\t}\n\n\t\tthis.children.add( this.tooltipView );\n\t\tthis.children.add( this.labelView );\n\n\t\tif ( this.withKeystroke ) {\n\t\t\tthis.children.add( this.keystrokeView );\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the {@link #element} of the button.\n\t */\n\tfocus() {\n\t\tthis.element.focus();\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/tooltip/tooltipview~TooltipView} instance and binds it with button\n\t * attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/tooltip/tooltipview~TooltipView}\n\t */\n\t_createTooltipView() {\n\t\tconst tooltipView = new TooltipView();\n\n\t\ttooltipView.bind( 'text' ).to( this, '_tooltipString' );\n\t\ttooltipView.bind( 'position' ).to( this, 'tooltipPosition' );\n\n\t\treturn tooltipView;\n\t}\n\n\t/**\n\t * Creates a label view instance and binds it with button attributes.\n\t *\n\t * @private\n\t * @param {String} ariaLabelUid The aria label UID.\n\t * @returns {module:ui/view~View}\n\t */\n\t_createLabelView( ariaLabelUid ) {\n\t\tconst labelView = new View();\n\t\tconst bind = this.bindTemplate;\n\n\t\tlabelView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__label'\n\t\t\t\t],\n\t\t\t\tstyle: bind.to( 'labelStyle' ),\n\t\t\t\tid: `ck-editor__aria-label_${ ariaLabelUid }`\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: this.bindTemplate.to( 'label' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn labelView;\n\t}\n\n\t/**\n\t * Creates a view that displays a keystroke next to a {@link #labelView label }\n\t * and binds it with button attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createKeystrokeView() {\n\t\tconst keystrokeView = new View();\n\n\t\tkeystrokeView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__keystroke'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: this.bindTemplate.to( 'keystroke', text => getEnvKeystrokeText( text ) )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn keystrokeView;\n\t}\n\n\t/**\n\t * Gets the text for the {@link #tooltipView} from the combination of\n\t * {@link #tooltip}, {@link #label} and {@link #keystroke} attributes.\n\t *\n\t * @private\n\t * @see #tooltip\n\t * @see #_tooltipString\n\t * @param {Boolean|String|Function} tooltip Button tooltip.\n\t * @param {String} label Button label.\n\t * @param {String} keystroke Button keystroke.\n\t * @returns {String}\n\t */\n\t_getTooltipString( tooltip, label, keystroke ) {\n\t\tif ( tooltip ) {\n\t\t\tif ( typeof tooltip == 'string' ) {\n\t\t\t\treturn tooltip;\n\t\t\t} else {\n\t\t\t\tif ( keystroke ) {\n\t\t\t\t\tkeystroke = getEnvKeystrokeText( keystroke );\n\t\t\t\t}\n\n\t\t\t\tif ( tooltip instanceof Function ) {\n\t\t\t\t\treturn tooltip( label, keystroke );\n\t\t\t\t} else {\n\t\t\t\t\treturn `${ label }${ keystroke ? ` (${ keystroke })` : '' }`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn '';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/button/switchbuttonview\n */\n\nimport View from '../view';\nimport ButtonView from './buttonview';\n\nimport '../../theme/components/button/switchbutton.css';\n\n/**\n * The switch button view class.\n *\n *\t\tconst view = new SwitchButtonView();\n *\n *\t\tview.set( {\n *\t\t\twithText: true,\n *\t\t\tlabel: 'Switch me!'\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class SwitchButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.isToggleable = true;\n\n\t\t/**\n\t\t * The toggle switch of the button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/view~View} #toggleSwitchView\n\t\t */\n\t\tthis.toggleSwitchView = this._createToggleView();\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-switchbutton'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.toggleSwitchView );\n\t}\n\n\t/**\n\t * Creates a toggle child view.\n\t *\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createToggleView() {\n\t\tconst toggleSwitchView = new View();\n\n\t\ttoggleSwitchView.setTemplate( {\n\t\t\ttag: 'span',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-button__toggle'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-button__toggle__inner'\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn toggleSwitchView;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/colorgrid/utils\n */\n\n/**\n * Returns color configuration options as defined in `editor.config.(fontColor|fontBackgroundColor).colors` or\n * `editor.config.table.(tableProperties|tableCellProperties).(background|border).colors\n * but processed to account for editor localization in the correct language.\n *\n * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n * when the user configuration is defined because the editor does not exist yet.\n *\n * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} options\n * @returns {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>}.\n */\nexport function getLocalizedColorOptions( locale, options ) {\n\tconst t = locale.t;\n\tconst localizedColorNames = {\n\t\tBlack: t( 'Black' ),\n\t\t'Dim grey': t( 'Dim grey' ),\n\t\tGrey: t( 'Grey' ),\n\t\t'Light grey': t( 'Light grey' ),\n\t\tWhite: t( 'White' ),\n\t\tRed: t( 'Red' ),\n\t\tOrange: t( 'Orange' ),\n\t\tYellow: t( 'Yellow' ),\n\t\t'Light green': t( 'Light green' ),\n\t\tGreen: t( 'Green' ),\n\t\tAquamarine: t( 'Aquamarine' ),\n\t\tTurquoise: t( 'Turquoise' ),\n\t\t'Light blue': t( 'Light blue' ),\n\t\tBlue: t( 'Blue' ),\n\t\tPurple: t( 'Purple' )\n\t};\n\n\treturn options.map( colorOption => {\n\t\tconst label = localizedColorNames[ colorOption.label ];\n\n\t\tif ( label && label != colorOption.label ) {\n\t\t\tcolorOption.label = label;\n\t\t}\n\n\t\treturn colorOption;\n\t} );\n}\n\n/**\n * Creates a unified color definition object from color configuration options.\n * The object contains the information necessary to both render the UI and initialize the conversion.\n *\n * @param {module:ui/colorgrid/colorgrid~ColorDefinition} options\n * @returns {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>}\n */\nexport function normalizeColorOptions( options ) {\n\treturn options\n\t\t.map( normalizeSingleColorDefinition )\n\t\t.filter( option => !!option );\n}\n\n// Creates a normalized color definition from the user-defined configuration.\n// The \"normalization\" means it will create full\n// {@link module:ui/colorgrid/colorgrid~ColorDefinition `ColorDefinition-like`}\n// object for string values, and add a `view` property, for each definition.\n//\n// @param {String|module:ui/colorgrid/colorgrid~ColorDefinition}\n// @returns {module:ui/colorgrid/colorgrid~ColorDefinition}\nexport function normalizeSingleColorDefinition( color ) {\n\tif ( typeof color === 'string' ) {\n\t\treturn {\n\t\t\tmodel: color,\n\t\t\tlabel: color,\n\t\t\thasBorder: false,\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\tcolor\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} else {\n\t\treturn {\n\t\t\tmodel: color.color,\n\t\t\tlabel: color.label || color.color,\n\t\t\thasBorder: color.hasBorder === undefined ? false : color.hasBorder,\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\tcolor: `${ color.color }`\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/colorgrid/colortile\n */\n\nimport ButtonView from '../button/buttonview';\nimport checkIcon from '../../theme/icons/color-tile-check.svg';\n\n/**\n * This class represents a single color tile in the {@link module:ui/colorgrid/colorgrid~ColorGridView}.\n *\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class ColorTileView extends ButtonView {\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * String representing a color shown as tile's background.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.set( 'color' );\n\n\t\t/**\n\t\t * A flag that toggles a special CSS class responsible for displaying\n\t\t * a border around the button.\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis.set( 'hasBorder' );\n\n\t\tthis.icon = checkIcon;\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tstyle: {\n\t\t\t\t\tbackgroundColor: bind.to( 'color' )\n\t\t\t\t},\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-color-grid__tile',\n\t\t\t\t\tbind.if( 'hasBorder', 'ck-color-table__color-tile_bordered' )\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.iconView.fillColor = 'hsl(0, 0%, 100%)';\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path class=\\\"ck-icon__fill\\\" d=\\\"M16.935 5.328a2 2 0 0 1 0 2.829l-7.778 7.778a2 2 0 0 1-2.829 0L3.5 13.107a1.999 1.999 0 1 1 2.828-2.829l.707.707a1 1 0 0 0 1.414 0l5.658-5.657a2 2 0 0 1 2.828 0z\\\"/><path d=\\\"M14.814 6.035 8.448 12.4a1 1 0 0 1-1.414 0l-1.413-1.415A1 1 0 1 0 4.207 12.4l2.829 2.829a1 1 0 0 0 1.414 0l7.778-7.778a1 1 0 1 0-1.414-1.415z\\\"/></svg>\";","/**\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 ui/focuscycler\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\n\n/**\n * A utility class that helps cycling over focusable {@link module:ui/view~View views} in a\n * {@link module:ui/viewcollection~ViewCollection} when the focus is tracked by the\n * {@link module:utils/focustracker~FocusTracker} instance. It helps implementing keyboard\n * navigation in HTML forms, toolbars, lists and the like.\n *\n * To work properly it requires:\n * * a collection of focusable (HTML `tabindex` attribute) views that implement the `focus()` method,\n * * an associated focus tracker to determine which view is focused.\n *\n * A simple cycler setup can look like this:\n *\n *\t\tconst focusables = new ViewCollection();\n *\t\tconst focusTracker = new FocusTracker();\n *\n *\t\t// Add focusable views to the focus tracker.\n *\t\tfocusTracker.add( ... );\n *\n * Then, the cycler can be used manually:\n *\n *\t\tconst cycler = new FocusCycler( { focusables, focusTracker } );\n *\n *\t\t// Will focus the first focusable view in #focusables.\n *\t\tcycler.focusFirst();\n *\n *\t\t// Will log the next focusable item in #focusables.\n *\t\tconsole.log( cycler.next );\n *\n * Alternatively, it can work side by side with the {@link module:utils/keystrokehandler~KeystrokeHandler}:\n *\n *\t\tconst keystrokeHandler = new KeystrokeHandler();\n *\n *\t\t// Activate the keystroke handler.\n *\t\tkeystrokeHandler.listenTo( sourceOfEvents );\n *\n *\t\tconst cycler = new FocusCycler( {\n *\t\t\tfocusables, focusTracker, keystrokeHandler,\n *\t\t\tactions: {\n *\t\t\t\t// When arrowup of arrowleft is detected by the #keystrokeHandler,\n *\t\t\t\t// focusPrevious() will be called on the cycler.\n *\t\t\t\tfocusPrevious: [ 'arrowup', 'arrowleft' ],\n *\t\t\t}\n *\t\t} );\n *\n * Check out the {@glink framework/guides/deep-dive/ui/focus-tracking \"Deep dive into focus tracking\" guide} to learn more.\n */\nexport default class FocusCycler {\n\t/**\n\t * Creates an instance of the focus cycler utility.\n\t *\n\t * @param {Object} options Configuration options.\n\t * @param {module:utils/collection~Collection|Object} options.focusables\n\t * @param {module:utils/focustracker~FocusTracker} options.focusTracker\n\t * @param {module:utils/keystrokehandler~KeystrokeHandler} [options.keystrokeHandler]\n\t * @param {Object} [options.actions]\n\t */\n\tconstructor( options ) {\n\t\tObject.assign( this, options );\n\n\t\t/**\n\t\t * A {@link module:ui/view~View view} collection that the cycler operates on.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/collection~Collection} #focusables\n\t\t */\n\n\t\t/**\n\t\t * A focus tracker instance that the cycler uses to determine the current focus\n\t\t * state in {@link #focusables}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * which can respond to certain keystrokes and cycle the focus.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler} #keystrokeHandler\n\t\t */\n\n\t\t/**\n\t\t * Actions that the cycler can take when a keystroke is pressed. Requires\n\t\t * `options.keystrokeHandler` to be passed and working. When an action is\n\t\t * performed, `preventDefault` and `stopPropagation` will be called on the event\n\t\t * the keystroke fired in the DOM.\n\t\t *\n\t\t *\t\tactions: {\n\t\t *\t\t\t// Will call #focusPrevious() when arrowleft or arrowup is pressed.\n\t\t *\t\t\tfocusPrevious: [ 'arrowleft', 'arrowup' ],\n\t\t *\n\t\t *\t\t\t// Will call #focusNext() when arrowdown is pressed.\n\t\t *\t\t\tfocusNext: 'arrowdown'\n\t\t *\t\t}\n\t\t *\n\t\t * @readonly\n\t\t * @member {Object} #actions\n\t\t */\n\n\t\tif ( options.actions && options.keystrokeHandler ) {\n\t\t\tfor ( const methodName in options.actions ) {\n\t\t\t\tlet actions = options.actions[ methodName ];\n\n\t\t\t\tif ( typeof actions == 'string' ) {\n\t\t\t\t\tactions = [ actions ];\n\t\t\t\t}\n\n\t\t\t\tfor ( const keystroke of actions ) {\n\t\t\t\t\toptions.keystrokeHandler.set( keystroke, ( data, cancel ) => {\n\t\t\t\t\t\tthis[ methodName ]();\n\t\t\t\t\t\tcancel();\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the first focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #first\n\t */\n\tget first() {\n\t\treturn this.focusables.find( isFocusable ) || null;\n\t}\n\n\t/**\n\t * Returns the last focusable view in {@link #focusables}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #last\n\t */\n\tget last() {\n\t\treturn this.focusables.filter( isFocusable ).slice( -1 )[ 0 ] || null;\n\t}\n\n\t/**\n\t * Returns the next focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #next\n\t */\n\tget next() {\n\t\treturn this._getFocusableItem( 1 );\n\t}\n\n\t/**\n\t * Returns the previous focusable view in {@link #focusables} based on {@link #current}.\n\t * Returns `null` if there is none.\n\t *\n\t * @readonly\n\t * @member {module:ui/view~View|null} #previous\n\t */\n\tget previous() {\n\t\treturn this._getFocusableItem( -1 );\n\t}\n\n\t/**\n\t * An index of the view in the {@link #focusables} which is focused according\n\t * to {@link #focusTracker}. Returns `null` when there is no such view.\n\t *\n\t * @readonly\n\t * @member {Number|null} #current\n\t */\n\tget current() {\n\t\tlet index = null;\n\n\t\t// There's no focused view in the focusables.\n\t\tif ( this.focusTracker.focusedElement === null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tthis.focusables.find( ( view, viewIndex ) => {\n\t\t\tconst focused = view.element === this.focusTracker.focusedElement;\n\n\t\t\tif ( focused ) {\n\t\t\t\tindex = viewIndex;\n\t\t\t}\n\n\t\t\treturn focused;\n\t\t} );\n\n\t\treturn index;\n\t}\n\n\t/**\n\t * Focuses the {@link #first} item in {@link #focusables}.\n\t */\n\tfocusFirst() {\n\t\tthis._focus( this.first );\n\t}\n\n\t/**\n\t * Focuses the {@link #last} item in {@link #focusables}.\n\t */\n\tfocusLast() {\n\t\tthis._focus( this.last );\n\t}\n\n\t/**\n\t * Focuses the {@link #next} item in {@link #focusables}.\n\t */\n\tfocusNext() {\n\t\tthis._focus( this.next );\n\t}\n\n\t/**\n\t * Focuses the {@link #previous} item in {@link #focusables}.\n\t */\n\tfocusPrevious() {\n\t\tthis._focus( this.previous );\n\t}\n\n\t/**\n\t * Focuses the given view if it exists.\n\t *\n\t * @protected\n\t * @param {module:ui/view~View} view\n\t */\n\t_focus( view ) {\n\t\tif ( view ) {\n\t\t\tview.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Returns the next or previous focusable view in {@link #focusables} with respect\n\t * to {@link #current}.\n\t *\n\t * @protected\n\t * @param {Number} step Either `1` for checking forward from {@link #current} or\n\t * `-1` for checking backwards.\n\t * @returns {module:ui/view~View|null}\n\t */\n\t_getFocusableItem( step ) {\n\t\t// Cache for speed.\n\t\tconst current = this.current;\n\t\tconst collectionLength = this.focusables.length;\n\n\t\tif ( !collectionLength ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Start from the beginning if no view is focused.\n\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/206\n\t\tif ( current === null ) {\n\t\t\treturn this[ step === 1 ? 'first' : 'last' ];\n\t\t}\n\n\t\t// Cycle in both directions.\n\t\tlet index = ( current + collectionLength + step ) % collectionLength;\n\n\t\tdo {\n\t\t\tconst view = this.focusables.get( index );\n\n\t\t\t// TODO: Check if view is visible.\n\t\t\tif ( isFocusable( view ) ) {\n\t\t\t\treturn view;\n\t\t\t}\n\n\t\t\t// Cycle in both directions.\n\t\t\tindex = ( index + collectionLength + step ) % collectionLength;\n\t\t} while ( index !== current );\n\n\t\treturn null;\n\t}\n}\n\n// Checks whether a view is focusable.\n//\n// @private\n// @param {module:ui/view~View} view A view to be checked.\n// @returns {Boolean}\nfunction isFocusable( view ) {\n\treturn !!( view.focus && global.window.getComputedStyle( view.element ).display != 'none' );\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 ui/colorgrid/colorgrid\n */\n\nimport View from '../view';\nimport ColorTileView from './colortileview';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport '../../theme/components/colorgrid/colorgrid.css';\n\n/**\n * A grid of {@link module:ui/colorgrid/colortile~ColorTileView color tiles}.\n *\n * @extends module:ui/view~View\n */\nexport default class ColorGridView extends View {\n\t/**\n\t * Creates an instance of a color grid containing {@link module:ui/colorgrid/colortile~ColorTileView tiles}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {Object} options Component configuration\n\t * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} [options.colorDefinitions] Array with definitions\n\t * required to create the {@link module:ui/colorgrid/colortile~ColorTileView tiles}.\n\t * @param {Number} options.columns A number of columns to display the tiles.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tconst colorDefinitions = options && options.colorDefinitions || [];\n\t\tconst viewStyleAttribute = {};\n\n\t\tif ( options && options.columns ) {\n\t\t\tviewStyleAttribute.gridTemplateColumns = `repeat( ${ options.columns }, 1fr)`;\n\t\t}\n\n\t\t/**\n\t\t * The color of the currently selected color tile in {@link #items}.\n\t\t *\n\t\t * @observable\n\t\t * @type {String}\n\t\t */\n\t\tthis.set( 'selectedColor' );\n\n\t\t/**\n\t\t * Collection of the child tile views.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the grid.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Helps cycling over focusable {@link #items} in the grid.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.items,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate grid items backwards using the arrowup key.\n\t\t\t\tfocusPrevious: 'arrowleft',\n\n\t\t\t\t// Navigate grid items forwards using the arrowdown key.\n\t\t\t\tfocusNext: 'arrowright'\n\t\t\t}\n\t\t} );\n\n\t\tthis.items.on( 'add', ( evt, colorTile ) => {\n\t\t\tcolorTile.isOn = colorTile.color === this.selectedColor;\n\t\t} );\n\n\t\tcolorDefinitions.forEach( color => {\n\t\t\tconst colorTile = new ColorTileView();\n\n\t\t\tcolorTile.set( {\n\t\t\t\tcolor: color.color,\n\t\t\t\tlabel: color.label,\n\t\t\t\ttooltip: true,\n\t\t\t\thasBorder: color.options.hasBorder\n\t\t\t} );\n\n\t\t\tcolorTile.on( 'execute', () => {\n\t\t\t\tthis.fire( 'execute', {\n\t\t\t\t\tvalue: color.color,\n\t\t\t\t\thasBorder: color.options.hasBorder,\n\t\t\t\t\tlabel: color.label\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\tthis.items.add( colorTile );\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tchildren: this.items,\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-color-grid'\n\t\t\t\t],\n\t\t\t\tstyle: viewStyleAttribute\n\t\t\t}\n\t\t} );\n\n\t\tthis.on( 'change:selectedColor', ( evt, name, selectedColor ) => {\n\t\t\tfor ( const item of this.items ) {\n\t\t\t\titem.isOn = item.color === selectedColor;\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #items}.\n\t */\n\tfocus() {\n\t\tif ( this.items.length ) {\n\t\t\tthis.items.first.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tif ( this.items.length ) {\n\t\t\tthis.items.last.focus();\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Fired when the `ColorTileView` for the picked item is executed.\n\t *\n\t * @event execute\n\t * @param {Object} data Additional information about the event.\n\t * @param {String} data.value The value of the selected color\n\t * ({@link module:ui/colorgrid/colorgrid~ColorDefinition#color `color.color`}).\n\t * @param {Boolean} data.hasBorder The `hasBorder` property of the selected color\n\t * ({@link module:ui/colorgrid/colorgrid~ColorDefinition#options `color.options.hasBorder`}).\n\t * @param {String} data.Label The label of the selected color\n\t * ({@link module:ui/colorgrid/colorgrid~ColorDefinition#label `color.label`})\n\t */\n}\n\n/**\n * A color definition used to create a {@link module:ui/colorgrid/colortile~ColorTileView}.\n *\n *\t\t{\n *\t\t\tcolor: 'hsl(0, 0%, 75%)',\n *\t\t\tlabel: 'Light Grey',\n *\t\t\toptions: {\n *\t\t\t\thasBorder: true\n *\t\t\t}\n *\t\t}\n *\n * @typedef {Object} module:ui/colorgrid/colorgrid~ColorDefinition\n * @type Object\n *\n * @property {String} color String representing a color.\n * It is used as value of background-color style in {@link module:ui/colorgrid/colortile~ColorTileView}.\n * @property {String} label String used as label for {@link module:ui/colorgrid/colortile~ColorTileView}.\n * @property {Object} options Additional options passed to create a {@link module:ui/colorgrid/colortile~ColorTileView}.\n * @property {Boolean} options.hasBorder A flag that indicates if special a CSS class should be added\n * to {@link module:ui/colorgrid/colortile~ColorTileView}, which renders a border around it.\n */\n","export default \"<svg viewBox=\\\"0 0 10 10\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M.941 4.523a.75.75 0 1 1 1.06-1.06l3.006 3.005 3.005-3.005a.75.75 0 1 1 1.06 1.06l-3.549 3.55a.75.75 0 0 1-1.168-.136L.941 4.523z\\\"/></svg>\";","/**\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 ui/dropdown/button/dropdownbuttonview\n */\n\nimport ButtonView from '../../button/buttonview';\n\nimport dropdownArrowIcon from '../../../theme/icons/dropdown-arrow.svg';\nimport IconView from '../../icon/iconview';\n\n/**\n * The default dropdown button view class.\n *\n *\t\tconst view = new DropdownButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * Also see the {@link module:ui/dropdown/utils~createDropdown `createDropdown()` util}.\n *\n * @implements module:ui/dropdown/button/dropdownbutton~DropdownButton\n * @extends module:ui/button/buttonview~ButtonView\n */\nexport default class DropdownButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * An icon that displays arrow to indicate a dropdown button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/icon/iconview~IconView}\n\t\t */\n\t\tthis.arrowView = this._createArrowView();\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\t'aria-haspopup': true\n\t\t\t}\n\t\t} );\n\n\t\t// The DropdownButton interface expects the open event upon which will open the dropdown.\n\t\tthis.delegate( 'execute' ).to( this, 'open' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.arrowView );\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/icon/iconview~IconView} instance as {@link #arrowView}.\n\t *\n\t * @private\n\t * @returns {module:ui/icon/iconview~IconView}\n\t */\n\t_createArrowView() {\n\t\tconst arrowView = new IconView();\n\n\t\tarrowView.content = dropdownArrowIcon;\n\n\t\tarrowView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-dropdown__arrow'\n\t\t\t}\n\t\t} );\n\n\t\treturn arrowView;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/button/splitbuttonview\n */\n\nimport View from '../../view';\nimport ButtonView from '../../button/buttonview';\n\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\n\nimport dropdownArrowIcon from '../../../theme/icons/dropdown-arrow.svg';\n\nimport '../../../theme/components/dropdown/splitbutton.css';\n\n/**\n * The split button view class.\n *\n *\t\tconst view = new SplitButtonView();\n *\n *\t\tview.set( {\n *\t\t\tlabel: 'A button',\n *\t\t\tkeystroke: 'Ctrl+B',\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.render();\n *\n *\t\tdocument.body.append( view.element );\n *\n * Also see the {@link module:ui/dropdown/utils~createDropdown `createDropdown()` util}.\n *\n * @implements module:ui/dropdown/button/dropdownbutton~DropdownButton\n * @extends module:ui/view~View\n */\nexport default class SplitButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t// Implement the Button interface.\n\t\tthis.set( 'icon' );\n\t\tthis.set( 'isEnabled', true );\n\t\tthis.set( 'isOn', false );\n\t\tthis.set( 'isToggleable', false );\n\t\tthis.set( 'isVisible', true );\n\t\tthis.set( 'keystroke' );\n\t\tthis.set( 'label' );\n\t\tthis.set( 'tabindex', -1 );\n\t\tthis.set( 'tooltip' );\n\t\tthis.set( 'tooltipPosition', 's' );\n\t\tthis.set( 'type', 'button' );\n\t\tthis.set( 'withText', false );\n\n\t\t/**\n\t\t * Collection of the child views inside of the split button {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * A main button of split button.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.actionView = this._createActionView();\n\n\t\t/**\n\t\t * A secondary button of split button that opens dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.arrowView = this._createArrowView();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. It manages\n\t\t * keystrokes of the split button:\n\t\t *\n\t\t * * <kbd>▶</kbd> moves focus to arrow view when action view is focused,\n\t\t * * <kbd>◀</kbd> moves focus to action view when arrow view is focused.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-splitbutton',\n\t\t\t\t\tbind.if( 'isVisible', 'ck-hidden', value => !value ),\n\t\t\t\t\tthis.arrowView.bindTemplate.if( 'isOn', 'ck-splitbutton_open' )\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.children.add( this.actionView );\n\t\tthis.children.add( this.arrowView );\n\n\t\tthis.focusTracker.add( this.actionView.element );\n\t\tthis.focusTracker.add( this.arrowView.element );\n\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\t// Overrides toolbar focus cycling behavior.\n\t\tthis.keystrokes.set( 'arrowright', ( evt, cancel ) => {\n\t\t\tif ( this.focusTracker.focusedElement === this.actionView.element ) {\n\t\t\t\tthis.arrowView.focus();\n\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Overrides toolbar focus cycling behavior.\n\t\tthis.keystrokes.set( 'arrowleft', ( evt, cancel ) => {\n\t\t\tif ( this.focusTracker.focusedElement === this.arrowView.element ) {\n\t\t\t\tthis.actionView.focus();\n\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the {@link #actionView#element} of the action part of split button.\n\t */\n\tfocus() {\n\t\tthis.actionView.focus();\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #actionView} and binds it with main split button\n\t * attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_createActionView() {\n\t\tconst actionView = new ButtonView();\n\n\t\tactionView.bind(\n\t\t\t'icon',\n\t\t\t'isEnabled',\n\t\t\t'isOn',\n\t\t\t'isToggleable',\n\t\t\t'keystroke',\n\t\t\t'label',\n\t\t\t'tabindex',\n\t\t\t'tooltip',\n\t\t\t'tooltipPosition',\n\t\t\t'type',\n\t\t\t'withText'\n\t\t).to( this );\n\n\t\tactionView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-splitbutton__action'\n\t\t\t}\n\t\t} );\n\n\t\tactionView.delegate( 'execute' ).to( this );\n\n\t\treturn actionView;\n\t}\n\n\t/**\n\t * Creates a {@link module:ui/button/buttonview~ButtonView} instance as {@link #arrowView} and binds it with main split button\n\t * attributes.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_createArrowView() {\n\t\tconst arrowView = new ButtonView();\n\t\tconst bind = arrowView.bindTemplate;\n\n\t\tarrowView.icon = dropdownArrowIcon;\n\n\t\tarrowView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-splitbutton__arrow',\n\t\t\t\t'aria-haspopup': true,\n\t\t\t\t'aria-expanded': bind.to( 'isOn', value => String( value ) )\n\t\t\t}\n\t\t} );\n\n\t\tarrowView.bind( 'isEnabled' ).to( this );\n\n\t\tarrowView.delegate( 'execute' ).to( this, 'open' );\n\n\t\treturn arrowView;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/dropdownpanelview\n */\n\nimport View from '../view';\n\n/**\n * The dropdown panel view class.\n *\n * See {@link module:ui/dropdown/dropdownview~DropdownView} to learn about the common usage.\n *\n * @extends module:ui/view~View\n */\nexport default class DropdownPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the panel is visible.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVisible\n\t\t */\n\t\tthis.set( 'isVisible', false );\n\n\t\t/**\n\t\t * The position of the panel, relative to the parent.\n\t\t *\n\t\t * This property is reflected in the CSS class set to {@link #element} that controls\n\t\t * the position of the panel.\n\t\t *\n\t\t * @observable\n\t\t * @default 'se'\n\t\t * @member {'s'|'se'|'sw'|'sme'|'smw'|'n'|'ne'|'nw'|'nme'|'nmw'} #position\n\t\t */\n\t\tthis.set( 'position', 'se' );\n\n\t\t/**\n\t\t * Collection of the child views in this panel.\n\t\t *\n\t\t * A common child type is the {@link module:ui/list/listview~ListView} and {@link module:ui/toolbar/toolbarview~ToolbarView}.\n\t\t * See {@link module:ui/dropdown/utils~addListToDropdown} and\n\t\t * {@link module:ui/dropdown/utils~addToolbarToDropdown} to learn more about child views of dropdowns.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset',\n\t\t\t\t\t'ck-dropdown__panel',\n\t\t\t\t\tbind.to( 'position', value => `ck-dropdown__panel_${ value }` ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-dropdown__panel-visible' )\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\t// Drag and drop in the panel should not break the selection in the editor.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/228\n\t\t\t\tselectstart: bind.to( evt => evt.preventDefault() )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the view element or first item in view collection on opening dropdown's panel.\n\t *\n\t * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.\n\t */\n\tfocus() {\n\t\tif ( this.children.length ) {\n\t\t\tthis.children.first.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the view element or last item in view collection on opening dropdown's panel.\n\t *\n\t * See also {@link module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable}.\n\t */\n\tfocusLast() {\n\t\tif ( this.children.length ) {\n\t\t\tconst lastChild = this.children.last;\n\n\t\t\tif ( typeof lastChild.focusLast === 'function' ) {\n\t\t\t\tlastChild.focusLast();\n\t\t\t} else {\n\t\t\t\tlastChild.focus();\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/dom/position\n */\n\nimport global from './global';\nimport Rect from './rect';\nimport getPositionedAncestor from './getpositionedancestor';\nimport getBorderWidths from './getborderwidths';\nimport { isFunction } from 'lodash-es';\n\n/**\n * Calculates the `position: absolute` coordinates of a given element so it can be positioned with respect to the\n * target in the visually most efficient way, taking various restrictions like viewport or limiter geometry\n * into consideration.\n *\n *\t\t// The element which is to be positioned.\n *\t\tconst element = document.body.querySelector( '#toolbar' );\n *\n *\t\t// A target to which the element is positioned relatively.\n *\t\tconst target = document.body.querySelector( '#container' );\n *\n *\t\t// Finding the optimal coordinates for the positioning.\n *\t\tconst { left, top, name } = getOptimalPosition( {\n *\t\t\telement: element,\n *\t\t\ttarget: target,\n *\n * \t\t\t// The algorithm will chose among these positions to meet the requirements such\n * \t\t\t// as \"limiter\" element or \"fitInViewport\", set below. The positions are considered\n * \t\t\t// in the order of the array.\n *\t\t\tpositions: [\n *\t\t\t\t//\n *\t\t\t \t//\t[ Target ]\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t| Element |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\n *\t\t\t\ttargetRect => ( {\n *\t\t\t\t\ttop: targetRect.bottom,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'mySouthEastPosition'\n *\t\t\t\t} ),\n *\n *\t\t\t\t//\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t| Element |\n *\t\t\t\t//\t+-----------------+\n *\t\t\t\t//\t[ Target ]\n *\t\t\t\t//\n *\t\t\t\t( targetRect, elementRect ) => ( {\n *\t\t\t\t\ttop: targetRect.top - elementRect.height,\n *\t\t\t\t\tleft: targetRect.left,\n *\t\t\t\t\tname: 'myNorthEastPosition'\n *\t\t\t\t} )\n *\t\t\t],\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of <body>.\n *\t\t\tlimiter: document.body,\n *\n *\t\t\t// Find a position such guarantees the element remains within visible boundaries of the browser viewport.\n *\t\t\tfitInViewport: true\n *\t\t} );\n *\n *\t\t// The best position which fits into document.body and the viewport. May be useful\n *\t\t// to set proper class on the `element`.\n *\t\tconsole.log( name ); // -> \"myNorthEastPosition\"\n *\n *\t\t// Using the absolute coordinates which has been found to position the element\n *\t\t// as in the diagram depicting the \"myNorthEastPosition\" position.\n *\t\telement.style.top = top;\n *\t\telement.style.left = left;\n *\n * @param {module:utils/dom/position~Options} options Positioning options object.\n * @returns {module:utils/dom/position~Position}\n */\nexport function getOptimalPosition( { element, target, positions, limiter, fitInViewport } ) {\n\t// If the {@link module:utils/dom/position~Options#target} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-utils/issues/157\n\tif ( isFunction( target ) ) {\n\t\ttarget = target();\n\t}\n\n\t// If the {@link module:utils/dom/position~Options#limiter} is a function, use what it returns.\n\t// https://github.com/ckeditor/ckeditor5-ui/issues/260\n\tif ( isFunction( limiter ) ) {\n\t\tlimiter = limiter();\n\t}\n\n\tconst positionedElementAncestor = getPositionedAncestor( element );\n\tconst elementRect = new Rect( element );\n\tconst targetRect = new Rect( target );\n\n\tlet bestPositionRect;\n\tlet bestPositionName;\n\n\t// If there are no limits, just grab the very first position and be done with that drama.\n\tif ( !limiter && !fitInViewport ) {\n\t\t[ bestPositionName, bestPositionRect ] = getPositionNameAndRect( positions[ 0 ], targetRect, elementRect );\n\t} else {\n\t\tconst limiterRect = limiter && new Rect( limiter ).getVisible();\n\t\tconst viewportRect = fitInViewport && new Rect( global.window );\n\t\tconst bestPosition = getBestPositionNameAndRect( positions, { targetRect, elementRect, limiterRect, viewportRect } );\n\n\t\t// If there's no best position found, i.e. when all intersections have no area because\n\t\t// rects have no width or height, then just use the first available position.\n\t\t[ bestPositionName, bestPositionRect ] = bestPosition || getPositionNameAndRect( positions[ 0 ], targetRect, elementRect );\n\t}\n\n\tlet absoluteRectCoordinates = getAbsoluteRectCoordinates( bestPositionRect );\n\n\tif ( positionedElementAncestor ) {\n\t\tabsoluteRectCoordinates = shiftRectCoordinatesDueToPositionedAncestor( absoluteRectCoordinates, positionedElementAncestor );\n\t}\n\n\treturn {\n\t\tleft: absoluteRectCoordinates.left,\n\t\ttop: absoluteRectCoordinates.top,\n\t\tname: bestPositionName\n\t};\n}\n\n// For given position function, returns a corresponding `Rect` instance.\n//\n// @private\n// @param {Function} position A function returning {@link module:utils/dom/position~Position}.\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of positioned element.\n// @returns {Array|null} An array containing position name and its Rect (or null if position should be ignored).\nfunction getPositionNameAndRect( position, targetRect, elementRect ) {\n\tconst positionData = position( targetRect, elementRect );\n\n\tif ( !positionData ) {\n\t\treturn null;\n\t}\n\n\tconst { left, top, name } = positionData;\n\n\treturn [ name, elementRect.clone().moveTo( left, top ) ];\n}\n\n// For a given array of positioning functions, returns such that provides the best\n// fit of the `elementRect` into the `limiterRect` and `viewportRect`.\n//\n// @private\n//\n// @param {Object} options\n// @param {module:utils/dom/position~Options#positions} positions Functions returning {@link module:utils/dom/position~Position}\n// to be checked, in the order of preference.\n// @param {Object} options\n// @param {utils/dom/rect~Rect} options.targetRect A rect of the {@link module:utils/dom/position~Options#target}.\n// @param {utils/dom/rect~Rect} options.elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.\n// @param {utils/dom/rect~Rect} options.limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.\n// @param {utils/dom/rect~Rect} options.viewportRect A rect of the viewport.\n//\n// @returns {Array} An array containing the name of the position and it's rect.\nfunction getBestPositionNameAndRect( positions, options ) {\n\tconst { elementRect, viewportRect } = options;\n\n\t// This is when element is fully visible.\n\tconst elementRectArea = elementRect.getArea();\n\n\t// Let's calculate intersection areas for positions. It will end early if best match is found.\n\tconst processedPositions = processPositionsToAreas( positions, options );\n\n\t// First let's check all positions that fully fit in the viewport.\n\tif ( viewportRect ) {\n\t\tconst processedPositionsInViewport = processedPositions.filter( ( { viewportIntersectArea } ) => {\n\t\t\treturn viewportIntersectArea === elementRectArea;\n\t\t} );\n\n\t\t// Try to find best position from those which fit completely in viewport.\n\t\tconst bestPositionData = getBestOfProcessedPositions( processedPositionsInViewport, elementRectArea );\n\n\t\tif ( bestPositionData ) {\n\t\t\treturn bestPositionData;\n\t\t}\n\t}\n\n\t// Either there is no viewportRect or there is no position that fits completely in the viewport.\n\treturn getBestOfProcessedPositions( processedPositions, elementRectArea );\n}\n\n// For a given array of positioning functions, calculates intersection areas for them.\n//\n// Note: If some position fully fits into the `limiterRect`, it will be returned early, without further consideration\n// of other positions.\n//\n// @private\n//\n// @param {module:utils/dom/position~Options#positions} positions Functions returning {@link module:utils/dom/position~Position}\n// to be checked, in the order of preference.\n// @param {Object} options\n// @param {utils/dom/rect~Rect} options.targetRect A rect of the {@link module:utils/dom/position~Options#target}.\n// @param {utils/dom/rect~Rect} options.elementRect A rect of positioned {@link module:utils/dom/position~Options#element}.\n// @param {utils/dom/rect~Rect} options.limiterRect A rect of the {@link module:utils/dom/position~Options#limiter}.\n// @param {utils/dom/rect~Rect} options.viewportRect A rect of the viewport.\n//\n// @returns {Array.<Object>} Array of positions with calculated intersection areas. Each item is an object containing:\n// * {String} positionName Name of position.\n// * {utils/dom/rect~Rect} positionRect Rect of position.\n// * {Number} limiterIntersectArea Area of intersection of the position with limiter part that is in the viewport.\n// * {Number} viewportIntersectArea Area of intersection of the position with viewport.\nfunction processPositionsToAreas( positions, { targetRect, elementRect, limiterRect, viewportRect } ) {\n\tconst processedPositions = [];\n\n\t// This is when element is fully visible.\n\tconst elementRectArea = elementRect.getArea();\n\n\tfor ( const position of positions ) {\n\t\tconst positionData = getPositionNameAndRect( position, targetRect, elementRect );\n\n\t\tif ( !positionData ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst [ positionName, positionRect ] = positionData;\n\t\tlet limiterIntersectArea = 0;\n\t\tlet viewportIntersectArea = 0;\n\n\t\tif ( limiterRect ) {\n\t\t\tif ( viewportRect ) {\n\t\t\t\t// Consider only the part of the limiter which is visible in the viewport. So the limiter is getting limited.\n\t\t\t\tconst limiterViewportIntersectRect = limiterRect.getIntersection( viewportRect );\n\n\t\t\t\tif ( limiterViewportIntersectRect ) {\n\t\t\t\t\t// If the limiter is within the viewport, then check the intersection between that part of the\n\t\t\t\t\t// limiter and actual position.\n\t\t\t\t\tlimiterIntersectArea = limiterViewportIntersectRect.getIntersectionArea( positionRect );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlimiterIntersectArea = limiterRect.getIntersectionArea( positionRect );\n\t\t\t}\n\t\t}\n\n\t\tif ( viewportRect ) {\n\t\t\tviewportIntersectArea = viewportRect.getIntersectionArea( positionRect );\n\t\t}\n\n\t\tconst processedPosition = {\n\t\t\tpositionName,\n\t\t\tpositionRect,\n\t\t\tlimiterIntersectArea,\n\t\t\tviewportIntersectArea\n\t\t};\n\n\t\t// If a such position is found that element is fully contained by the limiter then, obviously,\n\t\t// there will be no better one, so finishing.\n\t\tif ( limiterIntersectArea === elementRectArea ) {\n\t\t\treturn [ processedPosition ];\n\t\t}\n\n\t\tprocessedPositions.push( processedPosition );\n\t}\n\n\treturn processedPositions;\n}\n\n// For a given array of processed position data (with calculated Rects for positions and intersection areas)\n// returns such that provides the best fit of the `elementRect` into the `limiterRect` and `viewportRect` at the same time.\n//\n// **Note**: It will return early if some position fully fits into the `limiterRect`.\n//\n// @private\n// @param {Array.<Object>} Array of positions with calculated intersection areas (in order of preference).\n// Each item is an object containing:\n//\n//\t* {String} positionName Name of position.\n//\t* {utils/dom/rect~Rect} positionRect Rect of position.\n//\t* {Number} limiterIntersectArea Area of intersection of the position with limiter part that is in the viewport.\n//\t* {Number} viewportIntersectArea Area of intersection of the position with viewport.\n//\n// @param {Number} elementRectArea Area of positioned {@link module:utils/dom/position~Options#element}.\n// @returns {Array|null} An array containing the name of the position and it's rect, or null if not found.\nfunction getBestOfProcessedPositions( processedPositions, elementRectArea ) {\n\tlet maxFitFactor = 0;\n\tlet bestPositionRect;\n\tlet bestPositionName;\n\n\tfor ( const { positionName, positionRect, limiterIntersectArea, viewportIntersectArea } of processedPositions ) {\n\t\t// If a such position is found that element is fully container by the limiter then, obviously,\n\t\t// there will be no better one, so finishing.\n\t\tif ( limiterIntersectArea === elementRectArea ) {\n\t\t\treturn [ positionName, positionRect ];\n\t\t}\n\n\t\t// To maximize both viewport and limiter intersection areas we use distance on viewportIntersectArea\n\t\t// and limiterIntersectArea plane (without sqrt because we are looking for max value).\n\t\tconst fitFactor = viewportIntersectArea ** 2 + limiterIntersectArea ** 2;\n\n\t\tif ( fitFactor > maxFitFactor ) {\n\t\t\tmaxFitFactor = fitFactor;\n\t\t\tbestPositionRect = positionRect;\n\t\t\tbestPositionName = positionName;\n\t\t}\n\t}\n\n\treturn bestPositionRect ? [ bestPositionName, bestPositionRect ] : null;\n}\n\n// For a given absolute Rect coordinates object and a positioned element ancestor, it returns an object with\n// new Rect coordinates that make up for the position and the scroll of the ancestor.\n//\n// This is necessary because while Rects (and DOMRects) are relative to the browser's viewport, their coordinates\n// are used in reallife to position elements with `position: absolute`, which are scoped by any positioned\n// (and scrollable) ancestors.\n//\n// @private\n//\n// @param {Object} absoluteRectCoordinates An object with absolute rect coordinates.\n// @param {Object} absoluteRectCoordinates.top\n// @param {Object} absoluteRectCoordinates.left\n// @param {HTMLElement} positionedElementAncestor An ancestor element that should be considered.\n//\n// @returns {Object} An object corresponding to `absoluteRectCoordinates` input but with values shifted\n// to make up for the positioned element ancestor.\nfunction shiftRectCoordinatesDueToPositionedAncestor( { left, top }, positionedElementAncestor ) {\n\tconst ancestorPosition = getAbsoluteRectCoordinates( new Rect( positionedElementAncestor ) );\n\tconst ancestorBorderWidths = getBorderWidths( positionedElementAncestor );\n\n\t// (https://github.com/ckeditor/ckeditor5-ui-default/issues/126)\n\t// If there's some positioned ancestor of the panel, then its `Rect` must be taken into\n\t// consideration. `Rect` is always relative to the viewport while `position: absolute` works\n\t// with respect to that positioned ancestor.\n\tleft -= ancestorPosition.left;\n\ttop -= ancestorPosition.top;\n\n\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t// If there's some positioned ancestor of the panel, not only its position must be taken into\n\t// consideration (see above) but also its internal scrolls. Scroll have an impact here because `Rect`\n\t// is relative to the viewport (it doesn't care about scrolling), while `position: absolute`\n\t// must compensate that scrolling.\n\tleft += positionedElementAncestor.scrollLeft;\n\ttop += positionedElementAncestor.scrollTop;\n\n\t// (https://github.com/ckeditor/ckeditor5-utils/issues/139)\n\t// If there's some positioned ancestor of the panel, then its `Rect` includes its CSS `borderWidth`\n\t// while `position: absolute` positioning does not consider it.\n\t// E.g. `{ position: absolute, top: 0, left: 0 }` means upper left corner of the element,\n\t// not upper-left corner of its border.\n\tleft -= ancestorBorderWidths.left;\n\ttop -= ancestorBorderWidths.top;\n\n\treturn { left, top };\n}\n\n// DOMRect (also Rect) works in a scrollindependent geometry but `position: absolute` doesn't.\n// This function converts Rect to `position: absolute` coordinates.\n//\n// @private\n// @param {utils/dom/rect~Rect} rect A rect to be converted.\n// @returns {Object} Object containing `left` and `top` properties, in absolute coordinates.\nfunction getAbsoluteRectCoordinates( { left, top } ) {\n\tconst { scrollX, scrollY } = global.window;\n\n\treturn {\n\t\tleft: left + scrollX,\n\t\ttop: top + scrollY\n\t};\n}\n\n/**\n * The `getOptimalPosition()` helper options.\n *\n * @interface module:utils/dom/position~Options\n */\n\n/**\n * Element that is to be positioned.\n *\n * @member {HTMLElement} #element\n */\n\n/**\n * Target with respect to which the `element` is to be positioned.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #target\n */\n\n/**\n * An array of functions which return {@link module:utils/dom/position~Position} relative\n * to the `target`, in the order of preference.\n *\n * **Note**: If a function returns `null`, it is ignored by the `getOptimalPosition()`.\n *\n * @member {Array.<Function>} #positions\n */\n\n/**\n * When set, the algorithm will chose position which fits the most in the\n * limiter's bounding rect.\n *\n * @member {HTMLElement|Range|ClientRect|Rect|Function} #limiter\n */\n\n/**\n * When set, the algorithm will chose such a position which fits `element`\n * the most inside visible viewport.\n *\n * @member {Boolean} #fitInViewport\n */\n\n/**\n * An object describing a position in `position: absolute` coordinate\n * system, along with position name.\n *\n * @typedef {Object} module:utils/dom/position~Position\n *\n * @property {Number} top Top position offset.\n * @property {Number} left Left position offset.\n * @property {String} name Name of the position.\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 utils/dom/getpositionedancestor\n */\n\nimport global from './global';\n\n/**\n * For a given element, returns the nearest ancestor element which CSS position is not \"static\".\n *\n * @param {HTMLElement} element The native DOM element to be checked.\n * @returns {HTMLElement|null}\n */\nexport default function getPositionedAncestor( element ) {\n\tif ( !element || !element.parentNode ) {\n\t\treturn null;\n\t}\n\n\tif ( element.offsetParent === global.document.body ) {\n\t\treturn null;\n\t}\n\n\treturn element.offsetParent;\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 ui/dropdown/dropdownview\n */\n\nimport View from '../view';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport '../../theme/components/dropdown/dropdown.css';\n\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\n\n/**\n * The dropdown view class. It manages the dropdown button and dropdown panel.\n *\n * In most cases, the easiest way to create a dropdown is by using the {@link module:ui/dropdown/utils~createDropdown}\n * util:\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\tdropdown.panelView.element.textContent = 'Content of the panel';\n *\n *\t\t// Will render a dropdown with a panel containing a \"Content of the panel\" text.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * If you want to add a richer content to the dropdown panel, you can use the {@link module:ui/dropdown/utils~addListToDropdown}\n * and {@link module:ui/dropdown/utils~addToolbarToDropdown} helpers. See more examples in\n * {@link module:ui/dropdown/utils~createDropdown} documentation.\n *\n * If you want to create a completely custom dropdown, then you can compose it manually:\n *\n *\t\tconst button = new DropdownButtonView( locale );\n *\t\tconst panel = new DropdownPanelView( locale );\n *\t\tconst dropdown = new DropdownView( locale, button, panel );\n *\n *\t\tbutton.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\tpanel.element.textContent = 'Content of the panel';\n *\n *\t\t// Will render a dropdown with a panel containing a \"Content of the panel\" text.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * However, dropdown created this way will contain little behavior. You will need to implement handlers for actions\n * such as {@link module:ui/bindings/clickoutsidehandler~clickOutsideHandler clicking outside an open dropdown}\n * (which should close it) and support for arrow keys inside the panel. Therefore, unless you really know what\n * you do and you really need to do it, it is recommended to use the {@link module:ui/dropdown/utils~createDropdown} helper.\n *\n * @extends module:ui/view~View\n */\nexport default class DropdownView extends View {\n\t/**\n\t * Creates an instance of the dropdown.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {module:ui/dropdown/button/dropdownbutton~DropdownButton} buttonView\n\t * @param {module:ui/dropdown/dropdownpanelview~DropdownPanelView} panelView\n\t */\n\tconstructor( locale, buttonView, panelView ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Button of the dropdown view. Clicking the button opens the {@link #panelView}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/button/buttonview~ButtonView} #buttonView\n\t\t */\n\t\tthis.buttonView = buttonView;\n\n\t\t/**\n\t\t * Panel of the dropdown. It opens when the {@link #buttonView} is\n\t\t * {@link module:ui/button/buttonview~ButtonView#event:execute executed} (i.e. clicked).\n\t\t *\n\t\t * Child views can be added to the panel's `children` collection:\n\t\t *\n\t\t *\t\tdropdown.panelView.children.add( childView );\n\t\t *\n\t\t * See {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#children} and\n\t\t * {@link module:ui/viewcollection~ViewCollection#add}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownpanelview~DropdownPanelView} #panelView\n\t\t */\n\t\tthis.panelView = panelView;\n\n\t\t/**\n\t\t * Controls whether the dropdown view is open, i.e. shows or hides the {@link #panelView panel}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isOpen\n\t\t */\n\t\tthis.set( 'isOpen', false );\n\n\t\t/**\n\t\t * Controls whether the dropdown is enabled, i.e. it can be clicked and execute an action.\n\t\t *\n\t\t * See {@link module:ui/button/buttonview~ButtonView#isEnabled}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t/**\n\t\t * (Optional) The additional CSS class set on the dropdown {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * (Optional) The `id` attribute of the dropdown (i.e. to pair with a `<label>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.set( 'id' );\n\n\t\t/**\n\t\t * The position of the panel, relative to the dropdown.\n\t\t *\n\t\t * **Note**: When `'auto'`, the panel will use one of the remaining positions to stay\n\t\t * in the viewport, visible to the user. The positions correspond directly to\n\t\t * {@link module:ui/dropdown/dropdownview~DropdownView.defaultPanelPositions default panel positions}.\n\t\t *\n\t\t * **Note**: This value has an impact on the\n\t\t * {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView#position} property\n\t\t * each time the panel becomes {@link #isOpen open}.\n\t\t *\n\t\t * @observable\n\t\t * @default 'auto'\n\t\t * @member {'auto'|'s'|'se'|'sw'|'sme'|'smw'|'n'|'ne'|'nw'|'nme'|'nmw'} #panelPosition\n\t\t */\n\t\tthis.set( 'panelPosition', 'auto' );\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}. It manages\n\t\t * keystrokes of the dropdown:\n\t\t *\n\t\t * * <kbd>▼</kbd> opens the dropdown,\n\t\t * * <kbd>◀</kbd> and <kbd>Esc</kbd> closes the dropdown.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-dropdown',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value )\n\t\t\t\t],\n\t\t\t\tid: bind.to( 'id' ),\n\t\t\t\t'aria-describedby': bind.to( 'ariaDescribedById' )\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tbuttonView,\n\t\t\t\tpanelView\n\t\t\t]\n\t\t} );\n\n\t\tbuttonView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-dropdown__button'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * A child {@link module:ui/list/listview~ListView list view} of the dropdown located\n\t\t * in its {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addListToDropdown}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/list/listview~ListView} #listView\n\t\t */\n\n\t\t/**\n\t\t * A child toolbar of the dropdown located in the\n\t\t * {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addToolbarToDropdown}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarView} #toolbarView\n\t\t */\n\n\t\t/**\n\t\t * Fired when the toolbar button or list item is executed.\n\t\t *\n\t\t * For {@link #listView} It fires when a child of some {@link module:ui/list/listitemview~ListItemView}\n\t\t * fired `execute`.\n\t\t *\n\t\t * For {@link #toolbarView} It fires when one of the buttons has been\n\t\t * {@link module:ui/button/buttonview~ButtonView#event:execute executed}.\n\t\t *\n\t\t * **Note**: Only supported when dropdown has list view added using {@link module:ui/dropdown/utils~addListToDropdown}\n\t\t * or {@link module:ui/dropdown/utils~addToolbarToDropdown}.\n\t\t *\n\t\t * @event execute\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Toggle the dropdown when its button has been clicked.\n\t\tthis.listenTo( this.buttonView, 'open', () => {\n\t\t\tthis.isOpen = !this.isOpen;\n\t\t} );\n\n\t\t// Toggle the visibility of the panel when the dropdown becomes open.\n\t\tthis.panelView.bind( 'isVisible' ).to( this, 'isOpen' );\n\n\t\t// Let the dropdown control the position of the panel. The position must\n\t\t// be updated every time the dropdown is open.\n\t\tthis.on( 'change:isOpen', () => {\n\t\t\tif ( !this.isOpen ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If \"auto\", find the best position of the panel to fit into the viewport.\n\t\t\t// Otherwise, simply assign the static position.\n\t\t\tif ( this.panelPosition === 'auto' ) {\n\t\t\t\tthis.panelView.position = DropdownView._getOptimalPosition( {\n\t\t\t\t\telement: this.panelView.element,\n\t\t\t\t\ttarget: this.buttonView.element,\n\t\t\t\t\tfitInViewport: true,\n\t\t\t\t\tpositions: this._panelPositions\n\t\t\t\t} ).name;\n\t\t\t} else {\n\t\t\t\tthis.panelView.position = this.panelPosition;\n\t\t\t}\n\t\t} );\n\n\t\t// Listen for keystrokes coming from within #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tconst closeDropdown = ( data, cancel ) => {\n\t\t\tif ( this.isOpen ) {\n\t\t\t\tthis.buttonView.focus();\n\t\t\t\tthis.isOpen = false;\n\t\t\t\tcancel();\n\t\t\t}\n\t\t};\n\n\t\t// Open the dropdown panel using the arrow down key, just like with return or space.\n\t\tthis.keystrokes.set( 'arrowdown', ( data, cancel ) => {\n\t\t\t// Don't open if the dropdown is disabled or already open.\n\t\t\tif ( this.buttonView.isEnabled && !this.isOpen ) {\n\t\t\t\tthis.isOpen = true;\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Block the right arrow key (until nested dropdowns are implemented).\n\t\tthis.keystrokes.set( 'arrowright', ( data, cancel ) => {\n\t\t\tif ( this.isOpen ) {\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Close the dropdown using the arrow left/escape key.\n\t\tthis.keystrokes.set( 'arrowleft', closeDropdown );\n\t\tthis.keystrokes.set( 'esc', closeDropdown );\n\t}\n\n\t/**\n\t * Focuses the {@link #buttonView}.\n\t */\n\tfocus() {\n\t\tthis.buttonView.focus();\n\t}\n\n\t/**\n\t * Returns {@link #panelView panel} positions to be used by the\n\t * {@link module:utils/dom/position~getOptimalPosition `getOptimalPosition()`}\n\t * utility considering the direction of the language the UI of the editor is displayed in.\n\t *\n\t * @type {module:utils/dom/position~Options#positions}\n\t * @private\n\t */\n\tget _panelPositions() {\n\t\tconst {\n\t\t\tsouth, north,\n\t\t\tsouthEast, southWest,\n\t\t\tnorthEast, northWest,\n\t\t\tsouthMiddleEast, southMiddleWest,\n\t\t\tnorthMiddleEast, northMiddleWest\n\t\t} = DropdownView.defaultPanelPositions;\n\n\t\tif ( this.locale.uiLanguageDirection !== 'rtl' ) {\n\t\t\treturn [\n\t\t\t\tsouthEast, southWest, southMiddleEast, southMiddleWest, south,\n\t\t\t\tnorthEast, northWest, northMiddleEast, northMiddleWest, north\n\t\t\t];\n\t\t} else {\n\t\t\treturn [\n\t\t\t\tsouthWest, southEast, southMiddleWest, southMiddleEast, south,\n\t\t\t\tnorthWest, northEast, northMiddleWest, northMiddleEast, north\n\t\t\t];\n\t\t}\n\t}\n}\n\n/**\n * A set of positioning functions used by the dropdown view to determine\n * the optimal position (i.e. fitting into the browser viewport) of its\n * {@link module:ui/dropdown/dropdownview~DropdownView#panelView panel} when\n * {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition} is set to 'auto'`.\n *\n * The available positioning functions are as follow:\n *\n * **South**\n *\n * * `south`\n *\n *\t\t\t[ Button ]\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\n * * `southEast`\n *\n *\t\t[ Button ]\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\n * * `southWest`\n *\n *\t\t [ Button ]\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\n * * `southMiddleEast`\n *\n *\t\t [ Button ]\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\n * * `southMiddleWest`\n *\n *\t\t [ Button ]\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\n * **North**\n *\n * * `north`\n *\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\t\t [ Button ]\n *\n * * `northEast`\n *\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\t\t[ Button ]\n *\n * * `northWest`\n *\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\t\t [ Button ]\n *\n * * `northMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\t\t [ Button ]\n *\n * * `northMiddleWest`\n *\n *\t\t+-----------------+\n *\t\t| Panel |\n *\t\t+-----------------+\n *\t\t [ Button ]\n *\n * Positioning functions are compatible with {@link module:utils/dom/position~Position}.\n *\n * The name that position function returns will be reflected in dropdown panel's class that\n * controls its placement. See {@link module:ui/dropdown/dropdownview~DropdownView#panelPosition}\n * to learn more.\n *\n * @member {Object} module:ui/dropdown/dropdownview~DropdownView.defaultPanelPositions\n */\nDropdownView.defaultPanelPositions = {\n\tsouth: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left - ( panelRect.width - buttonRect.width ) / 2,\n\t\t\tname: 's'\n\t\t};\n\t},\n\tsouthEast: buttonRect => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left,\n\t\t\tname: 'se'\n\t\t};\n\t},\n\tsouthWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left - panelRect.width + buttonRect.width,\n\t\t\tname: 'sw'\n\t\t};\n\t},\n\tsouthMiddleEast: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left - ( panelRect.width - buttonRect.width ) / 4,\n\t\t\tname: 'sme'\n\t\t};\n\t},\n\tsouthMiddleWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.bottom,\n\t\t\tleft: buttonRect.left - ( panelRect.width - buttonRect.width ) * 3 / 4,\n\t\t\tname: 'smw'\n\t\t};\n\t},\n\tnorth: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.top - panelRect.height,\n\t\t\tleft: buttonRect.left - ( panelRect.width - buttonRect.width ) / 2,\n\t\t\tname: 'n'\n\t\t};\n\t},\n\tnorthEast: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.top - panelRect.height,\n\t\t\tleft: buttonRect.left,\n\t\t\tname: 'ne'\n\t\t};\n\t},\n\tnorthWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.top - panelRect.height,\n\t\t\tleft: buttonRect.left - panelRect.width + buttonRect.width,\n\t\t\tname: 'nw'\n\t\t};\n\t},\n\tnorthMiddleEast: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.top - panelRect.height,\n\t\t\tleft: buttonRect.left - ( panelRect.width - buttonRect.width ) / 4,\n\t\t\tname: 'nme'\n\t\t};\n\t},\n\tnorthMiddleWest: ( buttonRect, panelRect ) => {\n\t\treturn {\n\t\t\ttop: buttonRect.top - panelRect.height,\n\t\t\tleft: buttonRect.left - ( panelRect.width - buttonRect.width ) * 3 / 4,\n\t\t\tname: 'nmw'\n\t\t};\n\t}\n};\n\n/**\n * A function used to calculate the optimal position for the dropdown panel.\n *\n * @protected\n * @member {Function} module:ui/dropdown/dropdownview~DropdownView._getOptimalPosition\n */\nDropdownView._getOptimalPosition = getOptimalPosition;\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 ui/toolbar/toolbarseparatorview\n */\n\nimport View from '../view';\n\n/**\n * The toolbar separator view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ToolbarSeparatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__separator'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/toolbarlinebreakview\n */\n\nimport View from '../view';\n\n/**\n * The toolbar line break view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ToolbarLineBreakView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__line-break'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/normalizetoolbarconfig\n */\n\n/**\n * Normalizes the toolbar configuration (`config.toolbar`), which:\n *\n * * may be defined as an `Array`:\n *\n * \t\ttoolbar: [ 'heading', 'bold', 'italic', 'link', ... ]\n *\n * * or an `Object`:\n *\n *\t\ttoolbar: {\n *\t\t\titems: [ 'heading', 'bold', 'italic', 'link', ... ],\n *\t\t\tremoveItems: [ 'bold' ],\n *\t\t\t...\n *\t\t}\n *\n * * or may not be defined at all (`undefined`)\n *\n * and returns it in the object form.\n *\n * @param {Array|Object|undefined} config The value of `config.toolbar`.\n * @returns {Object} A normalized toolbar config object.\n */\nexport default function normalizeToolbarConfig( config ) {\n\tif ( Array.isArray( config ) ) {\n\t\treturn {\n\t\t\titems: config,\n\t\t\tremoveItems: []\n\t\t};\n\t}\n\n\tif ( !config ) {\n\t\treturn {\n\t\t\titems: [],\n\t\t\tremoveItems: []\n\t\t};\n\t}\n\n\treturn Object.assign( {\n\t\titems: [],\n\t\tremoveItems: []\n\t}, config );\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 ui/toolbar/toolbarview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport ToolbarSeparatorView from './toolbarseparatorview';\nimport ToolbarLineBreakView from './toolbarlinebreakview';\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\nimport preventDefault from '../bindings/preventdefault.js';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { createDropdown, addToolbarToDropdown } from '../dropdown/utils';\nimport { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport normalizeToolbarConfig from './normalizetoolbarconfig';\nimport { icons } from 'ckeditor5/src/core';\n\nimport '../../theme/components/toolbar/toolbar.css';\n\n/**\n * The toolbar view class.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class ToolbarView extends View {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~ToolbarView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} locale The localization services instance.\n\t * @param {module:ui/toolbar/toolbarview~ToolbarOptions} [options] Configuration options of the toolbar.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\t\tconst t = this.t;\n\n\t\t/**\n\t\t * A reference to the options object passed to the constructor.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarOptions}\n\t\t */\n\t\tthis.options = options || {};\n\n\t\t/**\n\t\t * Label used by assistive technologies to describe this toolbar element.\n\t\t *\n\t\t * @default 'Editor toolbar'\n\t\t * @member {String} #ariaLabel\n\t\t */\n\t\tthis.set( 'ariaLabel', t( 'Editor toolbar' ) );\n\n\t\t/**\n\t\t * The maximum width of the toolbar element.\n\t\t *\n\t\t * **Note**: When set to a specific value (e.g. `'200px'`), the value will affect the behavior of the\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull}\n\t\t * option by changing the number of {@link #items} that will be displayed in the toolbar at a time.\n\t\t *\n\t\t * @observable\n\t\t * @default 'auto'\n\t\t * @member {String} #maxWidth\n\t\t */\n\t\tthis.set( 'maxWidth', 'auto' );\n\n\t\t/**\n\t\t * A collection of toolbar items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}\n\t\t * to handle keyboard navigation in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * When set true, makes the toolbar look compact with {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {String} #isCompact\n\t\t */\n\t\tthis.set( 'isCompact', false );\n\n\t\t/**\n\t\t * A (child) view containing {@link #items toolbar items}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n\t\tthis.itemsView = new ItemsView( locale );\n\n\t\t/**\n\t\t * A toplevel collection aggregating building blocks of the toolbar.\n\t\t *\n\t\t *\t┌───────────────── ToolbarView ─────────────────┐\n\t\t *\t| ┌──────────────── #children ────────────────┐ |\n\t\t *\t| | ┌──────────── #itemsView ───────────┐ | |\n\t\t *\t| | | [ item1 ] [ item2 ] ... [ itemN ] | | |\n\t\t *\t| | └──────────────────────────────────-┘ | |\n\t\t *\t| └───────────────────────────────────────────┘ |\n\t\t *\t└───────────────────────────────────────────────┘\n\t\t *\n\t\t * By default, it contains the {@link #itemsView} but it can be extended with additional\n\t\t * UI elements when necessary.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\t\tthis.children.add( this.itemsView );\n\n\t\t/**\n\t\t * A collection of {@link #items} that take part in the focus cycling\n\t\t * (i.e. navigation using the keyboard). Usually, it contains a subset of {@link #items} with\n\t\t * some optional UI elements that also belong to the toolbar and should be focusable\n\t\t * by the user.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.focusables = this.createCollection();\n\n\t\t/**\n\t\t * Controls the orientation of toolbar items. Only available when\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull dynamic items grouping}\n\t\t * is **disabled**.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isVertical\n\t\t */\n\n\t\t/**\n\t\t * Helps cycling over {@link #focusables focusable items} in the toolbar.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate toolbar items backwards using the arrow[left,up] keys.\n\t\t\t\tfocusPrevious: [ 'arrowleft', 'arrowup' ],\n\n\t\t\t\t// Navigate toolbar items forwards using the arrow[right,down] keys.\n\t\t\t\tfocusNext: [ 'arrowright', 'arrowdown' ]\n\t\t\t}\n\t\t} );\n\n\t\tconst classes = [\n\t\t\t'ck',\n\t\t\t'ck-toolbar',\n\t\t\tbind.to( 'class' ),\n\t\t\tbind.if( 'isCompact', 'ck-toolbar_compact' )\n\t\t];\n\n\t\tif ( this.options.shouldGroupWhenFull && this.options.isFloating ) {\n\t\t\tclasses.push( 'ck-toolbar_floating' );\n\t\t}\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: classes,\n\t\t\t\trole: 'toolbar',\n\t\t\t\t'aria-label': bind.to( 'ariaLabel' ),\n\t\t\t\tstyle: {\n\t\t\t\t\tmaxWidth: bind.to( 'maxWidth' )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.children,\n\n\t\t\ton: {\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/206\n\t\t\t\tmousedown: preventDefault( this )\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * An instance of the active toolbar behavior that shapes its look and functionality.\n\t\t *\n\t\t * See {@link module:ui/toolbar/toolbarview~ToolbarBehavior} to learn more.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ToolbarBehavior}\n\t\t */\n\t\tthis._behavior = this.options.shouldGroupWhenFull ? new DynamicGrouping( this ) : new StaticLayout( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Children added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tthis._behavior.render( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._behavior.destroy();\n\n\t\treturn super.destroy();\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #focusables}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #focusables}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n\n\t/**\n\t * A utility that expands the plain toolbar configuration into\n\t * {@link module:ui/toolbar/toolbarview~ToolbarView#items} using a given component factory.\n\t *\n\t * @param {Array.<String>|Object} itemsOrConfig The toolbar items or the entire toolbar configuration object.\n\t * @param {module:ui/componentfactory~ComponentFactory} factory A factory producing toolbar items.\n\t */\n\tfillFromConfig( itemsOrConfig, factory ) {\n\t\tconst config = normalizeToolbarConfig( itemsOrConfig );\n\n\t\tconst itemsToClean = config.items\n\t\t\t.filter( ( name, idx, items ) => {\n\t\t\t\tif ( name === '|' ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// Items listed in `config.removeItems` should not be added to the toolbar.\n\t\t\t\tif ( config.removeItems.indexOf( name ) !== -1 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif ( name === '-' ) {\n\t\t\t\t\t// The toolbar line breaks must not be rendered when toolbar grouping is enabled.\n\t\t\t\t\t// (https://github.com/ckeditor/ckeditor5/issues/8582)\n\t\t\t\t\tif ( this.options.shouldGroupWhenFull ) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * The toolbar multiline breaks (`-` items) only work when the automatic button grouping\n\t\t\t\t\t\t * is disabled in the toolbar configuration.\n\t\t\t\t\t\t * To do this, set the `shouldNotGroupWhenFull` option to `true` in the editor configuration:\n\t\t\t\t\t\t *\n\t\t\t\t\t\t *\t\tconst config = {\n\t\t\t\t\t\t *\t\t\ttoolbar: {\n\t\t\t\t\t\t *\t\t\t\titems: [ ... ],\n\t\t\t\t\t\t *\t\t\t\tshouldNotGroupWhenFull: true\n\t\t\t\t\t\t *\t\t\t}\n\t\t\t\t\t\t *\t\t}\n\t\t\t\t\t\t *\n\t\t\t\t\t\t * Learn more about {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar configuration}.\n\t\t\t\t\t\t *\n\t\t\t\t\t\t * @error toolbarview-line-break-ignored-when-grouping-items\n\t\t\t\t\t\t */\n\t\t\t\t\t\tlogWarning( 'toolbarview-line-break-ignored-when-grouping-items', items );\n\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// For the items that cannot be instantiated we are sending warning message. We also filter them out.\n\t\t\t\tif ( !factory.has( name ) ) {\n\t\t\t\t\t/**\n\t\t\t\t\t * There was a problem processing the configuration of the toolbar. The item with the given\n\t\t\t\t\t * name does not exist so it was omitted when rendering the toolbar.\n\t\t\t\t\t *\n\t\t\t\t\t * This warning usually shows up when the {@link module:core/plugin~Plugin} which is supposed\n\t\t\t\t\t * to provide a toolbar item has not been loaded or there is a typo in the configuration.\n\t\t\t\t\t *\n\t\t\t\t\t * Make sure the plugin responsible for this toolbar item is loaded and the toolbar configuration\n\t\t\t\t\t * is correct, e.g. {@link module:basic-styles/bold~Bold} is loaded for the `'bold'` toolbar item.\n\t\t\t\t\t *\n\t\t\t\t\t * You can use the following snippet to retrieve all available toolbar items:\n\t\t\t\t\t *\n\t\t\t\t\t *\t\tArray.from( editor.ui.componentFactory.names() );\n\t\t\t\t\t *\n\t\t\t\t\t * @error toolbarview-item-unavailable\n\t\t\t\t\t * @param {String} name The name of the component.\n\t\t\t\t\t */\n\t\t\t\t\tlogWarning( 'toolbarview-item-unavailable', { name } );\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t} );\n\n\t\tconst itemsToAdd = this._cleanSeparators( itemsToClean )\n\t\t\t// Instantiate toolbar items.\n\t\t\t.map( name => {\n\t\t\t\tif ( name === '|' ) {\n\t\t\t\t\treturn new ToolbarSeparatorView();\n\t\t\t\t} else if ( name === '-' ) {\n\t\t\t\t\treturn new ToolbarLineBreakView();\n\t\t\t\t}\n\n\t\t\t\treturn factory.create( name );\n\t\t\t} );\n\n\t\tthis.items.addMany( itemsToAdd );\n\t}\n\n\t/**\n\t * Remove leading, trailing, and duplicated separators (`-` and `|`).\n\t *\n\t * @private\n\t * @param {Array.<String>} items\n\t */\n\t_cleanSeparators( items ) {\n\t\tconst nonSeparatorPredicate = item => ( item !== '-' && item !== '|' );\n\t\tconst count = items.length;\n\n\t\t// Find an index of the first item that is not a separator.\n\t\tconst firstCommandItem = items.findIndex( nonSeparatorPredicate );\n\n\t\t// Search from the end of the list, then convert found index back to the original direction.\n\t\tconst lastCommandItem = count - items\n\t\t\t.slice()\n\t\t\t.reverse()\n\t\t\t.findIndex( nonSeparatorPredicate );\n\n\t\treturn items\n\t\t\t// Return items without the leading and trailing separators.\n\t\t\t.slice( firstCommandItem, lastCommandItem )\n\t\t\t// Remove duplicated separators.\n\t\t\t.filter( ( name, idx, items ) => {\n\t\t\t\t// Filter only separators.\n\t\t\t\tif ( nonSeparatorPredicate( name ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tconst isDuplicated = idx > 0 && items[ idx - 1 ] === name;\n\n\t\t\t\treturn !isDuplicated;\n\t\t\t} );\n\t}\n\n\t/**\n\t * Fired when some toolbar {@link #items} were grouped or ungrouped as a result of some change\n\t * in the toolbar geometry.\n\t *\n\t * **Note**: This event is always fired **once** regardless of the number of items that were be\n\t * grouped or ungrouped at a time.\n\t *\n\t * **Note**: This event is fired only if the items grouping functionality was enabled in\n\t * the first place (see {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull}).\n\t *\n\t * @event groupedItemsUpdate\n\t */\n}\n\n/**\n * An inner block of the {@link module:ui/toolbar/toolbarview~ToolbarView} hosting its\n * {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n *\n * @private\n * @extends module:ui/view~View\n */\nclass ItemsView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * A collection of items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-toolbar__items'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n}\n\n/**\n * A toolbar behavior that makes it static and unresponsive to the changes of the environment.\n * At the same time, it also makes it possible to display a toolbar with a vertical layout\n * using the {@link module:ui/toolbar/toolbarview~ToolbarView#isVertical} property.\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass StaticLayout {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~StaticLayout} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\tconstructor( view ) {\n\t\tconst bind = view.bindTemplate;\n\n\t\t// Static toolbar can be vertical when needed.\n\t\tview.set( 'isVertical', false );\n\n\t\t// 1:1 passthrough binding, all ToolbarView#items are visible.\n\t\tview.itemsView.children.bindTo( view.items ).using( item => item );\n\n\t\t// 1:1 passthrough binding, all ToolbarView#items are focusable.\n\t\tview.focusables.bindTo( view.items ).using( item => item );\n\n\t\tview.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t// When vertical, the toolbar has an additional CSS class.\n\t\t\t\t\tbind.if( 'isVertical', 'ck-toolbar_vertical' )\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {}\n}\n\n/**\n * A toolbar behavior that makes the items respond to changes in the geometry.\n *\n * In a nutshell, it groups {@link module:ui/toolbar/toolbarview~ToolbarView#items}\n * that do not fit visually into a single row of the toolbar (due to limited space).\n * Items that do not fit are aggregated in a dropdown displayed at the end of the toolbar.\n *\n *\t┌──────────────────────────────────────── ToolbarView ──────────────────────────────────────────┐\n *\t| ┌─────────────────────────────────────── #children ─────────────────────────────────────────┐ |\n *\t| | ┌─────── #itemsView ────────┐ ┌──────────────────────┐ ┌── #groupedItemsDropdown ───┐ | |\n *\t| | | #ungroupedItems | | ToolbarSeparatorView | | #groupedItems | | |\n *\t| | └──────────────────────────-┘ └──────────────────────┘ └────────────────────────────┘ | |\n *\t| | \\---------- only when toolbar items overflow --------/ | |\n *\t| └───────────────────────────────────────────────────────────────────────────────────────────┘ |\n *\t└───────────────────────────────────────────────────────────────────────────────────────────────┘\n *\n * @private\n * @implements module:ui/toolbar/toolbarview~ToolbarBehavior\n */\nclass DynamicGrouping {\n\t/**\n\t * Creates an instance of the {@link module:ui/toolbar/toolbarview~DynamicGrouping} toolbar\n\t * behavior.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\tconstructor( view ) {\n\t\t/**\n\t\t * A toolbar view this behavior belongs to.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar~ToolbarView}\n\t\t */\n\t\tthis.view = view;\n\n\t\t/**\n\t\t * A collection of toolbar children.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.viewChildren = view.children;\n\n\t\t/**\n\t\t * A collection of focusable toolbar elements.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.viewFocusables = view.focusables;\n\n\t\t/**\n\t\t * A view containing toolbar items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbarview~ItemsView}\n\t\t */\n\t\tthis.viewItemsView = view.itemsView;\n\n\t\t/**\n\t\t * Toolbar focus tracker.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.viewFocusTracker = view.focusTracker;\n\n\t\t/**\n\t\t * Toolbar locale.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/locale~Locale}\n\t\t */\n\t\tthis.viewLocale = view.locale;\n\n\t\t/**\n\t\t * Toolbar element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {HTMLElement} #viewElement\n\t\t */\n\n\t\t/**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * Aggregates items that fit into a single row of the toolbar and were not {@link #groupedItems grouped}\n\t\t * into a {@link #groupedItemsDropdown dropdown}. Items of this collection are displayed in the\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#itemsView}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped, it\n\t\t * matches the {@link module:ui/toolbar/toolbarview~ToolbarView#items} collection in size and order.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.ungroupedItems = view.createCollection();\n\n\t\t/**\n\t\t * A subset of toolbar {@link module:ui/toolbar/toolbarview~ToolbarView#items}.\n\t\t * A collection of the toolbar items that do not fit into a single row of the toolbar.\n\t\t * Grouped items are displayed in a dedicated {@link #groupedItemsDropdown dropdown}.\n\t\t *\n\t\t * When none of the {@link module:ui/toolbar/toolbarview~ToolbarView#items} were grouped,\n\t\t * this collection is empty.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.groupedItems = view.createCollection();\n\n\t\t/**\n\t\t * The dropdown that aggregates {@link #groupedItems grouped items} that do not fit into a single\n\t\t * row of the toolbar. It is displayed on demand as the last of\n\t\t * {@link module:ui/toolbar/toolbarview~ToolbarView#children toolbar children} and offers another\n\t\t * (nested) toolbar which displays items that would normally overflow.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownview~DropdownView}\n\t\t */\n\t\tthis.groupedItemsDropdown = this._createGroupedItemsDropdown();\n\n\t\t/**\n\t\t * An instance of the resize observer that helps dynamically determine the geometry of the toolbar\n\t\t * and manage items that do not fit into a single row.\n\t\t *\n\t\t * **Note:** Created in {@link #_enableGroupingOnResize}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n\t\tthis.resizeObserver = null;\n\n\t\t/**\n\t\t * A cached value of the horizontal padding style used by {@link #_updateGrouping}\n\t\t * to manage the {@link module:ui/toolbar/toolbarview~ToolbarView#items} that do not fit into\n\t\t * a single toolbar line. This value can be reused between updates because it is unlikely that\n\t\t * the padding will change and reusing `Window.getComputedStyle()` is expensive.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cachedPadding = null;\n\n\t\t/**\n\t\t * A flag indicating that an items grouping update has been queued (e.g. due to the toolbar being visible)\n\t\t * and should be executed immediately the next time the toolbar shows up.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.shouldUpdateGroupingOnNextResize = false;\n\n\t\t// Only those items that were not grouped are visible to the user.\n\t\tview.itemsView.children.bindTo( this.ungroupedItems ).using( item => item );\n\n\t\t// Make sure all #items visible in the main space of the toolbar are \"focuscycleable\".\n\t\tthis.ungroupedItems.on( 'add', this._updateFocusCycleableItems.bind( this ) );\n\t\tthis.ungroupedItems.on( 'remove', this._updateFocusCycleableItems.bind( this ) );\n\n\t\t// Make sure the #groupedItemsDropdown is also included in cycling when it appears.\n\t\tview.children.on( 'add', this._updateFocusCycleableItems.bind( this ) );\n\t\tview.children.on( 'remove', this._updateFocusCycleableItems.bind( this ) );\n\n\t\t// ToolbarView#items is dynamic. When an item is added or removed, it should be automatically\n\t\t// represented in either grouped or ungrouped items at the right index.\n\t\t// In other words #items == concat( #ungroupedItems, #groupedItems )\n\t\t// (in length and order).\n\t\tview.items.on( 'change', ( evt, changeData ) => {\n\t\t\tconst index = changeData.index;\n\n\t\t\t// Removing.\n\t\t\tfor ( const removedItem of changeData.removed ) {\n\t\t\t\tif ( index >= this.ungroupedItems.length ) {\n\t\t\t\t\tthis.groupedItems.remove( removedItem );\n\t\t\t\t} else {\n\t\t\t\t\tthis.ungroupedItems.remove( removedItem );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Adding.\n\t\t\tfor ( let currentIndex = index; currentIndex < index + changeData.added.length; currentIndex++ ) {\n\t\t\t\tconst addedItem = changeData.added[ currentIndex - index ];\n\n\t\t\t\tif ( currentIndex > this.ungroupedItems.length ) {\n\t\t\t\t\tthis.groupedItems.add( addedItem, currentIndex - this.ungroupedItems.length );\n\t\t\t\t} else {\n\t\t\t\t\tthis.ungroupedItems.add( addedItem, currentIndex );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// When new ungrouped items join in and land in #ungroupedItems, there's a chance it causes\n\t\t\t// the toolbar to overflow.\n\t\t\t// Consequently if removed from grouped or ungrouped items, there is a chance\n\t\t\t// some new space is available and we could do some ungrouping.\n\t\t\tthis._updateGrouping();\n\t\t} );\n\n\t\tview.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t// To group items dynamically, the toolbar needs a dedicated CSS class.\n\t\t\t\t\t'ck-toolbar_grouping'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Enables dynamic items grouping based on the dimensions of the toolbar.\n\t *\n\t * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior\n\t * is added to.\n\t */\n\trender( view ) {\n\t\tthis.viewElement = view.element;\n\n\t\tthis._enableGroupingOnResize();\n\t\tthis._enableGroupingOnMaxWidthChange( view );\n\t}\n\n\t/**\n\t * Cleans up the internals used by this behavior.\n\t */\n\tdestroy() {\n\t\t// The dropdown may not be in ToolbarView#children at the moment of toolbar destruction\n\t\t// so let's make sure it's actually destroyed along with the toolbar.\n\t\tthis.groupedItemsDropdown.destroy();\n\n\t\tthis.resizeObserver.destroy();\n\t}\n\n\t/**\n\t * When called, it will check if any of the {@link #ungroupedItems} do not fit into a single row of the toolbar,\n\t * and it will move them to the {@link #groupedItems} when it happens.\n\t *\n\t * At the same time, it will also check if there is enough space in the toolbar for the first of the\n\t * {@link #groupedItems} to be returned back to {@link #ungroupedItems} and still fit into a single row\n\t * without the toolbar wrapping.\n\t *\n\t * @protected\n\t */\n\t_updateGrouping() {\n\t\t// Do no groupingrelated geometry analysis when the toolbar is detached from visible DOM,\n\t\t// for instance before #render(), or after render but without a parent or a parent detached\n\t\t// from DOM. DOMRects won't work anyway and there will be tons of warning in the console and\n\t\t// nothing else. This happens, for instance, when the toolbar is detached from DOM and\n\t\t// some logic adds or removes its #items.\n\t\tif ( !this.viewElement.ownerDocument.body.contains( this.viewElement ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not update grouping when the element is invisible. Such toolbar has DOMRect filled with zeros\n\t\t// and that would cause all items to be grouped. Instead, queue the grouping so it runs next time\n\t\t// the toolbar is visible (the next ResizeObserver callback execution). This is handy because\n\t\t// the grouping could be caused by increasing the #maxWidth when the toolbar was invisible and the next\n\t\t// time it shows up, some items could actually be ungrouped (https://github.com/ckeditor/ckeditor5/issues/6575).\n\t\tif ( !this.viewElement.offsetParent ) {\n\t\t\tthis.shouldUpdateGroupingOnNextResize = true;\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember how many items were initially grouped so at the it is possible to figure out if the number\n\t\t// of grouped items has changed. If the number has changed, geometry of the toolbar has also changed.\n\t\tconst initialGroupedItemsCount = this.groupedItems.length;\n\t\tlet wereItemsGrouped;\n\n\t\t// Group #items as long as some wrap to the next row. This will happen, for instance,\n\t\t// when the toolbar is getting narrow and there is not enough space to display all items in\n\t\t// a single row.\n\t\twhile ( this._areItemsOverflowing ) {\n\t\t\tthis._groupLastItem();\n\n\t\t\twereItemsGrouped = true;\n\t\t}\n\n\t\t// If none were grouped now but there were some items already grouped before,\n\t\t// then, what the hell, maybe let's see if some of them can be ungrouped. This happens when,\n\t\t// for instance, the toolbar is stretching and there's more space in it than before.\n\t\tif ( !wereItemsGrouped && this.groupedItems.length ) {\n\t\t\t// Ungroup items as long as none are overflowing or there are none to ungroup left.\n\t\t\twhile ( this.groupedItems.length && !this._areItemsOverflowing ) {\n\t\t\t\tthis._ungroupFirstItem();\n\t\t\t}\n\n\t\t\t// If the ungrouping ended up with some item wrapping to the next row,\n\t\t\t// put it back to the group toolbar (\"undo the last ungroup\"). We don't know whether\n\t\t\t// an item will wrap or not until we ungroup it (that's a DOM/CSS thing) so this\n\t\t\t// cleanup is vital for the algorithm.\n\t\t\tif ( this._areItemsOverflowing ) {\n\t\t\t\tthis._groupLastItem();\n\t\t\t}\n\t\t}\n\n\t\tif ( this.groupedItems.length !== initialGroupedItemsCount ) {\n\t\t\tthis.view.fire( 'groupedItemsUpdate' );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when {@link module:ui/toolbar/toolbarview~ToolbarView#element} children visually overflow,\n\t * for instance if the toolbar is narrower than its members. Returns `false` otherwise.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _areItemsOverflowing() {\n\t\t// An empty toolbar cannot overflow.\n\t\tif ( !this.ungroupedItems.length ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst element = this.viewElement;\n\t\tconst uiLanguageDirection = this.viewLocale.uiLanguageDirection;\n\t\tconst lastChildRect = new Rect( element.lastChild );\n\t\tconst toolbarRect = new Rect( element );\n\n\t\tif ( !this.cachedPadding ) {\n\t\t\tconst computedStyle = global.window.getComputedStyle( element );\n\t\t\tconst paddingProperty = uiLanguageDirection === 'ltr' ? 'paddingRight' : 'paddingLeft';\n\n\t\t\t// parseInt() is essential because of quirky floating point numbers logic and DOM.\n\t\t\t// If the padding turned out too big because of that, the grouped items dropdown would\n\t\t\t// always look (from the Rect perspective) like it overflows (while it's not).\n\t\t\tthis.cachedPadding = Number.parseInt( computedStyle[ paddingProperty ] );\n\t\t}\n\n\t\tif ( uiLanguageDirection === 'ltr' ) {\n\t\t\treturn lastChildRect.right > toolbarRect.right - this.cachedPadding;\n\t\t} else {\n\t\t\treturn lastChildRect.left < toolbarRect.left + this.cachedPadding;\n\t\t}\n\t}\n\n\t/**\n\t * Enables the functionality that prevents {@link #ungroupedItems} from overflowing (wrapping to the next row)\n\t * upon resize when there is little space available. Instead, the toolbar items are moved to the\n\t * {@link #groupedItems} collection and displayed in a dropdown at the end of the row (which has its own nested toolbar).\n\t *\n\t * When called, the toolbar will automatically analyze the location of its {@link #ungroupedItems} and \"group\"\n\t * them in the dropdown if necessary. It will also observe the browser window for size changes in\n\t * the future and respond to them by grouping more items or reverting already grouped back, depending\n\t * on the visual space available.\n\t *\n\t * @private\n\t */\n\t_enableGroupingOnResize() {\n\t\tlet previousWidth;\n\n\t\t// TODO: Consider debounce.\n\t\tthis.resizeObserver = new ResizeObserver( this.viewElement, entry => {\n\t\t\tif ( !previousWidth || previousWidth !== entry.contentRect.width || this.shouldUpdateGroupingOnNextResize ) {\n\t\t\t\tthis.shouldUpdateGroupingOnNextResize = false;\n\n\t\t\t\tthis._updateGrouping();\n\n\t\t\t\tpreviousWidth = entry.contentRect.width;\n\t\t\t}\n\t\t} );\n\n\t\tthis._updateGrouping();\n\t}\n\n\t/**\n\t * Enables the grouping functionality, just like {@link #_enableGroupingOnResize} but the difference is that\n\t * it listens to the changes of {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth} instead.\n\t *\n\t * @private\n\t */\n\t_enableGroupingOnMaxWidthChange( view ) {\n\t\tview.on( 'change:maxWidth', () => {\n\t\t\tthis._updateGrouping();\n\t\t} );\n\t}\n\n\t/**\n\t * When called, it will remove the last item from {@link #ungroupedItems} and move it back\n\t * to the {@link #groupedItems} collection.\n\t *\n\t * The opposite of {@link #_ungroupFirstItem}.\n\t *\n\t * @private\n\t */\n\t_groupLastItem() {\n\t\tif ( !this.groupedItems.length ) {\n\t\t\tthis.viewChildren.add( new ToolbarSeparatorView() );\n\t\t\tthis.viewChildren.add( this.groupedItemsDropdown );\n\t\t\tthis.viewFocusTracker.add( this.groupedItemsDropdown.element );\n\t\t}\n\n\t\tthis.groupedItems.add( this.ungroupedItems.remove( this.ungroupedItems.last ), 0 );\n\t}\n\n\t/**\n\t * Moves the very first item belonging to {@link #groupedItems} back\n\t * to the {@link #ungroupedItems} collection.\n\t *\n\t * The opposite of {@link #_groupLastItem}.\n\t *\n\t * @private\n\t */\n\t_ungroupFirstItem() {\n\t\tthis.ungroupedItems.add( this.groupedItems.remove( this.groupedItems.first ) );\n\n\t\tif ( !this.groupedItems.length ) {\n\t\t\tthis.viewChildren.remove( this.groupedItemsDropdown );\n\t\t\tthis.viewChildren.remove( this.viewChildren.last );\n\t\t\tthis.viewFocusTracker.remove( this.groupedItemsDropdown.element );\n\t\t}\n\t}\n\n\t/**\n\t * Creates the {@link #groupedItemsDropdown} that hosts the members of the {@link #groupedItems}\n\t * collection when there is not enough space in the toolbar to display all items in a single row.\n\t *\n\t * @private\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_createGroupedItemsDropdown() {\n\t\tconst locale = this.viewLocale;\n\t\tconst t = locale.t;\n\t\tconst dropdown = createDropdown( locale );\n\n\t\tdropdown.class = 'ck-toolbar__grouped-dropdown';\n\n\t\t// Make sure the dropdown never sticks out to the left/right. It should be under the main toolbar.\n\t\t// (https://github.com/ckeditor/ckeditor5/issues/5608)\n\t\tdropdown.panelPosition = locale.uiLanguageDirection === 'ltr' ? 'sw' : 'se';\n\n\t\taddToolbarToDropdown( dropdown, [] );\n\n\t\tdropdown.buttonView.set( {\n\t\t\tlabel: t( 'Show more items' ),\n\t\t\ttooltip: true,\n\t\t\ttooltipPosition: locale.uiLanguageDirection === 'rtl' ? 'se' : 'sw',\n\t\t\ticon: icons.threeVerticalDots\n\t\t} );\n\n\t\t// 1:1 passthrough binding.\n\t\tdropdown.toolbarView.items.bindTo( this.groupedItems ).using( item => item );\n\n\t\treturn dropdown;\n\t}\n\n\t/**\n\t * Updates the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables focuscycleable items}\n\t * collection so it represents the uptodate state of the UI from the perspective of the user.\n\t *\n\t * For instance, the {@link #groupedItemsDropdown} can show up and hide but when it is visible,\n\t * it must be subject to focus cycling in the toolbar.\n\t *\n\t * See the {@link module:ui/toolbar/toolbarview~ToolbarView#focusables collection} documentation\n\t * to learn more about the purpose of this method.\n\t *\n\t * @private\n\t */\n\t_updateFocusCycleableItems() {\n\t\tthis.viewFocusables.clear();\n\n\t\tthis.ungroupedItems.map( item => {\n\t\t\tthis.viewFocusables.add( item );\n\t\t} );\n\n\t\tif ( this.groupedItems.length ) {\n\t\t\tthis.viewFocusables.add( this.groupedItemsDropdown );\n\t\t}\n\t}\n}\n\n/**\n * Options passed to the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n *\n * @interface module:ui/toolbar/toolbarview~ToolbarOptions\n */\n\n/**\n * When set to `true`, the toolbar will automatically group {@link module:ui/toolbar/toolbarview~ToolbarView#items} that\n * would normally wrap to the next line when there is not enough space to display them in a single row, for\n * instance, if the parent container of the toolbar is narrow. For toolbars in absolutely positioned containers\n * without width restrictions also the {@link module:ui/toolbar/toolbarview~ToolbarOptions#isFloating} option is required to be `true`.\n *\n * See also: {@link module:ui/toolbar/toolbarview~ToolbarView#maxWidth}.\n *\n * @member {Boolean} module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull\n */\n\n/**\n * This option should be enabled for toolbars in absolutely positioned containers without width restrictions\n * to enable automatic {@link module:ui/toolbar/toolbarview~ToolbarView#items} grouping.\n * When this option is set to `true`, the items will stop wrapping to the next line\n * and together with {@link module:ui/toolbar/toolbarview~ToolbarOptions#shouldGroupWhenFull},\n * this will allow grouping them when there is not enough space in a single row.\n *\n * @member {Boolean} module:ui/toolbar/toolbarview~ToolbarOptions#isFloating\n */\n\n/**\n * A class interface defining the behavior of the {@link module:ui/toolbar/toolbarview~ToolbarView}.\n *\n * Toolbar behaviors extend its look and functionality and have an impact on the\n * {@link module:ui/toolbar/toolbarview~ToolbarView#element} template or\n * {@link module:ui/toolbar/toolbarview~ToolbarView#render rendering}. They can be enabled\n * conditionally, e.g. depending on the configuration of the toolbar.\n *\n * @private\n * @interface module:ui/toolbar/toolbarview~ToolbarBehavior\n */\n\n/**\n * Creates a new toolbar behavior instance.\n *\n * The instance is created in the {@link module:ui/toolbar/toolbarview~ToolbarView#constructor} of the toolbar.\n * This is the right place to extend the {@link module:ui/toolbar/toolbarview~ToolbarView#template} of\n * the toolbar, define extra toolbar properties, etc.\n *\n * @method #constructor\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar that this behavior is added to.\n */\n\n/**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#render rendered}.\n * It can be used to, for example, customize the behavior of the toolbar when its {@link module:ui/toolbar/toolbarview~ToolbarView#element}\n * is available.\n *\n * @readonly\n * @member {Function} #render\n * @param {module:ui/toolbar/toolbarview~ToolbarView} view An instance of the toolbar being rendered.\n */\n\n/**\n * A method called after the toolbar has been {@link module:ui/toolbar/toolbarview~ToolbarView#destroy destroyed}.\n * It allows cleaning up after the toolbar behavior, for instance, this is the right place to detach\n * event listeners, free up references, etc.\n *\n * @readonly\n * @member {Function} #destroy\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 ui/bindings/preventdefault\n */\n\n/**\n * A helper which executes a native `Event.preventDefault()` if the target of an event equals the\n * {@link module:ui/view~View#element element of the view}. It shortens the definition of a\n * {@link module:ui/view~View#template template}.\n *\n *\t\t// In a class extending View.\n *\t\timport preventDefault from '@ckeditor/ckeditor5-ui/src/bindings/preventdefault';\n *\n *\t\t// ...\n *\n *\t\tthis.setTemplate( {\n *\t\t\ttag: 'div',\n *\n *\t\t\ton: {\n *\t\t\t\t// Prevent the default mousedown action on this view.\n *\t\t\t\tmousedown: preventDefault( this )\n *\t\t\t}\n *\t\t} );\n *\n * @param {module:ui/view~View} view View instance that defines the template.\n * @returns {module:ui/template~TemplateToBinding}\n */\nexport default function preventDefault( view ) {\n\treturn view.bindTemplate.to( evt => {\n\t\tif ( evt.target === view.element ) {\n\t\t\tevt.preventDefault();\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/list/listview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '../focuscycler';\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\n\nimport '../../theme/components/list/list.css';\n\n/**\n * The list view class.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class ListView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor() {\n\t\tsuper();\n\n\t\t/**\n\t\t * Collection of the child list views.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Helps cycling over focusable {@link #items} in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.items,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate list items backwards using the arrowup key.\n\t\t\t\tfocusPrevious: 'arrowup',\n\n\t\t\t\t// Navigate toolbar items forwards using the arrowdown key.\n\t\t\t\tfocusNext: 'arrowdown'\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'ul',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-reset',\n\t\t\t\t\t'ck-list'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.items\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\tthis.items.on( 'add', ( evt, item ) => {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t} );\n\n\t\tthis.items.on( 'remove', ( evt, item ) => {\n\t\t\tthis.focusTracker.remove( item.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the first focusable in {@link #items}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/list/listitemview\n */\n\nimport View from '../view';\n\n/**\n * The list item view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ListItemView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views inside of the list item {@link #element}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'li',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-list__item'\n\t\t\t\t]\n\t\t\t},\n\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the list item.\n\t */\n\tfocus() {\n\t\tthis.children.first.focus();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/list/listseparatorview\n */\n\nimport View from '../view';\n\n/**\n * The list separator view class.\n *\n * @extends module:ui/view~View\n */\nexport default class ListSeparatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'li',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-list__separator'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/dropdown/utils\n */\n\nimport DropdownPanelView from './dropdownpanelview';\nimport DropdownView from './dropdownview';\nimport DropdownButtonView from './button/dropdownbuttonview';\nimport ToolbarView from '../toolbar/toolbarview';\nimport ListView from '../list/listview';\nimport ListItemView from '../list/listitemview';\nimport ListSeparatorView from '../list/listseparatorview';\nimport ButtonView from '../button/buttonview';\nimport SwitchButtonView from '../button/switchbuttonview';\n\nimport clickOutsideHandler from '../bindings/clickoutsidehandler';\n\nimport '../../theme/components/dropdown/toolbardropdown.css';\nimport '../../theme/components/dropdown/listdropdown.css';\n\n/**\n * A helper for creating dropdowns. It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown},\n * with a {@link module:ui/dropdown/button/dropdownbutton~DropdownButton button},\n * {@link module:ui/dropdown/dropdownpanelview~DropdownPanelView panel} and all standard dropdown's behaviors.\n *\n * # Creating dropdowns\n *\n * By default, the default {@link module:ui/dropdown/button/dropdownbuttonview~DropdownButtonView} class is used as\n * definition of the button:\n *\n *\t\tconst dropdown = createDropdown( model );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\t// Will render a dropdown labeled \"A dropdown\" with an empty panel.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * You can also provide other button views (they need to implement the\n * {@link module:ui/dropdown/button/dropdownbutton~DropdownButton} interface). For instance, you can use\n * {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} to create a dropdown with a split button.\n *\n *\t\tconst dropdown = createDropdown( model, SplitButtonView );\n *\n *\t\t// Configure dropdown's button properties:\n *\t\tdropdown.buttonView.set( {\n *\t\t\tlabel: 'A dropdown',\n *\t\t\twithText: true\n *\t\t} );\n *\n *\t\tdropdown.buttonView.on( 'execute', () => {\n *\t\t\t// Add the behavior of the \"action part\" of the split button.\n *\t\t\t// Split button consists of the \"action part\" and \"arrow part\".\n *\t\t\t// The arrow opens the dropdown while the action part can have some other behavior.\n * \t\t} );\n *\n *\t\tdropdown.render();\n *\n *\t\t// Will render a dropdown labeled \"A dropdown\" with an empty panel.\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * # Adding content to the dropdown's panel\n *\n * The content of the panel can be inserted directly into the `dropdown.panelView.element`:\n *\n *\t\tdropdown.panelView.element.textContent = 'Content of the panel';\n *\n * However, most of the time you will want to add there either a {@link module:ui/list/listview~ListView list of options}\n * or a list of buttons (i.e. a {@link module:ui/toolbar/toolbarview~ToolbarView toolbar}).\n * To simplify the task, you can use, respectively, {@link module:ui/dropdown/utils~addListToDropdown} or\n * {@link module:ui/dropdown/utils~addToolbarToDropdown} utils.\n *\n * @param {module:utils/locale~Locale} locale The locale instance.\n * @param {Function} ButtonClass The dropdown button view class. Needs to implement the\n * {@link module:ui/dropdown/button/dropdownbutton~DropdownButton} interface.\n * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance.\n */\nexport function createDropdown( locale, ButtonClass = DropdownButtonView ) {\n\tconst buttonView = new ButtonClass( locale );\n\n\tconst panelView = new DropdownPanelView( locale );\n\tconst dropdownView = new DropdownView( locale, buttonView, panelView );\n\n\tbuttonView.bind( 'isEnabled' ).to( dropdownView );\n\n\tif ( buttonView instanceof DropdownButtonView ) {\n\t\tbuttonView.bind( 'isOn' ).to( dropdownView, 'isOpen' );\n\t} else {\n\t\tbuttonView.arrowView.bind( 'isOn' ).to( dropdownView, 'isOpen' );\n\t}\n\n\taddDefaultBehavior( dropdownView );\n\n\treturn dropdownView;\n}\n\n/**\n * Adds an instance of {@link module:ui/toolbar/toolbarview~ToolbarView} to a dropdown.\n *\n *\t\tconst buttons = [];\n *\n *\t\t// Either create a new ButtonView instance or create existing.\n *\t\tbuttons.push( new ButtonView() );\n *\t\tbuttons.push( editor.ui.componentFactory.create( 'someButton' ) );\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\taddToolbarToDropdown( dropdown, buttons );\n *\n *\t\tdropdown.toolbarView.isVertical = true;\n *\n *\t\t// Will render a vertical button dropdown labeled \"A button dropdown\"\n *\t\t// with a button group in the panel containing two buttons.\n *\t\tdropdown.render()\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * See {@link module:ui/dropdown/utils~createDropdown} and {@link module:ui/toolbar/toolbarview~ToolbarView}.\n *\n * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdown instance to which `ToolbarView` will be added.\n * @param {Iterable.<module:ui/button/buttonview~ButtonView>} buttons\n */\nexport function addToolbarToDropdown( dropdownView, buttons ) {\n\tconst locale = dropdownView.locale;\n\tconst t = locale.t;\n\tconst toolbarView = dropdownView.toolbarView = new ToolbarView( locale );\n\n\ttoolbarView.set( 'ariaLabel', t( 'Dropdown toolbar' ) );\n\n\tdropdownView.extendTemplate( {\n\t\tattributes: {\n\t\t\tclass: [ 'ck-toolbar-dropdown' ]\n\t\t}\n\t} );\n\n\tbuttons.map( view => toolbarView.items.add( view ) );\n\n\tdropdownView.panelView.children.add( toolbarView );\n\ttoolbarView.items.delegate( 'execute' ).to( dropdownView );\n}\n\n/**\n * Adds an instance of {@link module:ui/list/listview~ListView} to a dropdown.\n *\n *\t\tconst items = new Collection();\n *\n *\t\titems.add( {\n *\t\t\ttype: 'button',\n *\t\t\tmodel: new Model( {\n *\t\t\t\twithText: true,\n *\t\t\t\tlabel: 'First item',\n *\t\t\t\tlabelStyle: 'color: red'\n *\t\t\t} )\n *\t\t} );\n *\n *\t\titems.add( {\n *\t\t\t type: 'button',\n *\t\t\t model: new Model( {\n *\t\t\t\twithText: true,\n *\t\t\t\tlabel: 'Second item',\n *\t\t\t\tlabelStyle: 'color: green',\n *\t\t\t\tclass: 'foo'\n *\t\t\t} )\n *\t\t} );\n *\n *\t\tconst dropdown = createDropdown( locale );\n *\n *\t\taddListToDropdown( dropdown, items );\n *\n *\t\t// Will render a dropdown with a list in the panel containing two items.\n *\t\tdropdown.render()\n *\t\tdocument.body.appendChild( dropdown.element );\n *\n * The `items` collection passed to this methods controls the presence and attributes of respective\n * {@link module:ui/list/listitemview~ListItemView list items}.\n *\n *\n * See {@link module:ui/dropdown/utils~createDropdown} and {@link module:list/list~List}.\n *\n * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView A dropdown instance to which `ListVIew` will be added.\n * @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} items\n * A collection of the list item definitions to populate the list.\n */\nexport function addListToDropdown( dropdownView, items ) {\n\tconst locale = dropdownView.locale;\n\tconst listView = dropdownView.listView = new ListView( locale );\n\n\tlistView.items.bindTo( items ).using( ( { type, model } ) => {\n\t\tif ( type === 'separator' ) {\n\t\t\treturn new ListSeparatorView( locale );\n\t\t} else if ( type === 'button' || type === 'switchbutton' ) {\n\t\t\tconst listItemView = new ListItemView( locale );\n\t\t\tlet buttonView;\n\n\t\t\tif ( type === 'button' ) {\n\t\t\t\tbuttonView = new ButtonView( locale );\n\t\t\t} else {\n\t\t\t\tbuttonView = new SwitchButtonView( locale );\n\t\t\t}\n\n\t\t\t// Bind all model properties to the button view.\n\t\t\tbuttonView.bind( ...Object.keys( model ) ).to( model );\n\t\t\tbuttonView.delegate( 'execute' ).to( listItemView );\n\n\t\t\tlistItemView.children.add( buttonView );\n\n\t\t\treturn listItemView;\n\t\t}\n\t} );\n\n\tdropdownView.panelView.children.add( listView );\n\n\tlistView.items.delegate( 'execute' ).to( dropdownView );\n}\n\n// Add a set of default behaviors to dropdown view.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction addDefaultBehavior( dropdownView ) {\n\tcloseDropdownOnBlur( dropdownView );\n\tcloseDropdownOnExecute( dropdownView );\n\tfocusDropdownContentsOnArrows( dropdownView );\n}\n\n// Adds a behavior to a dropdownView that closes opened dropdown when user clicks outside the dropdown.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction closeDropdownOnBlur( dropdownView ) {\n\tdropdownView.on( 'render', () => {\n\t\tclickOutsideHandler( {\n\t\t\temitter: dropdownView,\n\t\t\tactivator: () => dropdownView.isOpen,\n\t\t\tcallback: () => {\n\t\t\t\tdropdownView.isOpen = false;\n\t\t\t},\n\t\t\tcontextElements: [ dropdownView.element ]\n\t\t} );\n\t} );\n}\n\n// Adds a behavior to a dropdownView that closes the dropdown view on \"execute\" event.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction closeDropdownOnExecute( dropdownView ) {\n\t// Close the dropdown when one of the list items has been executed.\n\tdropdownView.on( 'execute', evt => {\n\t\t// Toggling a switch button view should not close the dropdown.\n\t\tif ( evt.source instanceof SwitchButtonView ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdropdownView.isOpen = false;\n\t} );\n}\n\n// Adds a behavior to a dropdownView that focuses the dropdown's panel view contents on keystrokes.\n//\n// @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\nfunction focusDropdownContentsOnArrows( dropdownView ) {\n\t// If the dropdown panel is already open, the arrow down key should focus the first child of the #panelView.\n\tdropdownView.keystrokes.set( 'arrowdown', ( data, cancel ) => {\n\t\tif ( dropdownView.isOpen ) {\n\t\t\tdropdownView.panelView.focus();\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\t// If the dropdown panel is already open, the arrow up key should focus the last child of the #panelView.\n\tdropdownView.keystrokes.set( 'arrowup', ( data, cancel ) => {\n\t\tif ( dropdownView.isOpen ) {\n\t\t\tdropdownView.panelView.focusLast();\n\t\t\tcancel();\n\t\t}\n\t} );\n}\n\n/**\n * A definition of the list item used by the {@link module:ui/dropdown/utils~addListToDropdown}\n * utility.\n *\n * @typedef {Object} module:ui/dropdown/utils~ListDropdownItemDefinition\n *\n * @property {String} type Either `'separator'`, `'button'` or `'switchbutton'`.\n * @property {module:ui/model~Model} [model] Model of the item (when **not** `'separator'`).\n * Its properties fuel the newly created list item (or its children, depending on the `type`).\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 ui/editorui/editoruiview\n */\n\nimport View from '../view';\nimport BodyCollection from './bodycollection';\n\nimport '../../theme/components/editorui/editorui.css';\n\n/**\n * The editor UI view class. Base class for the editor main views.\n *\n * @extends module:ui/view~View\n */\nexport default class EditorUIView extends View {\n\t/**\n\t * Creates an instance of the editor UI view class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Collection of the child views, detached from the DOM\n\t\t * structure of the editor, like panels, icons etc.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection} #body\n\t\t */\n\t\tthis.body = new BodyCollection( locale );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.body.attachToDom();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis.body.detachFromDom();\n\n\t\treturn super.destroy();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/label/labelview\n */\n\nimport View from '../view';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\n\nimport '../../theme/components/label/label.css';\n\n/**\n * The label view class.\n *\n * @extends module:ui/view~View\n */\nexport default class LabelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The text of the label.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #text\n\t\t */\n\t\tthis.set( 'text' );\n\n\t\t/**\n\t\t * The `for` attribute of the label (i.e. to pair with an `<input>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #for\n\t\t */\n\t\tthis.set( 'for' );\n\n\t\t/**\n\t\t * An unique id of the label. It can be used by other UI components to reference\n\t\t * the label, for instance, using the `aria-describedby` DOM attribute.\n\t\t *\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.id = `ck-editor__label_${ uid() }`;\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'label',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-label'\n\t\t\t\t],\n\t\t\t\tid: this.id,\n\t\t\t\tfor: bind.to( 'for' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: bind.to( 'text' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/editableui/editableuiview\n */\n\nimport View from '../view';\n\n/**\n * The editable UI view class.\n *\n * @extends module:ui/view~View\n */\nexport default class EditableUIView extends View {\n\t/**\n\t * Creates an instance of EditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, this view\n\t * should create it. Otherwise, the existing element should be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-content',\n\t\t\t\t\t'ck-editor__editable',\n\t\t\t\t\t'ck-rounded-corners'\n\t\t\t\t],\n\t\t\t\tlang: locale.contentLanguage,\n\t\t\t\tdir: locale.contentLanguageDirection\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * The name of the editable UI view.\n\t\t *\n\t\t * @member {String} #name\n\t\t */\n\t\tthis.name = null;\n\n\t\t/**\n\t\t * Controls whether the editable is focused, i.e. the user is typing in it.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The element which is the main editable element (usually the one with `contentEditable=\"true\"`).\n\t\t *\n\t\t * @private\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis._editableElement = editableElement;\n\n\t\t/**\n\t\t * Whether an external {@link #_editableElement} was passed into the constructor, which also means\n\t\t * the view will not render its {@link #template}.\n\t\t *\n\t\t * @private\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis._hasExternalElement = !!this._editableElement;\n\n\t\t/**\n\t\t * The editing view instance the editable is related to. Editable uses the editing\n\t\t * view to dynamically modify its certain DOM attributes after {@link #render rendering}.\n\t\t *\n\t\t * **Note**: The DOM attributes are performed by the editing view and not UI\n\t\t * {@link module:ui/view~View#bindTemplate template bindings} because once rendered,\n\t\t * the editable DOM element must remain under the full control of the engine to work properly.\n\t\t *\n\t\t * @protected\n\t\t * @type {module:engine/view/view~View}\n\t\t */\n\t\tthis._editingView = editingView;\n\t}\n\n\t/**\n\t * Renders the view by either applying the {@link #template} to the existing\n\t * {@link #_editableElement} or assigning {@link #element} as {@link #_editableElement}.\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.apply( this.element = this._editableElement );\n\t\t} else {\n\t\t\tthis._editableElement = this.element;\n\t\t}\n\n\t\tthis.on( 'change:isFocused', () => this._updateIsFocusedClasses() );\n\t\tthis._updateIsFocusedClasses();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._hasExternalElement ) {\n\t\t\tthis.template.revert( this._editableElement );\n\t\t}\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Updates the `ck-focused` and `ck-blurred` CSS classes on the {@link #element} according to\n\t * the {@link #isFocused} property value using the {@link #_editingView editing view} API.\n\t *\n\t * @private\n\t */\n\t_updateIsFocusedClasses() {\n\t\tconst editingView = this._editingView;\n\n\t\tif ( editingView.isRenderingInProgress ) {\n\t\t\tupdateAfterRender( this );\n\t\t} else {\n\t\t\tupdate( this );\n\t\t}\n\n\t\tfunction update( view ) {\n\t\t\teditingView.change( writer => {\n\t\t\t\tconst viewRoot = editingView.document.getRoot( view.name );\n\n\t\t\t\twriter.addClass( view.isFocused ? 'ck-focused' : 'ck-blurred', viewRoot );\n\t\t\t\twriter.removeClass( view.isFocused ? 'ck-blurred' : 'ck-focused', viewRoot );\n\t\t\t} );\n\t\t}\n\n\t\t// In a case of a multi-root editor, a callback will be attached more than once (one callback for each root).\n\t\t// While executing one callback the `isRenderingInProgress` observable is changing what causes executing another\n\t\t// callback and render is called inside the already pending render.\n\t\t// We need to be sure that callback is executed only when the value has changed from `true` to `false`.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1676.\n\t\tfunction updateAfterRender( view ) {\n\t\t\teditingView.once( 'change:isRenderingInProgress', ( evt, name, value ) => {\n\t\t\t\tif ( !value ) {\n\t\t\t\t\tupdate( view );\n\t\t\t\t} else {\n\t\t\t\t\tupdateAfterRender( view );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/editableui/inline/inlineeditableuiview\n */\n\nimport EditableUIView from '../../editableui/editableuiview';\n\n/**\n * The inline editable UI class implementing an inline {@link module:ui/editableui/editableuiview~EditableUIView}.\n *\n * @extends module:ui/editableui/editableuiview~EditableUIView\n */\nexport default class InlineEditableUIView extends EditableUIView {\n\t/**\n\t * Creates an instance of the InlineEditableUIView class.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The locale instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance the editable is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, the\n\t * {@link module:ui/editableui/editableuiview~EditableUIView}\n\t * will create it. Otherwise, the existing element will be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale, editingView, editableElement );\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\trole: 'textbox',\n\t\t\t\tclass: 'ck-editor__editable_inline'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tconst editingView = this._editingView;\n\t\tconst t = this.t;\n\n\t\teditingView.change( writer => {\n\t\t\tconst viewRoot = editingView.document.getRoot( this.name );\n\n\t\t\twriter.setAttribute( 'aria-label', t( 'Rich Text Editor, %0', this.name ), viewRoot );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/formheader/formheaderview\n */\n\nimport View from '../view';\n\nimport '../../theme/components/formheader/formheader.css';\n\n/**\n * The class component representing a form header view. It should be used in more advanced forms to\n * describe the main purpose of the form.\n *\n * By default the component contains a bolded label view that has to be set. The label is usually a short (at most 3-word) string.\n * The component can also be extended by any other elements, like: icons, dropdowns, etc.\n *\n * It is used i.a.\n * by {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView}\n * and {@link module:special-characters/ui/specialcharactersnavigationview~SpecialCharactersNavigationView}.\n *\n * The latter is an example, where the component has been extended by {@link module:ui/dropdown/dropdownview~DropdownView} view.\n *\n * @extends module:ui/view~View\n */\nexport default class FormHeaderView extends View {\n\t/**\n\t * Creates an instance of the form header class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance.\n\t * @param {Object} options\n\t * @param {String} options.label A label.\n\t * @param {String} [options.class] An additional class.\n\t */\n\tconstructor( locale, options = {} ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The label of the header.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.set( 'label', options.label || '' );\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class', options.class || null );\n\n\t\t/**\n\t\t * A collection of header items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-form__header',\n\t\t\t\t\tbind.to( 'class' )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\n\t\tconst label = new View( locale );\n\n\t\tlabel.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-form__header__label'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{ text: bind.to( 'label' ) }\n\t\t\t]\n\t\t} );\n\n\t\tthis.children.add( label );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/inputtext/inputtextview\n */\n\nimport View from '../view';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport '../../theme/components/inputtext/inputtext.css';\n\n/**\n * The text input view class.\n *\n * @extends module:ui/view~View\n */\nexport default class InputTextView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The value of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * The `id` attribute of the input (i.e. to pair with a `<label>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.set( 'id' );\n\n\t\t/**\n\t\t * The `placeholder` attribute of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.set( 'placeholder' );\n\n\t\t/**\n\t\t * Controls whether the input view is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Set to `true` when the field has some error. Usually controlled via\n\t\t * {@link module:ui/labeledinput/labeledinputview~LabeledInputView#errorText}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #hasError\n\t\t */\n\t\tthis.set( 'hasError', false );\n\n\t\t/**\n\t\t * The `id` of the element describing this field, e.g. when it has\n\t\t * some error, it helps screen readers read the error text.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #ariaDescribedById\n\t\t */\n\t\tthis.set( 'ariaDescribedById' );\n\n\t\t/**\n\t\t * Stores information about the editor UI focus and propagates it so various plugins and components\n\t\t * are unified as a focus group.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker} #focusTracker\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An observable flag set to `true` when the input is currently focused by the user.\n\t\t * Set to `false` otherwise.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t * @default false\n\t\t */\n\t\tthis.bind( 'isFocused' ).to( this.focusTracker );\n\n\t\t/**\n\t\t * An observable flag set to `true` when the input contains no text, i.e.\n\t\t * when {@link #value} is `''`, `null`, or `false`.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isEmpty\n\t\t * @default true\n\t\t */\n\t\tthis.set( 'isEmpty', true );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'input',\n\t\t\tattributes: {\n\t\t\t\ttype: 'text',\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-input',\n\t\t\t\t\t'ck-input-text',\n\t\t\t\t\tbind.if( 'isFocused', 'ck-input_focused' ),\n\t\t\t\t\tbind.if( 'isEmpty', 'ck-input-text_empty' ),\n\t\t\t\t\tbind.if( 'hasError', 'ck-error' )\n\t\t\t\t],\n\t\t\t\tid: bind.to( 'id' ),\n\t\t\t\tplaceholder: bind.to( 'placeholder' ),\n\t\t\t\treadonly: bind.to( 'isReadOnly' ),\n\t\t\t\t'aria-invalid': bind.if( 'hasError', true ),\n\t\t\t\t'aria-describedby': bind.to( 'ariaDescribedById' )\n\t\t\t},\n\t\t\ton: {\n\t\t\t\tinput: bind.to( 'input' ),\n\t\t\t\tchange: bind.to( this._updateIsEmpty.bind( this ) )\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Fired when the user types in the input. Corresponds to the native\n\t\t * DOM `input` event.\n\t\t *\n\t\t * @event input\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.focusTracker.add( this.element );\n\n\t\tthis._setDomElementValue( this.value );\n\t\tthis._updateIsEmpty();\n\n\t\t// Bind `this.value` to the DOM element's value.\n\t\t// We cannot use `value` DOM attribute because removing it on Edge does not clear the DOM element's value property.\n\t\tthis.on( 'change:value', ( evt, name, value ) => {\n\t\t\tthis._setDomElementValue( value );\n\t\t\tthis._updateIsEmpty();\n\t\t} );\n\t}\n\n\t/**\n\t * Moves the focus to the input and selects the value.\n\t */\n\tselect() {\n\t\tthis.element.select();\n\t}\n\n\t/**\n\t * Focuses the input.\n\t */\n\tfocus() {\n\t\tthis.element.focus();\n\t}\n\n\t/**\n\t * Updates the {@link #isEmpty} property value on demand.\n\t *\n\t * @private\n\t */\n\t_updateIsEmpty() {\n\t\tthis.isEmpty = isInputElementEmpty( this.element );\n\t}\n\n\t/**\n\t * Sets the `value` property of the {@link #element DOM element} on demand.\n\t *\n\t * @private\n\t */\n\t_setDomElementValue( value ) {\n\t\tthis.element.value = ( !value && value !== 0 ) ? '' : value;\n\t}\n}\n\nfunction isInputElementEmpty( domElement ) {\n\treturn !domElement.value;\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 ui/labeledfield/labeledfieldview\n */\n\nimport View from '../view';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport LabelView from '../label/labelview';\nimport '../../theme/components/labeledfield/labeledfieldview.css';\n\n/**\n * The labeled field view class. It can be used to enhance any view with the following features:\n *\n * * a label,\n * * (optional) an error message,\n * * (optional) an info (status) text,\n *\n * all bound logically by proper DOM attributes for UX and accessibility. It also provides an interface\n * (e.g. observable properties) that allows controlling those additional features.\n *\n * The constructor of this class requires a callback that returns a view to be labeled. The callback\n * is called with unique ids that allow binding of DOM properties:\n *\n *\t\tconst labeledInputView = new LabeledFieldView( locale, ( labeledFieldView, viewUid, statusUid ) => {\n *\t\t\tconst inputView = new InputTextView( labeledFieldView.locale );\n *\n *\t\t\tinputView.set( {\n *\t\t\t\tid: viewUid,\n *\t\t\t\tariaDescribedById: statusUid\n *\t\t\t} );\n *\n *\t\t\tinputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value );\n *\t\t\tinputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value );\n *\n *\t\t\treturn inputView;\n *\t\t} );\n *\n *\t\tlabeledInputView.label = 'User name';\n *\t\tlabeledInputView.infoText = 'Full name like for instance, John Doe.';\n *\t\tlabeledInputView.render();\n *\n *\t\tdocument.body.append( labeledInputView.element );\n *\n * See {@link module:ui/labeledfield/utils} to discover readytouse labeled input helpers for common\n * UI components.\n *\n * @extends module:ui/view~View\n */\nexport default class LabeledFieldView extends View {\n\t/**\n\t * Creates an instance of the labeled field view class using a provided creator function\n\t * that provides the view to be labeled.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance.\n\t * @param {Function} viewCreator A function that returns a {@link module:ui/view~View}\n\t * that will be labeled. The following arguments are passed to the creator function:\n\t *\n\t * * an instance of the `LabeledFieldView` to allow binding observable properties,\n\t * * an UID string that connects the {@link #labelView label} and the labeled field view in DOM,\n\t * * an UID string that connects the {@link #statusView status} and the labeled field view in DOM.\n\t */\n\tconstructor( locale, viewCreator ) {\n\t\tsuper( locale );\n\n\t\tconst viewUid = `ck-labeled-field-view-${ uid() }`;\n\t\tconst statusUid = `ck-labeled-field-view-status-${ uid() }`;\n\n\t\t/**\n\t\t * The field view that gets labeled.\n\t\t *\n\t\t * @member {module:ui/view~View} #fieldView\n\t\t */\n\t\tthis.fieldView = viewCreator( this, viewUid, statusUid );\n\n\t\t/**\n\t\t * The text of the label.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.set( 'label' );\n\n\t\t/**\n\t\t * Controls whether the component is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t/**\n\t\t * An observable flag set to `true` when {@link #fieldView} is empty (`false` otherwise).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isEmpty\n\t\t * @default true\n\t\t */\n\t\tthis.set( 'isEmpty', true );\n\n\t\t/**\n\t\t * An observable flag set to `true` when {@link #fieldView} is currently focused by\n\t\t * the user (`false` otherwise).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t * @default false\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * The validation error text. When set, it will be displayed\n\t\t * next to the {@link #fieldView} as a typical validation error message.\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** Setting this property to anything but `null` will automatically\n\t\t * make the `hasError` of the {@link #fieldView} `true`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #errorText\n\t\t */\n\t\tthis.set( 'errorText', null );\n\n\t\t/**\n\t\t * The additional information text displayed next to the {@link #fieldView} which can\n\t\t * be used to inform the user about its purpose, provide help or hints.\n\t\t *\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** This text will be displayed in the same place as {@link #errorText} but the\n\t\t * latter always takes precedence: if the {@link #errorText} is set, it replaces\n\t\t * {@link #infoText}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #infoText\n\t\t * @default null\n\t\t */\n\t\tthis.set( 'infoText', null );\n\n\t\t/**\n\t\t * (Optional) The additional CSS class set on the dropdown {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * The content of the `placeholder` attribute of the {@link #fieldView}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.set( 'placeholder' );\n\n\t\t/**\n\t\t * The label view instance that describes the entire view.\n\t\t *\n\t\t * @member {module:ui/label/labelview~LabelView} #labelView\n\t\t */\n\t\tthis.labelView = this._createLabelView( viewUid );\n\n\t\t/**\n\t\t * The status view for the {@link #fieldView}. It displays {@link #errorText} and\n\t\t * {@link #infoText}.\n\t\t *\n\t\t * @member {module:ui/view~View} #statusView\n\t\t */\n\t\tthis.statusView = this._createStatusView( statusUid );\n\n\t\t/**\n\t\t * The combined status text made of {@link #errorText} and {@link #infoText}.\n\t\t * Note that when present, {@link #errorText} always takes precedence in the\n\t\t * status.\n\t\t *\n\t\t * @see #errorText\n\t\t * @see #infoText\n\t\t * @see #statusView\n\t\t * @private\n\t\t * @observable\n\t\t * @member {String|null} #_statusText\n\t\t */\n\t\tthis.bind( '_statusText' ).to(\n\t\t\tthis, 'errorText',\n\t\t\tthis, 'infoText',\n\t\t\t( errorText, infoText ) => errorText || infoText\n\t\t);\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-field-view',\n\t\t\t\t\tbind.to( 'class' ),\n\t\t\t\t\tbind.if( 'isEnabled', 'ck-disabled', value => !value ),\n\t\t\t\t\tbind.if( 'isEmpty', 'ck-labeled-field-view_empty' ),\n\t\t\t\t\tbind.if( 'isFocused', 'ck-labeled-field-view_focused' ),\n\t\t\t\t\tbind.if( 'placeholder', 'ck-labeled-field-view_placeholder' ),\n\t\t\t\t\tbind.if( 'errorText', 'ck-error' )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-labeled-field-view__input-wrapper'\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tthis.fieldView,\n\t\t\t\t\t\tthis.labelView\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\tthis.statusView\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * Creates label view class instance and bind with view.\n\t *\n\t * @private\n\t * @param {String} id Unique id to set as labelView#for attribute.\n\t * @returns {module:ui/label/labelview~LabelView}\n\t */\n\t_createLabelView( id ) {\n\t\tconst labelView = new LabelView( this.locale );\n\n\t\tlabelView.for = id;\n\t\tlabelView.bind( 'text' ).to( this, 'label' );\n\n\t\treturn labelView;\n\t}\n\n\t/**\n\t * Creates the status view instance. It displays {@link #errorText} and {@link #infoText}\n\t * next to the {@link #fieldView}. See {@link #_statusText}.\n\t *\n\t * @private\n\t * @param {String} statusUid Unique id of the status, shared with the {@link #fieldView view's}\n\t * `aria-describedby` attribute.\n\t * @returns {module:ui/view~View}\n\t */\n\t_createStatusView( statusUid ) {\n\t\tconst statusView = new View( this.locale );\n\t\tconst bind = this.bindTemplate;\n\n\t\tstatusView.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-field-view__status',\n\t\t\t\t\tbind.if( 'errorText', 'ck-labeled-field-view__status_error' ),\n\t\t\t\t\tbind.if( '_statusText', 'ck-hidden', value => !value )\n\t\t\t\t],\n\t\t\t\tid: statusUid,\n\t\t\t\trole: bind.if( 'errorText', 'alert' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: bind.to( '_statusText' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn statusView;\n\t}\n\n\t/**\n\t * Focuses the {@link #fieldView}.\n\t */\n\tfocus() {\n\t\tthis.fieldView.focus();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/labeledfield/utils\n */\n\nimport InputTextView from '../inputtext/inputtextview';\nimport { createDropdown } from '../dropdown/utils';\n\n/**\n * A helper for creating labeled inputs.\n *\n * It creates an instance of a {@link module:ui/inputtext/inputtextview~InputTextView input text} that is\n * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled view} in DOM.\n *\n * The helper does the following:\n *\n * * It sets input's `id` and `ariaDescribedById` attributes.\n * * It binds input's `isReadOnly` to the labeled view.\n * * It binds input's `hasError` to the labeled view.\n * * It enables a logic that cleans up the error when user starts typing in the input..\n *\n * Usage:\n *\n *\t\tconst labeledInputView = new LabeledFieldView( locale, createLabeledDropdown );\n *\t\tconsole.log( labeledInputView.view ); // An input instance.\n *\n * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled field view.\n * @param {String} viewUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view's label} and the input.\n * @param {String} statusUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#statusView labeled view's status} and the input.\n * @returns {module:ui/inputtext/inputtextview~InputTextView} The input text view instance.\n */\nexport function createLabeledInputText( labeledFieldView, viewUid, statusUid ) {\n\tconst inputView = new InputTextView( labeledFieldView.locale );\n\n\tinputView.set( {\n\t\tid: viewUid,\n\t\tariaDescribedById: statusUid\n\t} );\n\n\tinputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value );\n\tinputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value );\n\n\tinputView.on( 'input', () => {\n\t\t// UX: Make the error text disappear and disable the error indicator as the user\n\t\t// starts fixing the errors.\n\t\tlabeledFieldView.errorText = null;\n\t} );\n\n\tlabeledFieldView.bind( 'isEmpty', 'isFocused', 'placeholder' ).to( inputView );\n\n\treturn inputView;\n}\n\n/**\n * A helper for creating labeled dropdowns.\n *\n * It creates an instance of a {@link module:ui/dropdown/dropdownview~DropdownView dropdown} that is\n * logically related to a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled field view}.\n *\n * The helper does the following:\n *\n * * It sets dropdown's `id` and `ariaDescribedById` attributes.\n * * It binds input's `isEnabled` to the labeled view.\n *\n * Usage:\n *\n *\t\tconst labeledInputView = new LabeledFieldView( locale, createLabeledDropdown );\n *\t\tconsole.log( labeledInputView.view ); // A dropdown instance.\n *\n * @param {module:ui/labeledfield/labeledfieldview~LabeledFieldView} labeledFieldView The instance of the labeled field view.\n * @param {String} viewUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#labelView labeled view label} and the dropdown.\n * @param {String} statusUid An UID string that allows DOM logical connection between the\n * {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView#statusView labeled view status} and the dropdown.\n * @returns {module:ui/dropdown/dropdownview~DropdownView} The dropdown view instance.\n */\nexport function createLabeledDropdown( labeledFieldView, viewUid, statusUid ) {\n\tconst dropdownView = createDropdown( labeledFieldView.locale );\n\n\tdropdownView.set( {\n\t\tid: viewUid,\n\t\tariaDescribedById: statusUid\n\t} );\n\n\tdropdownView.bind( 'isEnabled' ).to( labeledFieldView );\n\n\treturn dropdownView;\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 ui/notification/notification\n */\n\n/* globals window */\n\nimport { ContextPlugin } from 'ckeditor5/src/core';\n\n/**\n * The Notification plugin.\n *\n * This plugin sends a few types of notifications: `success`, `info` and `warning`. The notifications need to be\n * handled and displayed by a plugin responsible for showing the UI of the notifications. Using this plugin for dispatching\n * notifications makes it possible to switch the notifications UI.\n *\n * Note that every unhandled and not stopped `warning` notification will be displayed as a system alert.\n * See {@link module:ui/notification/notification~Notification#showWarning}.\n *\n * @extends module:core/contextplugin~ContextPlugin\n */\nexport default class Notification extends ContextPlugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Notification';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t// Each unhandled and not stopped `show:warning` event is displayed as a system alert.\n\t\tthis.on( 'show:warning', ( evt, data ) => {\n\t\t\twindow.alert( data.message ); // eslint-disable-line no-alert\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Shows a success notification.\n\t *\n\t * By default, it fires the {@link #event:show:success `show:success` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowSuccess( 'Image is uploaded.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:success:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowSuccess( 'Image is uploaded.', {\n\t *\t\t\ttitle: 'Image upload success'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowSuccess( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'success',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows an information notification.\n\t *\n\t * By default, it fires the {@link #event:show:info `show:info` event} with the given `data`. The event namespace can be extended\n\t * using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowInfo( 'Editor is offline.', {\n\t * \t\t\tnamespace: 'editor:status'\n\t * \t\t} );\n\t *\n\t * will fire the `show:info:editor:status` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowInfo( 'Editor is offline.', {\n\t *\t\t\ttitle: 'Network information'\n\t *\t\t} );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowInfo( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'info',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Shows a warning notification.\n\t *\n\t * By default, it fires the {@link #event:show:warning `show:warning` event}\n\t * with the given `data`. The event namespace can be extended using the `data.namespace` option. For example:\n\t *\n\t * \t\tshowWarning( 'Image upload error.', {\n\t * \t\t\tnamespace: 'upload:image'\n\t * \t\t} );\n\t *\n\t * will fire the `show:warning:upload:image` event.\n\t *\n\t * You can provide the title of the notification:\n\t *\n\t *\t\tshowWarning( 'Image upload error.', {\n\t *\t\t\ttitle: 'Upload failed'\n\t *\t\t} );\n\t *\n\t * Note that each unhandled and not stopped `warning` notification will be displayed as a system alert.\n\t * The plugin responsible for displaying warnings should `stop()` the event to prevent displaying it as an alert:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Do something with the data.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t} );\n\t *\n\t * You can attach many listeners to the same event and `stop()` this event in a listener with a low priority:\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Show the warning in the UI, but do not stop it.\n\t * \t\t} );\n\t *\n\t * \t\tnotifications.on( 'show:warning', ( evt, data ) => {\n\t * \t\t\t// Log the warning to some error tracker.\n\t *\n\t * \t\t\t// Stop this event to prevent displaying it as an alert.\n\t * \t\t\tevt.stop();\n\t * \t\t}, { priority: 'low' } );\n\t *\n\t * @param {String} message The content of the notification.\n\t * @param {Object} [data={}] Additional data.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title] The title of the notification.\n\t */\n\tshowWarning( message, data = {} ) {\n\t\tthis._showNotification( {\n\t\t\tmessage,\n\t\t\ttype: 'warning',\n\t\t\tnamespace: data.namespace,\n\t\t\ttitle: data.title\n\t\t} );\n\t}\n\n\t/**\n\t * Fires the `show` event with the specified type, namespace and message.\n\t *\n\t * @private\n\t * @param {Object} data The message data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the message.\n\t * @param {String} [data.namespace] Additional event namespace.\n\t * @param {String} [data.title=''] The title of the notification.\n\t */\n\t_showNotification( data ) {\n\t\tconst event = `show:${ data.type }` + ( data.namespace ? `:${ data.namespace }` : '' );\n\n\t\tthis.fire( event, {\n\t\t\tmessage: data.message,\n\t\t\ttype: data.type,\n\t\t\ttitle: data.title || ''\n\t\t} );\n\t}\n\n\t/**\n\t * Fired when one of the `showSuccess()`, `showInfo()`, `showWarning()` methods is called.\n\t *\n\t * @event show\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'|'info'|'warning'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showSuccess()` method is called.\n\t *\n\t * @event show:success\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'success'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showInfo()` method is called.\n\t *\n\t * @event show:info\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'info'} data.type The type of the notification.\n\t */\n\n\t/**\n\t * Fired when the `showWarning()` method is called.\n\t *\n\t * When this event is not handled or stopped by `event.stop()`, the `data.message` of this event will\n\t * be automatically displayed as a system alert.\n\t *\n\t * @event show:warning\n\t * @param {Object} data The notification data.\n\t * @param {String} data.message The content of the notification.\n\t * @param {String} data.title The title of the notification.\n\t * @param {'warning'} data.type The type of the notification.\n\t */\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/model\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport { extend } from 'lodash-es';\n\n/**\n * The base MVC model class.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Model {\n\t/**\n\t * Creates a new Model instance.\n\t *\n\t * @param {Object} [attributes] The model state attributes to be defined during the instance creation.\n\t * @param {Object} [properties] The (out of state) properties to be appended to the instance during creation.\n\t */\n\tconstructor( attributes, properties ) {\n\t\t// Extend this instance with the additional (out of state) properties.\n\t\tif ( properties ) {\n\t\t\textend( this, properties );\n\t\t}\n\n\t\t// Initialize the attributes.\n\t\tif ( attributes ) {\n\t\t\tthis.set( attributes );\n\t\t}\n\t}\n}\n\nmix( Model, ObservableMixin );\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module ui/panel/balloon/balloonpanelview\n */\n\nimport View from '../../view';\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\nimport isRange from '@ckeditor/ckeditor5-utils/src/dom/isrange';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { isElement } from 'lodash-es';\n\nimport '../../../theme/components/panel/balloonpanel.css';\n\nconst toPx = toUnit( 'px' );\nconst defaultLimiterElement = global.document.body;\n\n/**\n * The balloon panel view class.\n *\n * A floating container which can\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#pin pin} to any\n * {@link module:utils/dom/position~Options#target target} in the DOM and remain in that position\n * e.g. when the web page is scrolled.\n *\n * The balloon panel can be used to display contextual, non-blocking UI like forms, toolbars and\n * the like in its {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#content} view\n * collection.\n *\n * There is a number of {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}\n * that the balloon can use, automatically switching from one to another when the viewport space becomes\n * scarce to keep the balloon visible to the user as long as it is possible. The balloon will also\n * accept any custom position set provided by the user compatible with the\n * {@link module:utils/dom/position~Options options}.\n *\n *\t\tconst panel = new BalloonPanelView( locale );\n *\t\tconst childView = new ChildView();\n *\t\tconst positions = BalloonPanelView.defaultPositions;\n *\n *\t\tpanel.render();\n *\n *\t\t// Add a child view to the panel's content collection.\n *\t\tpanel.content.add( childView );\n *\n *\t\t// Start pinning the panel to an element with the \"target\" id DOM.\n *\t\t// The balloon will remain pinned until unpin() is called.\n *\t\tpanel.pin( {\n *\t\t\ttarget: document.querySelector( '#target' ),\n *\t\t\tpositions: [\n *\t\t\t\tpositions.northArrowSouth,\n *\t\t\t\tpositions.southArrowNorth\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:ui/view~View\n */\nexport default class BalloonPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The absolute top position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #top\n\t\t */\n\t\tthis.set( 'top', 0 );\n\n\t\t/**\n\t\t * The absolute left position of the balloon panel in pixels.\n\t\t *\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #left\n\t\t */\n\t\tthis.set( 'left', 0 );\n\n\t\t/**\n\t\t * The balloon panel's current position. The position name is reflected in the CSS class set\n\t\t * to the balloon, i.e. `.ck-balloon-panel_arrow_nw` for the \"arrow_nw\" position. The class\n\t\t * controls the minor aspects of the balloon's visual appearance like the placement\n\t\t * of an {@link #withArrow arrow}. To support a new position, an additional CSS must be created.\n\t\t *\n\t\t * Default position names correspond with\n\t\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t\t *\n\t\t * See the {@link #attachTo} and {@link #pin} methods to learn about custom balloon positions.\n\t\t *\n\t\t * @observable\n\t\t * @default 'arrow_nw'\n\t\t * @member {'arrow_nw'|'arrow_ne'|'arrow_sw'|'arrow_se'} #position\n\t\t */\n\t\tthis.set( 'position', 'arrow_nw' );\n\n\t\t/**\n\t\t * Controls whether the balloon panel is visible or not.\n\t\t *\n\t\t * @observable\n\t\t * @default false\n\t\t * @member {Boolean} #isVisible\n\t\t */\n\t\tthis.set( 'isVisible', false );\n\n\t\t/**\n\t\t * Controls whether the balloon panel has an arrow. The presence of the arrow\n\t\t * is reflected in the `ck-balloon-panel_with-arrow` CSS class.\n\t\t *\n\t\t * @observable\n\t\t * @default true\n\t\t * @member {Boolean} #withArrow\n\t\t */\n\t\tthis.set( 'withArrow', true );\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class' );\n\n\t\t/**\n\t\t * A callback that starts pinning the panel when {@link #isVisible} gets\n\t\t * `true`. Used by {@link #pin}.\n\t\t *\n\t\t * @private\n\t\t * @member {Function} #_pinWhenIsVisibleCallback\n\t\t */\n\n\t\t/**\n\t\t * A collection of the child views that creates the balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-balloon-panel',\n\t\t\t\t\tbind.to( 'position', value => `ck-balloon-panel_${ value }` ),\n\t\t\t\t\tbind.if( 'isVisible', 'ck-balloon-panel_visible' ),\n\t\t\t\t\tbind.if( 'withArrow', 'ck-balloon-panel_with-arrow' ),\n\t\t\t\t\tbind.to( 'class' )\n\t\t\t\t],\n\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', toPx ),\n\t\t\t\t\tleft: bind.to( 'left', toPx )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} );\n\t}\n\n\t/**\n\t * Shows the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\tshow() {\n\t\tthis.isVisible = true;\n\t}\n\n\t/**\n\t * Hides the panel.\n\t *\n\t * See {@link #isVisible}.\n\t */\n\thide() {\n\t\tthis.isVisible = false;\n\t}\n\n\t/**\n\t * Attaches the panel to a specified {@link module:utils/dom/position~Options#target} with a\n\t * smart positioning heuristics that chooses from available positions to make sure the panel\n\t * is visible to the user i.e. within the limits of the viewport.\n\t *\n\t * This method accepts configuration {@link module:utils/dom/position~Options options}\n\t * to set the `target`, optional `limiter` and `positions` the balloon should choose from.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Attach the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.attachTo( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * **Note**: Attaching the panel will also automatically {@link #show} it.\n\t *\n\t * **Note**: An attached panel will not follow its target when the window is scrolled or resized.\n\t * See the {@link #pin} method for a more permanent positioning strategy.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tattachTo( options ) {\n\t\tthis.show();\n\n\t\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\t\tconst positionOptions = Object.assign( {}, {\n\t\t\telement: this.element,\n\t\t\tpositions: [\n\t\t\t\tdefaultPositions.southArrowNorth,\n\t\t\t\tdefaultPositions.southArrowNorthMiddleWest,\n\t\t\t\tdefaultPositions.southArrowNorthMiddleEast,\n\t\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\t\tdefaultPositions.southArrowNorthEast,\n\t\t\t\tdefaultPositions.northArrowSouth,\n\t\t\t\tdefaultPositions.northArrowSouthMiddleWest,\n\t\t\t\tdefaultPositions.northArrowSouthMiddleEast,\n\t\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\t\tdefaultPositions.northArrowSouthEast\n\t\t\t],\n\t\t\tlimiter: defaultLimiterElement,\n\t\t\tfitInViewport: true\n\t\t}, options );\n\n\t\tconst optimalPosition = BalloonPanelView._getOptimalPosition( positionOptions );\n\n\t\t// Usually browsers make some problems with super accurate values like 104.345px\n\t\t// so it is better to use int values.\n\t\tconst left = parseInt( optimalPosition.left );\n\t\tconst top = parseInt( optimalPosition.top );\n\t\tconst position = optimalPosition.name;\n\n\t\tObject.assign( this, { top, left, position } );\n\t}\n\n\t/**\n\t * Works the same way as the {@link #attachTo} method except that the position of the panel is\n\t * continuously updated when:\n\t *\n\t * * any ancestor of the {@link module:utils/dom/position~Options#target}\n\t * or {@link module:utils/dom/position~Options#limiter} is scrolled,\n\t * * the browser window gets resized or scrolled.\n\t *\n\t * Thanks to that, the panel always sticks to the {@link module:utils/dom/position~Options#target}\n\t * and is immune to the changing environment.\n\t *\n\t *\t\tconst panel = new BalloonPanelView( locale );\n\t *\t\tconst positions = BalloonPanelView.defaultPositions;\n\t *\n\t *\t\tpanel.render();\n\t *\n\t *\t\t// Pin the panel to an element with the \"target\" id DOM.\n\t *\t\tpanel.pin( {\n\t *\t\t\ttarget: document.querySelector( '#target' ),\n\t *\t\t\tpositions: [\n\t *\t\t\t\tpositions.northArrowSouth,\n\t *\t\t\t\tpositions.southArrowNorth\n\t *\t\t\t]\n\t *\t\t} );\n\t *\n\t * To leave the pinned state, use the {@link #unpin} method.\n\t *\n\t * **Note**: Pinning the panel will also automatically {@link #show} it.\n\t *\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is\n\t * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.\n\t */\n\tpin( options ) {\n\t\tthis.unpin();\n\n\t\tthis._pinWhenIsVisibleCallback = () => {\n\t\t\tif ( this.isVisible ) {\n\t\t\t\tthis._startPinning( options );\n\t\t\t} else {\n\t\t\t\tthis._stopPinning();\n\t\t\t}\n\t\t};\n\n\t\tthis._startPinning( options );\n\n\t\t// Control the state of the listeners depending on whether the panel is visible\n\t\t// or not.\n\t\t// TODO: Use on() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\tthis.listenTo( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\t}\n\n\t/**\n\t * Stops pinning the panel, as set up by {@link #pin}.\n\t */\n\tunpin() {\n\t\tif ( this._pinWhenIsVisibleCallback ) {\n\t\t\t// Deactivate listeners attached by pin().\n\t\t\tthis._stopPinning();\n\n\t\t\t// Deactivate the panel pin() control logic.\n\t\t\t// TODO: Use off() (https://github.com/ckeditor/ckeditor5-utils/issues/144).\n\t\t\tthis.stopListening( this, 'change:isVisible', this._pinWhenIsVisibleCallback );\n\n\t\t\tthis._pinWhenIsVisibleCallback = null;\n\n\t\t\tthis.hide();\n\t\t}\n\t}\n\n\t/**\n\t * Starts managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t * @param {module:utils/dom/position~Options} options Positioning options compatible with\n\t * {@link module:utils/dom/position~getOptimalPosition}.\n\t */\n\t_startPinning( options ) {\n\t\tthis.attachTo( options );\n\n\t\tconst targetElement = getDomElement( options.target );\n\t\tconst limiterElement = options.limiter ? getDomElement( options.limiter ) : defaultLimiterElement;\n\n\t\t// Then we need to listen on scroll event of eny element in the document.\n\t\tthis.listenTo( global.document, 'scroll', ( evt, domEvt ) => {\n\t\t\tconst scrollTarget = domEvt.target;\n\n\t\t\t// The position needs to be updated if the positioning target is within the scrolled element.\n\t\t\tconst isWithinScrollTarget = targetElement && scrollTarget.contains( targetElement );\n\n\t\t\t// The position needs to be updated if the positioning limiter is within the scrolled element.\n\t\t\tconst isLimiterWithinScrollTarget = limiterElement && scrollTarget.contains( limiterElement );\n\n\t\t\t// The positioning target and/or limiter can be a Rect, object etc..\n\t\t\t// There's no way to optimize the listener then.\n\t\t\tif ( isWithinScrollTarget || isLimiterWithinScrollTarget || !targetElement || !limiterElement ) {\n\t\t\t\tthis.attachTo( options );\n\t\t\t}\n\t\t}, { useCapture: true } );\n\n\t\t// We need to listen on window resize event and update position.\n\t\tthis.listenTo( global.window, 'resize', () => {\n\t\t\tthis.attachTo( options );\n\t\t} );\n\t}\n\n\t/**\n\t * Stops managing the pinned state of the panel. See {@link #pin}.\n\t *\n\t * @private\n\t */\n\t_stopPinning() {\n\t\tthis.stopListening( global.document, 'scroll' );\n\t\tthis.stopListening( global.window, 'resize' );\n\t}\n}\n\n// Returns the DOM element for given object or null, if there is none,\n// e.g. when the passed object is a Rect instance or so.\n//\n// @private\n// @param {*} object\n// @returns {HTMLElement|null}\nfunction getDomElement( object ) {\n\tif ( isElement( object ) ) {\n\t\treturn object;\n\t}\n\n\tif ( isRange( object ) ) {\n\t\treturn object.commonAncestorContainer;\n\t}\n\n\tif ( typeof object == 'function' ) {\n\t\treturn getDomElement( object() );\n\t}\n\n\treturn null;\n}\n\n/**\n * A horizontal offset of the arrow tip from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-----|---------...\n *\t\t | |\n *\t\t | |\n *\t\t | |\n *\t\t | |\n *\t\t +--+ | +------...\n *\t\t \\ | /\n *\t\t \\|/\n *\t >|-----|<---------------- horizontal offset\n *\n * @default 30\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowHorizontalOffset\n */\nBalloonPanelView.arrowHorizontalOffset = 25;\n\n/**\n * A vertical offset of the arrow from the edge of the balloon. Controlled by CSS.\n *\n *\t\t +-------------...\n *\t\t |\n *\t\t |\n *\t\t | /-- vertical offset\n *\t\t | V\n *\t\t +--+ +-----... ---------\n *\t\t \\ / |\n *\t\t \\/ |\n *\t\t-------------------------------\n *\t\t ^\n *\n * @default 15\n * @member {Number} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.arrowVerticalOffset\n */\nBalloonPanelView.arrowVerticalOffset = 10;\n\n/**\n * Function used to calculate the optimal position for the balloon.\n *\n * @protected\n * @member {Function} module:ui/panel/balloon/balloonpanelview~BalloonPanelView._getOptimalPosition\n */\nBalloonPanelView._getOptimalPosition = getOptimalPosition;\n\n/**\n * A default set of positioning functions used by the balloon panel view\n * when attaching using the {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo} method.\n *\n * The available positioning functions are as follows:\n *\n *\n *\n * **North west**\n *\n * * `northWestArrowSouthWest`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouthMiddleWest`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northWestArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n *\n *\n * **North**\n *\n * * `northArrowSouthWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northArrowSouthMiddleWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * **North east**\n *\n * * `northEastArrowSouthWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n *\n * * `northEastArrowSouthMiddleWest`\n *\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northEastArrowSouth`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t[ Target ]\n *\n * * `northEastArrowSouthMiddleEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n * * `northEastArrowSouthEast`\n *\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\t\t V\n *\t\t [ Target ]\n *\n *\n *\n * **South**\n *\n *\n * * `southArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southArrowNorthMiddleWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southArrowNorth`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southArrowNorthMiddleEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n *\n *\n * **South west**\n *\n * * `southWestArrowNorthWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthMiddleWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southWestArrowNorth`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthMiddleEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southWestArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n *\n *\n * **South east**\n *\n * * `southEastArrowNorthWest`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n* * `southEastArrowNorthMiddleWest`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t +-----------------+\n *\t\t | Balloon |\n *\t\t +-----------------+\n *\n * * `southEastArrowNorth`\n *\n *\t\t[ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthMiddleEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n * * `southEastArrowNorthEast`\n *\n *\t\t [ Target ]\n *\t\t ^\n *\t\t+-----------------+\n *\t\t| Balloon |\n *\t\t+-----------------+\n *\n *\n * See {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView#attachTo}.\n *\n * Positioning functions must be compatible with {@link module:utils/dom/position~Position}.\n *\n * The name that the position function returns will be reflected in the balloon panel's class that\n * controls the placement of the \"arrow\". See {@link #position} to learn more.\n *\n * @member {Object} module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions\n */\nBalloonPanelView.defaultPositions = {\n\n\t// ------- North west\n\n\tnorthWestArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthWestArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\n\tnorthWestArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthWestArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthWestArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\t// ------- North\n\n\tnorthArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\n\tnorthArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\n\t// ------- North east\n\n\tnorthEastArrowSouthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sw'\n\t} ),\n\n\tnorthEastArrowSouthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_smw'\n\t} ),\n\tnorthEastArrowSouth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_s'\n\t} ),\n\n\tnorthEastArrowSouthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_sme'\n\t} ),\n\n\tnorthEastArrowSouthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getNorthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_se'\n\t} ),\n\t// ------- South west\n\n\tsouthWestArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\tsouthWestArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthWestArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthWestArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthWestArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\t// ------- South\n\n\tsouthArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\tsouthArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - ( balloonRect.width * 0.75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.left + targetRect.width / 2 - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} ),\n\n\t// ------- South east\n\n\tsouthEastArrowNorthWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nw'\n\t} ),\n\n\tsouthEastArrowNorthMiddleWest: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .25 ) - BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nmw'\n\t} ),\n\n\tsouthEastArrowNorth: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width / 2,\n\t\tname: 'arrow_n'\n\t} ),\n\n\tsouthEastArrowNorthMiddleEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - ( balloonRect.width * .75 ) + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_nme'\n\t} ),\n\n\tsouthEastArrowNorthEast: ( targetRect, balloonRect ) => ( {\n\t\ttop: getSouthTop( targetRect, balloonRect ),\n\t\tleft: targetRect.right - balloonRect.width + BalloonPanelView.arrowHorizontalOffset,\n\t\tname: 'arrow_ne'\n\t} )\n\n};\n\n// Returns the top coordinate for positions starting with `north*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getNorthTop( targetRect, balloonRect ) {\n\treturn targetRect.top - balloonRect.height - BalloonPanelView.arrowVerticalOffset;\n}\n\n// Returns the top coordinate for positions starting with `south*`.\n//\n// @private\n// @param {utils/dom/rect~Rect} targetRect A rect of the target.\n// @param {utils/dom/rect~Rect} elementRect A rect of the balloon.\n// @returns {Number}\nfunction getSouthTop( targetRect ) {\n\treturn targetRect.bottom + BalloonPanelView.arrowVerticalOffset;\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 ui/panel/balloon/contextualballoon\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport BalloonPanelView from './balloonpanelview';\nimport View from '../../view';\nimport ButtonView from '../../button/buttonview';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\nimport prevIcon from '../../../theme/icons/previous-arrow.svg';\nimport nextIcon from '../../../theme/icons/next-arrow.svg';\n\nimport '../../../theme/components/panel/balloonrotator.css';\nimport '../../../theme/components/panel/fakepanel.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * Provides the common contextual balloon for the editor.\n *\n * The role of this plugin is to unify the contextual balloons logic, simplify views management and help\n * avoid the unnecessary complexity of handling multiple {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n * instances in the editor.\n *\n * This plugin allows for creating single or multiple panel stacks.\n *\n * Each stack may have multiple views, with the one on the top being visible. When the visible view is removed from the stack,\n * the previous view becomes visible.\n *\n * It might be useful to implement nested navigation in a balloon. For instance, a toolbar view may contain a link button.\n * When you click it, a link view (which lets you set the URL) is created and put on top of the toolbar view, so the link panel\n * is displayed. When you finish editing the link and close (remove) the link view, the toolbar view is visible again.\n *\n * However, there are cases when there are multiple independent balloons to be displayed, for instance, if the selection\n * is inside two inline comments at the same time. For such cases, you can create two independent panel stacks.\n * The contextual balloon plugin will create a navigation bar to let the users switch between these panel stacks using the \"Next\"\n * and \"Previous\" buttons.\n *\n * If there are no views in the current stack, the balloon panel will try to switch to the next stack. If there are no\n * panels in any stack, the balloon panel will be hidden.\n *\n * **Note**: To force the balloon panel to show only one view, even if there are other stacks, use the `singleViewMode=true` option\n * when {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon#add adding} a view to a panel.\n *\n * From the implementation point of view, the contextual ballon plugin is reusing a single\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView} instance to display multiple contextual balloon\n * panels in the editor. It also creates a special {@link module:ui/panel/balloon/contextualballoon~RotatorView rotator view},\n * used to manage multiple panel stacks. Rotator view is a child of the balloon panel view and the parent of the specific\n * view you want to display. If there is more than one panel stack to be displayed, the rotator view will add a\n * navigation bar. If there is only one stack, the rotator view is transparent (it does not add any UI elements).\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ContextualBalloon extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ContextualBalloon';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The {@link module:utils/dom/position~Options#limiter position limiter}\n\t\t * for the {@link #view balloon}, used when no `limiter` has been passed into {@link #add}\n\t\t * or {@link #updatePosition}.\n\t\t *\n\t\t * By default, a function that obtains the farthest DOM\n\t\t * {@link module:engine/view/rooteditableelement~RootEditableElement}\n\t\t * of the {@link module:engine/view/document~Document#selection}.\n\t\t *\n\t\t * @member {module:utils/dom/position~Options#limiter} #positionLimiter\n\t\t */\n\t\tthis.positionLimiter = () => {\n\t\t\tconst view = this.editor.editing.view;\n\t\t\tconst viewDocument = view.document;\n\t\t\tconst editableElement = viewDocument.selection.editableElement;\n\n\t\t\tif ( editableElement ) {\n\t\t\t\treturn view.domConverter.mapViewToDom( editableElement.root );\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\n\t\t/**\n\t\t * The currently visible view or `null` when there are no views in any stack.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {module:ui/view~View|null} #visibleView\n\t\t */\n\t\tthis.set( 'visibleView', null );\n\n\t\t/**\n\t\t * The common balloon panel view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/panel/balloon/balloonpanelview~BalloonPanelView} #view\n\t\t */\n\t\tthis.view = new BalloonPanelView( editor.locale );\n\t\teditor.ui.view.body.add( this.view );\n\t\teditor.ui.focusTracker.add( this.view.element );\n\n\t\t/**\n\t\t * The map of views and their stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:ui/view~View,Set>}\n\t\t */\n\t\tthis._viewToStack = new Map();\n\n\t\t/**\n\t\t * The map of IDs and stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<String,Set>}\n\t\t */\n\t\tthis._idToStack = new Map();\n\n\t\t/**\n\t\t * A total number of all stacks in the balloon.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #_numberOfStacks\n\t\t */\n\t\tthis.set( '_numberOfStacks', 0 );\n\n\t\t/**\n\t\t * A flag that controls the single view mode.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_singleViewMode\n\t\t */\n\t\tthis.set( '_singleViewMode', false );\n\n\t\t/**\n\t\t * Rotator view embedded in the contextual balloon.\n\t\t * Displays the currently visible view in the balloon and provides navigation for switching stacks.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t\t */\n\t\tthis._rotatorView = this._createRotatorView();\n\n\t\t/**\n\t\t * Displays fake panels under the balloon panel view when multiple stacks are added to the balloon.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/view~View}\n\t\t */\n\t\tthis._fakePanelsView = this._createFakePanelsView();\n\t}\n\n\t/**\n\t * Returns `true` when the given view is in one of the stacks. Otherwise returns `false`.\n\t *\n\t * @param {module:ui/view~View} view\n\t * @returns {Boolean}\n\t */\n\thasView( view ) {\n\t\treturn Array.from( this._viewToStack.keys() ).includes( view );\n\t}\n\n\t/**\n\t * Adds a new view to the stack and makes it visible if the current stack is visible\n\t * or it is the first view in the balloon.\n\t *\n\t * @param {Object} data The configuration of the view.\n\t * @param {String} [data.stackId='main'] The ID of the stack that the view is added to.\n\t * @param {module:ui/view~View} [data.view] The content of the balloon.\n\t * @param {module:utils/dom/position~Options} [data.position] Positioning options.\n\t * @param {String} [data.balloonClassName] An additional CSS class added to the {@link #view balloon} when visible.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t * @param {Boolean} [data.singleViewMode=false] Whether the view should be the only visible view even if other stacks were added.\n\t */\n\tadd( data ) {\n\t\tif ( this.hasView( data.view ) ) {\n\t\t\t/**\n\t\t\t * Trying to add configuration of the same view more than once.\n\t\t\t *\n\t\t\t * @error contextualballoon-add-view-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-add-view-exist',\n\t\t\t\t[ this, data ]\n\t\t\t);\n\t\t}\n\n\t\tconst stackId = data.stackId || 'main';\n\n\t\t// If new stack is added, creates it and show view from this stack.\n\t\tif ( !this._idToStack.has( stackId ) ) {\n\t\t\tthis._idToStack.set( stackId, new Map( [ [ data.view, data ] ] ) );\n\t\t\tthis._viewToStack.set( data.view, this._idToStack.get( stackId ) );\n\t\t\tthis._numberOfStacks = this._idToStack.size;\n\n\t\t\tif ( !this._visibleStack || data.singleViewMode ) {\n\t\t\t\tthis.showStack( stackId );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst stack = this._idToStack.get( stackId );\n\n\t\tif ( data.singleViewMode ) {\n\t\t\tthis.showStack( stackId );\n\t\t}\n\n\t\t// Add new view to the stack.\n\t\tstack.set( data.view, data );\n\t\tthis._viewToStack.set( data.view, stack );\n\n\t\t// And display it if is added to the currently visible stack.\n\t\tif ( stack === this._visibleStack ) {\n\t\t\tthis._showView( data );\n\t\t}\n\t}\n\n\t/**\n\t * Removes the given view from the stack. If the removed view was visible,\n\t * the view preceding it in the stack will become visible instead.\n\t * When there is no view in the stack, the next stack will be displayed.\n\t * When there are no more stacks, the balloon will hide.\n\t *\n\t * @param {module:ui/view~View} view A view to be removed from the balloon.\n\t */\n\tremove( view ) {\n\t\tif ( !this.hasView( view ) ) {\n\t\t\t/**\n\t\t\t * Trying to remove the configuration of the view not defined in the stack.\n\t\t\t *\n\t\t\t * @error contextualballoon-remove-view-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-remove-view-not-exist',\n\t\t\t\t[ this, view ]\n\t\t\t);\n\t\t}\n\n\t\tconst stack = this._viewToStack.get( view );\n\n\t\tif ( this._singleViewMode && this.visibleView === view ) {\n\t\t\tthis._singleViewMode = false;\n\t\t}\n\n\t\t// When visible view will be removed we need to show a preceding view or next stack\n\t\t// if a view is the only view in the stack.\n\t\tif ( this.visibleView === view ) {\n\t\t\tif ( stack.size === 1 ) {\n\t\t\t\tif ( this._idToStack.size > 1 ) {\n\t\t\t\t\tthis._showNextStack();\n\t\t\t\t} else {\n\t\t\t\t\tthis.view.hide();\n\t\t\t\t\tthis.visibleView = null;\n\t\t\t\t\tthis._rotatorView.hideView();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._showView( Array.from( stack.values() )[ stack.size - 2 ] );\n\t\t\t}\n\t\t}\n\n\t\tif ( stack.size === 1 ) {\n\t\t\tthis._idToStack.delete( this._getStackId( stack ) );\n\t\t\tthis._numberOfStacks = this._idToStack.size;\n\t\t} else {\n\t\t\tstack.delete( view );\n\t\t}\n\n\t\tthis._viewToStack.delete( view );\n\t}\n\n\t/**\n\t * Updates the position of the balloon using the position data of the first visible view in the stack.\n\t * When new position data is given, the position data of the currently visible view will be updated.\n\t *\n\t * @param {module:utils/dom/position~Options} [position] position options.\n\t */\n\tupdatePosition( position ) {\n\t\tif ( position ) {\n\t\t\tthis._visibleStack.get( this.visibleView ).position = position;\n\t\t}\n\n\t\tthis.view.pin( this._getBalloonPosition() );\n\t\tthis._fakePanelsView.updatePosition();\n\t}\n\n\t/**\n\t * Shows the last view from the stack of a given ID.\n\t *\n\t * @param {String} id\n\t */\n\tshowStack( id ) {\n\t\tthis.visibleStack = id;\n\t\tconst stack = this._idToStack.get( id );\n\n\t\tif ( !stack ) {\n\t\t\t/**\n\t\t\t * Trying to show a stack that does not exist.\n\t\t\t *\n\t\t\t * @error contextualballoon-showstack-stack-not-exist\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'contextualballoon-showstack-stack-not-exist',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( this._visibleStack === stack ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._showView( Array.from( stack.values() ).pop() );\n\t}\n\n\t/**\n\t * Returns the stack of the currently visible view.\n\t *\n\t * @private\n\t * @type {Set}\n\t */\n\tget _visibleStack() {\n\t\treturn this._viewToStack.get( this.visibleView );\n\t}\n\n\t/**\n\t * Returns the ID of the given stack.\n\t *\n\t * @private\n\t * @param {Set} stack\n\t * @returns {String}\n\t */\n\t_getStackId( stack ) {\n\t\tconst entry = Array.from( this._idToStack.entries() ).find( entry => entry[ 1 ] === stack );\n\n\t\treturn entry[ 0 ];\n\t}\n\n\t/**\n\t * Shows the last view from the next stack.\n\t *\n\t * @private\n\t */\n\t_showNextStack() {\n\t\tconst stacks = Array.from( this._idToStack.values() );\n\n\t\tlet nextIndex = stacks.indexOf( this._visibleStack ) + 1;\n\n\t\tif ( !stacks[ nextIndex ] ) {\n\t\t\tnextIndex = 0;\n\t\t}\n\n\t\tthis.showStack( this._getStackId( stacks[ nextIndex ] ) );\n\t}\n\n\t/**\n\t * Shows the last view from the previous stack.\n\t *\n\t * @private\n\t */\n\t_showPrevStack() {\n\t\tconst stacks = Array.from( this._idToStack.values() );\n\n\t\tlet nextIndex = stacks.indexOf( this._visibleStack ) - 1;\n\n\t\tif ( !stacks[ nextIndex ] ) {\n\t\t\tnextIndex = stacks.length - 1;\n\t\t}\n\n\t\tthis.showStack( this._getStackId( stacks[ nextIndex ] ) );\n\t}\n\n\t/**\n\t * Creates a rotator view.\n\t *\n\t * @private\n\t * @returns {module:ui/panel/balloon/contextualballoon~RotatorView}\n\t */\n\t_createRotatorView() {\n\t\tconst view = new RotatorView( this.editor.locale );\n\t\tconst t = this.editor.locale.t;\n\n\t\tthis.view.content.add( view );\n\n\t\t// Hide navigation when there is only a one stack & not in single view mode.\n\t\tview.bind( 'isNavigationVisible' ).to( this, '_numberOfStacks', this, '_singleViewMode', ( value, isSingleViewMode ) => {\n\t\t\treturn !isSingleViewMode && value > 1;\n\t\t} );\n\n\t\t// Update balloon position after toggling navigation.\n\t\tview.on( 'change:isNavigationVisible', () => ( this.updatePosition() ), { priority: 'low' } );\n\n\t\t// Update stacks counter value.\n\t\tview.bind( 'counter' ).to( this, 'visibleView', this, '_numberOfStacks', ( visibleView, numberOfStacks ) => {\n\t\t\tif ( numberOfStacks < 2 ) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\tconst current = Array.from( this._idToStack.values() ).indexOf( this._visibleStack ) + 1;\n\n\t\t\treturn t( '%0 of %1', [ current, numberOfStacks ] );\n\t\t} );\n\n\t\tview.buttonNextView.on( 'execute', () => {\n\t\t\t// When current view has a focus then move focus to the editable before removing it,\n\t\t\t// otherwise editor will lost focus.\n\t\t\tif ( view.focusTracker.isFocused ) {\n\t\t\t\tthis.editor.editing.view.focus();\n\t\t\t}\n\n\t\t\tthis._showNextStack();\n\t\t} );\n\n\t\tview.buttonPrevView.on( 'execute', () => {\n\t\t\t// When current view has a focus then move focus to the editable before removing it,\n\t\t\t// otherwise editor will lost focus.\n\t\t\tif ( view.focusTracker.isFocused ) {\n\t\t\t\tthis.editor.editing.view.focus();\n\t\t\t}\n\n\t\t\tthis._showPrevStack();\n\t\t} );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * @private\n\t * @returns {module:ui/view~View}\n\t */\n\t_createFakePanelsView() {\n\t\tconst view = new FakePanelsView( this.editor.locale, this.view );\n\n\t\tview.bind( 'numberOfPanels' ).to( this, '_numberOfStacks', this, '_singleViewMode', ( number, isSingleViewMode ) => {\n\t\t\tconst showPanels = !isSingleViewMode && number >= 2;\n\n\t\t\treturn showPanels ? Math.min( number - 1, 2 ) : 0;\n\t\t} );\n\n\t\tview.listenTo( this.view, 'change:top', () => view.updatePosition() );\n\t\tview.listenTo( this.view, 'change:left', () => view.updatePosition() );\n\n\t\tthis.editor.ui.view.body.add( view );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * Sets the view as the content of the balloon and attaches the balloon using position\n\t * options of the first view.\n\t *\n\t * @private\n\t * @param {Object} data Configuration.\n\t * @param {module:ui/view~View} [data.view] The view to show in the balloon.\n\t * @param {String} [data.balloonClassName=''] Additional class name which will be added to the {@link #view balloon}.\n\t * @param {Boolean} [data.withArrow=true] Whether the {@link #view balloon} should be rendered with an arrow.\n\t */\n\t_showView( { view, balloonClassName = '', withArrow = true, singleViewMode = false } ) {\n\t\tthis.view.class = balloonClassName;\n\t\tthis.view.withArrow = withArrow;\n\n\t\tthis._rotatorView.showView( view );\n\t\tthis.visibleView = view;\n\t\tthis.view.pin( this._getBalloonPosition() );\n\t\tthis._fakePanelsView.updatePosition();\n\n\t\tif ( singleViewMode ) {\n\t\t\tthis._singleViewMode = true;\n\t\t}\n\t}\n\n\t/**\n\t * Returns position options of the last view in the stack.\n\t * This keeps the balloon in the same position when the view is changed.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n\t_getBalloonPosition() {\n\t\tlet position = Array.from( this._visibleStack.values() ).pop().position;\n\n\t\t// Use the default limiter if none has been specified.\n\t\tif ( position && !position.limiter ) {\n\t\t\t// Don't modify the original options object.\n\t\t\tposition = Object.assign( {}, position, {\n\t\t\t\tlimiter: this.positionLimiter\n\t\t\t} );\n\t\t}\n\n\t\treturn position;\n\t}\n}\n\n/**\n * Rotator view is a helper class for the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon}.\n * It is used for displaying the last view from the current stack and providing navigation buttons for switching stacks.\n * See the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon ContextualBalloon} documentation to learn more.\n *\n * @extends module:ui/view~View\n */\nclass RotatorView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Defines whether navigation is visible or not.\n\t\t *\n\t\t * @member {Boolean} #isNavigationVisible\n\t\t */\n\t\tthis.set( 'isNavigationVisible', true );\n\n\t\t/**\n\t\t * Used for checking if a view is focused or not.\n\t\t *\n\t\t * @type {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * Navigation button for switching the stack to the previous one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonPrevView = this._createButtonView( t( 'Previous' ), prevIcon );\n\n\t\t/**\n\t\t * Navigation button for switching the stack to the next one.\n\t\t *\n\t\t * @type {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonNextView = this._createButtonView( t( 'Next' ), nextIcon );\n\n\t\t/**\n\t\t * A collection of the child views that creates the rotator content.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-balloon-rotator'\n\t\t\t\t],\n\t\t\t\t'z-index': '-1'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck-balloon-rotator__navigation',\n\t\t\t\t\t\t\tbind.to( 'isNavigationVisible', value => value ? '' : 'ck-hidden' )\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tthis.buttonPrevView,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttag: 'span',\n\n\t\t\t\t\t\t\tattributes: {\n\t\t\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t\t\t'ck-balloon-rotator__counter'\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttext: bind.to( 'counter' )\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\tthis.buttonNextView\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: 'ck-balloon-rotator__content'\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.content\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.focusTracker.add( this.element );\n\t}\n\n\t/**\n\t * Shows a given view.\n\t *\n\t * @param {module:ui/view~View} view The view to show.\n\t */\n\tshowView( view ) {\n\t\tthis.hideView();\n\t\tthis.content.add( view );\n\t}\n\n\t/**\n\t * Hides the currently displayed view.\n\t */\n\thideView() {\n\t\tthis.content.clear();\n\t}\n\n\t/**\n\t * Creates a navigation button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_createButtonView( label, icon ) {\n\t\tconst view = new ButtonView( this.locale );\n\n\t\tview.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\treturn view;\n\t}\n}\n\n// Displays additional layers under the balloon when multiple stacks are added to the balloon.\n//\n// @private\n// @extends module:ui/view~View\nclass FakePanelsView extends View {\n\t// @inheritDoc\n\tconstructor( locale, balloonPanelView ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t// Fake panels top offset.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #top\n\t\tthis.set( 'top', 0 );\n\n\t\t// Fake panels left offset.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #left\n\t\tthis.set( 'left', 0 );\n\n\t\t// Fake panels height.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #height\n\t\tthis.set( 'height', 0 );\n\n\t\t// Fake panels width.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #width\n\t\tthis.set( 'width', 0 );\n\n\t\t// Number of rendered fake panels.\n\t\t//\n\t\t// @observable\n\t\t// @member {Number} #numberOfPanels\n\t\tthis.set( 'numberOfPanels', 0 );\n\n\t\t// Collection of the child views which creates fake panel content.\n\t\t//\n\t\t// @readonly\n\t\t// @type {module:ui/viewcollection~ViewCollection}\n\t\tthis.content = this.createCollection();\n\n\t\t// Context.\n\t\t//\n\t\t// @private\n\t\t// @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n\t\tthis._balloonPanelView = balloonPanelView;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-fake-panel',\n\t\t\t\t\tbind.to( 'numberOfPanels', number => number ? '' : 'ck-hidden' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', toPx ),\n\t\t\t\t\tleft: bind.to( 'left', toPx ),\n\t\t\t\t\twidth: bind.to( 'width', toPx ),\n\t\t\t\t\theight: bind.to( 'height', toPx )\n\t\t\t\t}\n\t\t\t},\n\t\t\tchildren: this.content\n\t\t} );\n\n\t\tthis.on( 'change:numberOfPanels', ( evt, name, next, prev ) => {\n\t\t\tif ( next > prev ) {\n\t\t\t\tthis._addPanels( next - prev );\n\t\t\t} else {\n\t\t\t\tthis._removePanels( prev - next );\n\t\t\t}\n\n\t\t\tthis.updatePosition();\n\t\t} );\n\t}\n\n\t// @private\n\t// @param {Number} number\n\t_addPanels( number ) {\n\t\twhile ( number-- ) {\n\t\t\tconst view = new View();\n\n\t\t\tview.setTemplate( { tag: 'div' } );\n\n\t\t\tthis.content.add( view );\n\t\t\tthis.registerChild( view );\n\t\t}\n\t}\n\n\t// @private\n\t// @param {Number} number\n\t_removePanels( number ) {\n\t\twhile ( number-- ) {\n\t\t\tconst view = this.content.last;\n\n\t\t\tthis.content.remove( view );\n\t\t\tthis.deregisterChild( view );\n\t\t\tview.destroy();\n\t\t}\n\t}\n\n\t// Updates coordinates of fake panels.\n\tupdatePosition() {\n\t\tif ( this.numberOfPanels ) {\n\t\t\tconst { top, left } = this._balloonPanelView;\n\t\t\tconst { width, height } = new Rect( this._balloonPanelView.element );\n\n\t\t\tObject.assign( this, { top, left, width, height } );\n\t\t}\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.463 5.187a.888.888 0 1 1 1.254 1.255L9.16 10l3.557 3.557a.888.888 0 1 1-1.254 1.255L7.26 10.61a.888.888 0 0 1 .16-1.382l4.043-4.042z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M8.537 14.813a.888.888 0 1 1-1.254-1.255L10.84 10 7.283 6.442a.888.888 0 1 1 1.254-1.255L12.74 9.39a.888.888 0 0 1-.16 1.382l-4.043 4.042z\\\"/></svg>\";","/**\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 ui/panel/sticky/stickypanelview\n */\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport View from '../../view';\nimport Template from '../../template';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nimport '../../../theme/components/panel/stickypanel.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The sticky panel view class.\n */\nexport default class StickyPanelView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the sticky panel should be active.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isActive\n\t\t */\n\t\tthis.set( 'isActive', false );\n\n\t\t/**\n\t\t * Controls whether the sticky panel is in the \"sticky\" state.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isSticky\n\t\t */\n\t\tthis.set( 'isSticky', false );\n\n\t\t/**\n\t\t * The limiter element for the sticky panel instance. Its bounding rect limits\n\t\t * the \"stickyness\" of the panel, i.e. when the panel reaches the bottom\n\t\t * edge of the limiter, it becomes sticky to that edge and does not float\n\t\t * off the limiter. It is mandatory for the panel to work properly and once\n\t\t * set, it cannot be changed.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {HTMLElement} #limiterElement\n\t\t */\n\t\tthis.set( 'limiterElement', null );\n\n\t\t/**\n\t\t * The offset from the bottom edge of {@link #limiterElement}\n\t\t * which stops the panel from stickying any further to prevent limiter's content\n\t\t * from being completely covered.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 50\n\t\t * @member {Number} #limiterBottomOffset\n\t\t */\n\t\tthis.set( 'limiterBottomOffset', 50 );\n\n\t\t/**\n\t\t * The offset from the top edge of the web browser's viewport which makes the\n\t\t * panel become sticky. The default value is `0`, which means the panel becomes\n\t\t * sticky when it's upper edge touches the top of the page viewport.\n\t\t *\n\t\t * This attribute is useful when the web page has UI elements positioned to the top\n\t\t * either using `position: fixed` or `position: sticky`, which would cover the\n\t\t * sticky panel or viceversa (depending on the `z-index` hierarchy).\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @default 0\n\t\t * @member {Number} #viewportTopOffset\n\t\t */\n\t\tthis.set( 'viewportTopOffset', 0 );\n\n\t\t/**\n\t\t * Controls the `margin-left` CSS style of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String} #_marginLeft\n\t\t */\n\t\tthis.set( '_marginLeft', null );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel reached the bottom edge of the\n\t\t * {@link #limiterElement}.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_isStickyToTheLimiter\n\t\t */\n\t\tthis.set( '_isStickyToTheLimiter', false );\n\n\t\t/**\n\t\t * Set `true` if the sticky panel uses the {@link #viewportTopOffset},\n\t\t * i.e. not {@link #_isStickyToTheLimiter} and the {@link #viewportTopOffset}\n\t\t * is not `0`.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #_hasViewportTopOffset\n\t\t */\n\t\tthis.set( '_hasViewportTopOffset', false );\n\n\t\t/**\n\t\t * Collection of the child views which creates balloon panel contents.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.content = this.createCollection();\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link module:ui/view~View#element} of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_panelRect\n\t\t */\n\n\t\t/**\n\t\t * The DOM bounding client rect of the {@link #limiterElement}\n\t\t * of the panel.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object} #_limiterRect\n\t\t */\n\n\t\t/**\n\t\t * A dummy element which visually fills the space as long as the\n\t\t * actual panel is sticky. It prevents flickering of the UI.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanelPlaceholder = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel__placeholder'\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\tdisplay: bind.to( 'isSticky', isSticky => isSticky ? 'block' : 'none' ),\n\t\t\t\t\theight: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._panelRect.height ) : null;\n\t\t\t\t\t} )\n\t\t\t\t}\n\t\t\t}\n\t\t} ).render();\n\n\t\t/**\n\t\t * The panel which accepts children into {@link #content} collection.\n\t\t * Also an element which is positioned when {@link #isSticky}.\n\t\t *\n\t\t * @protected\n\t\t * @property {HTMLElement}\n\t\t */\n\t\tthis._contentPanel = new Template( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel__content',\n\t\t\t\t\t// Toggle class of the panel when \"sticky\" state changes in the view.\n\t\t\t\t\tbind.if( 'isSticky', 'ck-sticky-panel__content_sticky' ),\n\t\t\t\t\tbind.if( '_isStickyToTheLimiter', 'ck-sticky-panel__content_sticky_bottom-limit' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\twidth: bind.to( 'isSticky', isSticky => {\n\t\t\t\t\t\treturn isSticky ? toPx( this._contentPanelPlaceholder.getBoundingClientRect().width ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\ttop: bind.to( '_hasViewportTopOffset', _hasViewportTopOffset => {\n\t\t\t\t\t\treturn _hasViewportTopOffset ? toPx( this.viewportTopOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tbottom: bind.to( '_isStickyToTheLimiter', _isStickyToTheLimiter => {\n\t\t\t\t\t\treturn _isStickyToTheLimiter ? toPx( this.limiterBottomOffset ) : null;\n\t\t\t\t\t} ),\n\n\t\t\t\t\tmarginLeft: bind.to( '_marginLeft' )\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tchildren: this.content\n\t\t} ).render();\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-sticky-panel'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis._contentPanelPlaceholder,\n\t\t\t\tthis._contentPanel\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Check if the panel should go into the sticky state immediately.\n\t\tthis._checkIfShouldBeSticky();\n\n\t\t// Update sticky state of the panel as the window is being scrolled.\n\t\tthis.listenTo( global.window, 'scroll', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\n\t\t// Synchronize with `model.isActive` because sticking an inactive panel is pointless.\n\t\tthis.listenTo( this, 'change:isActive', () => {\n\t\t\tthis._checkIfShouldBeSticky();\n\t\t} );\n\t}\n\n\t/**\n\t * Analyzes the environment to decide whether the panel should\n\t * be sticky or not.\n\t *\n\t * @protected\n\t */\n\t_checkIfShouldBeSticky() {\n\t\tconst panelRect = this._panelRect = this._contentPanel.getBoundingClientRect();\n\t\tlet limiterRect;\n\n\t\tif ( !this.limiterElement ) {\n\t\t\tthis.isSticky = false;\n\t\t} else {\n\t\t\tlimiterRect = this._limiterRect = this.limiterElement.getBoundingClientRect();\n\n\t\t\t// The panel must be active to become sticky.\n\t\t\tthis.isSticky = this.isActive &&\n\t\t\t\t// The limiter's top edge must be beyond the upper edge of the visible viewport (+the viewportTopOffset).\n\t\t\t\tlimiterRect.top < this.viewportTopOffset &&\n\t\t\t\t// The model#limiterElement's height mustn't be smaller than the panel's height and model#limiterBottomOffset.\n\t\t\t\t// There's no point in entering the sticky mode if the model#limiterElement is very, very small, because\n\t\t\t\t// it would immediately set model#_isStickyToTheLimiter true and, given model#limiterBottomOffset, the panel\n\t\t\t\t// would be positioned before the model#limiterElement.\n\t\t\t\tthis._panelRect.height + this.limiterBottomOffset < limiterRect.height;\n\t\t}\n\n\t\t// Stick the panel to the top edge of the viewport simulating CSS position:sticky.\n\t\t// TODO: Possibly replaced by CSS in the future http://caniuse.com/#feat=css-sticky\n\t\tif ( this.isSticky ) {\n\t\t\tthis._isStickyToTheLimiter =\n\t\t\t\tlimiterRect.bottom < panelRect.height + this.limiterBottomOffset + this.viewportTopOffset;\n\t\t\tthis._hasViewportTopOffset = !this._isStickyToTheLimiter && !!this.viewportTopOffset;\n\t\t\tthis._marginLeft = this._isStickyToTheLimiter ? null : toPx( -global.window.scrollX );\n\t\t}\n\t\t// Detach the panel from the top edge of the viewport.\n\t\telse {\n\t\t\tthis._isStickyToTheLimiter = false;\n\t\t\tthis._hasViewportTopOffset = false;\n\t\t\tthis._marginLeft = null;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/balloon/balloontoolbar\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ContextualBalloon from '../../panel/balloon/contextualballoon';\nimport ToolbarView from '../toolbarview';\nimport BalloonPanelView from '../../panel/balloon/balloonpanelview.js';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport normalizeToolbarConfig from '../normalizetoolbarconfig';\nimport { debounce } from 'lodash-es';\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The contextual toolbar.\n *\n * It uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BalloonToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BalloonToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A cached and normalized `config.balloonToolbar` object.\n\t\t *\n\t\t * @type {module:core/editor/editorconfig~EditorConfig#balloonToolbar}\n\t\t * @private\n\t\t */\n\t\tthis._balloonConfig = normalizeToolbarConfig( editor.config.get( 'balloonToolbar' ) );\n\n\t\t/**\n\t\t * The toolbar view displayed in the balloon.\n\t\t *\n\t\t * @type {module:ui/toolbar/toolbarview~ToolbarView}\n\t\t */\n\t\tthis.toolbarView = this._createToolbarView();\n\n\t\t/**\n\t\t * Tracks the focus of the {@link module:core/editor/editorui~EditorUI#getEditableElement editable element}\n\t\t * and the {@link #toolbarView}. When both are blurred then the toolbar should hide.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils:focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t// Wait for the EditorUI#init. EditableElement is not available before.\n\t\teditor.ui.once( 'ready', () => {\n\t\t\tthis.focusTracker.add( editor.ui.getEditableElement() );\n\t\t\tthis.focusTracker.add( this.toolbarView.element );\n\t\t} );\n\n\t\t/**\n\t\t * An instance of the resize observer that allows to respond to changes in editable's geometry\n\t\t * so the toolbar can stay within its boundaries (and group toolbar items that do not fit).\n\t\t *\n\t\t * **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the\n\t\t * {@link module:core/editor/editorconfig~EditorConfig#balloonToolbar configuration}.\n\t\t *\n\t\t * **Note:** Created in {@link #init}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n\t\tthis._resizeObserver = null;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @type {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t/**\n\t\t * Fires {@link #event:_selectionChangeDebounced} event using `lodash#debounce`.\n\t\t *\n\t\t * This function is stored as a plugin property to make possible to cancel\n\t\t * trailing debounced invocation on destroy.\n\t\t *\n\t\t * @private\n\t\t * @type {Function}\n\t\t */\n\t\tthis._fireSelectionChangeDebounced = debounce( () => this.fire( '_selectionChangeDebounced' ), 200 );\n\n\t\t// The appearance of the BalloonToolbar method is eventdriven.\n\t\t// It is possible to stop the #show event and this prevent the toolbar from showing up.\n\t\tthis.decorate( 'show' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\n\t\t// Show/hide the toolbar on editable focus/blur.\n\t\tthis.listenTo( this.focusTracker, 'change:isFocused', ( evt, name, isFocused ) => {\n\t\t\tconst isToolbarVisible = this._balloon.visibleView === this.toolbarView;\n\n\t\t\tif ( !isFocused && isToolbarVisible ) {\n\t\t\t\tthis.hide();\n\t\t\t} else if ( isFocused ) {\n\t\t\t\tthis.show();\n\t\t\t}\n\t\t} );\n\n\t\t// Hide the toolbar when the selection is changed by a direct change or has changed to collapsed.\n\t\tthis.listenTo( selection, 'change:range', ( evt, data ) => {\n\t\t\tif ( data.directChange || selection.isCollapsed ) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\n\t\t\t// Fire internal `_selectionChangeDebounced` event to use it for showing\n\t\t\t// the toolbar after the selection stops changing.\n\t\t\tthis._fireSelectionChangeDebounced();\n\t\t} );\n\n\t\t// Show the toolbar when the selection stops changing.\n\t\tthis.listenTo( this, '_selectionChangeDebounced', () => {\n\t\t\tif ( this.editor.editing.view.document.isFocused ) {\n\t\t\t\tthis.show();\n\t\t\t}\n\t\t} );\n\n\t\tif ( !this._balloonConfig.shouldNotGroupWhenFull ) {\n\t\t\tthis.listenTo( editor, 'ready', () => {\n\t\t\t\tconst editableElement = editor.ui.view.editable.element;\n\n\t\t\t\t// Set #toolbarView's max-width on the initialization and update it on the editable resize.\n\t\t\t\tthis._resizeObserver = new ResizeObserver( editableElement, () => {\n\t\t\t\t\t// The max-width equals 90% of the editable's width for the best user experience.\n\t\t\t\t\t// The value keeps the balloon very close to the boundaries of the editable and limits the cases\n\t\t\t\t\t// when the balloon juts out from the editable element it belongs to.\n\t\t\t\t\tthis.toolbarView.maxWidth = toPx( new Rect( editableElement ).width * .9 );\n\t\t\t\t} );\n\t\t\t} );\n\t\t}\n\n\t\t// Listen to the toolbar view and whenever it changes its geometry due to some items being\n\t\t// grouped or ungrouped, update the position of the balloon because a shorter/longer toolbar\n\t\t// means the balloon could be pointing at the wrong place. Once updated, the balloon will point\n\t\t// at the right selection in the content again.\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6444\n\t\tthis.listenTo( this.toolbarView, 'groupedItemsUpdate', () => {\n\t\t\tthis._updatePosition();\n\t\t} );\n\t}\n\n\t/**\n\t * Creates toolbar components based on given configuration.\n\t * This needs to be done when all plugins are ready.\n\t *\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst factory = this.editor.ui.componentFactory;\n\n\t\tthis.toolbarView.fillFromConfig( this._balloonConfig, factory );\n\t}\n\n\t/**\n\t * Creates the toolbar view instance.\n\t *\n\t * @private\n\t * @returns {module:ui/toolbar/toolbarview~ToolbarView}\n\t */\n\t_createToolbarView() {\n\t\tconst shouldGroupWhenFull = !this._balloonConfig.shouldNotGroupWhenFull;\n\t\tconst toolbarView = new ToolbarView( this.editor.locale, {\n\t\t\tshouldGroupWhenFull,\n\t\t\tisFloating: true\n\t\t} );\n\n\t\ttoolbarView.render();\n\n\t\treturn toolbarView;\n\t}\n\n\t/**\n\t * Shows the toolbar and attaches it to the selection.\n\t *\n\t * Fires {@link #event:show} event which can be stopped to prevent the toolbar from showing up.\n\t */\n\tshow() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst schema = editor.model.schema;\n\n\t\t// Do not add the toolbar to the balloon stack twice.\n\t\tif ( this._balloon.hasView( this.toolbarView ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not show the toolbar when the selection is collapsed.\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not show the toolbar when there is more than one range in the selection and they fully contain selectable elements.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/6443.\n\t\tif ( selectionContainsOnlyMultipleSelectables( selection, schema ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Don not show the toolbar when all components inside are disabled\n\t\t// see https://github.com/ckeditor/ckeditor5-ui/issues/269.\n\t\tif ( Array.from( this.toolbarView.items ).every( item => item.isEnabled !== undefined && !item.isEnabled ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update the toolbar position when the editor ui should be refreshed.\n\t\tthis.listenTo( this.editor.ui, 'update', () => {\n\t\t\tthis._updatePosition();\n\t\t} );\n\n\t\t// Add the toolbar to the common editor contextual balloon.\n\t\tthis._balloon.add( {\n\t\t\tview: this.toolbarView,\n\t\t\tposition: this._getBalloonPositionData(),\n\t\t\tballoonClassName: 'ck-toolbar-container'\n\t\t} );\n\t}\n\n\t/**\n\t * Hides the toolbar.\n\t */\n\thide() {\n\t\tif ( this._balloon.hasView( this.toolbarView ) ) {\n\t\t\tthis.stopListening( this.editor.ui, 'update' );\n\t\t\tthis._balloon.remove( this.toolbarView );\n\t\t}\n\t}\n\n\t/**\n\t * Returns positioning options for the {@link #_balloon}. They control the way balloon is attached\n\t * to the selection.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n\t_getBalloonPositionData() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\t\tconst viewSelection = viewDocument.selection;\n\n\t\t// Get direction of the selection.\n\t\tconst isBackward = viewDocument.selection.isBackward;\n\n\t\treturn {\n\t\t\t// Because the target for BalloonPanelView is a Rect (not DOMRange), it's geometry will stay fixed\n\t\t\t// as the window scrolls. To let the BalloonPanelView follow such Rect, is must be continuously\n\t\t\t// computed and hence, the target is defined as a function instead of a static value.\n\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/195\n\t\t\ttarget: () => {\n\t\t\t\tconst range = isBackward ? viewSelection.getFirstRange() : viewSelection.getLastRange();\n\t\t\t\tconst rangeRects = Rect.getDomRangeRects( view.domConverter.viewRangeToDom( range ) );\n\n\t\t\t\t// Select the proper range rect depending on the direction of the selection.\n\t\t\t\tif ( isBackward ) {\n\t\t\t\t\treturn rangeRects[ 0 ];\n\t\t\t\t} else {\n\t\t\t\t\t// Ditch the zero-width \"orphan\" rect in the next line for the forward selection if there's\n\t\t\t\t\t// another one preceding it. It is not rendered as a selection by the web browser anyway.\n\t\t\t\t\t// https://github.com/ckeditor/ckeditor5-ui/issues/308\n\t\t\t\t\tif ( rangeRects.length > 1 && rangeRects[ rangeRects.length - 1 ].width === 0 ) {\n\t\t\t\t\t\trangeRects.pop();\n\t\t\t\t\t}\n\n\t\t\t\t\treturn rangeRects[ rangeRects.length - 1 ];\n\t\t\t\t}\n\t\t\t},\n\t\t\tpositions: getBalloonPositions( isBackward )\n\t\t};\n\t}\n\n\t/**\n\t * Updates the position of the {@link #_balloon} to make up for changes:\n\t *\n\t * * in the geometry of the selection it is attached to (e.g. the selection moved in the viewport or expanded or shrunk),\n\t * * or the geometry of the balloon toolbar itself (e.g. the toolbar has grouped or ungrouped some items and it is shorter or longer).\n\t *\n\t * @private\n\t */\n\t_updatePosition() {\n\t\tthis._balloon.updatePosition( this._getBalloonPositionData() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis.stopListening();\n\t\tthis._fireSelectionChangeDebounced.cancel();\n\t\tthis.toolbarView.destroy();\n\t\tthis.focusTracker.destroy();\n\n\t\tif ( this._resizeObserver ) {\n\t\t\tthis._resizeObserver.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * This event is fired just before the toolbar shows up. Stopping this event will prevent this.\n\t *\n\t * @event show\n\t */\n\n\t/**\n\t * This is internal plugin event which is fired 200 ms after model selection last change.\n\t * This is to makes easy test debounced action without need to use `setTimeout`.\n\t *\n\t * @protected\n\t * @event _selectionChangeDebounced\n\t */\n}\n\n// Returns toolbar positions for the given direction of the selection.\n//\n// @private\n// @param {Boolean} isBackward\n// @returns {Array.<module:utils/dom/position~Position>}\nfunction getBalloonPositions( isBackward ) {\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\treturn isBackward ? [\n\t\tdefaultPositions.northWestArrowSouth,\n\t\tdefaultPositions.northWestArrowSouthWest,\n\t\tdefaultPositions.northWestArrowSouthEast,\n\t\tdefaultPositions.northWestArrowSouthMiddleEast,\n\t\tdefaultPositions.northWestArrowSouthMiddleWest,\n\t\tdefaultPositions.southWestArrowNorth,\n\t\tdefaultPositions.southWestArrowNorthWest,\n\t\tdefaultPositions.southWestArrowNorthEast,\n\t\tdefaultPositions.southWestArrowNorthMiddleWest,\n\t\tdefaultPositions.southWestArrowNorthMiddleEast\n\t] : [\n\t\tdefaultPositions.southEastArrowNorth,\n\t\tdefaultPositions.southEastArrowNorthEast,\n\t\tdefaultPositions.southEastArrowNorthWest,\n\t\tdefaultPositions.southEastArrowNorthMiddleEast,\n\t\tdefaultPositions.southEastArrowNorthMiddleWest,\n\t\tdefaultPositions.northEastArrowSouth,\n\t\tdefaultPositions.northEastArrowSouthEast,\n\t\tdefaultPositions.northEastArrowSouthWest,\n\t\tdefaultPositions.northEastArrowSouthMiddleEast,\n\t\tdefaultPositions.northEastArrowSouthMiddleWest\n\t];\n}\n\n// Returns \"true\" when the selection has multiple ranges and each range contains a selectable element\n// and nothing else.\n//\n// @private\n// @param {module:engine/model/selection~Selection} selection\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction selectionContainsOnlyMultipleSelectables( selection, schema ) {\n\t// It doesn't contain multiple objects if there is only one range.\n\tif ( selection.rangeCount === 1 ) {\n\t\treturn false;\n\t}\n\n\treturn [ ...selection.getRanges() ].every( range => {\n\t\tconst element = range.getContainedElement();\n\n\t\treturn element && schema.isSelectable( element );\n\t} );\n}\n\n/**\n * Contextual toolbar configuration. Used by the {@link module:ui/toolbar/balloon/balloontoolbar~BalloonToolbar}\n * feature.\n *\n * ## Configuring toolbar items\n *\n *\t\tconst config = {\n *\t\t\tballoonToolbar: [ 'bold', 'italic', 'undo', 'redo' ]\n *\t\t};\n *\n * You can also use `'|'` to create a separator between groups of items:\n *\n *\t\tconst config = {\n *\t\t\tballoonToolbar: [ 'bold', 'italic', | 'undo', 'redo' ]\n *\t\t};\n *\n * Read also about configuring the main editor toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * ## Configuring items grouping\n *\n * You can prevent automatic items grouping by setting the `shouldNotGroupWhenFull` option:\n *\n *\t\tconst config = {\n *\t\t\tballoonToolbar: {\n *\t\t\t\titems: [ 'bold', 'italic', 'undo', 'redo' ],\n *\t\t\t\tshouldNotGroupWhenFull: true\n *\t\t\t},\n *\t\t};\n *\n * @member {Array.<String>|Object} module:core/editor/editorconfig~EditorConfig#balloonToolbar\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 ui/toolbar/block/blockbuttonview\n */\n\nimport ButtonView from '../../button/buttonview';\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\nimport '../../../theme/components/toolbar/blocktoolbar.css';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The block button view class.\n *\n * This view represents a button attached next to block element where the selection is anchored.\n *\n * See {@link module:ui/toolbar/block/blocktoolbar~BlockToolbar}.\n *\n * @extends {module:ui/button/buttonview~ButtonView}\n */\nexport default class BlockButtonView extends ButtonView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t// Hide button on init.\n\t\tthis.isVisible = false;\n\n\t\tthis.isToggleable = true;\n\n\t\t/**\n\t\t * Top offset.\n\t\t *\n\t\t * @member {Number} #top\n\t\t */\n\t\tthis.set( 'top', 0 );\n\n\t\t/**\n\t\t * Left offset.\n\t\t *\n\t\t * @member {Number} #left\n\t\t */\n\t\tthis.set( 'left', 0 );\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-block-toolbar-button',\n\t\t\t\tstyle: {\n\t\t\t\t\ttop: bind.to( 'top', val => toPx( val ) ),\n\t\t\t\t\tleft: bind.to( 'left', val => toPx( val ) )\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/block/blocktoolbar\n */\n\n/* global window */\n\nimport { Plugin, icons } from 'ckeditor5/src/core';\n\nimport BlockButtonView from './blockbuttonview';\nimport BalloonPanelView from '../../panel/balloon/balloonpanelview';\nimport ToolbarView from '../toolbarview';\n\nimport clickOutsideHandler from '../../bindings/clickoutsidehandler';\n\nimport { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport normalizeToolbarConfig from '../normalizetoolbarconfig';\n\nimport ResizeObserver from '@ckeditor/ckeditor5-utils/src/dom/resizeobserver';\n\nimport toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';\n\nconst toPx = toUnit( 'px' );\n\n/**\n * The block toolbar plugin.\n *\n * This plugin provides a button positioned next to the block of content where the selection is anchored.\n * Upon clicking the button, a dropdown providing access to editor features shows up, as configured in\n * {@link module:core/editor/editorconfig~EditorConfig#blockToolbar}.\n *\n * By default, the button is displayed next to all elements marked in {@link module:engine/model/schema~Schema}\n * as `$block` for which the toolbar provides at least one option.\n *\n * By default, the button is attached so its right boundary is touching the\n * {@link module:engine/view/editableelement~EditableElement}:\n *\n * \t\t __ |\n * \t\t| || This is a block of content that the\n * \t\t ¯¯ | button is attached to. This is a\n * \t\t | block of content that the button is\n * \t\t | attached to.\n *\n * The position of the button can be adjusted using the CSS `transform` property:\n *\n * \t\t.ck-block-toolbar-button {\n * \t\t\ttransform: translateX( -10px );\n * \t\t}\n *\n * \t\t __ |\n * \t\t| | | This is a block of content that the\n * \t\t ¯¯ | button is attached to. This is a\n * \t\t | block of content that the button is\n * \t\t | attached to.\n *\n * **Note**: If you plan to run the editor in a righttoleft (RTL) language, keep in mind the button\n * will be attached to the **right** boundary of the editable area. In that case, make sure the\n * CSS position adjustment works properly by adding the following styles:\n *\n * \t\t.ck[dir=\"rtl\"] .ck-block-toolbar-button {\n * \t\t\ttransform: translateX( 10px );\n * \t\t}\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A cached and normalized `config.blockToolbar` object.\n\t\t *\n\t\t * @type {module:core/editor/editorconfig~EditorConfig#blockToolbar}\n\t\t * @private\n\t\t */\n\t\tthis._blockToolbarConfig = normalizeToolbarConfig( this.editor.config.get( 'blockToolbar' ) );\n\n\t\t/**\n\t\t * The toolbar view.\n\t\t *\n\t\t * @type {module:ui/toolbar/toolbarview~ToolbarView}\n\t\t */\n\t\tthis.toolbarView = this._createToolbarView();\n\n\t\t/**\n\t\t * The balloon panel view, containing the {@link #toolbarView}.\n\t\t *\n\t\t * @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n\t\t */\n\t\tthis.panelView = this._createPanelView();\n\n\t\t/**\n\t\t * The button view that opens the {@link #toolbarView}.\n\t\t *\n\t\t * @type {module:ui/toolbar/block/blockbuttonview~BlockButtonView}\n\t\t */\n\t\tthis.buttonView = this._createButtonView();\n\n\t\t/**\n\t\t * An instance of the resize observer that allows to respond to changes in editable's geometry\n\t\t * so the toolbar can stay within its boundaries (and group toolbar items that do not fit).\n\t\t *\n\t\t * **Note**: Used only when `shouldNotGroupWhenFull` was **not** set in the\n\t\t * {@link module:core/editor/editorconfig~EditorConfig#blockToolbar configuration}.\n\t\t *\n\t\t * **Note:** Created in {@link #afterInit}.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:utils/dom/resizeobserver~ResizeObserver}\n\t\t */\n\t\tthis._resizeObserver = null;\n\n\t\t// Close the #panelView upon clicking outside of the plugin UI.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this.panelView,\n\t\t\tcontextElements: [ this.panelView.element, this.buttonView.element ],\n\t\t\tactivator: () => this.panelView.isVisible,\n\t\t\tcallback: () => this._hidePanel()\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Hides panel on a direct selection change.\n\t\tthis.listenTo( editor.model.document.selection, 'change:range', ( evt, data ) => {\n\t\t\tif ( data.directChange ) {\n\t\t\t\tthis._hidePanel();\n\t\t\t}\n\t\t} );\n\n\t\tthis.listenTo( editor.ui, 'update', () => this._updateButton() );\n\t\t// `low` priority is used because of https://github.com/ckeditor/ckeditor5-core/issues/133.\n\t\tthis.listenTo( editor, 'change:isReadOnly', () => this._updateButton(), { priority: 'low' } );\n\t\tthis.listenTo( editor.ui.focusTracker, 'change:isFocused', () => this._updateButton() );\n\n\t\t// Reposition button on resize.\n\t\tthis.listenTo( this.buttonView, 'change:isVisible', ( evt, name, isVisible ) => {\n\t\t\tif ( isVisible ) {\n\t\t\t\t// Keep correct position of button and panel on window#resize.\n\t\t\t\tthis.buttonView.listenTo( window, 'resize', () => this._updateButton() );\n\t\t\t} else {\n\t\t\t\t// Stop repositioning button when is hidden.\n\t\t\t\tthis.buttonView.stopListening( window, 'resize' );\n\n\t\t\t\t// Hide the panel when the button disappears.\n\t\t\t\tthis._hidePanel();\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Fills the toolbar with its items based on the configuration.\n\t *\n\t * **Note:** This needs to be done after all plugins are ready.\n\t *\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst factory = this.editor.ui.componentFactory;\n\t\tconst config = this._blockToolbarConfig;\n\n\t\tthis.toolbarView.fillFromConfig( config, factory );\n\n\t\t// Hide panel before executing each button in the panel.\n\t\tfor ( const item of this.toolbarView.items ) {\n\t\t\titem.on( 'execute', () => this._hidePanel( true ), { priority: 'high' } );\n\t\t}\n\n\t\tif ( !config.shouldNotGroupWhenFull ) {\n\t\t\tthis.listenTo( this.editor, 'ready', () => {\n\t\t\t\tconst editableElement = this.editor.ui.view.editable.element;\n\n\t\t\t\t// Set #toolbarView's max-width just after the initialization and update it on the editable resize.\n\t\t\t\tthis._resizeObserver = new ResizeObserver( editableElement, () => {\n\t\t\t\t\tthis.toolbarView.maxWidth = this._getToolbarMaxWidth();\n\t\t\t\t} );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis.panelView.destroy();\n\t\tthis.buttonView.destroy();\n\t\tthis.toolbarView.destroy();\n\n\t\tif ( this._resizeObserver ) {\n\t\t\tthis._resizeObserver.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * Creates the {@link #toolbarView}.\n\t *\n\t * @private\n\t * @returns {module:ui/toolbar/toolbarview~ToolbarView}\n\t */\n\t_createToolbarView() {\n\t\tconst shouldGroupWhenFull = !this._blockToolbarConfig.shouldNotGroupWhenFull;\n\t\tconst toolbarView = new ToolbarView( this.editor.locale, {\n\t\t\tshouldGroupWhenFull,\n\t\t\tisFloating: true\n\t\t} );\n\n\t\t// When toolbar lost focus then panel should hide.\n\t\ttoolbarView.focusTracker.on( 'change:isFocused', ( evt, name, is ) => {\n\t\t\tif ( !is ) {\n\t\t\t\tthis._hidePanel();\n\t\t\t}\n\t\t} );\n\n\t\treturn toolbarView;\n\t}\n\n\t/**\n\t * Creates the {@link #panelView}.\n\t *\n\t * @private\n\t * @returns {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}\n\t */\n\t_createPanelView() {\n\t\tconst editor = this.editor;\n\t\tconst panelView = new BalloonPanelView( editor.locale );\n\n\t\tpanelView.content.add( this.toolbarView );\n\t\tpanelView.class = 'ck-toolbar-container';\n\t\teditor.ui.view.body.add( panelView );\n\t\teditor.ui.focusTracker.add( panelView.element );\n\n\t\t// Close #panelView on `Esc` press.\n\t\tthis.toolbarView.keystrokes.set( 'Esc', ( evt, cancel ) => {\n\t\t\tthis._hidePanel( true );\n\t\t\tcancel();\n\t\t} );\n\n\t\treturn panelView;\n\t}\n\n\t/**\n\t * Creates the {@link #buttonView}.\n\t *\n\t * @private\n\t * @returns {module:ui/toolbar/block/blockbuttonview~BlockButtonView}\n\t */\n\t_createButtonView() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst buttonView = new BlockButtonView( editor.locale );\n\n\t\tbuttonView.set( {\n\t\t\tlabel: t( 'Edit block' ),\n\t\t\ticon: icons.pilcrow,\n\t\t\twithText: false\n\t\t} );\n\n\t\t// Bind the panelView observable properties to the buttonView.\n\t\tbuttonView.bind( 'isOn' ).to( this.panelView, 'isVisible' );\n\t\tbuttonView.bind( 'tooltip' ).to( this.panelView, 'isVisible', isVisible => !isVisible );\n\n\t\t// Toggle the panelView upon buttonView#execute.\n\t\tthis.listenTo( buttonView, 'execute', () => {\n\t\t\tif ( !this.panelView.isVisible ) {\n\t\t\t\tthis._showPanel();\n\t\t\t} else {\n\t\t\t\tthis._hidePanel( true );\n\t\t\t}\n\t\t} );\n\n\t\teditor.ui.view.body.add( buttonView );\n\t\teditor.ui.focusTracker.add( buttonView.element );\n\n\t\treturn buttonView;\n\t}\n\n\t/**\n\t * Shows or hides the button.\n\t * When all the conditions for displaying the button are matched, it shows the button. Hides otherwise.\n\t *\n\t * @private\n\t */\n\t_updateButton() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\n\t\t// Hides the button when the editor is not focused.\n\t\tif ( !editor.ui.focusTracker.isFocused ) {\n\t\t\tthis._hideButton();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Hides the button when the editor switches to the read-only mode.\n\t\tif ( editor.isReadOnly ) {\n\t\t\tthis._hideButton();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Get the first selected block, button will be attached to this element.\n\t\tconst modelTarget = Array.from( model.document.selection.getSelectedBlocks() )[ 0 ];\n\n\t\t// Hides the button when there is no enabled item in toolbar for the current block element.\n\t\tif ( !modelTarget || Array.from( this.toolbarView.items ).every( item => !item.isEnabled ) ) {\n\t\t\tthis._hideButton();\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Get DOM target element.\n\t\tconst domTarget = view.domConverter.mapViewToDom( editor.editing.mapper.toViewElement( modelTarget ) );\n\n\t\t// Show block button.\n\t\tthis.buttonView.isVisible = true;\n\n\t\t// Attach block button to target DOM element.\n\t\tthis._attachButtonToElement( domTarget );\n\n\t\t// When panel is opened then refresh it position to be properly aligned with block button.\n\t\tif ( this.panelView.isVisible ) {\n\t\t\tthis._showPanel();\n\t\t}\n\t}\n\n\t/**\n\t * Hides the button.\n\t *\n\t * @private\n\t */\n\t_hideButton() {\n\t\tthis.buttonView.isVisible = false;\n\t}\n\n\t/**\n\t * Shows the {@link #toolbarView} attached to the {@link #buttonView}.\n\t * If the toolbar is already visible, then it simply repositions it.\n\t *\n\t * @private\n\t */\n\t_showPanel() {\n\t\tconst wasVisible = this.panelView.isVisible;\n\n\t\t// So here's the thing: If there was no initial panelView#show() or these two were in different order, the toolbar\n\t\t// positioning will break in RTL editors. Weird, right? What you show know is that the toolbar\n\t\t// grouping works thanks to:\n\t\t//\n\t\t// * the ResizeObserver, which kicks in as soon as the toolbar shows up in DOM (becomes visible again).\n\t\t// * the observable ToolbarView#maxWidth, which triggers re-grouping when changed.\n\t\t//\n\t\t// Here are the possible scenarios:\n\t\t//\n\t\t// 1. (WRONG ❌) If the #maxWidth is set when the toolbar is invisible, it won't affect item grouping (no DOMRects, no grouping).\n\t\t// Then, when panelView.pin() is called, the position of the toolbar will be calculated for the old\n\t\t// items grouping state, and when finally ResizeObserver kicks in (hey, the toolbar is visible now, right?)\n\t\t// it will group/ungroup some items and the length of the toolbar will change. But since in RTL the toolbar\n\t\t// is attached on the right side and the positioning uses CSS \"left\", it will result in the toolbar shifting\n\t\t// to the left and being displayed in the wrong place.\n\t\t// 2. (WRONG ❌) If the panelView.pin() is called first and #maxWidth set next, then basically the story repeats. The balloon\n\t\t// calculates the position for the old toolbar grouping state, then the toolbar re-groups items and because\n\t\t// it is positioned using CSS \"left\" it will move.\n\t\t// 3. (RIGHT ✅) We show the panel first (the toolbar does re-grouping but it does not matter), then the #maxWidth\n\t\t// is set allowing the toolbar to re-group again and finally panelView.pin() does the positioning when the\n\t\t// items grouping state is stable and final.\n\t\t//\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6449, https://github.com/ckeditor/ckeditor5/issues/6575\n\t\tthis.panelView.show();\n\t\tthis.toolbarView.maxWidth = this._getToolbarMaxWidth();\n\n\t\tthis.panelView.pin( {\n\t\t\ttarget: this.buttonView.element,\n\t\t\tlimiter: this.editor.ui.getEditableElement()\n\t\t} );\n\n\t\tif ( !wasVisible ) {\n\t\t\tthis.toolbarView.items.get( 0 ).focus();\n\t\t}\n\t}\n\n\t/**\n\t * Hides the {@link #toolbarView}.\n\t *\n\t * @private\n\t * @param {Boolean} [focusEditable=false] When `true`, the editable will be focused after hiding the panel.\n\t */\n\t_hidePanel( focusEditable ) {\n\t\tthis.panelView.isVisible = false;\n\n\t\tif ( focusEditable ) {\n\t\t\tthis.editor.editing.view.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Attaches the {@link #buttonView} to the target block of content.\n\t *\n\t * @protected\n\t * @param {HTMLElement} targetElement Target element.\n\t */\n\t_attachButtonToElement( targetElement ) {\n\t\tconst contentStyles = window.getComputedStyle( targetElement );\n\n\t\tconst editableRect = new Rect( this.editor.ui.getEditableElement() );\n\t\tconst contentPaddingTop = parseInt( contentStyles.paddingTop, 10 );\n\t\t// When line height is not an integer then thread it as \"normal\".\n\t\t// MDN says that 'normal' == ~1.2 on desktop browsers.\n\t\tconst contentLineHeight = parseInt( contentStyles.lineHeight, 10 ) || parseInt( contentStyles.fontSize, 10 ) * 1.2;\n\n\t\tconst position = getOptimalPosition( {\n\t\t\telement: this.buttonView.element,\n\t\t\ttarget: targetElement,\n\t\t\tpositions: [\n\t\t\t\t( contentRect, buttonRect ) => {\n\t\t\t\t\tlet left;\n\n\t\t\t\t\tif ( this.editor.locale.uiLanguageDirection === 'ltr' ) {\n\t\t\t\t\t\tleft = editableRect.left - buttonRect.width;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tleft = editableRect.right;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttop: contentRect.top + contentPaddingTop + ( contentLineHeight - buttonRect.height ) / 2,\n\t\t\t\t\t\tleft\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\tthis.buttonView.top = position.top;\n\t\tthis.buttonView.left = position.left;\n\t}\n\n\t/**\n\t * Gets the {@link #toolbarView} max-width, based on\n\t * editable width plus distance between farthest edge of the {@link #buttonView} and the editable.\n\t *\n\t * @private\n\t * @returns {String} maxWidth A maximum width that toolbar can have, in pixels.\n\t */\n\t_getToolbarMaxWidth() {\n\t\tconst editableElement = this.editor.ui.view.editable.element;\n\t\tconst editableRect = new Rect( editableElement );\n\t\tconst buttonRect = new Rect( this.buttonView.element );\n\t\tconst isRTL = this.editor.locale.uiLanguageDirection === 'rtl';\n\t\tconst offset = isRTL ? ( buttonRect.left - editableRect.right ) + buttonRect.width : editableRect.left - buttonRect.left;\n\n\t\treturn toPx( editableRect.width + offset );\n\t}\n}\n\n/**\n * The block toolbar configuration. Used by the {@link module:ui/toolbar/block/blocktoolbar~BlockToolbar}\n * feature.\n *\n *\t\tconst config = {\n *\t\t\tblockToolbar: [ 'paragraph', 'heading1', 'heading2', 'bulletedList', 'numberedList' ]\n *\t\t};\n *\n * You can also use `'|'` to create a separator between groups of items:\n *\n *\t\tconst config = {\n *\t\t\tblockToolbar: [ 'paragraph', 'heading1', 'heading2', '|', 'bulletedList', 'numberedList' ]\n *\t\t};\n *\n * ## Configuring items grouping\n *\n * You can prevent automatic items grouping by setting the `shouldNotGroupWhenFull` option:\n *\n *\t\tconst config = {\n *\t\t\tblockToolbar: {\n *\t\t\t\titems: [ 'paragraph', 'heading1', 'heading2', '|', 'bulletedList', 'numberedList' ],\n *\t\t\t\tshouldNotGroupWhenFull: true\n *\t\t\t},\n *\t\t};\n *\n * Read more about configuring the main editor toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>|Object} module:core/editor/editorconfig~EditorConfig#blockToolbar\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/view/placeholder\n */\n\nimport '../../theme/placeholder.css';\n\n// Each document stores information about its placeholder elements and check functions.\nconst documentPlaceholders = new WeakMap();\n\n/**\n * A helper that enables a placeholder on the provided view element (also updates its visibility).\n * The placeholder is a CSS pseudoelement (with a text content) attached to the element.\n *\n * To change the placeholder text, simply call this method again with new options.\n *\n * To disable the placeholder, use {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} helper.\n *\n * @param {Object} [options] Configuration options of the placeholder.\n * @param {module:engine/view/view~View} options.view Editing view instance.\n * @param {module:engine/view/element~Element} options.element Element that will gain a placeholder.\n * See `options.isDirectHost` to learn more.\n * @param {String} options.text Placeholder text.\n * @param {Boolean} [options.isDirectHost=true] If set `false`, the placeholder will not be enabled directly\n * in the passed `element` but in one of its children (selected automatically, i.e. a first empty child element).\n * Useful when attaching placeholders to elements that can host other elements (not just text), for instance,\n * editable root elements.\n * @param {Boolean} [options.keepOnFocus=false] If set `true`, the placeholder stay visible when the host element is focused.\n */\nexport function enablePlaceholder( options ) {\n\tconst { view, element, text, isDirectHost = true, keepOnFocus = false } = options;\n\tconst doc = view.document;\n\n\t// Use a single a single post fixer per—document to update all placeholders.\n\tif ( !documentPlaceholders.has( doc ) ) {\n\t\tdocumentPlaceholders.set( doc, new Map() );\n\n\t\t// If a post-fixer callback makes a change, it should return `true` so other postfixers\n\t\t// can reevaluate the document again.\n\t\tdoc.registerPostFixer( writer => updateDocumentPlaceholders( doc, writer ) );\n\t}\n\n\t// Store information about the element placeholder under its document.\n\tdocumentPlaceholders.get( doc ).set( element, {\n\t\ttext,\n\t\tisDirectHost,\n\t\tkeepOnFocus,\n\t\thostElement: isDirectHost ? element : null\n\t} );\n\n\t// Update the placeholders right away.\n\tview.change( writer => updateDocumentPlaceholders( doc, writer ) );\n}\n\n/**\n * Disables the placeholder functionality from a given element.\n *\n * See {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} to learn more.\n *\n * @param {module:engine/view/view~View} view\n * @param {module:engine/view/element~Element} element\n */\nexport function disablePlaceholder( view, element ) {\n\tconst doc = element.document;\n\n\tview.change( writer => {\n\t\tif ( !documentPlaceholders.has( doc ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst placeholders = documentPlaceholders.get( doc );\n\t\tconst config = placeholders.get( element );\n\n\t\twriter.removeAttribute( 'data-placeholder', config.hostElement );\n\t\thidePlaceholder( writer, config.hostElement );\n\n\t\tplaceholders.delete( element );\n\t} );\n}\n\n/**\n * Shows a placeholder in the provided element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a onetime state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * **Note**: This helper will blindly show the placeholder directly in the root editable element if\n * one is passed, which could result in a visual clash if the editable element has some children\n * (for instance, an empty paragraph). Use {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`}\n * in that case or make sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function showPlaceholder( writer, element ) {\n\tif ( !element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.addClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Hides a placeholder in the element by changing related attributes and CSS classes.\n *\n * **Note**: This helper will not update the placeholder visibility nor manage the\n * it in any way in the future. What it does is a onetime state change of an element. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} and\n * {@link module:engine/view/placeholder~disablePlaceholder `disablePlaceholder()`} for full\n * placeholder functionality.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {module:engine/view/element~Element} element\n * @returns {Boolean} `true`, if any changes were made to the `element`.\n */\nexport function hidePlaceholder( writer, element ) {\n\tif ( element.hasClass( 'ck-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-placeholder', element );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Checks if a placeholder should be displayed in the element.\n *\n * **Note**: This helper will blindly check the possibility of showing a placeholder directly in the\n * root editable element if one is passed, which may not be the expected result. If an element can\n * host other elements (not just text), most likely one of its children should be checked instead\n * because it will be the final host for the placeholder. Use\n * {@link module:engine/view/placeholder~enablePlaceholder `enablePlaceholder()`} in that case or make\n * sure the correct element is passed to the helper.\n *\n * @param {module:engine/view/element~Element} element Element that holds the placeholder.\n * @param {Boolean} keepOnFocus Focusing the element will keep the placeholder visible.\n * @returns {Boolean}\n */\nexport function needsPlaceholder( element, keepOnFocus ) {\n\tif ( !element.isAttached() ) {\n\t\treturn false;\n\t}\n\n\t// Anything but uiElement(s) counts as content.\n\tconst hasContent = Array.from( element.getChildren() )\n\t\t.some( element => !element.is( 'uiElement' ) );\n\n\tif ( hasContent ) {\n\t\treturn false;\n\t}\n\n\t// Skip the focus check and make the placeholder visible already regardless of document focus state.\n\tif ( keepOnFocus ) {\n\t\treturn true;\n\t}\n\n\tconst doc = element.document;\n\n\t// If the document is blurred.\n\tif ( !doc.isFocused ) {\n\t\treturn true;\n\t}\n\n\tconst viewSelection = doc.selection;\n\tconst selectionAnchor = viewSelection.anchor;\n\n\t// If document is focused and the element is empty but the selection is not anchored inside it.\n\treturn selectionAnchor && selectionAnchor.parent !== element;\n}\n\n// Updates all placeholders associated with a document in a postfixer callback.\n//\n// @private\n// @param { module:engine/view/document~Document} doc\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updateDocumentPlaceholders( doc, writer ) {\n\tconst placeholders = documentPlaceholders.get( doc );\n\tconst directHostElements = [];\n\tlet wasViewModified = false;\n\n\t// First set placeholders on the direct hosts.\n\tfor ( const [ element, config ] of placeholders ) {\n\t\tif ( config.isDirectHost ) {\n\t\t\tdirectHostElements.push( element );\n\n\t\t\tif ( updatePlaceholder( writer, element, config ) ) {\n\t\t\t\twasViewModified = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Then set placeholders on the indirect hosts but only on those that does not already have an direct host placeholder.\n\tfor ( const [ element, config ] of placeholders ) {\n\t\tif ( config.isDirectHost ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst hostElement = getChildPlaceholderHostSubstitute( element );\n\n\t\t// When not a direct host, it could happen that there is no child element\n\t\t// capable of displaying a placeholder.\n\t\tif ( !hostElement ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Don't override placeholder if the host element already has some direct placeholder.\n\t\tif ( directHostElements.includes( hostElement ) ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Update the host element (used for setting and removing the placeholder).\n\t\tconfig.hostElement = hostElement;\n\n\t\tif ( updatePlaceholder( writer, element, config ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t}\n\n\treturn wasViewModified;\n}\n\n// Updates a single placeholder in a postfixer callback.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/element~Element} element\n// @param {Object} config Configuration of the placeholder\n// @param {String} config.text\n// @param {Boolean} config.isDirectHost\n// @returns {Boolean} True if any changes were made to the view document.\nfunction updatePlaceholder( writer, element, config ) {\n\tconst { text, isDirectHost, hostElement } = config;\n\n\tlet wasViewModified = false;\n\n\t// This may be necessary when updating the placeholder text to something else.\n\tif ( hostElement.getAttribute( 'data-placeholder' ) !== text ) {\n\t\twriter.setAttribute( 'data-placeholder', text, hostElement );\n\t\twasViewModified = true;\n\t}\n\n\t// If the host element is not a direct host then placeholder is needed only when there is only one element.\n\tconst isOnlyChild = isDirectHost || element.childCount == 1;\n\n\tif ( isOnlyChild && needsPlaceholder( hostElement, config.keepOnFocus ) ) {\n\t\tif ( showPlaceholder( writer, hostElement ) ) {\n\t\t\twasViewModified = true;\n\t\t}\n\t} else if ( hidePlaceholder( writer, hostElement ) ) {\n\t\twasViewModified = true;\n\t}\n\n\treturn wasViewModified;\n}\n\n// Gets a child element capable of displaying a placeholder if a parent element can host more\n// than just text (for instance, when it is a root editable element). The child element\n// can then be used in other placeholder helpers as a substitute of its parent.\n//\n// @private\n// @param {module:engine/view/element~Element} parent\n// @returns {module:engine/view/element~Element|null}\nfunction getChildPlaceholderHostSubstitute( parent ) {\n\tif ( parent.childCount ) {\n\t\tconst firstChild = parent.getChild( 0 );\n\n\t\tif ( firstChild.is( 'element' ) && !firstChild.is( 'uiElement' ) ) {\n\t\t\treturn firstChild;\n\t\t}\n\t}\n\n\treturn null;\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\nimport InsertOperation from './insertoperation';\nimport AttributeOperation from './attributeoperation';\nimport RenameOperation from './renameoperation';\nimport MarkerOperation from './markeroperation';\nimport MoveOperation from './moveoperation';\nimport RootAttributeOperation from './rootattributeoperation';\nimport MergeOperation from './mergeoperation';\nimport SplitOperation from './splitoperation';\nimport NoOperation from './nooperation';\nimport Range from '../range';\nimport Position from '../position';\n\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\nconst transformations = new Map();\n\n/**\n * @module engine/model/operation/transform\n */\n\n/**\n * Sets a transformation function to be be used to transform instances of class `OperationA` by instances of class `OperationB`.\n *\n * The `transformationFunction` is passed three parameters:\n *\n * * `a` - operation to be transformed, an instance of `OperationA`,\n * * `b` - operation to be transformed by, an instance of `OperationB`,\n * * {@link module:engine/model/operation/transform~TransformationContext `context`} - object with additional information about\n * transformation context.\n *\n * The `transformationFunction` should return transformation result, which is an array with one or multiple\n * {@link module:engine/model/operation/operation~Operation operation} instances.\n *\n * @protected\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @param {Function} transformationFunction Function to use for transforming.\n */\nfunction setTransformation( OperationA, OperationB, transformationFunction ) {\n\tlet aGroup = transformations.get( OperationA );\n\n\tif ( !aGroup ) {\n\t\taGroup = new Map();\n\t\ttransformations.set( OperationA, aGroup );\n\t}\n\n\taGroup.set( OperationB, transformationFunction );\n}\n\n/**\n * Returns a previously set transformation function for transforming an instance of `OperationA` by an instance of `OperationB`.\n *\n * If no transformation was set for given pair of operations, {@link module:engine/model/operation/transform~noUpdateTransformation}\n * is returned. This means that if no transformation was set, the `OperationA` instance will not change when transformed\n * by the `OperationB` instance.\n *\n * @private\n * @param {Function} OperationA\n * @param {Function} OperationB\n * @returns {Function} Function set to transform an instance of `OperationA` by an instance of `OperationB`.\n */\nfunction getTransformation( OperationA, OperationB ) {\n\tconst aGroup = transformations.get( OperationA );\n\n\tif ( aGroup && aGroup.has( OperationB ) ) {\n\t\treturn aGroup.get( OperationB );\n\t}\n\n\treturn noUpdateTransformation;\n}\n\n/**\n * A transformation function that only clones operation to transform, without changing it.\n *\n * @private\n * @param {module:engine/model/operation/operation~Operation} a Operation to transform.\n * @returns {Array.<module:engine/model/operation/operation~Operation>}\n */\nfunction noUpdateTransformation( a ) {\n\treturn [ a ];\n}\n\n/**\n * Transforms operation `a` by operation `b`.\n *\n * @param {module:engine/model/operation/operation~Operation} a Operation to be transformed.\n * @param {module:engine/model/operation/operation~Operation} b Operation to transform by.\n * @param {module:engine/model/operation/transform~TransformationContext} context Transformation context for this transformation.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} Transformation result.\n */\nexport function transform( a, b, context = {} ) {\n\tconst transformationFunction = getTransformation( a.constructor, b.constructor );\n\n\t/* eslint-disable no-useless-catch */\n\ttry {\n\t\ta = a.clone();\n\n\t\treturn transformationFunction( a, b, context );\n\t} catch ( e ) {\n\t\t// @if CK_DEBUG // console.warn( 'Error during operation transformation!', e.message );\n\t\t// @if CK_DEBUG // console.warn( 'Transformed operation', a );\n\t\t// @if CK_DEBUG // console.warn( 'Operation transformed by', b );\n\t\t// @if CK_DEBUG // console.warn( 'context.aIsStrong', context.aIsStrong );\n\t\t// @if CK_DEBUG // console.warn( 'context.aWasUndone', context.aWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.bWasUndone', context.bWasUndone );\n\t\t// @if CK_DEBUG // console.warn( 'context.abRelation', context.abRelation );\n\t\t// @if CK_DEBUG // console.warn( 'context.baRelation', context.baRelation );\n\n\t\tthrow e;\n\t}\n\t/* eslint-enable no-useless-catch */\n}\n\n/**\n * Performs a transformation of two sets of operations - `operationsA` and `operationsB`. The transformation is two-way -\n * both transformed `operationsA` and transformed `operationsB` are returned.\n *\n * Note, that the first operation in each set should base on the same document state (\n * {@link module:engine/model/document~Document#version document version}).\n *\n * It is assumed that `operationsA` are \"more important\" during conflict resolution between two operations.\n *\n * New copies of both passed arrays and operations inside them are returned. Passed arguments are not altered.\n *\n * Base versions of the transformed operations sets are updated accordingly. For example, assume that base versions are `4`\n * and there are `3` operations in `operationsA` and `5` operations in `operationsB`. Then:\n *\n * * transformed `operationsA` will start from base version `9` (`4` base version + `5` operations B),\n * * transformed `operationsB` will start from base version `7` (`4` base version + `3` operations A).\n *\n * If no operation was broken into two during transformation, then both sets will end up with an operation that bases on version `11`:\n *\n * * transformed `operationsA` start from `9` and there are `3` of them, so the last will have `baseVersion` equal to `11`,\n * * transformed `operationsB` start from `7` and there are `5` of them, so the last will have `baseVersion` equal to `11`.\n *\n * @param {Array.<module:engine/model/operation/operation~Operation>} operationsA\n * @param {Array.<module:engine/model/operation/operation~Operation>} operationsB\n * @param {Object} options Additional transformation options.\n * @param {module:engine/model/document~Document|null} options.document Document which the operations change.\n * @param {Boolean} [options.useRelations=false] Whether during transformation relations should be used (used during undo for\n * better conflict resolution).\n * @param {Boolean} [options.padWithNoOps=false] Whether additional {@link module:engine/model/operation/nooperation~NoOperation}s\n * should be added to the transformation results to force the same last base version for both transformed sets (in case\n * if some operations got broken into multiple operations during transformation).\n * @returns {Object} Transformation result.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} return.operationsA Transformed `operationsA`.\n * @returns {Array.<module:engine/model/operation/operation~Operation>} return.operationsB Transformed `operationsB`.\n * @returns {Map} return.originalOperations A map that links transformed operations to original operations. The keys are the transformed\n * operations and the values are the original operations from the input (`operationsA` and `operationsB`).\n */\nexport function transformSets( operationsA, operationsB, options ) {\n\t// Create new arrays so the originally passed arguments are not changed.\n\t// No need to clone operations, they are cloned as they are transformed.\n\toperationsA = operationsA.slice();\n\toperationsB = operationsB.slice();\n\n\tconst contextFactory = new ContextFactory( options.document, options.useRelations, options.forceWeakRemove );\n\tcontextFactory.setOriginalOperations( operationsA );\n\tcontextFactory.setOriginalOperations( operationsB );\n\n\tconst originalOperations = contextFactory.originalOperations;\n\n\t// If one of sets is empty there is simply nothing to transform, so return sets as they are.\n\tif ( operationsA.length == 0 || operationsB.length == 0 ) {\n\t\treturn { operationsA, operationsB, originalOperations };\n\t}\n\t//\n\t// Following is a description of transformation process:\n\t//\n\t// There are `operationsA` and `operationsB` to be transformed, both by both.\n\t//\n\t// So, suppose we have sets of two operations each: `operationsA` = `[ a1, a2 ]`, `operationsB` = `[ b1, b2 ]`.\n\t//\n\t// Remember, that we can only transform operations that base on the same context. We assert that `a1` and `b1` base on\n\t// the same context and we transform them. Then, we get `a1'` and `b1'`. `a2` bases on a context with `a1` -- `a2`\n\t// is an operation that followed `a1`. Similarly, `b2` bases on a context with `b1`.\n\t//\n\t// However, since `a1'` is a result of transformation by `b1`, `a1'` now also has a context with `b1`. This means that\n\t// we can safely transform `a1'` by `b2`. As we finish transforming `a1`, we also transformed all `operationsB`.\n\t// All `operationsB` also have context including `a1`. Now, we can properly transform `a2` by those operations.\n\t//\n\t// The transformation process can be visualized on a transformation diagram (\"diamond diagram\"):\n\t//\n\t// [the initial state]\n\t// [common for a1 and b1]\n\t//\n\t// *\n\t// / \\\n\t// / \\\n\t// b1 a1\n\t// / \\\n\t// / \\\n\t// * *\n\t// / \\ / \\\n\t// / \\ / \\\n\t// b2 a1' b1' a2\n\t// / \\ / \\\n\t// / \\ / \\\n\t// * * *\n\t// \\ / \\ /\n\t// \\ / \\ /\n\t// a1'' b2' a2' b1''\n\t// \\ / \\ /\n\t// \\ / \\ /\n\t// * *\n\t// \\ /\n\t// \\ /\n\t// a2'' b2''\n\t// \\ /\n\t// \\ /\n\t// *\n\t//\n\t// [the final state]\n\t//\n\t// The final state can be reached from the initial state by applying `a1`, `a2`, `b1''` and `b2''`, as well as by\n\t// applying `b1`, `b2`, `a1''`, `a2''`. Note how the operations get to a proper common state before each pair is\n\t// transformed.\n\t//\n\t// Another thing to consider is that an operation during transformation can be broken into multiple operations.\n\t// Suppose that `a1` * `b1` = `[ a11', a12' ]` (instead of `a1'` that we considered previously).\n\t//\n\t// In that case, we leave `a12'` for later and we continue transforming `a11'` until it is transformed by all `operationsB`\n\t// (in our case it is just `b2`). At this point, `b1` is transformed by \"whole\" `a1`, while `b2` is only transformed\n\t// by `a11'`. Similarly, `a12'` is only transformed by `b1`. This leads to a conclusion that we need to start transforming `a12'`\n\t// from the moment just after it was broken. So, `a12'` is transformed by `b2`. Now, \"the whole\" `a1` is transformed\n\t// by `operationsB`, while all `operationsB` are transformed by \"the whole\" `a1`. This means that we can continue with\n\t// following `operationsA` (in our case it is just `a2`).\n\t//\n\t// Of course, also `operationsB` can be broken. However, since we focus on transforming operation `a` to the end,\n\t// the only thing to do is to store both pieces of operation `b`, so that the next transformed operation `a` will\n\t// be transformed by both of them.\n\t//\n\t// *\n\t// / \\\n\t// / \\\n\t// / \\\n\t// b1 a1\n\t// / \\\n\t// / \\\n\t// / \\\n\t// * *\n\t// / \\ / \\\n\t// / a11' / \\\n\t// / \\ / \\\n\t// b2 * b1' a2\n\t// / / \\ / \\\n\t// / / a12' / \\\n\t// / / \\ / \\\n\t// * b2' * *\n\t// \\ / / \\ /\n\t// a11'' / b21'' \\ /\n\t// \\ / / \\ /\n\t// * * a2' b1''\n\t// \\ / \\ \\ /\n\t// a12'' b22''\\ \\ /\n\t// \\ / \\ \\ /\n\t// * a2'' *\n\t// \\ \\ /\n\t// \\ \\ b21'''\n\t// \\ \\ /\n\t// a2''' *\n\t// \\ /\n\t// \\ b22'''\n\t// \\ /\n\t// *\n\t//\n\t// Note, how `a1` is broken and transformed into `a11'` and `a12'`, while `b2'` got broken and transformed into `b21''` and `b22''`.\n\t//\n\t// Having all that on mind, here is an outline for the transformation process algorithm:\n\t//\n\t// 1. We have `operationsA` and `operationsB` array, which we dynamically update as the transformation process goes.\n\t//\n\t// 2. We take next (or first) operation from `operationsA` and check from which operation `b` we need to start transforming it.\n\t// All original `operationsA` are set to be transformed starting from the first operation `b`.\n\t//\n\t// 3. We take operations from `operationsB`, one by one, starting from the correct one, and transform operation `a`\n\t// by operation `b` (and vice versa). We update `operationsA` and `operationsB` by replacing the original operations\n\t// with the transformation results.\n\t//\n\t// 4. If operation is broken into multiple operations, we save all the new operations in the place of the\n\t// original operation.\n\t//\n\t// 5. Additionally, if operation `a` was broken, for the \"new\" operation, we remember from which operation `b` it should\n\t// be transformed by.\n\t//\n\t// 6. We continue transforming \"current\" operation `a` until it is transformed by all `operationsB`. Then, go to 2.\n\t// unless the last operation `a` was transformed.\n\t//\n\t// The actual implementation of the above algorithm is slightly different, as only one loop (while) is used.\n\t// The difference is that we have \"current\" `a` operation to transform and we store the index of the next `b` operation\n\t// to transform by. Each loop operates on two indexes then: index pointing to currently processed `a` operation and\n\t// index pointing to next `b` operation. Each loop is just one `a * b` + `b * a` transformation. After each loop\n\t// operation `b` index is updated. If all `b` operations were visited for the current `a` operation, we change\n\t// current `a` operation index to the next one.\n\t//\n\n\t// For each operation `a`, keeps information what is the index in `operationsB` from which the transformation should start.\n\tconst nextTransformIndex = new WeakMap();\n\n\t// For all the original `operationsA`, set that they should be transformed starting from the first of `operationsB`.\n\tfor ( const op of operationsA ) {\n\t\tnextTransformIndex.set( op, 0 );\n\t}\n\n\t// Additional data that is used for some postprocessing after the main transformation process is done.\n\tconst data = {\n\t\tnextBaseVersionA: operationsA[ operationsA.length - 1 ].baseVersion + 1,\n\t\tnextBaseVersionB: operationsB[ operationsB.length - 1 ].baseVersion + 1,\n\t\toriginalOperationsACount: operationsA.length,\n\t\toriginalOperationsBCount: operationsB.length\n\t};\n\n\t// Index of currently transformed operation `a`.\n\tlet i = 0;\n\n\t// While not all `operationsA` are transformed...\n\twhile ( i < operationsA.length ) {\n\t\t// Get \"current\" operation `a`.\n\t\tconst opA = operationsA[ i ];\n\n\t\t// For the \"current\" operation `a`, get the index of the next operation `b` to transform by.\n\t\tconst indexB = nextTransformIndex.get( opA );\n\n\t\t// If operation `a` was already transformed by every operation `b`, change \"current\" operation `a` to the next one.\n\t\tif ( indexB == operationsB.length ) {\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst opB = operationsB[ indexB ];\n\n\t\t// Transform `a` by `b` and `b` by `a`.\n\t\tconst newOpsA = transform( opA, opB, contextFactory.getContext( opA, opB, true ) );\n\t\tconst newOpsB = transform( opB, opA, contextFactory.getContext( opB, opA, false ) );\n\t\t// As a result we get one or more `newOpsA` and one or more `newOpsB` operations.\n\n\t\t// Update contextual information about operations.\n\t\tcontextFactory.updateRelation( opA, opB );\n\n\t\tcontextFactory.setOriginalOperations( newOpsA, opA );\n\t\tcontextFactory.setOriginalOperations( newOpsB, opB );\n\n\t\t// For new `a` operations, update their index of the next operation `b` to transform them by.\n\t\t//\n\t\t// This is needed even if there was only one result (`a` was not broken) because that information is used\n\t\t// at the beginning of this loop every time.\n\t\tfor ( const newOpA of newOpsA ) {\n\t\t\t// Acknowledge, that operation `b` also might be broken into multiple operations.\n\t\t\t//\n\t\t\t// This is why we raise `indexB` not just by 1. If `newOpsB` are multiple operations, they will be\n\t\t\t// spliced in the place of `opB`. So we need to change `transformBy` accordingly, so that an operation won't\n\t\t\t// be transformed by the same operation (part of it) again.\n\t\t\tnextTransformIndex.set( newOpA, indexB + newOpsB.length );\n\t\t}\n\n\t\t// Update `operationsA` and `operationsB` with the transformed versions.\n\t\toperationsA.splice( i, 1, ...newOpsA );\n\t\toperationsB.splice( indexB, 1, ...newOpsB );\n\t}\n\n\tif ( options.padWithNoOps ) {\n\t\t// If no-operations padding is enabled, count how many extra `a` and `b` operations were generated.\n\t\tconst brokenOperationsACount = operationsA.length - data.originalOperationsACount;\n\t\tconst brokenOperationsBCount = operationsB.length - data.originalOperationsBCount;\n\n\t\t// Then, if that number is not the same, pad `operationsA` or `operationsB` with correct number of no-ops so\n\t\t// that the base versions are equalled.\n\t\t//\n\t\t// Note that only one array will be updated, as only one of those subtractions can be greater than zero.\n\t\tpadWithNoOps( operationsA, brokenOperationsBCount - brokenOperationsACount );\n\t\tpadWithNoOps( operationsB, brokenOperationsACount - brokenOperationsBCount );\n\t}\n\n\t// Finally, update base versions of transformed operations.\n\tupdateBaseVersions( operationsA, data.nextBaseVersionB );\n\tupdateBaseVersions( operationsB, data.nextBaseVersionA );\n\n\treturn { operationsA, operationsB, originalOperations };\n}\n\n// Gathers additional data about operations processed during transformation. Can be used to obtain contextual information\n// about two operations that are about to be transformed. This contextual information can be used for better conflict resolution.\nclass ContextFactory {\n\t// Creates `ContextFactory` instance.\n\t//\n\t// @param {module:engine/model/document~Document} document Document which the operations change.\n\t// @param {Boolean} useRelations Whether during transformation relations should be used (used during undo for\n\t// better conflict resolution).\n\t// @param {Boolean} [forceWeakRemove=false] If set to `false`, remove operation will be always stronger than move operation,\n\t// so the removed nodes won't end up back in the document root. When set to `true`, context data will be used.\n\tconstructor( document, useRelations, forceWeakRemove = false ) {\n\t\t// For each operation that is created during transformation process, we keep a reference to the original operation\n\t\t// which it comes from. The original operation works as a kind of \"identifier\". Every contextual information\n\t\t// gathered during transformation that we want to save for given operation, is actually saved for the original operation.\n\t\t// This way no matter if operation `a` is cloned, then transformed, even breaks, we still have access to the previously\n\t\t// gathered data through original operation reference.\n\t\tthis.originalOperations = new Map();\n\n\t\t// `model.History` instance which information about undone operations will be taken from.\n\t\tthis._history = document.history;\n\n\t\t// Whether additional context should be used.\n\t\tthis._useRelations = useRelations;\n\n\t\tthis._forceWeakRemove = !!forceWeakRemove;\n\n\t\t// Relations is a double-map structure (maps in map) where for two operations we store how those operations were related\n\t\t// to each other. Those relations are evaluated during transformation process. For every transformated pair of operations\n\t\t// we keep relations between them.\n\t\tthis._relations = new Map();\n\t}\n\n\t// Sets \"original operation\" for given operations.\n\t//\n\t// During transformation process, operations are cloned, then changed, then processed again, sometimes broken into two\n\t// or multiple operations. When gathering additional data it is important that all operations can be somehow linked\n\t// so a cloned and transformed \"version\" still kept track of the data assigned earlier to it.\n\t//\n\t// The original operation object will be used as such an universal linking id. Throughout the transformation process\n\t// all cloned operations will refer to \"the original operation\" when storing and reading additional data.\n\t//\n\t// If `takeFrom` is not set, each operation from `operations` array will be assigned itself as \"the original operation\".\n\t// This should be used as an initialization step.\n\t//\n\t// If `takeFrom` is set, each operation from `operations` will be assigned the same original operation as assigned\n\t// for `takeFrom` operation. This should be used to update original operations. It should be used in a way that\n\t// `operations` are the result of `takeFrom` transformation to ensure proper \"original operation propagation\".\n\t//\n\t// @param {Array.<module:engine/model/operation/operation~Operation>} operations\n\t// @param {module:engine/model/operation/operation~Operation|null} [takeFrom=null]\n\tsetOriginalOperations( operations, takeFrom = null ) {\n\t\tconst originalOperation = takeFrom ? this.originalOperations.get( takeFrom ) : null;\n\n\t\tfor ( const operation of operations ) {\n\t\t\tthis.originalOperations.set( operation, originalOperation || operation );\n\t\t}\n\t}\n\n\t// Saves a relation between operations `opA` and `opB`.\n\t//\n\t// Relations are then later used to help solve conflicts when operations are transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\tupdateRelation( opA, opB ) {\n\t\t// The use of relations is described in a bigger detail in transformation functions.\n\t\t//\n\t\t// In brief, this function, for specified pairs of operation types, checks how positions defined in those operations relate.\n\t\t// Then those relations are saved. For example, for two move operations, it is saved if one of those operations target\n\t\t// position is before the other operation source position. This kind of information gives contextual information when\n\t\t// transformation is used during undo. Similar checks are done for other pairs of operations.\n\t\t//\n\t\tswitch ( opA.constructor ) {\n\t\t\tcase MoveOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opB.movedRange.containsPosition( opA.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAtSource' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isEqual( opB.deletionPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBetween' );\n\t\t\t\t\t\t} else if ( opA.targetPosition.isAfter( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'moveTargetAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.targetPosition.isEqual( opB.sourcePosition ) || opA.targetPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertBefore' );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'insertAfter' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase SplitOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tif ( opA.splitPosition.isEqual( opB.sourcePosition ) || opA.splitPosition.isBefore( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitBefore' );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst range = Range._createFromPositionAndShift( opB.sourcePosition, opB.howMany );\n\n\t\t\t\t\t\t\tif ( opA.splitPosition.hasSameParentAs( opB.sourcePosition ) && range.containsPosition( opA.splitPosition ) ) {\n\t\t\t\t\t\t\t\tconst howMany = range.end.offset - opA.splitPosition.offset;\n\t\t\t\t\t\t\t\tconst offset = opA.splitPosition.offset - range.start.offset;\n\n\t\t\t\t\t\t\t\tthis._setRelation( opA, opB, { howMany, offset } );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MergeOperation: {\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tif ( !opA.targetPosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeTargetNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.targetPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSourceNotMoved' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.sourcePosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'mergeSameElement' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase SplitOperation: {\n\t\t\t\t\t\tif ( opA.sourcePosition.isEqual( opB.splitPosition ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, 'splitAtSource' );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase MarkerOperation: {\n\t\t\t\tconst markerRange = opA.newRange;\n\n\t\t\t\tif ( !markerRange ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch ( opB.constructor ) {\n\t\t\t\t\tcase MoveOperation: {\n\t\t\t\t\t\tconst movedRange = Range._createFromPositionAndShift( opB.sourcePosition, opB.howMany );\n\n\t\t\t\t\t\tconst affectedLeft = movedRange.containsPosition( markerRange.start ) ||\n\t\t\t\t\t\t\tmovedRange.start.isEqual( markerRange.start );\n\n\t\t\t\t\t\tconst affectedRight = movedRange.containsPosition( markerRange.end ) ||\n\t\t\t\t\t\t\tmovedRange.end.isEqual( markerRange.end );\n\n\t\t\t\t\t\tif ( ( affectedLeft || affectedRight ) && !movedRange.containsRange( markerRange ) ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\tside: affectedLeft ? 'left' : 'right',\n\t\t\t\t\t\t\t\tpath: affectedLeft ? markerRange.start.path.slice() : markerRange.end.path.slice()\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tcase MergeOperation: {\n\t\t\t\t\t\tconst wasInLeftElement = markerRange.start.isEqual( opB.targetPosition );\n\t\t\t\t\t\tconst wasStartBeforeMergedElement = markerRange.start.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasEndBeforeMergedElement = markerRange.end.isEqual( opB.deletionPosition );\n\t\t\t\t\t\tconst wasInRightElement = markerRange.end.isEqual( opB.sourcePosition );\n\n\t\t\t\t\t\tif ( wasInLeftElement || wasStartBeforeMergedElement || wasEndBeforeMergedElement || wasInRightElement ) {\n\t\t\t\t\t\t\tthis._setRelation( opA, opB, {\n\t\t\t\t\t\t\t\twasInLeftElement,\n\t\t\t\t\t\t\t\twasStartBeforeMergedElement,\n\t\t\t\t\t\t\t\twasEndBeforeMergedElement,\n\t\t\t\t\t\t\t\twasInRightElement\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Evaluates and returns contextual information about two given operations `opA` and `opB` which are about to be transformed.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {module:engine/model/operation/transform~TransformationContext}\n\tgetContext( opA, opB, aIsStrong ) {\n\t\treturn {\n\t\t\taIsStrong,\n\t\t\taWasUndone: this._wasUndone( opA ),\n\t\t\tbWasUndone: this._wasUndone( opB ),\n\t\t\tabRelation: this._useRelations ? this._getRelation( opA, opB ) : null,\n\t\t\tbaRelation: this._useRelations ? this._getRelation( opB, opA ) : null,\n\t\t\tforceWeakRemove: this._forceWeakRemove\n\t\t};\n\t}\n\n\t// Returns whether given operation `op` has already been undone.\n\t//\n\t// Information whether an operation was undone gives more context when making a decision when two operations are in conflict.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} op\n\t// @returns {Boolean}\n\t_wasUndone( op ) {\n\t\t// For `op`, get its original operation. After all, if `op` is a clone (or even transformed clone) of another\n\t\t// operation, literally `op` couldn't be undone. It was just generated. If anything, it was the operation it origins\n\t\t// from which was undone. So get that original operation.\n\t\tconst originalOp = this.originalOperations.get( op );\n\n\t\t// And check with the document if the original operation was undone.\n\t\treturn originalOp.wasUndone || this._history.isUndoneOperation( originalOp );\n\t}\n\n\t// Returns a relation between `opA` and an operation which is undone by `opB`. This can be `String` value if a relation\n\t// was set earlier or `null` if there was no relation between those operations.\n\t//\n\t// This is a little tricky to understand, so let's compare it to `ContextFactory#_wasUndone`.\n\t//\n\t// When `wasUndone( opB )` is used, we check if the `opB` has already been undone. It is obvious, that the\n\t// undoing operation must happen after the undone operation. So, essentially, we have `opB`, we take document history,\n\t// we look forward in the future and ask if in that future `opB` was undone.\n\t//\n\t// Relations is a backward process to `wasUndone()`.\n\t//\n\t// Long story short - using relations is asking what happened in the past. Looking back. This time we have an undoing\n\t// operation `opB` which has undone some other operation. When there is a transformation `opA` x `opB` and there is\n\t// a conflict to solve and `opB` is an undoing operation, we can look back in the history and see what was a relation\n\t// between `opA` and the operation which `opB` undone. Basing on that relation from the past, we can now make\n\t// a better decision when resolving a conflict between two operations, because we know more about the context of\n\t// those two operations.\n\t//\n\t// This is why this function does not return a relation directly between `opA` and `opB` because we need to look\n\t// back to search for a meaningful contextual information.\n\t//\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @returns {String|null}\n\t_getRelation( opA, opB ) {\n\t\t// Get the original operation. Similarly as in `wasUndone()` it is used as an universal identifier for stored data.\n\t\tconst origB = this.originalOperations.get( opB );\n\t\tconst undoneB = this._history.getUndoneOperation( origB );\n\n\t\t// If `opB` is not undoing any operation, there is no relation.\n\t\tif ( !undoneB ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst relationsA = this._relations.get( origA );\n\n\t\t// Get all relations for `opA`, and check if there is a relation with `opB`-undone-counterpart. If so, return it.\n\t\tif ( relationsA ) {\n\t\t\treturn relationsA.get( undoneB ) || null;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t// Helper function for `ContextFactory#updateRelations`.\n\t//\n\t// @private\n\t// @param {module:engine/model/operation/operation~Operation} opA\n\t// @param {module:engine/model/operation/operation~Operation} opB\n\t// @param {String} relation\n\t_setRelation( opA, opB, relation ) {\n\t\t// As always, setting is for original operations, not the clones/transformed operations.\n\t\tconst origA = this.originalOperations.get( opA );\n\t\tconst origB = this.originalOperations.get( opB );\n\n\t\tlet relationsA = this._relations.get( origA );\n\n\t\tif ( !relationsA ) {\n\t\t\trelationsA = new Map();\n\t\t\tthis._relations.set( origA, relationsA );\n\t\t}\n\n\t\trelationsA.set( origB, relation );\n\t}\n}\n\n/**\n * Holds additional contextual information about a transformed pair of operations (`a` and `b`). Those information\n * can be used for better conflict resolving.\n *\n * @typedef {Object} module:engine/model/operation/transform~TransformationContext\n *\n * @property {Boolean} aIsStrong Whether `a` is strong operation in this transformation, or weak.\n * @property {Boolean} aWasUndone Whether `a` operation was undone.\n * @property {Boolean} bWasUndone Whether `b` operation was undone.\n * @property {String|null} abRelation The relation between `a` operation and an operation undone by `b` operation.\n * @property {String|null} baRelation The relation between `b` operation and an operation undone by `a` operation.\n */\n\n/**\n * An utility function that updates {@link module:engine/model/operation/operation~Operation#baseVersion base versions}\n * of passed operations.\n *\n * The function simply sets `baseVersion` as a base version of the first passed operation and then increments it for\n * each following operation in `operations`.\n *\n * @private\n * @param {Array.<module:engine/model/operation/operation~Operation>} operations Operations to update.\n * @param {Number} baseVersion Base version to set for the first operation in `operations`.\n */\nfunction updateBaseVersions( operations, baseVersion ) {\n\tfor ( const operation of operations ) {\n\t\toperation.baseVersion = baseVersion++;\n\t}\n}\n\n/**\n * Adds `howMany` instances of {@link module:engine/model/operation/nooperation~NoOperation} to `operations` set.\n *\n * @private\n * @param {Array.<module:engine/model/operation/operation~Operation>} operations\n * @param {Number} howMany\n */\nfunction padWithNoOps( operations, howMany ) {\n\tfor ( let i = 0; i < howMany; i++ ) {\n\t\toperations.push( new NoOperation( 0 ) );\n\t}\n}\n\n// -----------------------\n\nsetTransformation( AttributeOperation, AttributeOperation, ( a, b, context ) => {\n\t// If operations in conflict, check if their ranges intersect and manage them properly.\n\t//\n\t// Operations can be in conflict only if:\n\t//\n\t// * their key is the same (they change the same attribute), and\n\t// * they are in the same parent (operations for ranges [ 1 ] - [ 3 ] and [ 2, 0 ] - [ 2, 5 ] change different\n\t// elements and can't be in conflict).\n\tif ( a.key === b.key && a.range.start.hasSameParentAs( b.range.start ) ) {\n\t\t// First, we want to apply change to the part of a range that has not been changed by the other operation.\n\t\tconst operations = a.range.getDifference( b.range ).map( range => {\n\t\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, 0 );\n\t\t} );\n\n\t\t// Then we take care of the common part of ranges.\n\t\tconst common = a.range.getIntersection( b.range );\n\n\t\tif ( common ) {\n\t\t\t// If this operation is more important, we also want to apply change to the part of the\n\t\t\t// original range that has already been changed by the other operation. Since that range\n\t\t\t// got changed we also have to update `oldValue`.\n\t\t\tif ( context.aIsStrong ) {\n\t\t\t\toperations.push( new AttributeOperation( common, b.key, b.newValue, a.newValue, 0 ) );\n\t\t\t}\n\t\t}\n\n\t\tif ( operations.length == 0 ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\treturn operations;\n\t} else {\n\t\t// If operations don't conflict, simply return an array containing just a clone of this operation.\n\t\treturn [ a ];\n\t}\n} );\n\nsetTransformation( AttributeOperation, InsertOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.position ) && a.range.containsPosition( b.position ) ) {\n\t\t// If new nodes should not receive attributes, two separated ranges will be returned.\n\t\t// Otherwise, one expanded range will be returned.\n\t\tconst range = a.range._getTransformedByInsertion( b.position, b.howMany, !b.shouldReceiveAttributes );\n\t\tconst result = range.map( r => {\n\t\t\treturn new AttributeOperation( r, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t\t} );\n\n\t\tif ( b.shouldReceiveAttributes ) {\n\t\t\t// `AttributeOperation#range` includes some newly inserted text.\n\t\t\t// The operation should also change the attribute of that text. An example:\n\t\t\t//\n\t\t\t// Bold should be applied on the following range:\n\t\t\t// <p>Fo[zb]ar</p>\n\t\t\t//\n\t\t\t// In meantime, new text is typed:\n\t\t\t// <p>Fozxxbar</p>\n\t\t\t//\n\t\t\t// Bold should be applied also on the new text:\n\t\t\t// <p>Fo[zxxb]ar</p>\n\t\t\t// <p>Fo<$text bold=\"true\">zxxb</$text>ar</p>\n\t\t\t//\n\t\t\t// There is a special case to consider here to consider.\n\t\t\t//\n\t\t\t// Consider setting an attribute with multiple possible values, for example `highlight`. The inserted text might\n\t\t\t// have already an attribute value applied and the `oldValue` property of the attribute operation might be wrong:\n\t\t\t//\n\t\t\t// Attribute `highlight=\"yellow\"` should be applied on the following range:\n\t\t\t// <p>Fo[zb]ar<p>\n\t\t\t//\n\t\t\t// In meantime, character `x` with `highlight=\"red\"` is typed:\n\t\t\t// <p>Fo[z<$text highlight=\"red\">x</$text>b]ar</p>\n\t\t\t//\n\t\t\t// In this case we cannot simply apply operation changing the attribute value from `null` to `\"yellow\"` for the whole range\n\t\t\t// because that would lead to an exception (`oldValue` is incorrect for `x`).\n\t\t\t//\n\t\t\t// We also cannot break the original range as this would mess up a scenario when there are multiple following\n\t\t\t// insert operations, because then only the first inserted character is included in those ranges:\n\t\t\t// <p>Fo[z][x][b]ar</p> --> <p>Fo[z][x]x[b]ar</p> --> <p>Fo[z][x]xx[b]ar</p>\n\t\t\t//\n\t\t\t// So, the attribute range needs be expanded, no matter what attributes are set on the inserted nodes:\n\t\t\t//\n\t\t\t// <p>Fo[z<$text highlight=\"red\">x</$text>b]ar</p> <--- Change from `null` to `yellow`, throwing an exception.\n\t\t\t//\n\t\t\t// But before that operation would be applied, we will add an additional attribute operation that will change\n\t\t\t// attributes on the inserted nodes in a way which would make the original operation correct:\n\t\t\t//\n\t\t\t// <p>Fo[z{<$text highlight=\"red\">}x</$text>b]ar</p> <--- Change range `{}` from `red` to `null`.\n\t\t\t// <p>Fo[zxb]ar</p> <--- Now change from `null` to `yellow` is completely fine.\n\t\t\t//\n\n\t\t\t// Generate complementary attribute operation. Be sure to add it before the original operation.\n\t\t\tconst op = _getComplementaryAttributeOperations( b, a.key, a.oldValue );\n\n\t\t\tif ( op ) {\n\t\t\t\tresult.unshift( op );\n\t\t\t}\n\t\t}\n\n\t\t// If nodes should not receive new attribute, we are done here.\n\t\treturn result;\n\t}\n\n\t// If insert operation is not expanding the attribute operation range, simply transform the range.\n\ta.range = a.range._getTransformedByInsertion( b.position, b.howMany, false )[ 0 ];\n\n\treturn [ a ];\n} );\n\n/**\n * Helper function for `AttributeOperation` x `InsertOperation` (and reverse) transformation.\n *\n * For given `insertOperation` it checks the inserted node if it has an attribute `key` set to a value different\n * than `newValue`. If so, it generates an `AttributeOperation` which changes the value of `key` attribute to `newValue`.\n *\n * @private\n * @param {module:engine/model/operation/insertoperation~InsertOperation} insertOperation\n * @param {String} key\n * @param {*} newValue\n * @returns {module:engine/model/operation/attributeoperation~AttributeOperation|null}\n */\nfunction _getComplementaryAttributeOperations( insertOperation, key, newValue ) {\n\tconst nodes = insertOperation.nodes;\n\n\t// At the beginning we store the attribute value from the first node.\n\tconst insertValue = nodes.getNode( 0 ).getAttribute( key );\n\n\tif ( insertValue == newValue ) {\n\t\treturn null;\n\t}\n\n\tconst range = new Range( insertOperation.position, insertOperation.position.getShiftedBy( insertOperation.howMany ) );\n\n\treturn new AttributeOperation( range, key, insertValue, newValue, 0 );\n}\n\nsetTransformation( AttributeOperation, MergeOperation, ( a, b ) => {\n\tconst ranges = [];\n\n\t// Case 1:\n\t//\n\t// Attribute change on the merged element. In this case, the merged element was moved to the graveyard.\n\t// An additional attribute operation that will change the (re)moved element needs to be generated.\n\t//\n\tif ( a.range.start.hasSameParentAs( b.deletionPosition ) ) {\n\t\tif ( a.range.containsPosition( b.deletionPosition ) || a.range.start.isEqual( b.deletionPosition ) ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.graveyardPosition, 1 ) );\n\t\t}\n\t}\n\n\tconst range = a.range._getTransformedByMergeOperation( b );\n\n\t// Do not add empty (collapsed) ranges to the result. `range` may be collapsed if it contained only the merged element.\n\tif ( !range.isCollapsed ) {\n\t\tranges.push( range );\n\t}\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => {\n\t\treturn new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion );\n\t} );\n} );\n\nsetTransformation( AttributeOperation, MoveOperation, ( a, b ) => {\n\tconst ranges = _breakRangeByMoveOperation( a.range, b );\n\n\t// Create `AttributeOperation`s out of the ranges.\n\treturn ranges.map( range => new AttributeOperation( range, a.key, a.oldValue, a.newValue, a.baseVersion ) );\n} );\n\n// Helper function for `AttributeOperation` x `MoveOperation` transformation.\n//\n// Takes the passed `range` and transforms it by move operation `moveOp` in a specific way. Only top-level nodes of `range`\n// are considered to be in the range. If move operation moves nodes deep from inside of the range, those nodes won't\n// be included in the result. In other words, top-level nodes of the ranges from the result are exactly the same as\n// top-level nodes of the original `range`.\n//\n// This is important for `AttributeOperation` because, for its range, it changes only the top-level nodes. So we need to\n// track only how those nodes have been affected by `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/operation/moveoperation~MoveOperation} moveOp\n// @returns {Array.<module:engine/model/range~Range>}\nfunction _breakRangeByMoveOperation( range, moveOp ) {\n\tconst moveRange = Range._createFromPositionAndShift( moveOp.sourcePosition, moveOp.howMany );\n\n\t// We are transforming `range` (original range) by `moveRange` (range moved by move operation). As usual when it comes to\n\t// transforming a ranges, we may have a common part of the ranges and we may have a difference part (zero to two ranges).\n\tlet common = null;\n\tlet difference = [];\n\n\t// Let's compare the ranges.\n\tif ( moveRange.containsRange( range, true ) ) {\n\t\t// If the whole original range is moved, treat it whole as a common part. There's also no difference part.\n\t\tcommon = range;\n\t} else if ( range.start.hasSameParentAs( moveRange.start ) ) {\n\t\t// If the ranges are \"on the same level\" (in the same parent) then move operation may move exactly those nodes\n\t\t// that are changed by the attribute operation. In this case we get common part and difference part in the usual way.\n\t\tdifference = range.getDifference( moveRange );\n\t\tcommon = range.getIntersection( moveRange );\n\t} else {\n\t\t// In any other situation we assume that original range is different than move range, that is that move operation\n\t\t// moves other nodes that attribute operation change. Even if the moved range is deep inside in the original range.\n\t\t//\n\t\t// Note that this is different than in `.getIntersection` (we would get a common part in that case) and different\n\t\t// than `.getDifference` (we would get two ranges).\n\t\tdifference = [ range ];\n\t}\n\n\tconst result = [];\n\n\t// The default behaviour of `_getTransformedByMove` might get wrong results for difference part, though, so\n\t// we do it by hand.\n\tfor ( let diff of difference ) {\n\t\t// First, transform the range by removing moved nodes. Since this is a difference, this is safe, `null` won't be returned\n\t\t// as the range is different than the moved range.\n\t\tdiff = diff._getTransformedByDeletion( moveOp.sourcePosition, moveOp.howMany );\n\n\t\t// Transform also `targetPosition`.\n\t\tconst targetPosition = moveOp.getMovedRangeStart();\n\n\t\t// Spread the range only if moved nodes are inserted only between the top-level nodes of the `diff` range.\n\t\tconst spread = diff.start.hasSameParentAs( targetPosition );\n\n\t\t// Transform by insertion of moved nodes.\n\t\tdiff = diff._getTransformedByInsertion( targetPosition, moveOp.howMany, spread );\n\n\t\tresult.push( ...diff );\n\t}\n\n\t// Common part can be simply transformed by the move operation. This is because move operation will not target to\n\t// that common part (the operation would have to target inside its own moved range).\n\tif ( common ) {\n\t\tresult.push(\n\t\t\tcommon._getTransformedByMove( moveOp.sourcePosition, moveOp.targetPosition, moveOp.howMany, false )[ 0 ]\n\t\t);\n\t}\n\n\treturn result;\n}\n\nsetTransformation( AttributeOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Split node is the last node in `AttributeOperation#range`.\n\t// `AttributeOperation#range` needs to be expanded to include the new (split) node.\n\t//\n\t// Attribute `type` to be changed to `numbered` but the `listItem` is split.\n\t// <listItem type=\"bulleted\">foobar</listItem>\n\t//\n\t// After split:\n\t// <listItem type=\"bulleted\">foo</listItem><listItem type=\"bulleted\">bar</listItem>\n\t//\n\t// After attribute change:\n\t// <listItem type=\"numbered\">foo</listItem><listItem type=\"numbered\">foo</listItem>\n\t//\n\tif ( a.range.end.isEqual( b.insertionPosition ) ) {\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.range.end.offset++;\n\t\t}\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split position is inside `AttributeOperation#range`, at the same level, so the nodes to change are\n\t// not going to make a flat range.\n\t//\n\t// Content with range-to-change and split position:\n\t// <p>Fo[zb^a]r</p>\n\t//\n\t// After split:\n\t// <p>Fozb</p><p>ar</p>\n\t//\n\t// Make two separate ranges containing all nodes to change:\n\t// <p>Fo[zb]</p><p>[a]r</p>\n\t//\n\tif ( a.range.start.hasSameParentAs( b.splitPosition ) && a.range.containsPosition( b.splitPosition ) ) {\n\t\tconst secondPart = a.clone();\n\n\t\tsecondPart.range = new Range(\n\t\t\tb.moveTargetPosition.clone(),\n\t\t\ta.range.end._getCombined( b.splitPosition, b.moveTargetPosition )\n\t\t);\n\n\t\ta.range.end = b.splitPosition.clone();\n\t\ta.range.end.stickiness = 'toPrevious';\n\n\t\treturn [ a, secondPart ];\n\t}\n\n\t// The default case.\n\t//\n\ta.range = a.range._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, AttributeOperation, ( a, b ) => {\n\tconst result = [ a ];\n\n\t// Case 1:\n\t//\n\t// The attribute operation range includes the position where nodes were inserted.\n\t// There are two possible scenarios: the inserted nodes were text and they should receive attributes or\n\t// the inserted nodes were elements and they should not receive attributes.\n\t//\n\t// This is a mirror scenario to the one described in `AttributeOperation` x `InsertOperation` transformation,\n\t// although this case is a little less complicated. In this case we simply need to change attributes of the\n\t// inserted nodes and that's it.\n\t//\n\tif ( a.shouldReceiveAttributes && a.position.hasSameParentAs( b.range.start ) && b.range.containsPosition( a.position ) ) {\n\t\tconst op = _getComplementaryAttributeOperations( a, b.key, b.newValue );\n\n\t\tif ( op ) {\n\t\t\tresult.push( op );\n\t\t}\n\t}\n\n\t// The default case is: do nothing.\n\t// `AttributeOperation` does not change the model tree structure so `InsertOperation` does not need to be changed.\n\t//\n\treturn result;\n} );\n\nsetTransformation( InsertOperation, InsertOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Two insert operations insert nodes at the same position. Since they are the same, it needs to be decided\n\t// what will be the order of inserted nodes. However, there is no additional information to help in that\n\t// decision. Also, when `b` will be transformed by `a`, the same order must be maintained.\n\t//\n\t// To achieve that, we will check if the operation is strong.\n\t// If it is, it won't get transformed. If it is not, it will be moved.\n\t//\n\tif ( a.position.isEqual( b.position ) && context.aIsStrong ) {\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MoveOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, SplitOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( InsertOperation, MergeOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MarkerOperation, InsertOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByInsertOperation( b )[ 0 ];\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MarkerOperation, ( a, b, context ) => {\n\tif ( a.name == b.name ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldRange = b.newRange ? b.newRange.clone() : null;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MergeOperation, ( a, b ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedByMergeOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\ta.newRange = a.newRange._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, MoveOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = Range._createFromRanges( a.oldRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\n\t\t\tif ( context.abRelation.side == 'left' && b.targetPosition.isEqual( a.newRange.start ) ) {\n\t\t\t\ta.newRange.start.path = context.abRelation.path;\n\t\t\t\ta.newRange.end = aNewRange.end;\n\n\t\t\t\treturn [ a ];\n\t\t\t} else if ( context.abRelation.side == 'right' && b.targetPosition.isEqual( a.newRange.end ) ) {\n\t\t\t\ta.newRange.start = aNewRange.start;\n\t\t\t\ta.newRange.end.path = context.abRelation.path;\n\n\t\t\t\treturn [ a ];\n\t\t\t}\n\t\t}\n\n\t\ta.newRange = Range._createFromRanges( a.newRange._getTransformedByMoveOperation( b ) );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MarkerOperation, SplitOperation, ( a, b, context ) => {\n\tif ( a.oldRange ) {\n\t\ta.oldRange = a.oldRange._getTransformedBySplitOperation( b );\n\t}\n\n\tif ( a.newRange ) {\n\t\tif ( context.abRelation ) {\n\t\t\tconst aNewRange = a.newRange._getTransformedBySplitOperation( b );\n\n\t\t\tif ( a.newRange.start.isEqual( b.splitPosition ) && context.abRelation.wasStartBeforeMergedElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.insertionPosition );\n\t\t\t} else if ( a.newRange.start.isEqual( b.splitPosition ) && !context.abRelation.wasInLeftElement ) {\n\t\t\t\ta.newRange.start = Position._createAt( b.moveTargetPosition );\n\t\t\t}\n\n\t\t\tif ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasInRightElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.moveTargetPosition );\n\t\t\t} else if ( a.newRange.end.isEqual( b.splitPosition ) && context.abRelation.wasEndBeforeMergedElement ) {\n\t\t\t\ta.newRange.end = Position._createAt( b.insertionPosition );\n\t\t\t} else {\n\t\t\t\ta.newRange.end = aNewRange.end;\n\t\t\t}\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\ta.newRange = a.newRange._getTransformedBySplitOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MergeOperation, InsertOperation, ( a, b ) => {\n\tif ( a.sourcePosition.hasSameParentAs( b.position ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByInsertOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Same merge operations.\n\t//\n\t// Both operations have same source and target positions. So the element already got merged and there is\n\t// theoretically nothing to do.\n\t//\n\tif ( a.sourcePosition.isEqual( b.sourcePosition ) && a.targetPosition.isEqual( b.targetPosition ) ) {\n\t\t// There are two ways that we can provide a do-nothing operation.\n\t\t//\n\t\t// First is simply a NoOperation instance. We will use it if `b` operation was not undone.\n\t\t//\n\t\t// Second is a merge operation that has the source operation in the merged element - in the graveyard -\n\t\t// same target position and `howMany` equal to `0`. So it is basically merging an empty element from graveyard\n\t\t// which is almost the same as NoOperation.\n\t\t//\n\t\t// This way the merge operation can be later transformed by split operation\n\t\t// to provide correct undo. This will be used if `b` operation was undone (only then it is correct).\n\t\t//\n\t\tif ( !context.bWasUndone ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\tconst path = b.graveyardPosition.path.slice();\n\t\t\tpath.push( 0 );\n\n\t\t\ta.sourcePosition = new Position( b.graveyardPosition.root, path );\n\t\t\ta.howMany = 0;\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same merge source position but different target position.\n\t//\n\t// This can happen during collaboration. For example, if one client merged a paragraph to the previous paragraph\n\t// and the other person removed that paragraph and merged the same paragraph to something before:\n\t//\n\t// Client A:\n\t// <p>Foo</p><p>Bar</p><p>[]Xyz</p>\n\t// <p>Foo</p><p>BarXyz</p>\n\t//\n\t// Client B:\n\t// <p>Foo</p>[<p>Bar</p>]<p>Xyz</p>\n\t// <p>Foo</p><p>[]Xyz</p>\n\t// <p>FooXyz</p>\n\t//\n\t// In this case we need to decide where finally \"Xyz\" will land:\n\t//\n\t// <p>FooXyz</p> graveyard: <p>Bar</p>\n\t// <p>Foo</p> graveyard: <p>BarXyz</p>\n\t//\n\t// Let's move it in a way so that a merge operation that does not target to graveyard is more important so that\n\t// nodes does not end up in the graveyard. It makes sense. Both for Client A and for Client B \"Xyz\" finally did not\n\t// end up in the graveyard (see above).\n\t//\n\t// If neither or both operations point to graveyard, then let `aIsStrong` decide.\n\t//\n\tif (\n\t\ta.sourcePosition.isEqual( b.sourcePosition ) && !a.targetPosition.isEqual( b.targetPosition ) &&\n\t\t!context.bWasUndone && context.abRelation != 'splitAtSource'\n\t) {\n\t\tconst aToGraveyard = a.targetPosition.root.rootName == '$graveyard';\n\t\tconst bToGraveyard = b.targetPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aToGraveyard && !bToGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bToGraveyard && !aToGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst sourcePosition = b.targetPosition._getTransformedByMergeOperation( b );\n\t\t\tconst targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\treturn [ new MoveOperation( sourcePosition, a.howMany, targetPosition, 0 ) ];\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMergeOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t// Handle positions in graveyard.\n\t// If graveyard positions are same and `a` operation is strong - do not transform.\n\tif ( !a.graveyardPosition.isEqual( b.graveyardPosition ) || !context.aIsStrong ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, MoveOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// The element to merge got removed.\n\t//\n\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t// from technical point of view. However, if the element was removed, the intention of the user deleting it\n\t// was to have it all deleted, together with its children. From user experience point of view, moving back the\n\t// removed nodes might be unexpected. This means that in this scenario we will block the merging.\n\t//\n\t// The exception of this rule would be if the remove operation was later undone.\n\t//\n\tconst removedRange = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\tif ( a.deletionPosition.hasSameParentAs( b.sourcePosition ) && removedRange.containsPosition( a.sourcePosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\tif ( a.sourcePosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedByMoveOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedByMoveOperation( b );\n\n\t// `MergeOperation` graveyard position is like `MoveOperation` target position. It is a position where element(s) will\n\t// be moved. Like in other similar cases, we need to consider the scenario when those positions are same.\n\t// Here, we will treat `MergeOperation` like it is always strong (see `InsertOperation` x `InsertOperation` for comparison).\n\t// This means that we won't transform graveyard position if it is equal to move operation target position.\n\tif ( !a.graveyardPosition.isEqual( b.targetPosition ) ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MergeOperation, SplitOperation, ( a, b, context ) => {\n\tif ( b.graveyardPosition ) {\n\t\t// If `b` operation defines graveyard position, a node from graveyard will be moved. This means that we need to\n\t\t// transform `a.graveyardPosition` accordingly.\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByDeletion( b.graveyardPosition, 1 );\n\n\t\t// This is a scenario foreseen in `MergeOperation` x `MergeOperation`, with two identical merge operations.\n\t\t//\n\t\t// So, there was `MergeOperation` x `MergeOperation` transformation earlier. Now, `a` is a merge operation which\n\t\t// source position is in graveyard. Interestingly, split operation wants to use the node to be merged by `a`. This\n\t\t// means that `b` is undoing that merge operation from earlier, which caused `a` to be in graveyard.\n\t\t//\n\t\t// If that's the case, at this point, we will only \"fix\" `a.howMany`. It was earlier set to `0` in\n\t\t// `MergeOperation` x `MergeOperation` transformation. Later transformations in this function will change other\n\t\t// properties.\n\t\t//\n\t\tif ( a.deletionPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\ta.howMany = b.howMany;\n\t\t}\n\t}\n\n\t// Case 1:\n\t//\n\t// Merge operation moves nodes to the place where split happens.\n\t// This is a classic situation when there are two paragraphs, and there is a split (enter) after the first\n\t// paragraph and there is a merge (delete) at the beginning of the second paragraph:\n\t//\n\t// <p>Foo{}</p><p>[]Bar</p>.\n\t//\n\t// Split is after `Foo`, while merge is from `Bar` to the end of `Foo`.\n\t//\n\t// State after split:\n\t// <p>Foo</p><p></p><p>Bar</p>\n\t//\n\t// Now, `Bar` should be merged to the new paragraph:\n\t// <p>Foo</p><p>Bar</p>\n\t//\n\t// Instead of merging it to the original paragraph:\n\t// <p>FooBar</p><p></p>\n\t//\n\t// This means that `targetPosition` needs to be transformed. This is the default case though.\n\t// For example, if the split would be after `F`, `targetPosition` should also be transformed.\n\t//\n\t// There are three exceptions, though, when we want to keep `targetPosition` as it was.\n\t//\n\t// First exception is when the merge target position is inside an element (not at the end, as usual). This\n\t// happens when the merge operation earlier was transformed by \"the same\" merge operation. If merge operation\n\t// targets inside the element we want to keep the original target position (and not transform it) because\n\t// we have additional context telling us that we want to merge to the original element. We can check if the\n\t// merge operation points inside element by checking what is `SplitOperation#howMany`. Since merge target position\n\t// is same as split position, if `howMany` is non-zero, it means that the merge target position is inside an element.\n\t//\n\t// Second exception is when the element to merge is in the graveyard and split operation uses it. In that case\n\t// if target position would be transformed, the merge operation would target at the source position:\n\t//\n\t// root: <p>Foo</p>\t\t\t\tgraveyard: <p></p>\n\t//\n\t// SplitOperation: root [ 0, 3 ] using graveyard [ 0 ] (howMany = 0)\n\t// MergeOperation: graveyard [ 0, 0 ] -> root [ 0, 3 ] (howMany = 0)\n\t//\n\t// Since split operation moves the graveyard node back to the root, the merge operation source position changes.\n\t// We would like to merge from the empty <p> to the \"Foo\" <p>:\n\t//\n\t// root: <p>Foo</p><p></p>\t\t\tgraveyard:\n\t//\n\t// MergeOperation#sourcePosition = root [ 1, 0 ]\n\t//\n\t// If `targetPosition` is transformed, it would become root [ 1, 0 ] as well. It has to be kept as it was.\n\t//\n\t// Third exception is connected with relations. If this happens during undo and we have explicit information\n\t// that target position has not been affected by the operation which is undone by this split then this split should\n\t// not move the target position either.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) ) {\n\t\tconst mergeInside = b.howMany != 0;\n\t\tconst mergeSplittingElement = b.graveyardPosition && a.deletionPosition.isEqual( b.graveyardPosition );\n\n\t\tif ( mergeInside || mergeSplittingElement || context.abRelation == 'mergeTargetNotMoved' ) {\n\t\t\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Merge source is at the same position as split position. This sometimes happen, mostly during undo.\n\t// The decision here is mostly to choose whether merge source position should stay where it is (so it will be at the end of the\n\t// split element) or should be move to the beginning of the new element.\n\t//\n\tif ( a.sourcePosition.isEqual( b.splitPosition ) ) {\n\t\t// Use context to check if `SplitOperation` is not undoing a merge operation, that didn't change the `a` operation.\n\t\t// This scenario happens the undone merge operation moved nodes at the source position of `a` operation.\n\t\t// In that case `a` operation source position should stay where it is.\n\t\tif ( context.abRelation == 'mergeSourceNotMoved' ) {\n\t\t\ta.howMany = 0;\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\n\t\t// This merge operation might have been earlier transformed by a merge operation which both merged the same element.\n\t\t// See that case in `MergeOperation` x `MergeOperation` transformation. In that scenario, if the merge operation has been undone,\n\t\t// the special case is not applied.\n\t\t//\n\t\t// Now, the merge operation is transformed by the split which has undone that previous merge operation.\n\t\t// So now we are fixing situation which was skipped in `MergeOperation` x `MergeOperation` case.\n\t\t//\n\t\tif ( context.abRelation == 'mergeSameElement' || a.sourcePosition.offset > 0 ) {\n\t\t\ta.sourcePosition = b.moveTargetPosition.clone();\n\t\t\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.sourcePosition.hasSameParentAs( b.splitPosition ) ) {\n\t\ta.howMany = b.splitPosition.offset;\n\t}\n\n\ta.sourcePosition = a.sourcePosition._getTransformedBySplitOperation( b );\n\ta.targetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( MoveOperation, InsertOperation, ( a, b ) => {\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByInsertOperation( b, false )[ 0 ];\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\n\t// See `InsertOperation` x `MoveOperation` transformation for details on this case.\n\t//\n\t// In summary, both operations point to the same place, so the order of nodes needs to be decided.\n\t// `MoveOperation` is considered weaker, so it is always transformed, unless there was a certain relation\n\t// between operations.\n\t//\n\tif ( !a.targetPosition.isEqual( b.position ) ) {\n\t\ta.targetPosition = a.targetPosition._getTransformedByInsertOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( MoveOperation, MoveOperation, ( a, b, context ) => {\n\t//\n\t// Setting and evaluating some variables that will be used in special cases and default algorithm.\n\t//\n\t// Create ranges from `MoveOperations` properties.\n\tconst rangeA = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst rangeB = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\t// Assign `context.aIsStrong` to a different variable, because the value may change during execution of\n\t// this algorithm and we do not want to override original `context.aIsStrong` that will be used in later transformations.\n\tlet aIsStrong = context.aIsStrong;\n\n\t// This will be used to decide the order of nodes if both operations target at the same position.\n\t// By default, use strong/weak operation mechanism.\n\tlet insertBefore = !context.aIsStrong;\n\n\t// If the relation is set, then use it to decide nodes order.\n\tif ( context.abRelation == 'insertBefore' || context.baRelation == 'insertAfter' ) {\n\t\tinsertBefore = true;\n\t} else if ( context.abRelation == 'insertAfter' || context.baRelation == 'insertBefore' ) {\n\t\tinsertBefore = false;\n\t}\n\n\t// `a.targetPosition` could be affected by the `b` operation. We will transform it.\n\tlet newTargetPosition;\n\n\tif ( a.targetPosition.isEqual( b.targetPosition ) && insertBefore ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByDeletion(\n\t\t\tb.sourcePosition,\n\t\t\tb.howMany\n\t\t);\n\t} else {\n\t\tnewTargetPosition = a.targetPosition._getTransformedByMove(\n\t\t\tb.sourcePosition,\n\t\t\tb.targetPosition,\n\t\t\tb.howMany\n\t\t);\n\t}\n\n\t//\n\t// Special case #1 + mirror.\n\t//\n\t// Special case when both move operations' target positions are inside nodes that are\n\t// being moved by the other move operation. So in other words, we move ranges into inside of each other.\n\t// This case can't be solved reasonably (on the other hand, it should not happen often).\n\tif ( _moveTargetIntoMovedRange( a, b ) && _moveTargetIntoMovedRange( b, a ) ) {\n\t\t// Instead of transforming operation, we return a reverse of the operation that we transform by.\n\t\t// So when the results of this \"transformation\" will be applied, `b` MoveOperation will get reversed.\n\t\treturn [ b.getReversed() ];\n\t}\n\t//\n\t// End of special case #1.\n\t//\n\n\t//\n\t// Special case #2.\n\t//\n\t// Check if `b` operation targets inside `rangeA`.\n\tconst bTargetsToA = rangeA.containsPosition( b.targetPosition );\n\n\t// If `b` targets to `rangeA` and `rangeA` contains `rangeB`, `b` operation has no influence on `a` operation.\n\t// You might say that operation `b` is captured inside operation `a`.\n\tif ( bTargetsToA && rangeA.containsRange( rangeB, true ) ) {\n\t\t// There is a mini-special case here, where `rangeB` is on other level than `rangeA`. That's why\n\t\t// we need to transform `a` operation anyway.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\n\t//\n\t// Special case #2 mirror.\n\t//\n\tconst aTargetsToB = rangeB.containsPosition( a.targetPosition );\n\n\tif ( aTargetsToB && rangeB.containsRange( rangeA, true ) ) {\n\t\t// `a` operation is \"moved together\" with `b` operation.\n\t\t// Here, just move `rangeA` \"inside\" `rangeB`.\n\t\trangeA.start = rangeA.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\trangeA.end = rangeA.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #2.\n\t//\n\n\t//\n\t// Special case #3 + mirror.\n\t//\n\t// `rangeA` has a node which is an ancestor of `rangeB`. In other words, `rangeB` is inside `rangeA`\n\t// but not on the same tree level. In such case ranges have common part but we have to treat it\n\t// differently, because in such case those ranges are not really conflicting and should be treated like\n\t// two separate ranges. Also we have to discard two difference parts.\n\tconst aCompB = compareArrays( a.sourcePosition.getParentPath(), b.sourcePosition.getParentPath() );\n\n\tif ( aCompB == 'prefix' || aCompB == 'extension' ) {\n\t\t// Transform `rangeA` by `b` operation and make operation out of it, and that's all.\n\t\t// Note that this is a simplified version of default case, but here we treat the common part (whole `rangeA`)\n\t\t// like a one difference part.\n\t\trangeA.start = rangeA.start._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\t\trangeA.end = rangeA.end._getTransformedByMove( b.sourcePosition, b.targetPosition, b.howMany );\n\n\t\treturn _makeMoveOperationsFromRanges( [ rangeA ], newTargetPosition );\n\t}\n\t//\n\t// End of special case #3.\n\t//\n\n\t//\n\t// Default case - ranges are on the same level or are not connected with each other.\n\t//\n\t// Modifier for default case.\n\t// Modifies `aIsStrong` flag in certain conditions.\n\t//\n\t// If only one of operations is a remove operation, we force remove operation to be the \"stronger\" one\n\t// to provide more expected results.\n\tif ( a.type == 'remove' && b.type != 'remove' && !context.aWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = true;\n\t} else if ( a.type != 'remove' && b.type == 'remove' && !context.bWasUndone && !context.forceWeakRemove ) {\n\t\taIsStrong = false;\n\t}\n\n\t// Handle operation's source ranges - check how `rangeA` is affected by `b` operation.\n\t// This will aggregate transformed ranges.\n\tconst ranges = [];\n\n\t// Get the \"difference part\" of `a` operation source range.\n\t// This is an array with one or two ranges. Two ranges if `rangeB` is inside `rangeA`.\n\tconst difference = rangeA.getDifference( rangeB );\n\n\tfor ( const range of difference ) {\n\t\t// Transform those ranges by `b` operation. For example if `b` moved range from before those ranges, fix those ranges.\n\t\trange.start = range.start._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\trange.end = range.end._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\n\t\t// If `b` operation targets into `rangeA` on the same level, spread `rangeA` into two ranges.\n\t\tconst shouldSpread = compareArrays( range.start.getParentPath(), b.getMovedRangeStart().getParentPath() ) == 'same';\n\t\tconst newRanges = range._getTransformedByInsertion( b.getMovedRangeStart(), b.howMany, shouldSpread );\n\n\t\tranges.push( ...newRanges );\n\t}\n\n\t// Then, we have to manage the \"common part\" of both move ranges.\n\tconst common = rangeA.getIntersection( rangeB );\n\n\tif ( common !== null && aIsStrong ) {\n\t\t// Calculate the new position of that part of original range.\n\t\tcommon.start = common.start._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\t\tcommon.end = common.end._getCombined( b.sourcePosition, b.getMovedRangeStart() );\n\n\t\t// Take care of proper range order.\n\t\t//\n\t\t// Put `common` at appropriate place. Keep in mind that we are interested in original order.\n\t\t// Basically there are only three cases: there is zero, one or two difference ranges.\n\t\t//\n\t\t// If there is zero difference ranges, just push `common` in the array.\n\t\tif ( ranges.length === 0 ) {\n\t\t\tranges.push( common );\n\t\t}\n\t\t// If there is one difference range, we need to check whether common part was before it or after it.\n\t\telse if ( ranges.length == 1 ) {\n\t\t\tif ( rangeB.start.isBefore( rangeA.start ) || rangeB.start.isEqual( rangeA.start ) ) {\n\t\t\t\tranges.unshift( common );\n\t\t\t} else {\n\t\t\t\tranges.push( common );\n\t\t\t}\n\t\t}\n\t\t// If there are more ranges (which means two), put common part between them. This is the only scenario\n\t\t// where there could be two difference ranges so we don't have to make any comparisons.\n\t\telse {\n\t\t\tranges.splice( 1, 0, common );\n\t\t}\n\t}\n\n\tif ( ranges.length === 0 ) {\n\t\t// If there are no \"source ranges\", nothing should be changed.\n\t\t// Note that this can happen only if `aIsStrong == false` and `rangeA.isEqual( rangeB )`.\n\t\treturn [ new NoOperation( a.baseVersion ) ];\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, SplitOperation, ( a, b, context ) => {\n\tlet newTargetPosition = a.targetPosition.clone();\n\n\t// Do not transform if target position is same as split insertion position and this split comes from undo.\n\t// This should be done on relations but it is too much work for now as it would require relations working in collaboration.\n\t// We need to make a decision how we will resolve such conflict and this is less harmful way.\n\tif ( !a.targetPosition.isEqual( b.insertionPosition ) || !b.graveyardPosition || context.abRelation == 'moveTargetAfter' ) {\n\t\tnewTargetPosition = a.targetPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 1:\n\t//\n\t// Last element in the moved range got split.\n\t//\n\t// In this case the default range transformation will not work correctly as the element created by\n\t// split operation would be outside the range. The range to move needs to be fixed manually.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( moveRange.end.isEqual( b.insertionPosition ) ) {\n\t\t// Do it only if this is a \"natural\" split, not a one that comes from undo.\n\t\t// If this is undo split, only `targetPosition` needs to be changed (if the move is a remove).\n\t\tif ( !b.graveyardPosition ) {\n\t\t\ta.howMany++;\n\t\t}\n\n\t\ta.targetPosition = newTargetPosition;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 2:\n\t//\n\t// Split happened between the moved nodes. In this case two ranges to move need to be generated.\n\t//\n\t// Characters `ozba` are moved to the end of paragraph `Xyz` but split happened.\n\t// <p>F[oz|ba]r</p><p>Xyz</p>\n\t//\n\t// After split:\n\t// <p>F[oz</p><p>ba]r</p><p>Xyz</p>\n\t//\n\t// Correct ranges:\n\t// <p>F[oz]</p><p>[ba]r</p><p>Xyz</p>\n\t//\n\t// After move:\n\t// <p>F</p><p>r</p><p>Xyzozba</p>\n\t//\n\tif ( moveRange.start.hasSameParentAs( b.splitPosition ) && moveRange.containsPosition( b.splitPosition ) ) {\n\t\tlet rightRange = new Range( b.splitPosition, moveRange.end );\n\t\trightRange = rightRange._getTransformedBySplitOperation( b );\n\n\t\tconst ranges = [\n\t\t\tnew Range( moveRange.start, b.splitPosition ),\n\t\t\trightRange\n\t\t];\n\n\t\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n\t}\n\n\t// Case 3:\n\t//\n\t// Move operation targets at the split position. We need to decide if the nodes should be inserted\n\t// at the end of the split element or at the beginning of the new element.\n\t//\n\tif ( a.targetPosition.isEqual( b.splitPosition ) && context.abRelation == 'insertAtSource' ) {\n\t\tnewTargetPosition = b.moveTargetPosition;\n\t}\n\n\t// Case 4:\n\t//\n\t// Move operation targets just after the split element. We need to decide if the nodes should be inserted\n\t// between two parts of split element, or after the new element.\n\t//\n\t// Split at `|`, while move operation moves `<p>Xyz</p>` and targets at `^`:\n\t// <p>Foo|bar</p>^<p>baz</p>\n\t// <p>Foo</p>^<p>bar</p><p>baz</p> or <p>Foo</p><p>bar</p>^<p>baz</p>?\n\t//\n\t// If there is no contextual information between operations (for example, they come from collaborative\n\t// editing), we don't want to put some unrelated content (move) between parts of related content (split parts).\n\t// However, if the split is from undo, in the past, the moved content might be targeting between the\n\t// split parts, meaning that was exactly user's intention:\n\t//\n\t// <p>Foo</p>^<p>bar</p>\t\t<--- original situation, in \"past\".\n\t// <p>Foobar</p>^\t\t\t\t<--- after merge target position is transformed.\n\t// <p>Foo|bar</p>^\t\t\t\t<--- then the merge is undone, and split happens, which leads us to current situation.\n\t//\n\t// In this case it is pretty clear that the intention was to put new paragraph between those nodes,\n\t// so we need to transform accordingly. We can detect this scenario thanks to relations.\n\t//\n\tif ( a.targetPosition.isEqual( b.insertionPosition ) && context.abRelation == 'insertBetween' ) {\n\t\tnewTargetPosition = a.targetPosition;\n\t}\n\n\t// The default case.\n\t//\n\tconst transformed = moveRange._getTransformedBySplitOperation( b );\n\tconst ranges = [ transformed ];\n\n\t// Case 5:\n\t//\n\t// Moved range contains graveyard element used by split operation. Add extra move operation to the result.\n\t//\n\tif ( b.graveyardPosition ) {\n\t\tconst movesGraveyardElement = moveRange.start.isEqual( b.graveyardPosition ) || moveRange.containsPosition( b.graveyardPosition );\n\n\t\tif ( a.howMany > 1 && movesGraveyardElement && !context.aWasUndone ) {\n\t\t\tranges.push( Range._createFromPositionAndShift( b.insertionPosition, 1 ) );\n\t\t}\n\t}\n\n\treturn _makeMoveOperationsFromRanges( ranges, newTargetPosition );\n} );\n\nsetTransformation( MoveOperation, MergeOperation, ( a, b, context ) => {\n\tconst movedRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\n\tif ( b.deletionPosition.hasSameParentAs( a.sourcePosition ) && movedRange.containsPosition( b.sourcePosition ) ) {\n\t\tif ( a.type == 'remove' && !context.forceWeakRemove ) {\n\t\t\t// Case 1:\n\t\t\t//\n\t\t\t// The element to remove got merged.\n\t\t\t//\n\t\t\t// Merge operation does support merging elements which are not siblings. So it would not be a problem\n\t\t\t// from technical point of view. However, if the element was removed, the intention of the user\n\t\t\t// deleting it was to have it all deleted. From user experience point of view, moving back the\n\t\t\t// removed nodes might be unexpected. This means that in this scenario we will reverse merging and remove the element.\n\t\t\t//\n\t\t\tif ( !context.aWasUndone ) {\n\t\t\t\tconst results = [];\n\n\t\t\t\tlet gyMoveSource = b.graveyardPosition.clone();\n\t\t\t\tlet splitNodesMoveSource = b.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\tif ( a.howMany > 1 ) {\n\t\t\t\t\tresults.push( new MoveOperation( a.sourcePosition, a.howMany - 1, a.targetPosition, 0 ) );\n\n\t\t\t\t\tgyMoveSource = gyMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( a.sourcePosition, a.targetPosition, a.howMany - 1 );\n\t\t\t\t}\n\n\t\t\t\tconst gyMoveTarget = b.deletionPosition._getCombined( a.sourcePosition, a.targetPosition );\n\t\t\t\tconst gyMove = new MoveOperation( gyMoveSource, 1, gyMoveTarget, 0 );\n\n\t\t\t\tconst splitNodesMoveTargetPath = gyMove.getMovedRangeStart().path.slice();\n\t\t\t\tsplitNodesMoveTargetPath.push( 0 );\n\n\t\t\t\tconst splitNodesMoveTarget = new Position( gyMove.targetPosition.root, splitNodesMoveTargetPath );\n\t\t\t\tsplitNodesMoveSource = splitNodesMoveSource._getTransformedByMove( gyMoveSource, gyMoveTarget, 1 );\n\t\t\t\tconst splitNodesMove = new MoveOperation( splitNodesMoveSource, b.howMany, splitNodesMoveTarget, 0 );\n\n\t\t\t\tresults.push( gyMove );\n\t\t\t\tresults.push( splitNodesMove );\n\n\t\t\t\treturn results;\n\t\t\t}\n\t\t} else {\n\t\t\t// Case 2:\n\t\t\t//\n\t\t\t// The element to move got merged and it was the only element to move.\n\t\t\t// In this case just don't do anything, leave the node in the graveyard. Without special case\n\t\t\t// it would be a move operation that moves 0 nodes, so maybe it is better just to return no-op.\n\t\t\t//\n\t\t\tif ( a.howMany == 1 ) {\n\t\t\t\tif ( !context.bWasUndone ) {\n\t\t\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t\t\t} else {\n\t\t\t\t\ta.sourcePosition = b.graveyardPosition.clone();\n\t\t\t\t\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\t\t\t\t\treturn [ a ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// The default case.\n\t//\n\tconst moveRange = Range._createFromPositionAndShift( a.sourcePosition, a.howMany );\n\tconst transformed = moveRange._getTransformedByMergeOperation( b );\n\n\ta.sourcePosition = transformed.start;\n\ta.howMany = transformed.end.offset - transformed.start.offset;\n\ta.targetPosition = a.targetPosition._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RenameOperation, InsertOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MergeOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// Element to rename got merged, so it was moved to `b.graveyardPosition`.\n\t//\n\tif ( a.position.isEqual( b.deletionPosition ) ) {\n\t\ta.position = b.graveyardPosition.clone();\n\t\ta.position.stickiness = 'toNext';\n\n\t\treturn [ a ];\n\t}\n\n\ta.position = a.position._getTransformedByMergeOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, MoveOperation, ( a, b ) => {\n\ta.position = a.position._getTransformedByMoveOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, RenameOperation, ( a, b, context ) => {\n\tif ( a.position.isEqual( b.position ) ) {\n\t\tif ( context.aIsStrong ) {\n\t\t\ta.oldName = b.newName;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( RenameOperation, SplitOperation, ( a, b ) => {\n\t// Case 1:\n\t//\n\t// The element to rename has been split. In this case, the new element should be also renamed.\n\t//\n\t// User decides to change the paragraph to a list item:\n\t// <paragraph>Foobar</paragraph>\n\t//\n\t// However, in meantime, split happens:\n\t// <paragraph>Foo</paragraph><paragraph>bar</paragraph>\n\t//\n\t// As a result, rename both elements:\n\t// <listItem>Foo</listItem><listItem>bar</listItem>\n\t//\n\tconst renamePath = a.position.path;\n\tconst splitPath = b.splitPosition.getParentPath();\n\n\tif ( compareArrays( renamePath, splitPath ) == 'same' && !b.graveyardPosition ) {\n\t\tconst extraRename = new RenameOperation( a.position.getShiftedBy( 1 ), a.oldName, a.newName, 0 );\n\n\t\treturn [ a, extraRename ];\n\t}\n\n\t// The default case.\n\t//\n\ta.position = a.position._getTransformedBySplitOperation( b );\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( RootAttributeOperation, RootAttributeOperation, ( a, b, context ) => {\n\tif ( a.root === b.root && a.key === b.key ) {\n\t\tif ( !context.aIsStrong || a.newValue === b.newValue ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t} else {\n\t\t\ta.oldValue = b.newValue;\n\t\t}\n\t}\n\n\treturn [ a ];\n} );\n\n// -----------------------\n\nsetTransformation( SplitOperation, InsertOperation, ( a, b ) => {\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.position ) && a.splitPosition.offset < b.position.offset ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByInsertOperation( b );\n\ta.insertionPosition = a.insertionPosition._getTransformedByInsertOperation( b );\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MergeOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split element got merged. If two different elements were merged, clients will have different content.\n\t//\n\t// Example. Merge at `{}`, split at `[]`:\n\t// <heading>Foo</heading>{}<paragraph>B[]ar</paragraph>\n\t//\n\t// On merge side it will look like this:\n\t// <heading>FooB[]ar</heading>\n\t// <heading>FooB</heading><heading>ar</heading>\n\t//\n\t// On split side it will look like this:\n\t// <heading>Foo</heading>{}<paragraph>B</paragraph><paragraph>ar</paragraph>\n\t// <heading>FooB</heading><paragraph>ar</paragraph>\n\t//\n\t// Clearly, the second element is different for both clients.\n\t//\n\t// We could use the removed merge element from graveyard as a split element but then clients would have a different\n\t// model state (in graveyard), because the split side client would still have an element in graveyard (removed by merge).\n\t//\n\t// To overcome this, in `SplitOperation` x `MergeOperation` transformation we will add additional `SplitOperation`\n\t// in the graveyard, which will actually clone the merged-and-deleted element. Then, that cloned element will be\n\t// used for splitting. Example below.\n\t//\n\t// Original state:\n\t// <heading>Foo</heading>{}<paragraph>B[]ar</paragraph>\n\t//\n\t// Merge side client:\n\t//\n\t// After merge:\n\t// <heading>FooB[]ar</heading> graveyard: <paragraph></paragraph>\n\t//\n\t// Extra split:\n\t// <heading>FooB[]ar</heading> graveyard: <paragraph></paragraph><paragraph></paragraph>\n\t//\n\t// Use the \"cloned\" element from graveyard:\n\t// <heading>FooB</heading><paragraph>ar</paragraph> graveyard: <paragraph></paragraph>\n\t//\n\t// Split side client:\n\t//\n\t// After split:\n\t// <heading>Foo</heading>{}<paragraph>B</paragraph><paragraph>ar</paragraph>\n\t//\n\t// After merge:\n\t// <heading>FooB</heading><paragraph>ar</paragraph> graveyard: <paragraph></paragraph>\n\t//\n\t// This special case scenario only applies if the original split operation clones the split element.\n\t// If the original split operation has `graveyardPosition` set, it all doesn't have sense because split operation\n\t// knows exactly which element it should use. So there would be no original problem with different contents.\n\t//\n\t// Additionally, the special case applies only if the merge wasn't already undone.\n\t//\n\tif ( !a.graveyardPosition && !context.bWasUndone && a.splitPosition.hasSameParentAs( b.sourcePosition ) ) {\n\t\tconst splitPath = b.graveyardPosition.path.slice();\n\t\tsplitPath.push( 0 );\n\n\t\tconst splitPosition = new Position( b.graveyardPosition.root, splitPath );\n\t\tconst insertionPosition = SplitOperation.getInsertionPosition( new Position( b.graveyardPosition.root, splitPath ) );\n\n\t\tconst additionalSplit = new SplitOperation( splitPosition, 0, insertionPosition, null, 0 );\n\n\t\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t\ta.graveyardPosition = additionalSplit.insertionPosition.clone();\n\t\ta.graveyardPosition.stickiness = 'toNext';\n\n\t\treturn [ additionalSplit, a ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.deletionPosition ) && !a.splitPosition.isAfter( b.deletionPosition ) ) {\n\t\ta.howMany--;\n\t}\n\n\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) ) {\n\t\ta.howMany += b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedByMergeOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMergeOperation( b );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, MoveOperation, ( a, b, context ) => {\n\tconst rangeToMove = Range._createFromPositionAndShift( b.sourcePosition, b.howMany );\n\n\tif ( a.graveyardPosition ) {\n\t\t// Case 1:\n\t\t//\n\t\t// Split operation graveyard node was moved. In this case move operation is stronger. Since graveyard element\n\t\t// is already moved to the correct position, we need to only move the nodes after the split position.\n\t\t// This will be done by `MoveOperation` instead of `SplitOperation`.\n\t\t//\n\t\tconst gyElementMoved = rangeToMove.start.isEqual( a.graveyardPosition ) || rangeToMove.containsPosition( a.graveyardPosition );\n\n\t\tif ( !context.bWasUndone && gyElementMoved ) {\n\t\t\tconst sourcePosition = a.splitPosition._getTransformedByMoveOperation( b );\n\n\t\t\tconst newParentPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t\t\tconst newTargetPath = newParentPosition.path.slice();\n\t\t\tnewTargetPath.push( 0 );\n\n\t\t\tconst newTargetPosition = new Position( newParentPosition.root, newTargetPath );\n\t\t\tconst moveOp = new MoveOperation( sourcePosition, a.howMany, newTargetPosition, 0 );\n\n\t\t\treturn [ moveOp ];\n\t\t}\n\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedByMoveOperation( b );\n\t}\n\n\t// Case 2:\n\t//\n\t// Split is at a position where nodes were moved.\n\t//\n\t// This is a scenario described in `MoveOperation` x `SplitOperation` transformation but from the\n\t// \"split operation point of view\".\n\t//\n\tconst splitAtTarget = a.splitPosition.isEqual( b.targetPosition );\n\n\tif ( splitAtTarget && ( context.baRelation == 'insertAtSource' || context.abRelation == 'splitBefore' ) ) {\n\t\ta.howMany += b.howMany;\n\t\ta.splitPosition = a.splitPosition._getTransformedByDeletion( b.sourcePosition, b.howMany );\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\tif ( splitAtTarget && context.abRelation && context.abRelation.howMany ) {\n\t\tconst { howMany, offset } = context.abRelation;\n\n\t\ta.howMany += howMany;\n\t\ta.splitPosition = a.splitPosition.getShiftedBy( offset );\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 3:\n\t//\n\t// If the split position is inside the moved range, we need to shift the split position to a proper place.\n\t// The position cannot be moved together with moved range because that would result in splitting of an incorrect element.\n\t//\n\t// Characters `bc` should be moved to the second paragraph while split position is between them:\n\t// <paragraph>A[b|c]d</paragraph><paragraph>Xyz</paragraph>\n\t//\n\t// After move, new split position is incorrect:\n\t// <paragraph>Ad</paragraph><paragraph>Xb|cyz</paragraph>\n\t//\n\t// Correct split position:\n\t// <paragraph>A|d</paragraph><paragraph>Xbcyz</paragraph>\n\t//\n\t// After split:\n\t// <paragraph>A</paragraph><paragraph>d</paragraph><paragraph>Xbcyz</paragraph>\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && rangeToMove.containsPosition( a.splitPosition ) ) {\n\t\tconst howManyRemoved = b.howMany - ( a.splitPosition.offset - b.sourcePosition.offset );\n\t\ta.howMany -= howManyRemoved;\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\n\t\ta.splitPosition = b.sourcePosition.clone();\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\t\treturn [ a ];\n\t}\n\n\t// The default case.\n\t// Don't change `howMany` if move operation does not really move anything.\n\t//\n\tif ( !b.sourcePosition.isEqual( b.targetPosition ) ) {\n\t\tif ( a.splitPosition.hasSameParentAs( b.sourcePosition ) && a.splitPosition.offset <= b.sourcePosition.offset ) {\n\t\t\ta.howMany -= b.howMany;\n\t\t}\n\n\t\tif ( a.splitPosition.hasSameParentAs( b.targetPosition ) && a.splitPosition.offset < b.targetPosition.offset ) {\n\t\t\ta.howMany += b.howMany;\n\t\t}\n\t}\n\n\t// Change position stickiness to force a correct transformation.\n\ta.splitPosition.stickiness = 'toNone';\n\ta.splitPosition = a.splitPosition._getTransformedByMoveOperation( b );\n\ta.splitPosition.stickiness = 'toNext';\n\n\tif ( a.graveyardPosition ) {\n\t\ta.insertionPosition = a.insertionPosition._getTransformedByMoveOperation( b );\n\t} else {\n\t\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\t}\n\n\treturn [ a ];\n} );\n\nsetTransformation( SplitOperation, SplitOperation, ( a, b, context ) => {\n\t// Case 1:\n\t//\n\t// Split at the same position.\n\t//\n\t// If there already was a split at the same position as in `a` operation, it means that the intention\n\t// conveyed by `a` operation has already been fulfilled and `a` should not do anything (to avoid double split).\n\t//\n\t// However, there is a difference if these are new splits or splits created by undo. These have different\n\t// intentions. Also splits moving back different elements from graveyard have different intentions. They\n\t// are just different operations.\n\t//\n\t// So we cancel split operation only if it was really identical.\n\t//\n\t// Also, there is additional case, where split operations aren't identical and should not be cancelled, however the\n\t// default transformation is incorrect too.\n\t//\n\tif ( a.splitPosition.isEqual( b.splitPosition ) ) {\n\t\tif ( !a.graveyardPosition && !b.graveyardPosition ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\n\t\t// Use context to know that the `a.splitPosition` should stay where it is.\n\t\t// This happens during undo when first a merge operation moved nodes to `a.splitPosition` and now `b` operation undoes that merge.\n\t\tif ( context.abRelation == 'splitBefore' ) {\n\t\t\t// Since split is at the same position, there are no nodes left to split.\n\t\t\ta.howMany = 0;\n\n\t\t\t// Note: there was `if ( a.graveyardPosition )` here but it was uncovered in tests and I couldn't find any scenarios for now.\n\t\t\t// That would have to be a `SplitOperation` that didn't come from undo but is transformed by operations that were undone.\n\t\t\t// It could happen if `context` is enabled in collaboration.\n\t\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\n\t\t\treturn [ a ];\n\t\t}\n\t}\n\n\t// Case 2:\n\t//\n\t// Same node is using to split different elements. This happens in undo when previously same element was merged to\n\t// two different elements. This is described in `MergeOperation` x `MergeOperation` transformation.\n\t//\n\t// In this case we will follow the same logic. We will assume that `insertionPosition` is same for both\n\t// split operations. This might not always be true but in the real cases that were experienced it was. After all,\n\t// if these splits are reverses of merge operations that were merging the same element, then the `insertionPosition`\n\t// should be same for both of those splits.\n\t//\n\t// Again, we will decide which operation is stronger by checking if split happens in graveyard or in non-graveyard root.\n\t//\n\tif ( a.graveyardPosition && b.graveyardPosition && a.graveyardPosition.isEqual( b.graveyardPosition ) ) {\n\t\tconst aInGraveyard = a.splitPosition.root.rootName == '$graveyard';\n\t\tconst bInGraveyard = b.splitPosition.root.rootName == '$graveyard';\n\n\t\t// If `aIsWeak` it means that `a` points to graveyard while `b` doesn't. Don't move nodes then.\n\t\tconst aIsWeak = aInGraveyard && !bInGraveyard;\n\n\t\t// If `bIsWeak` it means that `b` points to graveyard while `a` doesn't. Force moving nodes then.\n\t\tconst bIsWeak = bInGraveyard && !aInGraveyard;\n\n\t\t// Force move if `b` is weak or neither operation is weak but `a` is stronger through `context.aIsStrong`.\n\t\tconst forceMove = bIsWeak || ( !aIsWeak && context.aIsStrong );\n\n\t\tif ( forceMove ) {\n\t\t\tconst result = [];\n\n\t\t\t// First we need to move any nodes split by `b` back to where they were.\n\t\t\t// Do it only if `b` actually moved something.\n\t\t\tif ( b.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( b.moveTargetPosition, b.howMany, b.splitPosition, 0 ) );\n\t\t\t}\n\n\t\t\t// Then we need to move nodes from `a` split position to their new element.\n\t\t\t// Do it only if `a` actually should move something.\n\t\t\tif ( a.howMany ) {\n\t\t\t\tresult.push( new MoveOperation( a.splitPosition, a.howMany, a.moveTargetPosition, 0 ) );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} else {\n\t\t\treturn [ new NoOperation( 0 ) ];\n\t\t}\n\t}\n\n\tif ( a.graveyardPosition ) {\n\t\ta.graveyardPosition = a.graveyardPosition._getTransformedBySplitOperation( b );\n\t}\n\n\t// Case 3:\n\t//\n\t// Position where operation `b` inserted a new node after split is the same as the operation `a` split position.\n\t// As in similar cases, there is ambiguity if the split should be before the new node (created by `b`) or after.\n\t//\n\tif ( a.splitPosition.isEqual( b.insertionPosition ) && context.abRelation == 'splitBefore' ) {\n\t\ta.howMany++;\n\n\t\treturn [ a ];\n\t}\n\n\t// Case 4:\n\t//\n\t// This is a mirror to the case 2. above.\n\t//\n\tif ( b.splitPosition.isEqual( a.insertionPosition ) && context.baRelation == 'splitBefore' ) {\n\t\tconst newPositionPath = b.insertionPosition.path.slice();\n\t\tnewPositionPath.push( 0 );\n\n\t\tconst newPosition = new Position( b.insertionPosition.root, newPositionPath );\n\t\tconst moveOp = new MoveOperation( a.insertionPosition, 1, newPosition, 0 );\n\n\t\treturn [ a, moveOp ];\n\t}\n\n\t// The default case.\n\t//\n\tif ( a.splitPosition.hasSameParentAs( b.splitPosition ) && a.splitPosition.offset < b.splitPosition.offset ) {\n\t\ta.howMany -= b.howMany;\n\t}\n\n\ta.splitPosition = a.splitPosition._getTransformedBySplitOperation( b );\n\ta.insertionPosition = SplitOperation.getInsertionPosition( a.splitPosition );\n\n\treturn [ a ];\n} );\n\n// Checks whether `MoveOperation` `targetPosition` is inside a node from the moved range of the other `MoveOperation`.\n//\n// @private\n// @param {module:engine/model/operation/moveoperation~MoveOperation} a\n// @param {module:engine/model/operation/moveoperation~MoveOperation} b\n// @returns {Boolean}\nfunction _moveTargetIntoMovedRange( a, b ) {\n\treturn a.targetPosition._getTransformedByDeletion( b.sourcePosition, b.howMany ) === null;\n}\n\n// Helper function for `MoveOperation` x `MoveOperation` transformation. Converts given ranges and target position to\n// move operations and returns them.\n//\n// Ranges and target position will be transformed on-the-fly when generating operations.\n//\n// Given `ranges` should be in the order of how they were in the original transformed operation.\n//\n// Given `targetPosition` is the target position of the first range from `ranges`.\n//\n// @private\n// @param {Array.<module:engine/model/range~Range>} ranges\n// @param {module:engine/model/position~Position} targetPosition\n// @returns {Array.<module:engine/model/operation/moveoperation~MoveOperation>}\nfunction _makeMoveOperationsFromRanges( ranges, targetPosition ) {\n\t// At this moment we have some ranges and a target position, to which those ranges should be moved.\n\t// Order in `ranges` array is the go-to order of after transformation.\n\t//\n\t// We are almost done. We have `ranges` and `targetPosition` to make operations from.\n\t// Unfortunately, those operations may affect each other. Precisely, first operation after move\n\t// may affect source range and target position of second and third operation. Same with second\n\t// operation affecting third.\n\t//\n\t// We need to fix those source ranges and target positions once again, before converting `ranges` to operations.\n\tconst operations = [];\n\n\t// Keep in mind that nothing will be transformed if there is just one range in `ranges`.\n\tfor ( let i = 0; i < ranges.length; i++ ) {\n\t\t// Create new operation out of a range and target position.\n\t\tconst range = ranges[ i ];\n\t\tconst op = new MoveOperation(\n\t\t\trange.start,\n\t\t\trange.end.offset - range.start.offset,\n\t\t\ttargetPosition,\n\t\t\t0\n\t\t);\n\n\t\toperations.push( op );\n\n\t\t// Transform other ranges by the generated operation.\n\t\tfor ( let j = i + 1; j < ranges.length; j++ ) {\n\t\t\t// All ranges in `ranges` array should be:\n\t\t\t//\n\t\t\t// * non-intersecting (these are part of original operation source range), and\n\t\t\t// * `targetPosition` does not target into them (opposite would mean that transformed operation targets \"inside itself\").\n\t\t\t//\n\t\t\t// This means that the transformation will be \"clean\" and always return one result.\n\t\t\tranges[ j ] = ranges[ j ]._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany )[ 0 ];\n\t\t}\n\n\t\ttargetPosition = targetPosition._getTransformedByMove( op.sourcePosition, op.targetPosition, op.howMany );\n\t}\n\n\treturn operations;\n}\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/view/observer/clickobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * {@link module:engine/view/document~Document#event:click Click} event observer.\n *\n * Note that this observer is not available by default. To make it available it needs to be added to\n * {@link module:engine/view/view~View view controller}\n * by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class ClickObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = 'click';\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when one of the editables has been clicked.\n *\n * Introduced by {@link module:engine/view/observer/clickobserver~ClickObserver}.\n *\n * Note that this event is not available by default. To make it available\n * {@link module:engine/view/observer/clickobserver~ClickObserver} needs to be added\n * to {@link module:engine/view/view~View} by a {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:engine/view/observer/clickobserver~ClickObserver\n * @event module:engine/view/document~Document#event:click\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\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/view/observer/mouseobserver\n */\n\nimport DomEventObserver from './domeventobserver';\n\n/**\n * Mouse events observer.\n *\n * Note that this observer is not available by default. To make it available it needs to be added to\n * {@link module:engine/view/view~View} by {@link module:engine/view/view~View#addObserver} method.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class MouseObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'mousedown', 'mouseup' ];\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when the mouse button is pressed down on one of the editing roots of the editor.\n *\n * Introduced by {@link module:engine/view/observer/mouseobserver~MouseObserver}.\n *\n * Note that this event is not available by default. To make it available, {@link module:engine/view/observer/mouseobserver~MouseObserver}\n * needs to be added to {@link module:engine/view/view~View} by the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:engine/view/observer/mouseobserver~MouseObserver\n * @event module:engine/view/document~Document#event:mousedown\n * @param {module:engine/view/observer/domeventdata~DomEventData} data The event data.\n */\n\n/**\n * Fired when the mouse button is released over one of the editing roots of the editor.\n *\n * Introduced by {@link module:engine/view/observer/mouseobserver~MouseObserver}.\n *\n * Note that this event is not available by default. To make it available, {@link module:engine/view/observer/mouseobserver~MouseObserver}\n * needs to be added to {@link module:engine/view/view~View} by the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:engine/view/observer/mouseobserver~MouseObserver\n * @event module:engine/view/document~Document#event:mouseup\n * @param {module:engine/view/observer/domeventdata~DomEventData} data The event data.\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 module:engine/view/upcastwriter\n */\n\nimport DocumentFragment from './documentfragment';\nimport Element from './element';\nimport Text from './text';\nimport { isPlainObject } from 'lodash-es';\nimport Position from './position';\nimport Range from './range';\nimport Selection from './selection';\n\n/**\n * View upcast writer. It provides a set of methods used to manipulate non-semantic view trees.\n *\n * It should be used only while working on a non-semantic view\n * (e.g. a view created from HTML string on paste).\n * To manipulate a view which was or is being downcasted from the the model use the\n * {@link module:engine/view/downcastwriter~DowncastWriter downcast writer}.\n *\n * Read more about changing the view in the {@glink framework/guides/architecture/editing-engine#changing-the-view Changing the view}\n * section of the {@glink framework/guides/architecture/editing-engine Editing engine architecture} guide.\n *\n * Unlike `DowncastWriter`, which is available in the {@link module:engine/view/view~View#change `View#change()`} block,\n * `UpcastWriter` can be created wherever you need it:\n *\n *\t\tconst writer = new UpcastWriter( viewDocument );\n *\t\tconst text = writer.createText( 'foo!' );\n *\n *\t\twriter.appendChild( text, someViewElement );\n */\nexport default class UpcastWriter {\n\t/**\n\t * @param {module:engine/view/document~Document} document The view document instance in which this upcast writer operates.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * The view document instance in which this upcast writer operates.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/documentfragment~DocumentFragment} instance.\n\t *\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into the created document fragment.\n\t * @returns {module:engine/view/documentfragment~DocumentFragment} The created document fragment.\n\t */\n\tcreateDocumentFragment( children ) {\n\t\treturn new DocumentFragment( this.document, children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/element~Element} instance.\n\t *\n\t * Attributes can be passed in various formats:\n\t *\n\t *\t\tupcastWriter.createElement( 'div', { class: 'editor', contentEditable: 'true' } ); // object\n\t *\t\tupcastWriter.createElement( 'div', [ [ 'class', 'editor' ], [ 'contentEditable', 'true' ] ] ); // map-like iterator\n\t *\t\tupcastWriter.createElement( 'div', mapOfAttributes ); // map\n\t *\n\t * @param {String} name Node name.\n\t * @param {Object|Iterable} [attrs] Collection of attributes.\n\t * @param {module:engine/view/node~Node|Iterable.<module:engine/view/node~Node>} [children]\n\t * A list of nodes to be inserted into created element.\n\t * @returns {module:engine/view/element~Element} Created element.\n\t */\n\tcreateElement( name, attrs, children ) {\n\t\treturn new Element( this.document, name, attrs, children );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/text~Text} instance.\n\t *\n\t * @param {String} data The text's data.\n\t * @returns {module:engine/view/text~Text} The created text node.\n\t */\n\tcreateText( data ) {\n\t\treturn new Text( this.document, data );\n\t}\n\n\t/**\n\t * Clones the provided element.\n\t *\n\t * @see module:engine/view/element~Element#_clone\n\t * @param {module:engine/view/element~Element} element Element to be cloned.\n\t * @param {Boolean} [deep=false] If set to `true` clones element and all its children recursively. When set to `false`,\n\t * element will be cloned without any children.\n\t * @returns {module:engine/view/element~Element} Clone of this element.\n\t */\n\tclone( element, deep = false ) {\n\t\treturn element._clone( deep );\n\t}\n\n\t/**\n\t * Appends a child node or a list of child nodes at the end of this node\n\t * and sets the parent of these nodes to this element.\n\t *\n\t * @see module:engine/view/element~Element#_appendChild\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * to which items will be appended.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Number} Number of appended nodes.\n\t */\n\tappendChild( items, element ) {\n\t\treturn element._appendChild( items );\n\t}\n\n\t/**\n\t * Inserts a child node or a list of child nodes on the given index and sets the parent of these nodes to\n\t * this element.\n\t *\n\t * @see module:engine/view/element~Element#_insertChild\n\t * @param {Number} index Offset at which nodes should be inserted.\n\t * @param {module:engine/view/item~Item|Iterable.<module:engine/view/item~Item>} items Items to be inserted.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * to which items will be inserted.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Number} Number of inserted nodes.\n\t */\n\tinsertChild( index, items, element ) {\n\t\treturn element._insertChild( index, items );\n\t}\n\n\t/**\n\t * Removes the given number of child nodes starting at the given index and set the parent of these nodes to `null`.\n\t *\n\t * @see module:engine/view/element~Element#_removeChildren\n\t * @param {Number} index Offset from which nodes will be removed.\n\t * @param {Number} howMany Number of nodes to remove.\n\t * @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} element Element\n\t * which children will be removed.\n\t * @fires module:engine/view/node~Node#event:change\n\t * @returns {Array.<module:engine/view/node~Node>} The array containing removed nodes.\n\t */\n\tremoveChildren( index, howMany, element ) {\n\t\treturn element._removeChildren( index, howMany );\n\t}\n\n\t/**\n\t * Removes given element from the view structure. Will not have effect on detached elements.\n\t *\n\t * @param {module:engine/view/element~Element} element Element which will be removed.\n\t * @returns {Array.<module:engine/view/node~Node>} The array containing removed nodes.\n\t */\n\tremove( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( parent ) {\n\t\t\treturn this.removeChildren( parent.getChildIndex( element ), 1, parent );\n\t\t}\n\n\t\treturn [];\n\t}\n\n\t/**\n\t * Replaces given element with the new one in the view structure. Will not have effect on detached elements.\n\t *\n\t * @param {module:engine/view/element~Element} oldElement Element which will be replaced.\n\t * @param {module:engine/view/element~Element} newElement Element which will be inserted in the place of the old element.\n\t * @returns {Boolean} Whether old element was successfully replaced.\n\t */\n\treplace( oldElement, newElement ) {\n\t\tconst parent = oldElement.parent;\n\n\t\tif ( parent ) {\n\t\t\tconst index = parent.getChildIndex( oldElement );\n\n\t\t\tthis.removeChildren( index, 1, parent );\n\t\t\tthis.insertChild( index, newElement, parent );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Removes given element from view structure and places its children in its position.\n\t * It does nothing if element has no parent.\n\t *\n\t * @param {module:engine/view/element~Element} element Element to unwrap.\n\t */\n\tunwrapElement( element ) {\n\t\tconst parent = element.parent;\n\n\t\tif ( parent ) {\n\t\t\tconst index = parent.getChildIndex( element );\n\n\t\t\tthis.remove( element );\n\t\t\tthis.insertChild( index, element.getChildren(), parent );\n\t\t}\n\t}\n\n\t/**\n\t * Renames element by creating a copy of a given element but with its name changed and then moving contents of the\n\t * old element to the new one.\n\t *\n\t * Since this function creates a new element and removes the given one, the new element is returned to keep reference.\n\t *\n\t * @param {String} newName New element name.\n\t * @param {module:engine/view/element~Element} element Element to be renamed.\n\t * @returns {module:engine/view/element~Element|null} New element or null if the old element\n\t * was not replaced (happens for detached elements).\n\t */\n\trename( newName, element ) {\n\t\tconst newElement = new Element( this.document, newName, element.getAttributes(), element.getChildren() );\n\n\t\treturn this.replace( element, newElement ) ? newElement : null;\n\t}\n\n\t/**\n\t * Adds or overwrites element's attribute with a specified key and value.\n\t *\n\t *\t\twriter.setAttribute( linkElement, 'href', 'http://ckeditor.com' );\n\t *\n\t * @see module:engine/view/element~Element#_setAttribute\n\t * @param {String} key Attribute key.\n\t * @param {String} value Attribute value.\n\t * @param {module:engine/view/element~Element} element Element for which attribute will be set.\n\t */\n\tsetAttribute( key, value, element ) {\n\t\telement._setAttribute( key, value );\n\t}\n\n\t/**\n\t * Removes attribute from the element.\n\t *\n\t *\t\twriter.removeAttribute( linkElement, 'href' );\n\t *\n\t * @see module:engine/view/element~Element#_removeAttribute\n\t * @param {String} key Attribute key.\n\t * @param {module:engine/view/element~Element} element Element from which attribute will be removed.\n\t */\n\tremoveAttribute( key, element ) {\n\t\telement._removeAttribute( key );\n\t}\n\n\t/**\n\t * Adds specified class to the element.\n\t *\n\t *\t\twriter.addClass( linkElement, 'foo' );\n\t *\t\twriter.addClass( linkElement, [ 'foo', 'bar' ] );\n\t *\n\t * @see module:engine/view/element~Element#_addClass\n\t * @param {Array.<String>|String} className Single class name or array of class names which will be added.\n\t * @param {module:engine/view/element~Element} element Element for which class will be added.\n\t */\n\taddClass( className, element ) {\n\t\telement._addClass( className );\n\t}\n\n\t/**\n\t * Removes specified class from the element.\n\t *\n\t *\t\twriter.removeClass( linkElement, 'foo' );\n\t *\t\twriter.removeClass( linkElement, [ 'foo', 'bar' ] );\n\t *\n\t * @see module:engine/view/element~Element#_removeClass\n\t * @param {Array.<String>|String} className Single class name or array of class names which will be removed.\n\t * @param {module:engine/view/element~Element} element Element from which class will be removed.\n\t */\n\tremoveClass( className, element ) {\n\t\telement._removeClass( className );\n\t}\n\n\t/**\n\t * Adds style to the element.\n\t *\n\t *\t\twriter.setStyle( element, 'color', 'red' );\n\t *\t\twriter.setStyle( element, {\n\t *\t\t\tcolor: 'red',\n\t *\t\t\tposition: 'fixed'\n\t *\t\t} );\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#set `StylesMap#set()`} for details.\n\t *\n\t * @see module:engine/view/element~Element#_setStyle\n\t * @param {String|Object} property Property name or object with key - value pairs.\n\t * @param {String} [value] Value to set. This parameter is ignored if object is provided as the first parameter.\n\t * @param {module:engine/view/element~Element} element Element for which style will be added.\n\t */\n\tsetStyle( property, value, element ) {\n\t\tif ( isPlainObject( property ) && element === undefined ) {\n\t\t\telement = value;\n\t\t}\n\t\telement._setStyle( property, value );\n\t}\n\n\t/**\n\t * Removes specified style from the element.\n\t *\n\t *\t\twriter.removeStyle( element, 'color' ); // Removes 'color' style.\n\t *\t\twriter.removeStyle( element, [ 'color', 'border-top' ] ); // Removes both 'color' and 'border-top' styles.\n\t *\n\t * **Note**: This method can work with normalized style names if\n\t * {@link module:engine/controller/datacontroller~DataController#addStyleProcessorRules a particular style processor rule is enabled}.\n\t * See {@link module:engine/view/stylesmap~StylesMap#remove `StylesMap#remove()`} for details.\n\t *\n\t * @see module:engine/view/element~Element#_removeStyle\n\t * @param {Array.<String>|String} property Style property name or names to be removed.\n\t * @param {module:engine/view/element~Element} element Element from which style will be removed.\n\t */\n\tremoveStyle( property, element ) {\n\t\telement._removeStyle( property );\n\t}\n\n\t/**\n\t * Sets a custom property on element. Unlike attributes, custom properties are not rendered to the DOM,\n\t * so they can be used to add special data to elements.\n\t *\n\t * @see module:engine/view/element~Element#_setCustomProperty\n\t * @param {String|Symbol} key Custom property name/key.\n\t * @param {*} value Custom property value to be stored.\n\t * @param {module:engine/view/element~Element} element Element for which custom property will be set.\n\t */\n\tsetCustomProperty( key, value, element ) {\n\t\telement._setCustomProperty( key, value );\n\t}\n\n\t/**\n\t * Removes a custom property stored under the given key.\n\t *\n\t * @see module:engine/view/element~Element#_removeCustomProperty\n\t * @param {String|Symbol} key Name/key of the custom property to be removed.\n\t * @param {module:engine/view/element~Element} element Element from which the custom property will be removed.\n\t * @returns {Boolean} Returns true if property was removed.\n\t */\n\tremoveCustomProperty( key, element ) {\n\t\treturn element._removeCustomProperty( key );\n\t}\n\n\t/**\n\t * Creates position at the given location. The location can be specified as:\n\t *\n\t * * a {@link module:engine/view/position~Position position},\n\t * * parent element and offset (offset defaults to `0`),\n\t * * parent element and `'end'` (sets position at the end of that element),\n\t * * {@link module:engine/view/item~Item view item} and `'before'` or `'after'` (sets position before or after given view item).\n\t *\n\t * This method is a shortcut to other constructors such as:\n\t *\n\t * * {@link #createPositionBefore},\n\t * * {@link #createPositionAfter},\n\t *\n\t * @param {module:engine/view/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/view/item~Item view item}.\n\t */\n\tcreatePositionAt( itemOrPosition, offset ) {\n\t\treturn Position._createAt( itemOrPosition, offset );\n\t}\n\n\t/**\n\t * Creates a new position after given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item after which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionAfter( item ) {\n\t\treturn Position._createAfter( item );\n\t}\n\n\t/**\n\t * Creates a new position before given view item.\n\t *\n\t * @param {module:engine/view/item~Item} item View item before which the position should be located.\n\t * @returns {module:engine/view/position~Position}\n\t */\n\tcreatePositionBefore( item ) {\n\t\treturn Position._createBefore( item );\n\t}\n\n\t/**\n\t * Creates a range spanning from `start` position to `end` position.\n\t *\n\t * **Note:** This factory method creates it's own {@link module:engine/view/position~Position} instances basing on passed values.\n\t *\n\t * @param {module:engine/view/position~Position} start Start position.\n\t * @param {module:engine/view/position~Position} [end] End position. If not set, range will be collapsed at `start` position.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRange( start, end ) {\n\t\treturn new Range( start, end );\n\t}\n\n\t/**\n\t * Creates a range that starts before given {@link module:engine/view/item~Item view item} and ends after it.\n\t *\n\t * @param {module:engine/view/item~Item} item\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeOn( item ) {\n\t\treturn Range._createOn( item );\n\t}\n\n\t/**\n\t * Creates a range inside an {@link module:engine/view/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 * @param {module:engine/view/element~Element} element Element which is a parent for the range.\n\t * @returns {module:engine/view/range~Range}\n\t */\n\tcreateRangeIn( element ) {\n\t\treturn Range._createIn( element );\n\t}\n\n\t/**\n\t * Creates a new {@link module:engine/view/selection~Selection} instance.\n\t *\n\t * \t\t// Creates empty selection without ranges.\n\t *\t\tconst selection = writer.createSelection();\n\t *\n\t *\t\t// Creates selection at the given range.\n\t *\t\tconst range = writer.createRange( start, end );\n\t *\t\tconst selection = writer.createSelection( range );\n\t *\n\t *\t\t// Creates selection at the given ranges\n\t * \t\tconst ranges = [ writer.createRange( start1, end2 ), writer.createRange( star2, end2 ) ];\n\t *\t\tconst selection = writer.createSelection( ranges );\n\t *\n\t *\t\t// Creates selection from the other selection.\n\t *\t\tconst otherSelection = writer.createSelection();\n\t *\t\tconst selection = writer.createSelection( otherSelection );\n\t *\n\t *\t\t// Creates selection from the document selection.\n\t *\t\tconst selection = writer.createSelection( editor.editing.view.document.selection );\n\t *\n\t * \t\t// Creates selection at the given position.\n\t *\t\tconst position = writer.createPositionFromPath( root, path );\n\t *\t\tconst selection = writer.createSelection( position );\n\t *\n\t *\t\t// Creates collapsed selection at the position of given item and offset.\n\t *\t\tconst paragraph = writer.createContainerElement( 'paragraph' );\n\t *\t\tconst selection = writer.createSelection( paragraph, offset );\n\t *\n\t *\t\t// Creates a range inside an {@link module:engine/view/element~Element element} which starts before the\n\t *\t\t// first child of that element and ends after the last child of that element.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'in' );\n\t *\n\t *\t\t// Creates a range on an {@link module:engine/view/item~Item item} which starts before the item and ends\n\t *\t\t// just after the item.\n\t *\t\tconst selection = writer.createSelection( paragraph, 'on' );\n\t *\n\t * `Selection`'s constructor allow passing additional options (`backward`, `fake` and `label`) as the last argument.\n\t *\n\t *\t\t// Creates backward selection.\n\t *\t\tconst selection = writer.createSelection( range, { backward: true } );\n\t *\n\t * Fake selection does not render as browser native selection over selected elements and is hidden to the user.\n\t * This way, no native selection UI artifacts are displayed to the user and selection over elements can be\n\t * represented in other way, for example by applying proper CSS class.\n\t *\n\t * Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM\n\t * (and be properly handled by screen readers).\n\t *\n\t *\t\t// Creates fake selection with label.\n\t *\t\tconst selection = writer.createSelection( range, { fake: true, label: 'foo' } );\n\t *\n\t * @param {module:engine/view/selection~Selectable} [selectable=null]\n\t * @param {Number|'before'|'end'|'after'|'on'|'in'} [placeOrOffset] Offset or place when selectable is an `Item`.\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.backward] Sets this selection instance to be backward.\n\t * @param {Boolean} [options.fake] Sets this selection instance to be marked as `fake`.\n\t * @param {String} [options.label] Label for the fake selection.\n\t * @returns {module:engine/view/selection~Selection}\n\t */\n\tcreateSelection( selectable, placeOrOffset, options ) {\n\t\treturn new Selection( selectable, placeOrOffset, options );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/styles/utils\n */\n\nconst HEX_COLOR_REGEXP = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst RGB_COLOR_REGEXP = /^rgb\\([ ]?([0-9]{1,3}[ %]?,[ ]?){2,3}[0-9]{1,3}[ %]?\\)$/i;\nconst RGBA_COLOR_REGEXP = /^rgba\\([ ]?([0-9]{1,3}[ %]?,[ ]?){3}(1|[0-9]+%|[0]?\\.?[0-9]+)\\)$/i;\nconst HSL_COLOR_REGEXP = /^hsl\\([ ]?([0-9]{1,3}[ %]?[,]?[ ]*){3}(1|[0-9]+%|[0]?\\.?[0-9]+)?\\)$/i;\nconst HSLA_COLOR_REGEXP = /^hsla\\([ ]?([0-9]{1,3}[ %]?,[ ]?){2,3}(1|[0-9]+%|[0]?\\.?[0-9]+)\\)$/i;\n\nconst COLOR_NAMES = new Set( [\n\t// CSS Level 1\n\t'black', 'silver', 'gray', 'white', 'maroon', 'red', 'purple', 'fuchsia',\n\t'green', 'lime', 'olive', 'yellow', 'navy', 'blue', 'teal', 'aqua',\n\t// CSS Level 2 (Revision 1)\n\t'orange',\n\t// CSS Color Module Level 3\n\t'aliceblue', 'antiquewhite', 'aquamarine', 'azure', 'beige', 'bisque', 'blanchedalmond', 'blueviolet', 'brown',\n\t'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan',\n\t'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta',\n\t'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue',\n\t'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey',\n\t'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod',\n\t'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush',\n\t'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray',\n\t'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategray',\n\t'lightslategrey', 'lightsteelblue', 'lightyellow', 'limegreen', 'linen', 'magenta', 'mediumaquamarine',\n\t'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen',\n\t'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite',\n\t'oldlace', 'olivedrab', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred',\n\t'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon',\n\t'sandybrown', 'seagreen', 'seashell', 'sienna', 'skyblue', 'slateblue', 'slategray', 'slategrey', 'snow',\n\t'springgreen', 'steelblue', 'tan', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'whitesmoke', 'yellowgreen',\n\t// CSS Color Module Level 4\n\t'rebeccapurple',\n\t// Keywords\n\t'currentcolor', 'transparent'\n] );\n\n/**\n * Checks if string contains [color](https://developer.mozilla.org/en-US/docs/Web/CSS/color) CSS value.\n *\n *\t\tisColor( '#f00' );\t\t\t\t\t\t// true\n *\t\tisColor( '#AA00BB33' );\t\t\t\t\t// true\n *\t\tisColor( 'rgb(0, 0, 250)' );\t\t\t// true\n *\t\tisColor( 'hsla(240, 100%, 50%, .7)' );\t// true\n *\t\tisColor( 'deepskyblue' );\t\t\t\t// true\n *\n * **Note**: It does not support CSS Level 4 whitespace syntax, system colors and radius values for HSL colors.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isColor( string ) {\n\t// As far as I was able to test checking some pre-conditions is faster than joining each test with ||.\n\tif ( string.startsWith( '#' ) ) {\n\t\treturn HEX_COLOR_REGEXP.test( string );\n\t}\n\n\tif ( string.startsWith( 'rgb' ) ) {\n\t\treturn RGB_COLOR_REGEXP.test( string ) || RGBA_COLOR_REGEXP.test( string );\n\t}\n\n\tif ( string.startsWith( 'hsl' ) ) {\n\t\treturn HSL_COLOR_REGEXP.test( string ) || HSLA_COLOR_REGEXP.test( string );\n\t}\n\n\t// Array check > RegExp test.\n\treturn COLOR_NAMES.has( string.toLowerCase() );\n}\n\nconst lineStyleValues = [ 'none', 'hidden', 'dotted', 'dashed', 'solid', 'double', 'groove', 'ridge', 'inset', 'outset' ];\n\n/**\n * Checks if string contains [line style](https://developer.mozilla.org/en-US/docs/Web/CSS/border-style) CSS value.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isLineStyle( string ) {\n\treturn lineStyleValues.includes( string );\n}\n\nconst lengthRegExp = /^([+-]?[0-9]*([.][0-9]+)?(px|cm|mm|in|pc|pt|ch|em|ex|rem|vh|vw|vmin|vmax)|0)$/;\n\n/**\n * Checks if string contains [length](https://developer.mozilla.org/en-US/docs/Web/CSS/length) CSS value.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isLength( string ) {\n\treturn lengthRegExp.test( string );\n}\n\nconst PERCENTAGE_VALUE_REGEXP = /^[+-]?[0-9]*([.][0-9]+)?%$/;\n\n/**\n * Checks if string contains [percentage](https://developer.mozilla.org/en-US/docs/Web/CSS/percentage) CSS value.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isPercentage( string ) {\n\treturn PERCENTAGE_VALUE_REGEXP.test( string );\n}\n\nconst repeatValues = [ 'repeat-x', 'repeat-y', 'repeat', 'space', 'round', 'no-repeat' ];\n\n/**\n * Checks if string contains [background repeat](https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat) CSS value.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isRepeat( string ) {\n\treturn repeatValues.includes( string );\n}\n\nconst positionValues = [ 'center', 'top', 'bottom', 'left', 'right' ];\n\n/**\n * Checks if string contains [background position](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position) CSS value.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isPosition( string ) {\n\treturn positionValues.includes( string );\n}\n\nconst attachmentValues = [ 'fixed', 'scroll', 'local' ];\n\n/**\n * Checks if string contains [background attachment](https://developer.mozilla.org/en-US/docs/Web/CSS/background-attachment) CSS value.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isAttachment( string ) {\n\treturn attachmentValues.includes( string );\n}\n\nconst urlRegExp = /^url\\(/;\n\n/**\n * Checks if string contains [URL](https://developer.mozilla.org/en-US/docs/Web/CSS/url) CSS value.\n *\n * @param {String} string\n * @returns {Boolean}\n */\nexport function isURL( string ) {\n\treturn urlRegExp.test( string );\n}\n\nexport function getBoxSidesValues( value = '' ) {\n\tif ( value === '' ) {\n\t\treturn { top: undefined, right: undefined, bottom: undefined, left: undefined };\n\t}\n\n\tconst values = getShorthandValues( value );\n\n\tconst top = values[ 0 ];\n\tconst bottom = values[ 2 ] || top;\n\tconst right = values[ 1 ] || top;\n\tconst left = values[ 3 ] || right;\n\n\treturn { top, bottom, right, left };\n}\n\n/**\n * Default reducer for CSS properties that concerns edges of a box\n * [shorthand](https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties) notations:\n *\n *\t\tstylesProcessor.setReducer( 'padding', getBoxSidesValueReducer( 'padding' ) );\n *\n * @param {String} styleShorthand\n * @returns {Function}\n */\nexport function getBoxSidesValueReducer( styleShorthand ) {\n\treturn value => {\n\t\tconst { top, right, bottom, left } = value;\n\n\t\tconst reduced = [];\n\n\t\tif ( ![ top, right, left, bottom ].every( value => !!value ) ) {\n\t\t\tif ( top ) {\n\t\t\t\treduced.push( [ styleShorthand + '-top', top ] );\n\t\t\t}\n\n\t\t\tif ( right ) {\n\t\t\t\treduced.push( [ styleShorthand + '-right', right ] );\n\t\t\t}\n\n\t\t\tif ( bottom ) {\n\t\t\t\treduced.push( [ styleShorthand + '-bottom', bottom ] );\n\t\t\t}\n\n\t\t\tif ( left ) {\n\t\t\t\treduced.push( [ styleShorthand + '-left', left ] );\n\t\t\t}\n\t\t} else {\n\t\t\treduced.push( [ styleShorthand, getBoxSidesShorthandValue( value ) ] );\n\t\t}\n\n\t\treturn reduced;\n\t};\n}\n\n/**\n * Returns a [shorthand](https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties) notation\n * of a CSS property value.\n *\n *\t\tgetBoxSidesShorthandValue( { top: '1px', right: '1px', bottom: '2px', left: '1px' } );\n *\t\t// will return '1px 1px 2px'\n *\n * @param {module:engine/view/stylesmap~BoxSides} styleShorthand\n * @returns {Function}\n */\nexport function getBoxSidesShorthandValue( { top, right, bottom, left } ) {\n\tconst out = [];\n\n\tif ( left !== right ) {\n\t\tout.push( top, right, bottom, left );\n\t} else if ( bottom !== top ) {\n\t\tout.push( top, right, bottom );\n\t} else if ( right !== top ) {\n\t\tout.push( top, right );\n\t} else {\n\t\tout.push( top );\n\t}\n\n\treturn out.join( ' ' );\n}\n\n/**\n * Creates a normalizer for a [shorthand](https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties) 1-to-4 value.\n *\n *\t\tstylesProcessor.setNormalizer( 'margin', getPositionShorthandNormalizer( 'margin' ) );\n *\n * @param {String} shorthand\n * @returns {Function}\n */\nexport function getPositionShorthandNormalizer( shorthand ) {\n\treturn value => {\n\t\treturn {\n\t\t\tpath: shorthand,\n\t\t\tvalue: getBoxSidesValues( value )\n\t\t};\n\t};\n}\n\n/**\n * Parses parts of a 1-to-4 value notation - handles some CSS values with spaces (like RGB()).\n *\n *\t\tgetShorthandValues( 'red blue RGB(0, 0, 0)');\n *\t\t// will return [ 'red', 'blue', 'RGB(0, 0, 0)' ]\n *\n * @param {String} string\n * @returns {Array.<String>}\n */\nexport function getShorthandValues( string ) {\n\treturn string\n\t\t.replace( /, /g, ',' ) // Exclude comma from spaces evaluation as values are separated by spaces.\n\t\t.split( ' ' )\n\t\t.map( string => string.replace( /,/g, ', ' ) ); // Restore original notation.\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/view/styles/background\n */\n\nimport { getShorthandValues, isAttachment, isColor, isPosition, isRepeat, isURL } from './utils';\n\n/**\n * Adds a background CSS styles processing rules.\n *\n *\t\teditor.data.addStyleProcessorRules( addBackgroundRules );\n *\n * The normalized value is stored as:\n *\n *\t\tconst styles = {\n *\t\t\tbackground: {\n *\t\t\t\tcolor,\n *\t\t\t\trepeat,\n *\t\t\t\tposition,\n *\t\t\t\tattachment,\n *\t\t\t\timage\n *\t\t\t}\n *\t\t};\n *\n * **Note**: Currently only `'background-color'` longhand value is parsed besides `'background'` shorthand. The reducer also supports only\n * `'background-color'` value.\n *\n * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n */\nexport function addBackgroundRules( stylesProcessor ) {\n\tstylesProcessor.setNormalizer( 'background', normalizeBackground );\n\tstylesProcessor.setNormalizer( 'background-color', value => ( { path: 'background.color', value } ) );\n\tstylesProcessor.setReducer( 'background', value => {\n\t\tconst ret = [];\n\n\t\tret.push( [ 'background-color', value.color ] );\n\n\t\treturn ret;\n\t} );\n}\n\nfunction normalizeBackground( value ) {\n\tconst background = {};\n\n\tconst parts = getShorthandValues( value );\n\n\tfor ( const part of parts ) {\n\t\tif ( isRepeat( part ) ) {\n\t\t\tbackground.repeat = background.repeat || [];\n\t\t\tbackground.repeat.push( part );\n\t\t} else if ( isPosition( part ) ) {\n\t\t\tbackground.position = background.position || [];\n\t\t\tbackground.position.push( part );\n\t\t} else if ( isAttachment( part ) ) {\n\t\t\tbackground.attachment = part;\n\t\t} else if ( isColor( part ) ) {\n\t\t\tbackground.color = part;\n\t\t} else if ( isURL( part ) ) {\n\t\t\tbackground.image = part;\n\t\t}\n\t}\n\n\treturn {\n\t\tpath: 'background',\n\t\tvalue: background\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module engine/view/styles/border\n */\n\nimport { getShorthandValues, getBoxSidesValueReducer, getBoxSidesValues, isLength, isLineStyle } from './utils';\n\n/**\n * Adds a border CSS styles processing rules.\n *\n *\t\teditor.data.addStyleProcessorRules( addBorderRules );\n *\n * This rules merges all [border](https://developer.mozilla.org/en-US/docs/Web/CSS/border) styles notation shorthands:\n *\n * - border\n * - border-top\n * - border-right\n * - border-bottom\n * - border-left\n * - border-color\n * - border-style\n * - border-width\n *\n * and all corresponding longhand forms (like `border-top-color`, `border-top-style`, etc).\n *\n * It does not handle other shorthands (like `border-radius` or `border-image`).\n *\n * The normalized model stores border values as:\n *\n *\t\tconst styles = {\n *\t\t\tborder: {\n *\t\t\t\tcolor: { top, right, bottom, left },\n *\t\t\t\tstyle: { top, right, bottom, left },\n *\t\t\t\twidth: { top, right, bottom, left },\n *\t\t\t}\n *\t\t};\n *\n * The `border` value is reduced to a 4 values for each box edge (even if they could be further reduces to a single\n * `border:<width> <style> <color>` style.\n *\n * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n */\nexport function addBorderRules( stylesProcessor ) {\n\tstylesProcessor.setNormalizer( 'border', borderNormalizer );\n\n\t// Border-position shorthands.\n\tstylesProcessor.setNormalizer( 'border-top', getBorderPositionNormalizer( 'top' ) );\n\tstylesProcessor.setNormalizer( 'border-right', getBorderPositionNormalizer( 'right' ) );\n\tstylesProcessor.setNormalizer( 'border-bottom', getBorderPositionNormalizer( 'bottom' ) );\n\tstylesProcessor.setNormalizer( 'border-left', getBorderPositionNormalizer( 'left' ) );\n\n\t// Border-property shorthands.\n\tstylesProcessor.setNormalizer( 'border-color', getBorderPropertyNormalizer( 'color' ) );\n\tstylesProcessor.setNormalizer( 'border-width', getBorderPropertyNormalizer( 'width' ) );\n\tstylesProcessor.setNormalizer( 'border-style', getBorderPropertyNormalizer( 'style' ) );\n\n\t// Border longhands.\n\tstylesProcessor.setNormalizer( 'border-top-color', getBorderPropertyPositionNormalizer( 'color', 'top' ) );\n\tstylesProcessor.setNormalizer( 'border-top-style', getBorderPropertyPositionNormalizer( 'style', 'top' ) );\n\tstylesProcessor.setNormalizer( 'border-top-width', getBorderPropertyPositionNormalizer( 'width', 'top' ) );\n\n\tstylesProcessor.setNormalizer( 'border-right-color', getBorderPropertyPositionNormalizer( 'color', 'right' ) );\n\tstylesProcessor.setNormalizer( 'border-right-style', getBorderPropertyPositionNormalizer( 'style', 'right' ) );\n\tstylesProcessor.setNormalizer( 'border-right-width', getBorderPropertyPositionNormalizer( 'width', 'right' ) );\n\n\tstylesProcessor.setNormalizer( 'border-bottom-color', getBorderPropertyPositionNormalizer( 'color', 'bottom' ) );\n\tstylesProcessor.setNormalizer( 'border-bottom-style', getBorderPropertyPositionNormalizer( 'style', 'bottom' ) );\n\tstylesProcessor.setNormalizer( 'border-bottom-width', getBorderPropertyPositionNormalizer( 'width', 'bottom' ) );\n\n\tstylesProcessor.setNormalizer( 'border-left-color', getBorderPropertyPositionNormalizer( 'color', 'left' ) );\n\tstylesProcessor.setNormalizer( 'border-left-style', getBorderPropertyPositionNormalizer( 'style', 'left' ) );\n\tstylesProcessor.setNormalizer( 'border-left-width', getBorderPropertyPositionNormalizer( 'width', 'left' ) );\n\n\tstylesProcessor.setExtractor( 'border-top', getBorderPositionExtractor( 'top' ) );\n\tstylesProcessor.setExtractor( 'border-right', getBorderPositionExtractor( 'right' ) );\n\tstylesProcessor.setExtractor( 'border-bottom', getBorderPositionExtractor( 'bottom' ) );\n\tstylesProcessor.setExtractor( 'border-left', getBorderPositionExtractor( 'left' ) );\n\n\tstylesProcessor.setExtractor( 'border-top-color', 'border.color.top' );\n\tstylesProcessor.setExtractor( 'border-right-color', 'border.color.right' );\n\tstylesProcessor.setExtractor( 'border-bottom-color', 'border.color.bottom' );\n\tstylesProcessor.setExtractor( 'border-left-color', 'border.color.left' );\n\n\tstylesProcessor.setExtractor( 'border-top-width', 'border.width.top' );\n\tstylesProcessor.setExtractor( 'border-right-width', 'border.width.right' );\n\tstylesProcessor.setExtractor( 'border-bottom-width', 'border.width.bottom' );\n\tstylesProcessor.setExtractor( 'border-left-width', 'border.width.left' );\n\n\tstylesProcessor.setExtractor( 'border-top-style', 'border.style.top' );\n\tstylesProcessor.setExtractor( 'border-right-style', 'border.style.right' );\n\tstylesProcessor.setExtractor( 'border-bottom-style', 'border.style.bottom' );\n\tstylesProcessor.setExtractor( 'border-left-style', 'border.style.left' );\n\n\tstylesProcessor.setReducer( 'border-color', getBoxSidesValueReducer( 'border-color' ) );\n\tstylesProcessor.setReducer( 'border-style', getBoxSidesValueReducer( 'border-style' ) );\n\tstylesProcessor.setReducer( 'border-width', getBoxSidesValueReducer( 'border-width' ) );\n\tstylesProcessor.setReducer( 'border-top', getBorderPositionReducer( 'top' ) );\n\tstylesProcessor.setReducer( 'border-right', getBorderPositionReducer( 'right' ) );\n\tstylesProcessor.setReducer( 'border-bottom', getBorderPositionReducer( 'bottom' ) );\n\tstylesProcessor.setReducer( 'border-left', getBorderPositionReducer( 'left' ) );\n\tstylesProcessor.setReducer( 'border', borderReducer );\n\n\tstylesProcessor.setStyleRelation( 'border', [\n\t\t'border-color', 'border-style', 'border-width',\n\t\t'border-top', 'border-right', 'border-bottom', 'border-left',\n\t\t'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color',\n\t\t'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style',\n\t\t'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width'\n\t] );\n\n\tstylesProcessor.setStyleRelation( 'border-color', [\n\t\t'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color'\n\t] );\n\tstylesProcessor.setStyleRelation( 'border-style', [\n\t\t'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style'\n\t] );\n\tstylesProcessor.setStyleRelation( 'border-width', [\n\t\t'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width'\n\t] );\n\n\tstylesProcessor.setStyleRelation( 'border-top', [ 'border-top-color', 'border-top-style', 'border-top-width' ] );\n\tstylesProcessor.setStyleRelation( 'border-right', [ 'border-right-color', 'border-right-style', 'border-right-width' ] );\n\tstylesProcessor.setStyleRelation( 'border-bottom', [ 'border-bottom-color', 'border-bottom-style', 'border-bottom-width' ] );\n\tstylesProcessor.setStyleRelation( 'border-left', [ 'border-left-color', 'border-left-style', 'border-left-width' ] );\n}\n\nfunction borderNormalizer( value ) {\n\tconst { color, style, width } = normalizeBorderShorthand( value );\n\n\treturn {\n\t\tpath: 'border',\n\t\tvalue: {\n\t\t\tcolor: getBoxSidesValues( color ),\n\t\t\tstyle: getBoxSidesValues( style ),\n\t\t\twidth: getBoxSidesValues( width )\n\t\t}\n\t};\n}\n\nfunction getBorderPositionNormalizer( side ) {\n\treturn value => {\n\t\tconst { color, style, width } = normalizeBorderShorthand( value );\n\n\t\tconst border = {};\n\n\t\tif ( color !== undefined ) {\n\t\t\tborder.color = { [ side ]: color };\n\t\t}\n\n\t\tif ( style !== undefined ) {\n\t\t\tborder.style = { [ side ]: style };\n\t\t}\n\n\t\tif ( width !== undefined ) {\n\t\t\tborder.width = { [ side ]: width };\n\t\t}\n\n\t\treturn {\n\t\t\tpath: 'border',\n\t\t\tvalue: border\n\t\t};\n\t};\n}\n\nfunction getBorderPropertyNormalizer( propertyName ) {\n\treturn value => {\n\t\treturn {\n\t\t\tpath: 'border',\n\t\t\tvalue: toBorderPropertyShorthand( value, propertyName )\n\t\t};\n\t};\n}\n\nfunction toBorderPropertyShorthand( value, property ) {\n\treturn {\n\t\t[ property ]: getBoxSidesValues( value )\n\t};\n}\n\nfunction getBorderPropertyPositionNormalizer( property, side ) {\n\treturn value => {\n\t\treturn {\n\t\t\tpath: 'border',\n\t\t\tvalue: {\n\t\t\t\t[ property ]: {\n\t\t\t\t\t[ side ]: value\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t};\n}\n\nfunction getBorderPositionExtractor( which ) {\n\treturn ( name, styles ) => {\n\t\tif ( styles.border ) {\n\t\t\treturn extractBorderPosition( styles.border, which );\n\t\t}\n\t};\n}\n\nfunction extractBorderPosition( border, which ) {\n\tconst value = {};\n\n\tif ( border.width && border.width[ which ] ) {\n\t\tvalue.width = border.width[ which ];\n\t}\n\n\tif ( border.style && border.style[ which ] ) {\n\t\tvalue.style = border.style[ which ];\n\t}\n\n\tif ( border.color && border.color[ which ] ) {\n\t\tvalue.color = border.color[ which ];\n\t}\n\n\treturn value;\n}\n\nfunction normalizeBorderShorthand( string ) {\n\tconst result = {};\n\n\tconst parts = getShorthandValues( string );\n\n\tfor ( const part of parts ) {\n\t\tif ( isLength( part ) || /thin|medium|thick/.test( part ) ) {\n\t\t\tresult.width = part;\n\t\t} else if ( isLineStyle( part ) ) {\n\t\t\tresult.style = part;\n\t\t} else {\n\t\t\tresult.color = part;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction borderReducer( value ) {\n\tconst reduced = [];\n\n\treduced.push( ...reduceBorderPosition( extractBorderPosition( value, 'top' ), 'top' ) );\n\treduced.push( ...reduceBorderPosition( extractBorderPosition( value, 'right' ), 'right' ) );\n\treduced.push( ...reduceBorderPosition( extractBorderPosition( value, 'bottom' ), 'bottom' ) );\n\treduced.push( ...reduceBorderPosition( extractBorderPosition( value, 'left' ), 'left' ) );\n\n\treturn reduced;\n}\n\nfunction getBorderPositionReducer( which ) {\n\treturn value => reduceBorderPosition( value, which );\n}\n\nfunction reduceBorderPosition( value, which ) {\n\tconst reduced = [];\n\n\tif ( value && value.width !== undefined ) {\n\t\treduced.push( value.width );\n\t}\n\n\tif ( value && value.style !== undefined ) {\n\t\treduced.push( value.style );\n\t}\n\n\tif ( value && value.color !== undefined ) {\n\t\treduced.push( value.color );\n\t}\n\n\tif ( reduced.length ) {\n\t\treturn [ [ `border-${ which }`, reduced.join( ' ' ) ] ];\n\t}\n\n\treturn [];\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/view/styles/margin\n */\n\nimport { getPositionShorthandNormalizer, getBoxSidesValueReducer } from './utils';\n\n/**\n * Adds a margin CSS styles processing rules.\n *\n *\t\teditor.data.addStyleProcessorRules( addMarginRules );\n *\n * The normalized value is stored as:\n *\n *\t\tconst styles = {\n *\t\t\tmargin: {\n *\t\t\t\ttop,\n *\t\t\t\tright,\n *\t\t\t\tbottom,\n *\t\t\t\tleft\n *\t\t\t}\n *\t\t};\n *\n * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n */\nexport function addMarginRules( stylesProcessor ) {\n\tstylesProcessor.setNormalizer( 'margin', getPositionShorthandNormalizer( 'margin' ) );\n\n\tstylesProcessor.setNormalizer( 'margin-top', value => ( { path: 'margin.top', value } ) );\n\tstylesProcessor.setNormalizer( 'margin-right', value => ( { path: 'margin.right', value } ) );\n\tstylesProcessor.setNormalizer( 'margin-bottom', value => ( { path: 'margin.bottom', value } ) );\n\tstylesProcessor.setNormalizer( 'margin-left', value => ( { path: 'margin.left', value } ) );\n\n\tstylesProcessor.setReducer( 'margin', getBoxSidesValueReducer( 'margin' ) );\n\n\tstylesProcessor.setStyleRelation( 'margin', [ 'margin-top', 'margin-right', 'margin-bottom', 'margin-left' ] );\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/view/styles/padding\n */\n\nimport { getPositionShorthandNormalizer, getBoxSidesValueReducer } from './utils';\n\n/**\n * Adds a margin CSS styles processing rules.\n *\n *\t\teditor.data.addStyleProcessorRules( addPaddingRules );\n *\n * The normalized value is stored as:\n *\n *\t\tconst styles = {\n *\t\t\tpadding: {\n *\t\t\t\ttop,\n *\t\t\t\tright,\n *\t\t\t\tbottom,\n *\t\t\t\tleft\n *\t\t\t}\n *\t\t};\n *\n * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n */\nexport function addPaddingRules( stylesProcessor ) {\n\tstylesProcessor.setNormalizer( 'padding', getPositionShorthandNormalizer( 'padding' ) );\n\tstylesProcessor.setNormalizer( 'padding-top', value => ( { path: 'padding.top', value } ) );\n\tstylesProcessor.setNormalizer( 'padding-right', value => ( { path: 'padding.right', value } ) );\n\tstylesProcessor.setNormalizer( 'padding-bottom', value => ( { path: 'padding.bottom', value } ) );\n\tstylesProcessor.setNormalizer( 'padding-left', value => ( { path: 'padding.left', value } ) );\n\n\tstylesProcessor.setReducer( 'padding', getBoxSidesValueReducer( 'padding' ) );\n\n\tstylesProcessor.setStyleRelation( 'padding', [ 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' ] );\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 editor-balloon/ballooneditorui\n */\n\nimport { EditorUI } from 'ckeditor5/src/core';\nimport { enableToolbarKeyboardFocus } from 'ckeditor5/src/ui';\nimport { enablePlaceholder } from 'ckeditor5/src/engine';\n\n/**\n * The balloon editor UI class.\n *\n * @extends module:core/editor/editorui~EditorUI\n */\nexport default class BalloonEditorUI extends EditorUI {\n\t/**\n\t * Creates an instance of the balloon editor UI class.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {module:ui/editorui/editoruiview~EditorUIView} view The view of the UI.\n\t */\n\tconstructor( editor, view ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The main (topmost) view of the editor UI.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editorui/editoruiview~EditorUIView} #view\n\t\t */\n\t\tthis.view = view;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tget element() {\n\t\treturn this.view.editable.element;\n\t}\n\n\t/**\n\t * Initializes the UI.\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = this.view;\n\t\tconst balloonToolbar = editor.plugins.get( 'BalloonToolbar' );\n\t\tconst editingView = editor.editing.view;\n\t\tconst editable = view.editable;\n\t\tconst editingRoot = editingView.document.getRoot();\n\n\t\t// The editable UI and editing root should share the same name. Then name is used\n\t\t// to recognize the particular editable, for instance in ARIA attributes.\n\t\teditable.name = editingRoot.rootName;\n\n\t\tview.render();\n\n\t\t// The editable UI element in DOM is available for sure only after the editor UI view has been rendered.\n\t\t// But it can be available earlier if a DOM element has been passed to BalloonEditor.create().\n\t\tconst editableElement = editable.element;\n\n\t\t// Register the editable UI view in the editor. A single editor instance can aggregate multiple\n\t\t// editable areas (roots) but the balloon editor has only one.\n\t\tthis.setEditableElement( editable.name, editableElement );\n\n\t\t// Let the global focus tracker know that the editable UI element is focusable and\n\t\t// belongs to the editor. From now on, the focus tracker will sustain the editor focus\n\t\t// as long as the editable is focused (e.g. the user is typing).\n\t\tthis.focusTracker.add( editableElement );\n\n\t\t// Let the editable UI element respond to the changes in the global editor focus\n\t\t// tracker. It has been added to the same tracker a few lines above but, in reality, there are\n\t\t// many focusable areas in the editor, like balloons, toolbars or dropdowns and as long\n\t\t// as they have focus, the editable should act like it is focused too (although technically\n\t\t// it isn't), e.g. by setting the proper CSS class, visually announcing focus to the user.\n\t\t// Doing otherwise will result in editable focus styles disappearing, once e.g. the\n\t\t// toolbar gets focused.\n\t\teditable.bind( 'isFocused' ).to( this.focusTracker );\n\n\t\t// Bind the editable UI element to the editing view, making it an end and entrypoint\n\t\t// of the editor's engine. This is where the engine meets the UI.\n\t\teditingView.attachDomRoot( editableElement );\n\n\t\tenableToolbarKeyboardFocus( {\n\t\t\torigin: editingView,\n\t\t\toriginFocusTracker: this.focusTracker,\n\t\t\toriginKeystrokeHandler: editor.keystrokes,\n\t\t\ttoolbar: balloonToolbar.toolbarView,\n\t\t\tbeforeFocus() {\n\t\t\t\tballoonToolbar.show();\n\t\t\t},\n\t\t\tafterBlur() {\n\t\t\t\tballoonToolbar.hide();\n\t\t\t}\n\t\t} );\n\n\t\tthis._initPlaceholder();\n\t\tthis.fire( 'ready' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tconst view = this.view;\n\t\tconst editingView = this.editor.editing.view;\n\n\t\teditingView.detachDomRoot( view.editable.name );\n\t\tview.destroy();\n\n\t\tsuper.destroy();\n\t}\n\n\t/**\n\t * Enable the placeholder text on the editing root, if any was configured.\n\t *\n\t * @private\n\t */\n\t_initPlaceholder() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst editingRoot = editingView.document.getRoot();\n\t\tconst sourceElement = editor.sourceElement;\n\n\t\tconst placeholderText = editor.config.get( 'placeholder' ) ||\n\t\t\tsourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.getAttribute( 'placeholder' );\n\n\t\tif ( placeholderText ) {\n\t\t\tenablePlaceholder( {\n\t\t\t\tview: editingView,\n\t\t\t\telement: editingRoot,\n\t\t\t\ttext: placeholderText,\n\t\t\t\tisDirectHost: false,\n\t\t\t\tkeepOnFocus: true\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module ui/toolbar/enabletoolbarkeyboardfocus\n */\n\n/**\n * Enables focus/blur toolbar navigation using `Alt+F10` and `Esc` keystrokes.\n *\n * @param {Object} options Options of the utility.\n * @param {*} options.origin A view to which the focus will return when `Esc` is pressed and\n * `options.toolbar` is focused.\n * @param {module:utils/keystrokehandler~KeystrokeHandler} options.originKeystrokeHandler A keystroke\n * handler to register `Alt+F10` keystroke.\n * @param {module:utils/focustracker~FocusTracker} options.originFocusTracker A focus tracker\n * for `options.origin`.\n * @param {module:ui/toolbar/toolbarview~ToolbarView} options.toolbar A toolbar which is to gain\n * focus when `Alt+F10` is pressed.\n * @param {Function} [options.beforeFocus] A callback executed before the `options.toolbar` gains focus\n * upon the `Alt+F10` keystroke.\n * @param {Function} [options.afterBlur] A callback executed after `options.toolbar` loses focus upon\n * `Esc` keystroke but before the focus goes back to `options.origin`.\n */\nexport default function enableToolbarKeyboardFocus( {\n\torigin,\n\toriginKeystrokeHandler,\n\toriginFocusTracker,\n\ttoolbar,\n\tbeforeFocus,\n\tafterBlur\n} ) {\n\t// Because toolbar items can get focus, the overall state of the toolbar must\n\t// also be tracked.\n\toriginFocusTracker.add( toolbar.element );\n\n\t// Focus the toolbar on the keystroke, if not already focused.\n\toriginKeystrokeHandler.set( 'Alt+F10', ( data, cancel ) => {\n\t\tif ( originFocusTracker.isFocused && !toolbar.focusTracker.isFocused ) {\n\t\t\tif ( beforeFocus ) {\n\t\t\t\tbeforeFocus();\n\t\t\t}\n\n\t\t\ttoolbar.focus();\n\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\t// Blur the toolbar and bring the focus back to origin.\n\ttoolbar.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\tif ( toolbar.focusTracker.isFocused ) {\n\t\t\torigin.focus();\n\n\t\t\tif ( afterBlur ) {\n\t\t\t\tafterBlur();\n\t\t\t}\n\n\t\t\tcancel();\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module editor-balloon/ballooneditoruiview\n */\n\nimport { EditorUIView, InlineEditableUIView } from 'ckeditor5/src/ui';\n\n/**\n * Contextual editor UI view. Uses the {@link module:ui/editableui/inline/inlineeditableuiview~InlineEditableUIView}.\n *\n * @extends module:ui/editorui/editoruiview~EditorUIView\n */\nexport default class BalloonEditorUIView extends EditorUIView {\n\t/**\n\t * Creates an instance of the balloon editor UI view.\n\t *\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n\t * @param {module:engine/view/view~View} editingView The editing view instance this view is related to.\n\t * @param {HTMLElement} [editableElement] The editable element. If not specified, it will be automatically created by\n\t * {@link module:ui/editableui/editableuiview~EditableUIView}. Otherwise, the given element will be used.\n\t */\n\tconstructor( locale, editingView, editableElement ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The editable UI view.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/editableui/inline/inlineeditableuiview~InlineEditableUIView}\n\t\t */\n\t\tthis.editable = new InlineEditableUIView( locale, editingView, editableElement );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.registerChild( this.editable );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module editor-balloon/ballooneditor\n */\n\nimport { Editor, DataApiMixin, ElementApiMixin, attachToForm, secureSourceElement } from 'ckeditor5/src/core';\nimport { BalloonToolbar } from 'ckeditor5/src/ui';\nimport { CKEditorError, setDataInElement, getDataFromElement, mix } from 'ckeditor5/src/utils';\n\nimport { isElement } from 'lodash-es';\n\nimport BalloonEditorUI from './ballooneditorui';\nimport BalloonEditorUIView from './ballooneditoruiview';\n\n/**\n * The {@glink builds/guides/overview#balloon-editor balloon editor} implementation (Medium-like editor).\n * It uses an inline editable and a toolbar based on the {@link module:ui/toolbar/balloon/balloontoolbar~BalloonToolbar}.\n * See the {@glink examples/builds/balloon-editor demo}.\n *\n * In order to create a balloon editor instance, use the static\n * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} method.\n *\n * # Balloon editor and balloon build\n *\n * The balloon editor can be used directly from source (if you installed the\n * [`@ckeditor/ckeditor5-editor-balloon`](https://www.npmjs.com/package/@ckeditor/ckeditor5-editor-balloon) package)\n * but it is also available in the {@glink builds/guides/overview#balloon-editor balloon build}.\n *\n * {@glink builds/guides/overview Builds} are ready-to-use editors with plugins bundled in. When using the editor from\n * source you need to take care of loading all plugins by yourself\n * (through the {@link module:core/editor/editorconfig~EditorConfig#plugins `config.plugins`} option).\n * Using the editor from source gives much better flexibility and allows easier customization.\n *\n * Read more about initializing the editor from source or as a build in\n * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.\n *\n * @mixes module:core/editor/utils/dataapimixin~DataApiMixin\n * @mixes module:core/editor/utils/elementapimixin~ElementApiMixin\n * @implements module:core/editor/editorwithui~EditorWithUI\n * @extends module:core/editor/editor~Editor\n */\nexport default class BalloonEditor extends Editor {\n\t/**\n\t * Creates an instance of the balloon editor.\n\t *\n\t * **Note:** do not use the constructor to create editor instances. Use the static\n\t * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`} method instead.\n\t *\n\t * @protected\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * (on which the editor will be initialized) or initial data for the editor. For more information see\n\t * {@link module:editor-balloon/ballooneditor~BalloonEditor.create `BalloonEditor.create()`}.\n\t * @param {module:core/editor/editorconfig~EditorConfig} config The editor configuration.\n\t */\n\tconstructor( sourceElementOrData, config ) {\n\t\tsuper( config );\n\n\t\tif ( isElement( sourceElementOrData ) ) {\n\t\t\tthis.sourceElement = sourceElementOrData;\n\t\t\tsecureSourceElement( this );\n\t\t}\n\n\t\tconst plugins = this.config.get( 'plugins' );\n\t\tplugins.push( BalloonToolbar );\n\n\t\tthis.config.set( 'plugins', plugins );\n\n\t\tthis.config.define( 'balloonToolbar', this.config.get( 'toolbar' ) );\n\n\t\tthis.model.document.createRoot();\n\n\t\tconst view = new BalloonEditorUIView( this.locale, this.editing.view, this.sourceElement );\n\t\tthis.ui = new BalloonEditorUI( this, view );\n\n\t\tattachToForm( this );\n\t}\n\n\t/**\n\t * Destroys the editor instance, releasing all resources used by it.\n\t *\n\t * Updates the original editor element with the data.\n\t *\n\t * @returns {Promise}\n\t */\n\tdestroy() {\n\t\t// Cache the data, then destroy.\n\t\t// It's safe to assume that the model->view conversion will not work after super.destroy().\n\t\tconst data = this.getData();\n\n\t\tthis.ui.destroy();\n\n\t\treturn super.destroy()\n\t\t\t.then( () => {\n\t\t\t\tif ( this.sourceElement ) {\n\t\t\t\t\tsetDataInElement( this.sourceElement, data );\n\t\t\t\t}\n\t\t\t} );\n\t}\n\n\t/**\n\t * Creates a new balloon editor instance.\n\t *\n\t * There are three general ways how the editor can be initialized.\n\t *\n\t * # Using an existing DOM element (and loading data from it)\n\t *\n\t * You can initialize the editor using an existing DOM element:\n\t *\n\t *\t\tBalloonEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ) )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * The element's content will be used as the editor data and the element will become the editable element.\n\t *\n\t * # Creating a detached editor\n\t *\n\t * Alternatively, you can initialize the editor by passing the initial data directly as a string.\n\t * In this case, the editor will render an element that must be inserted into the DOM for the editor to work properly:\n\t *\n\t *\t\tBalloonEditor\n\t *\t\t\t.create( '<p>Hello world!</p>' )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\n\t *\t\t\t\t// Initial data was provided so the editor UI element needs to be added manually to the DOM.\n\t *\t\t\t\tdocument.body.appendChild( editor.ui.element );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * This lets you dynamically append the editor to your web page whenever it is convenient for you. You may use this method if your\n\t * web page content is generated on the client side and the DOM structure is not ready at the moment when you initialize the editor.\n\t *\n\t * # Using an existing DOM element (and data provided in `config.initialData`)\n\t *\n\t * You can also mix these two ways by providing a DOM element to be used and passing the initial data through the configuration:\n\t *\n\t *\t\tBalloonEditor\n\t *\t\t\t.create( document.querySelector( '#editor' ), {\n\t *\t\t\t\tinitialData: '<h2>Initial data</h2><p>Foo bar.</p>'\n\t *\t\t\t} )\n\t *\t\t\t.then( editor => {\n\t *\t\t\t\tconsole.log( 'Editor was initialized', editor );\n\t *\t\t\t} )\n\t *\t\t\t.catch( err => {\n\t *\t\t\t\tconsole.error( err.stack );\n\t *\t\t\t} );\n\t *\n\t * This method can be used to initialize the editor on an existing element with the specified content in case if your integration\n\t * makes it difficult to set the content of the source element.\n\t *\n\t * Note that an error will be thrown if you pass the initial data both as the first parameter and also in the configuration.\n\t *\n\t * # Configuring the editor\n\t *\n\t * See the {@link module:core/editor/editorconfig~EditorConfig editor configuration documentation} to learn more about\n\t * customizing plugins, toolbar and more.\n\t *\n\t * # Using the editor from source\n\t *\n\t * The code samples listed in the previous sections of this documentation assume that you are using an\n\t * {@glink builds/guides/overview editor build} (for example `@ckeditor/ckeditor5-build-balloon`).\n\t *\n\t * If you want to use the balloon editor from source (`@ckeditor/ckeditor5-editor-balloon/src/ballooneditor`),\n\t * you need to define the list of\n\t * {@link module:core/editor/editorconfig~EditorConfig#plugins plugins to be initialized} and\n\t * {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar items}. Read more about using the editor from\n\t * source in the {@glink builds/guides/integration/advanced-setup \"Advanced setup\" guide}.\n\t *\n\t * @param {HTMLElement|String} sourceElementOrData The DOM element that will be the source for the created editor\n\t * or the editor's initial data.\n\t *\n\t * If a DOM element is passed, its content will be automatically loaded to the editor upon initialization.\n\t * Moreover, the editor data will be set back to the original element once the editor is destroyed.\n\t *\n\t * If the initial data is passed, a detached editor will be created. In this case you need to insert it into the DOM manually.\n\t * It is available under the {@link module:editor-balloon/ballooneditorui~BalloonEditorUI#element `editor.ui.element`} property.\n\t *\n\t * @param {module:core/editor/editorconfig~EditorConfig} [config] The editor configuration.\n\t * @returns {Promise} A promise resolved once the editor is ready. The promise resolves with the created editor instance.\n\t */\n\tstatic create( sourceElementOrData, config = {} ) {\n\t\treturn new Promise( resolve => {\n\t\t\tconst isHTMLElement = isElement( sourceElementOrData );\n\n\t\t\tif ( isHTMLElement && sourceElementOrData.tagName === 'TEXTAREA' ) {\n\t\t\t\t// Documented in core/editor/editor.js\n\t\t\t\t// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message\n\t\t\t\tthrow new CKEditorError( 'editor-wrong-element', null );\n\t\t\t}\n\n\t\t\tconst editor = new this( sourceElementOrData, config );\n\n\t\t\tresolve(\n\t\t\t\teditor.initPlugins()\n\t\t\t\t\t.then( () => {\n\t\t\t\t\t\teditor.ui.init();\n\t\t\t\t\t} )\n\t\t\t\t\t.then( () => {\n\t\t\t\t\t\tif ( !isHTMLElement && config.initialData ) {\n\t\t\t\t\t\t\t// Documented in core/editor/editorconfig.jdoc.\n\t\t\t\t\t\t\t// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message\n\t\t\t\t\t\t\tthrow new CKEditorError( 'editor-create-initial-data', null );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst initialData = config.initialData !== undefined ? config.initialData : getInitialData( sourceElementOrData );\n\n\t\t\t\t\t\treturn editor.data.init( initialData );\n\t\t\t\t\t} )\n\t\t\t\t\t.then( () => editor.fire( 'ready' ) )\n\t\t\t\t\t.then( () => editor )\n\t\t\t);\n\t\t} );\n\t}\n}\n\nmix( BalloonEditor, DataApiMixin );\nmix( BalloonEditor, ElementApiMixin );\n\nfunction getInitialData( sourceElementOrData ) {\n\treturn isElement( sourceElementOrData ) ? getDataFromElement( sourceElementOrData ) : sourceElementOrData;\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\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * @module core/editor/utils/securesourceelement\n */\n\n/**\n * Marks the source element on which the editor was initialized. This prevents other editor instances from using this element.\n *\n * Running multiple editor instances on the same source element causes various issues and it is\n * crucial this helper is called as soon as the source element is known to prevent collisions.\n *\n * @param {module:core/editor/editor~Editor} editor Editor instance.\n */\nexport default function secureSourceElement( editor ) {\n\tconst sourceElement = editor.sourceElement;\n\n\t// If the editor was initialized without specifying an element, we don't need to secure anything.\n\tif ( !sourceElement ) {\n\t\treturn;\n\t}\n\n\tif ( sourceElement.ckeditorInstance ) {\n\t\t/**\n\t\t * A DOM element used to create the editor (e.g.\n\t\t * {@link module:editor-inline/inlineeditor~InlineEditor.create `InlineEditor.create()`})\n\t\t * has already been used to create another editor instance. Make sure each editor is\n\t\t * created with an unique DOM element.\n\t\t *\n\t\t * @error editor-source-element-already-used\n\t\t * @param {HTMLElement} element DOM element that caused the collision.\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'editor-source-element-already-used',\n\t\t\teditor\n\t\t);\n\t}\n\n\tsourceElement.ckeditorInstance = editor;\n\n\teditor.once( 'destroy', () => {\n\t\tdelete sourceElement.ckeditorInstance;\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { isFunction } from 'lodash-es';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * @module core/editor/utils/attachtoform\n */\n\n/**\n * Checks if the editor is initialized on a `<textarea>` element that belongs to a form. If yes, it updates the editor's element\n * content before submitting the form.\n *\n * This helper requires the {@link module:core/editor/utils/elementapimixin~ElementApi ElementApi interface}.\n *\n * @param {module:core/editor/editor~Editor} editor Editor instance.\n */\nexport default function attachToForm( editor ) {\n\tif ( !isFunction( editor.updateSourceElement ) ) {\n\t\t/**\n\t\t * The editor passed to `attachToForm()` must implement the\n\t\t * {@link module:core/editor/utils/elementapimixin~ElementApi} interface.\n\t\t *\n\t\t * @error attachtoform-missing-elementapi-interface\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'attachtoform-missing-elementapi-interface',\n\t\t\teditor\n\t\t);\n\t}\n\n\tconst sourceElement = editor.sourceElement;\n\n\t// Only when replacing a textarea which is inside of a form element.\n\tif ( sourceElement && sourceElement.tagName.toLowerCase() === 'textarea' && sourceElement.form ) {\n\t\tlet originalSubmit;\n\t\tconst form = sourceElement.form;\n\t\tconst onSubmit = () => editor.updateSourceElement();\n\n\t\t// Replace the original form#submit() to call a custom submit function first.\n\t\t// Check if #submit is a function because the form might have an input named \"submit\".\n\t\tif ( isFunction( form.submit ) ) {\n\t\t\toriginalSubmit = form.submit;\n\n\t\t\tform.submit = () => {\n\t\t\t\tonSubmit();\n\t\t\t\toriginalSubmit.apply( form );\n\t\t\t};\n\t\t}\n\n\t\t// Update the replaced textarea with data before each form#submit event.\n\t\tform.addEventListener( 'submit', onSubmit );\n\n\t\t// Remove the submit listener and revert the original submit method on\n\t\t// editor#destroy.\n\t\teditor.on( 'destroy', () => {\n\t\t\tform.removeEventListener( 'submit', onSubmit );\n\n\t\t\tif ( originalSubmit ) {\n\t\t\t\tform.submit = originalSubmit;\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals HTMLTextAreaElement */\n\n/**\n * @module utils/dom/getdatafromelement\n */\n\n/**\n * Gets data from a given source element.\n *\n * @param {HTMLElement} el The element from which the data will be retrieved.\n * @returns {String} The data string.\n */\nexport default function getDataFromElement( el ) {\n\tif ( el instanceof HTMLTextAreaElement ) {\n\t\treturn el.value;\n\t}\n\n\treturn el.innerHTML;\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 upload/filereader\n */\n\n/* globals window */\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Wrapper over the native `FileReader`.\n */\nexport default class FileReader {\n\t/**\n\t * Creates an instance of the FileReader.\n\t */\n\tconstructor() {\n\t\tconst reader = new window.FileReader();\n\n\t\t/**\n\t\t * Instance of native FileReader.\n\t\t *\n\t\t * @private\n\t\t * @member {FileReader} #_reader\n\t\t */\n\t\tthis._reader = reader;\n\n\t\tthis._data = undefined;\n\n\t\t/**\n\t\t * Number of bytes loaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #loaded\n\t\t */\n\t\tthis.set( 'loaded', 0 );\n\n\t\treader.onprogress = evt => {\n\t\t\tthis.loaded = evt.loaded;\n\t\t};\n\t}\n\n\t/**\n\t * Returns error that occurred during file reading.\n\t *\n\t * @returns {Error}\n\t */\n\tget error() {\n\t\treturn this._reader.error;\n\t}\n\n\t/**\n\t * Holds the data of an already loaded file. The file must be first loaded\n\t * by using {@link module:upload/filereader~FileReader#read `read()`}.\n\t *\n\t * @type {File|undefined}\n\t */\n\tget data() {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Reads the provided file.\n\t *\n\t * @param {File} file Native File object.\n\t * @returns {Promise.<String>} Returns a promise that will be resolved with file's content.\n\t * The promise will be rejected in case of an error or when the reading process is aborted.\n\t */\n\tread( file ) {\n\t\tconst reader = this._reader;\n\t\tthis.total = file.size;\n\n\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\treader.onload = () => {\n\t\t\t\tconst result = reader.result;\n\n\t\t\t\tthis._data = result;\n\n\t\t\t\tresolve( result );\n\t\t\t};\n\n\t\t\treader.onerror = () => {\n\t\t\t\treject( 'error' );\n\t\t\t};\n\n\t\t\treader.onabort = () => {\n\t\t\t\treject( 'aborted' );\n\t\t\t};\n\n\t\t\tthis._reader.readAsDataURL( file );\n\t\t} );\n\t}\n\n\t/**\n\t * Aborts file reader.\n\t */\n\tabort() {\n\t\tthis._reader.abort();\n\t}\n}\n\nmix( FileReader, ObservableMixin );\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 upload/filerepository\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport PendingActions from '@ckeditor/ckeditor5-core/src/pendingactions';\nimport CKEditorError, { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport Collection from '@ckeditor/ckeditor5-utils/src/collection';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport FileReader from './filereader.js';\n\nimport uid from '@ckeditor/ckeditor5-utils/src/uid.js';\n\n/**\n * File repository plugin. A central point for managing file upload.\n *\n * To use it, first you need an upload adapter. Upload adapter's job is to handle communication with the server\n * (sending the file and handling server's response). You can use one of the existing plugins introducing upload adapters\n * (e.g. {@link module:easy-image/cloudservicesuploadadapter~CloudServicesUploadAdapter} or\n * {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter}) or write your own one see\n * the {@glink framework/guides/deep-dive/upload-adapter \"Custom image upload adapter\" deep dive guide}.\n *\n * Then, you can use {@link module:upload/filerepository~FileRepository#createLoader `createLoader()`} and the returned\n * {@link module:upload/filerepository~FileLoader} instance to load and upload files.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FileRepository extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FileRepository';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ PendingActions ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t/**\n\t\t * Collection of loaders associated with this repository.\n\t\t *\n\t\t * @member {module:utils/collection~Collection} #loaders\n\t\t */\n\t\tthis.loaders = new Collection();\n\n\t\t// Keeps upload in a sync with pending actions.\n\t\tthis.loaders.on( 'add', () => this._updatePendingAction() );\n\t\tthis.loaders.on( 'remove', () => this._updatePendingAction() );\n\n\t\t/**\n\t\t * Loaders mappings used to retrieve loaders references.\n\t\t *\n\t\t * @private\n\t\t * @member {Map<File|Promise, FileLoader>} #_loadersMap\n\t\t */\n\t\tthis._loadersMap = new Map();\n\n\t\t/**\n\t\t * Reference to a pending action registered in a {@link module:core/pendingactions~PendingActions} plugin\n\t\t * while upload is in progress. When there is no upload then value is `null`.\n\t\t *\n\t\t * @private\n\t\t * @member {Object} #_pendingAction\n\t\t */\n\t\tthis._pendingAction = null;\n\n\t\t/**\n\t\t * A factory function which should be defined before using `FileRepository`.\n\t\t *\n\t\t * It should return a new instance of {@link module:upload/filerepository~UploadAdapter} that will be used to upload files.\n\t\t * {@link module:upload/filerepository~FileLoader} instance associated with the adapter\n\t\t * will be passed to that function.\n\t\t *\n\t\t * For more information and example see {@link module:upload/filerepository~UploadAdapter}.\n\t\t *\n\t\t * @member {Function} #createUploadAdapter\n\t\t */\n\n\t\t/**\n\t\t * Number of bytes uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploaded\n\t\t */\n\t\tthis.set( 'uploaded', 0 );\n\n\t\t/**\n\t\t * Number of total bytes to upload.\n\t\t *\n\t\t * It might be different than the file size because of headers and additional data.\n\t\t * It contains `null` if value is not available yet, so it's better to use {@link #uploadedPercent} to monitor\n\t\t * the progress.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #uploadTotal\n\t\t */\n\t\tthis.set( 'uploadTotal', null );\n\n\t\t/**\n\t\t * Upload progress in percents.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploadedPercent\n\t\t */\n\t\tthis.bind( 'uploadedPercent' ).to( this, 'uploaded', this, 'uploadTotal', ( uploaded, total ) => {\n\t\t\treturn total ? ( uploaded / total * 100 ) : 0;\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the loader associated with specified file or promise.\n\t *\n\t * To get loader by id use `fileRepository.loaders.get( id )`.\n\t *\n\t * @param {File|Promise.<File>} fileOrPromise Native file or promise handle.\n\t * @returns {module:upload/filerepository~FileLoader|null}\n\t */\n\tgetLoader( fileOrPromise ) {\n\t\treturn this._loadersMap.get( fileOrPromise ) || null;\n\t}\n\n\t/**\n\t * Creates a loader instance for the given file.\n\t *\n\t * Requires {@link #createUploadAdapter} factory to be defined.\n\t *\n\t * @param {File|Promise.<File>} fileOrPromise Native File object or native Promise object which resolves to a File.\n\t * @returns {module:upload/filerepository~FileLoader|null}\n\t */\n\tcreateLoader( fileOrPromise ) {\n\t\tif ( !this.createUploadAdapter ) {\n\t\t\t/**\n\t\t\t * You need to enable an upload adapter in order to be able to upload files.\n\t\t\t *\n\t\t\t * This warning shows up when {@link module:upload/filerepository~FileRepository} is being used\n\t\t\t * without {@link #createUploadAdapter defining an upload adapter}.\n\t\t\t *\n\t\t\t * **If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}**\n\t\t\t * it means that you did not configure any of the upload adapters available by default in those builds.\n\t\t\t *\n\t\t\t * See the {@glink features/image-upload/image-upload comprehensive \"Image upload overview\"} to learn which upload\n\t\t\t * adapters are available in the builds and how to configure them.\n\t\t\t *\n\t\t\t * **If you see this warning when using a custom build** there is a chance that you enabled\n\t\t\t * a feature like {@link module:image/imageupload~ImageUpload},\n\t\t\t * or {@link module:image/imageupload/imageuploadui~ImageUploadUI} but you did not enable any upload adapter.\n\t\t\t * You can choose one of the existing upload adapters listed in the\n\t\t\t * {@glink features/image-upload/image-upload \"Image upload overview\"}.\n\t\t\t *\n\t\t\t * You can also implement your {@glink framework/guides/deep-dive/upload-adapter own image upload adapter}.\n\t\t\t *\n\t\t\t * @error filerepository-no-upload-adapter\n\t\t\t */\n\t\t\tlogWarning( 'filerepository-no-upload-adapter' );\n\n\t\t\treturn null;\n\t\t}\n\n\t\tconst loader = new FileLoader( Promise.resolve( fileOrPromise ), this.createUploadAdapter );\n\n\t\tthis.loaders.add( loader );\n\t\tthis._loadersMap.set( fileOrPromise, loader );\n\n\t\t// Store also file => loader mapping so loader can be retrieved by file instance returned upon Promise resolution.\n\t\tif ( fileOrPromise instanceof Promise ) {\n\t\t\tloader.file\n\t\t\t\t.then( file => {\n\t\t\t\t\tthis._loadersMap.set( file, loader );\n\t\t\t\t} )\n\t\t\t\t// Every then() must have a catch().\n\t\t\t\t// File loader state (and rejections) are handled in read() and upload().\n\t\t\t\t// Also, see the \"does not swallow the file promise rejection\" test.\n\t\t\t\t.catch( () => {} );\n\t\t}\n\n\t\tloader.on( 'change:uploaded', () => {\n\t\t\tlet aggregatedUploaded = 0;\n\n\t\t\tfor ( const loader of this.loaders ) {\n\t\t\t\taggregatedUploaded += loader.uploaded;\n\t\t\t}\n\n\t\t\tthis.uploaded = aggregatedUploaded;\n\t\t} );\n\n\t\tloader.on( 'change:uploadTotal', () => {\n\t\t\tlet aggregatedTotal = 0;\n\n\t\t\tfor ( const loader of this.loaders ) {\n\t\t\t\tif ( loader.uploadTotal ) {\n\t\t\t\t\taggregatedTotal += loader.uploadTotal;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.uploadTotal = aggregatedTotal;\n\t\t} );\n\n\t\treturn loader;\n\t}\n\n\t/**\n\t * Destroys the given loader.\n\t *\n\t * @param {File|Promise|module:upload/filerepository~FileLoader} fileOrPromiseOrLoader File or Promise associated\n\t * with that loader or loader itself.\n\t */\n\tdestroyLoader( fileOrPromiseOrLoader ) {\n\t\tconst loader = fileOrPromiseOrLoader instanceof FileLoader ? fileOrPromiseOrLoader : this.getLoader( fileOrPromiseOrLoader );\n\n\t\tloader._destroy();\n\n\t\tthis.loaders.remove( loader );\n\n\t\tthis._loadersMap.forEach( ( value, key ) => {\n\t\t\tif ( value === loader ) {\n\t\t\t\tthis._loadersMap.delete( key );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Registers or deregisters pending action bound with upload progress.\n\t *\n\t * @private\n\t */\n\t_updatePendingAction() {\n\t\tconst pendingActions = this.editor.plugins.get( PendingActions );\n\n\t\tif ( this.loaders.length ) {\n\t\t\tif ( !this._pendingAction ) {\n\t\t\t\tconst t = this.editor.t;\n\t\t\t\tconst getMessage = value => `${ t( 'Upload in progress' ) } ${ parseInt( value ) }%.`;\n\n\t\t\t\tthis._pendingAction = pendingActions.add( getMessage( this.uploadedPercent ) );\n\t\t\t\tthis._pendingAction.bind( 'message' ).to( this, 'uploadedPercent', getMessage );\n\t\t\t}\n\t\t} else {\n\t\t\tpendingActions.remove( this._pendingAction );\n\t\t\tthis._pendingAction = null;\n\t\t}\n\t}\n}\n\nmix( FileRepository, ObservableMixin );\n\n/**\n * File loader class.\n *\n * It is used to control the process of reading the file and uploading it using the specified upload adapter.\n */\nclass FileLoader {\n\t/**\n\t * Creates a new instance of `FileLoader`.\n\t *\n\t * @param {Promise.<File>} filePromise A promise which resolves to a file instance.\n\t * @param {Function} uploadAdapterCreator The function which returns {@link module:upload/filerepository~UploadAdapter} instance.\n\t */\n\tconstructor( filePromise, uploadAdapterCreator ) {\n\t\t/**\n\t\t * Unique id of FileLoader instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.id = uid();\n\n\t\t/**\n\t\t * Additional wrapper over the initial file promise passed to this loader.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/filerepository~FilePromiseWrapper}\n\t\t */\n\t\tthis._filePromiseWrapper = this._createFilePromiseWrapper( filePromise );\n\n\t\t/**\n\t\t * Adapter instance associated with this file loader.\n\t\t *\n\t\t * @private\n\t\t * @member {module:upload/filerepository~UploadAdapter}\n\t\t */\n\t\tthis._adapter = uploadAdapterCreator( this );\n\n\t\t/**\n\t\t * FileReader used by FileLoader.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/filereader~FileReader}\n\t\t */\n\t\tthis._reader = new FileReader();\n\n\t\t/**\n\t\t * Current status of FileLoader. It can be one of the following:\n\t\t *\n\t\t * * 'idle',\n\t\t * * 'reading',\n\t\t * * 'uploading',\n\t\t * * 'aborted',\n\t\t * * 'error'.\n\t\t *\n\t\t * When reading status can change in a following way:\n\t\t *\n\t\t * `idle` -> `reading` -> `idle`\n\t\t * `idle` -> `reading -> `aborted`\n\t\t * `idle` -> `reading -> `error`\n\t\t *\n\t\t * When uploading status can change in a following way:\n\t\t *\n\t\t * `idle` -> `uploading` -> `idle`\n\t\t * `idle` -> `uploading` -> `aborted`\n\t\t * `idle` -> `uploading` -> `error`\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String} #status\n\t\t */\n\t\tthis.set( 'status', 'idle' );\n\n\t\t/**\n\t\t * Number of bytes uploaded.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploaded\n\t\t */\n\t\tthis.set( 'uploaded', 0 );\n\n\t\t/**\n\t\t * Number of total bytes to upload.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #uploadTotal\n\t\t */\n\t\tthis.set( 'uploadTotal', null );\n\n\t\t/**\n\t\t * Upload progress in percents.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number} #uploadedPercent\n\t\t */\n\t\tthis.bind( 'uploadedPercent' ).to( this, 'uploaded', this, 'uploadTotal', ( uploaded, total ) => {\n\t\t\treturn total ? ( uploaded / total * 100 ) : 0;\n\t\t} );\n\n\t\t/**\n\t\t * Response of the upload.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Object|null} #uploadResponse\n\t\t */\n\t\tthis.set( 'uploadResponse', null );\n\t}\n\n\t/**\n\t * A `Promise` which resolves to a `File` instance associated with this file loader.\n\t *\n\t * @type {Promise.<File|null>}\n\t */\n\tget file() {\n\t\tif ( !this._filePromiseWrapper ) {\n\t\t\t// Loader was destroyed, return promise which resolves to null.\n\t\t\treturn Promise.resolve( null );\n\t\t} else {\n\t\t\t// The `this._filePromiseWrapper.promise` is chained and not simply returned to handle a case when:\n\t\t\t//\n\t\t\t//\t\t* The `loader.file.then( ... )` is called by external code (returned promise is pending).\n\t\t\t//\t\t* Then `loader._destroy()` is called (call is synchronous) which destroys the `loader`.\n\t\t\t//\t\t* Promise returned by the first `loader.file.then( ... )` call is resolved.\n\t\t\t//\n\t\t\t// Returning `this._filePromiseWrapper.promise` will still resolve to a `File` instance so there\n\t\t\t// is an additional check needed in the chain to see if `loader` was destroyed in the meantime.\n\t\t\treturn this._filePromiseWrapper.promise.then( file => this._filePromiseWrapper ? file : null );\n\t\t}\n\t}\n\n\t/**\n\t * Returns the file data. To read its data, you need for first load the file\n\t * by using the {@link module:upload/filerepository~FileLoader#read `read()`} method.\n\t *\n\t * @type {File|undefined}\n\t */\n\tget data() {\n\t\treturn this._reader.data;\n\t}\n\n\t/**\n\t * Reads file using {@link module:upload/filereader~FileReader}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-read-wrong-status` when status\n\t * is different than `idle`.\n\t *\n\t * Example usage:\n\t *\n\t *\tfileLoader.read()\n\t *\t\t.then( data => { ... } )\n\t *\t\t.catch( err => {\n\t *\t\t\tif ( err === 'aborted' ) {\n\t *\t\t\t\tconsole.log( 'Reading aborted.' );\n\t *\t\t\t} else {\n\t *\t\t\t\tconsole.log( 'Reading error.', err );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @returns {Promise.<String>} Returns promise that will be resolved with read data. Promise will be rejected if error\n\t * occurs or if read process is aborted.\n\t */\n\tread() {\n\t\tif ( this.status != 'idle' ) {\n\t\t\t/**\n\t\t\t * You cannot call read if the status is different than idle.\n\t\t\t *\n\t\t\t * @error filerepository-read-wrong-status\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'filerepository-read-wrong-status', this );\n\t\t}\n\n\t\tthis.status = 'reading';\n\n\t\treturn this.file\n\t\t\t.then( file => this._reader.read( file ) )\n\t\t\t.then( data => {\n\t\t\t\t// Edge case: reader was aborted after file was read - double check for proper status.\n\t\t\t\t// It can happen when image was deleted during its upload.\n\t\t\t\tif ( this.status !== 'reading' ) {\n\t\t\t\t\tthrow this.status;\n\t\t\t\t}\n\n\t\t\t\tthis.status = 'idle';\n\n\t\t\t\treturn data;\n\t\t\t} )\n\t\t\t.catch( err => {\n\t\t\t\tif ( err === 'aborted' ) {\n\t\t\t\t\tthis.status = 'aborted';\n\t\t\t\t\tthrow 'aborted';\n\t\t\t\t}\n\n\t\t\t\tthis.status = 'error';\n\t\t\t\tthrow this._reader.error ? this._reader.error : err;\n\t\t\t} );\n\t}\n\n\t/**\n\t * Reads file using the provided {@link module:upload/filerepository~UploadAdapter}.\n\t *\n\t * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-upload-wrong-status` when status\n\t * is different than `idle`.\n\t * Example usage:\n\t *\n\t *\tfileLoader.upload()\n\t *\t\t.then( data => { ... } )\n\t *\t\t.catch( e => {\n\t *\t\t\tif ( e === 'aborted' ) {\n\t *\t\t\t\tconsole.log( 'Uploading aborted.' );\n\t *\t\t\t} else {\n\t *\t\t\t\tconsole.log( 'Uploading error.', e );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * @returns {Promise.<Object>} Returns promise that will be resolved with response data. Promise will be rejected if error\n\t * occurs or if read process is aborted.\n\t */\n\tupload() {\n\t\tif ( this.status != 'idle' ) {\n\t\t\t/**\n\t\t\t * You cannot call upload if the status is different than idle.\n\t\t\t *\n\t\t\t * @error filerepository-upload-wrong-status\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'filerepository-upload-wrong-status', this );\n\t\t}\n\n\t\tthis.status = 'uploading';\n\n\t\treturn this.file\n\t\t\t.then( () => this._adapter.upload() )\n\t\t\t.then( data => {\n\t\t\t\tthis.uploadResponse = data;\n\t\t\t\tthis.status = 'idle';\n\n\t\t\t\treturn data;\n\t\t\t} )\n\t\t\t.catch( err => {\n\t\t\t\tif ( this.status === 'aborted' ) {\n\t\t\t\t\tthrow 'aborted';\n\t\t\t\t}\n\n\t\t\t\tthis.status = 'error';\n\t\t\t\tthrow err;\n\t\t\t} );\n\t}\n\n\t/**\n\t * Aborts loading process.\n\t */\n\tabort() {\n\t\tconst status = this.status;\n\t\tthis.status = 'aborted';\n\n\t\tif ( !this._filePromiseWrapper.isFulfilled ) {\n\t\t\t// Edge case: file loader is aborted before read() is called\n\t\t\t// so it might happen that no one handled the rejection of this promise.\n\t\t\t// See https://github.com/ckeditor/ckeditor5-upload/pull/100\n\t\t\tthis._filePromiseWrapper.promise.catch( () => {} );\n\n\t\t\tthis._filePromiseWrapper.rejecter( 'aborted' );\n\t\t} else if ( status == 'reading' ) {\n\t\t\tthis._reader.abort();\n\t\t} else if ( status == 'uploading' && this._adapter.abort ) {\n\t\t\tthis._adapter.abort();\n\t\t}\n\n\t\tthis._destroy();\n\t}\n\n\t/**\n\t * Performs cleanup.\n\t *\n\t * @private\n\t */\n\t_destroy() {\n\t\tthis._filePromiseWrapper = undefined;\n\t\tthis._reader = undefined;\n\t\tthis._adapter = undefined;\n\t\tthis.uploadResponse = undefined;\n\t}\n\n\t/**\n\t * Wraps a given file promise into another promise giving additional\n\t * control (resolving, rejecting, checking if fulfilled) over it.\n\t *\n\t * @private\n\t * @param filePromise The initial file promise to be wrapped.\n\t * @returns {module:upload/filerepository~FilePromiseWrapper}\n\t */\n\t_createFilePromiseWrapper( filePromise ) {\n\t\tconst wrapper = {};\n\n\t\twrapper.promise = new Promise( ( resolve, reject ) => {\n\t\t\twrapper.rejecter = reject;\n\t\t\twrapper.isFulfilled = false;\n\n\t\t\tfilePromise\n\t\t\t\t.then( file => {\n\t\t\t\t\twrapper.isFulfilled = true;\n\t\t\t\t\tresolve( file );\n\t\t\t\t} )\n\t\t\t\t.catch( err => {\n\t\t\t\t\twrapper.isFulfilled = true;\n\t\t\t\t\treject( err );\n\t\t\t\t} );\n\t\t} );\n\n\t\treturn wrapper;\n\t}\n}\n\nmix( FileLoader, ObservableMixin );\n\n/**\n * Upload adapter interface used by the {@link module:upload/filerepository~FileRepository file repository}\n * to handle file upload. An upload adapter is a bridge between the editor and server that handles file uploads.\n * It should contain a logic necessary to initiate an upload process and monitor its progress.\n *\n * Learn how to develop your own upload adapter for CKEditor 5 in the\n * {@glink framework/guides/deep-dive/upload-adapter \"Custom upload adapter\" guide}.\n *\n * @interface UploadAdapter\n */\n\n/**\n * Executes the upload process.\n * This method should return a promise that will resolve when data will be uploaded to server. Promise should be\n * resolved with an object containing information about uploaded file:\n *\n *\t\t{\n *\t\t\tdefault: 'http://server/default-size.image.png'\n *\t\t}\n *\n * Additionally, other image sizes can be provided:\n *\n *\t\t{\n *\t\t\tdefault: 'http://server/default-size.image.png',\n *\t\t\t'160': 'http://server/size-160.image.png',\n *\t\t\t'500': 'http://server/size-500.image.png',\n *\t\t\t'1000': 'http://server/size-1000.image.png',\n *\t\t\t'1052': 'http://server/default-size.image.png'\n *\t\t}\n *\n * You can also pass additional properties from the server. In this case you need to wrap URLs\n * in the `urls` object and pass additional properties along the `urls` property.\n *\n * \t\t{\n * \t\t\tmyCustomProperty: 'foo',\n * \t\t\turls: {\n *\t\t\t\tdefault: 'http://server/default-size.image.png',\n *\t\t\t\t'160': 'http://server/size-160.image.png',\n *\t\t\t\t'500': 'http://server/size-500.image.png',\n *\t\t\t\t'1000': 'http://server/size-1000.image.png',\n *\t\t\t\t'1052': 'http://server/default-size.image.png'\n *\t\t\t}\n *\t\t}\n *\n * NOTE: When returning multiple images, the widest returned one should equal the default one. It is essential to\n * correctly set `width` attribute of the image. See this discussion:\n * https://github.com/ckeditor/ckeditor5-easy-image/issues/4 for more information.\n *\n * Take a look at {@link module:upload/filerepository~UploadAdapter example Adapter implementation} and\n * {@link module:upload/filerepository~FileRepository#createUploadAdapter createUploadAdapter method}.\n *\n * @method module:upload/filerepository~UploadAdapter#upload\n * @returns {Promise.<Object>} Promise that should be resolved when data is uploaded.\n */\n\n/**\n * Aborts the upload process.\n * After aborting it should reject promise returned from {@link #upload upload()}.\n *\n * Take a look at {@link module:upload/filerepository~UploadAdapter example Adapter implementation} and\n * {@link module:upload/filerepository~FileRepository#createUploadAdapter createUploadAdapter method}.\n *\n * @method module:upload/filerepository~UploadAdapter#abort\n */\n\n/**\n * Object returned by {@link module:upload/filerepository~FileLoader#_createFilePromiseWrapper} method\n * to add more control over the initial file promise passed to {@link module:upload/filerepository~FileLoader}.\n *\n * @protected\n * @typedef {Object} module:upload/filerepository~FilePromiseWrapper\n * @property {Promise.<File>} promise Wrapper promise which can be chained for further processing.\n * @property {Function} rejecter Rejects the promise when called.\n * @property {Boolean} isFulfilled Whether original promise is already fulfilled.\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 upload/ui/filedialogbuttonview\n */\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport View from '@ckeditor/ckeditor5-ui/src/view';\n\n/**\n * The file dialog button view.\n *\n * This component provides a button that opens the native file selection dialog.\n * It can be used to implement the UI of a file upload feature.\n *\n *\t\tconst view = new FileDialogButtonView( locale );\n *\n *\t\tview.set( {\n *\t\t\tacceptedType: 'image/*',\n *\t\t\tallowMultipleFiles: true\n *\t\t} );\n *\n *\t\tview.buttonView.set( {\n *\t\t\tlabel: t( 'Insert image' ),\n *\t\t\ticon: imageIcon,\n *\t\t\ttooltip: true\n *\t\t} );\n *\n *\t\tview.on( 'done', ( evt, files ) => {\n *\t\t\tfor ( const file of Array.from( files ) ) {\n *\t\t\t\tconsole.log( 'Selected file', file );\n *\t\t\t}\n *\t\t} );\n *\n * @extends module:ui/view~View\n */\nexport default class FileDialogButtonView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * The button view of the component.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.buttonView = new ButtonView( locale );\n\n\t\t/**\n\t\t * A hidden `<input>` view used to execute file dialog.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:upload/ui/filedialogbuttonview~FileInputView}\n\t\t */\n\t\tthis._fileInputView = new FileInputView( locale );\n\n\t\t/**\n\t\t * Accepted file types. Can be provided in form of file extensions, media type or one of:\n\t\t * * `audio/*`,\n\t\t * * `video/*`,\n\t\t * * `image/*`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #acceptedType\n\t\t */\n\t\tthis._fileInputView.bind( 'acceptedType' ).to( this );\n\n\t\t/**\n\t\t * Indicates if multiple files can be selected. Defaults to `true`.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #allowMultipleFiles\n\t\t */\n\t\tthis._fileInputView.bind( 'allowMultipleFiles' ).to( this );\n\n\t\t/**\n\t\t * Fired when file dialog is closed with file selected.\n\t\t *\n\t\t *\t\tview.on( 'done', ( evt, files ) => {\n\t\t *\t\t\tfor ( const file of files ) {\n\t\t *\t\t\t\tconsole.log( 'Selected file', file );\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\n\t\t * @event done\n\t\t * @param {Array.<File>} files Array of selected files.\n\t\t */\n\t\tthis._fileInputView.delegate( 'done' ).to( this );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-file-dialog-button'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis.buttonView,\n\t\t\t\tthis._fileInputView\n\t\t\t]\n\t\t} );\n\n\t\tthis.buttonView.on( 'execute', () => {\n\t\t\tthis._fileInputView.open();\n\t\t} );\n\t}\n\n\t/**\n\t * Focuses the {@link #buttonView}.\n\t */\n\tfocus() {\n\t\tthis.buttonView.focus();\n\t}\n}\n\n/**\n * The hidden file input view class.\n *\n * @private\n * @extends module:ui/view~View\n */\nclass FileInputView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * Accepted file types. Can be provided in form of file extensions, media type or one of:\n\t\t * * `audio/*`,\n\t\t * * `video/*`,\n\t\t * * `image/*`.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #acceptedType\n\t\t */\n\t\tthis.set( 'acceptedType' );\n\n\t\t/**\n\t\t * Indicates if multiple files can be selected. Defaults to `false`.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #allowMultipleFiles\n\t\t */\n\t\tthis.set( 'allowMultipleFiles', false );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'input',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-hidden'\n\t\t\t\t],\n\t\t\t\ttype: 'file',\n\t\t\t\ttabindex: '-1',\n\t\t\t\taccept: bind.to( 'acceptedType' ),\n\t\t\t\tmultiple: bind.to( 'allowMultipleFiles' )\n\t\t\t},\n\n\t\t\ton: {\n\t\t\t\t// Removing from code coverage since we cannot programmatically set input element files.\n\t\t\t\tchange: bind.to( /* istanbul ignore next */ () => {\n\t\t\t\t\tif ( this.element && this.element.files && this.element.files.length ) {\n\t\t\t\t\t\tthis.fire( 'done', this.element.files );\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.element.value = '';\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Opens file dialog.\n\t */\n\topen() {\n\t\tthis.element.click();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/* globals window, document */\n\n/**\n * @module adapter-ckfinder/utils\n */\n\nconst TOKEN_COOKIE_NAME = 'ckCsrfToken';\nconst TOKEN_LENGTH = 40;\nconst tokenCharset = 'abcdefghijklmnopqrstuvwxyz0123456789';\n\n/**\n * Returns the CSRF token value. The value is a hash stored in `document.cookie`\n * under the `ckCsrfToken` key. The CSRF token can be used to secure the communication\n * between the web browser and the CKFinder server.\n *\n * @returns {String}\n */\nexport function getCsrfToken() {\n\tlet token = getCookie( TOKEN_COOKIE_NAME );\n\n\tif ( !token || token.length != TOKEN_LENGTH ) {\n\t\ttoken = generateToken( TOKEN_LENGTH );\n\t\tsetCookie( TOKEN_COOKIE_NAME, token );\n\t}\n\n\treturn token;\n}\n\n/**\n * Returns the value of the cookie with a given name or `null` if the cookie is not found.\n *\n * @param {String} name\n * @returns {String|null}\n */\nexport function getCookie( name ) {\n\tname = name.toLowerCase();\n\tconst parts = document.cookie.split( ';' );\n\n\tfor ( const part of parts ) {\n\t\tconst pair = part.split( '=' );\n\t\tconst key = decodeURIComponent( pair[ 0 ].trim().toLowerCase() );\n\n\t\tif ( key === name ) {\n\t\t\treturn decodeURIComponent( pair[ 1 ] );\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Sets the value of the cookie with a given name.\n *\n * @param {String} name\n * @param {String} value\n */\nexport function setCookie( name, value ) {\n\tdocument.cookie = encodeURIComponent( name ) + '=' + encodeURIComponent( value ) + ';path=/';\n}\n\n// Generates the CSRF token with the given length.\n//\n// @private\n// @param {Number} length\n// @returns {string}\nfunction generateToken( length ) {\n\tlet result = '';\n\tconst randValues = new Uint8Array( length );\n\n\twindow.crypto.getRandomValues( randValues );\n\n\tfor ( let j = 0; j < randValues.length; j++ ) {\n\t\tconst character = tokenCharset.charAt( randValues[ j ] % tokenCharset.length );\n\t\tresult += Math.random() > 0.5 ? character.toUpperCase() : character;\n\t}\n\n\treturn result;\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/* globals XMLHttpRequest, FormData */\n\n/**\n * @module adapter-ckfinder/uploadadapter\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { FileRepository } from 'ckeditor5/src/upload';\n\nimport { getCsrfToken } from './utils';\n\n/**\n * A plugin that enables file uploads in CKEditor 5 using the CKFinder serverside connector.\n *\n * See the {@glink features/image-upload/ckfinder \"CKFinder file manager integration\" guide} to learn how to configure\n * and use this feature as well as find out more about the full integration with the file manager\n * provided by the {@link module:ckfinder/ckfinder~CKFinder} plugin.\n *\n * Check out the {@glink features/image-upload/image-upload comprehensive \"Image upload overview\"} to learn about\n * other ways to upload images into CKEditor 5.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CKFinderUploadAdapter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CKFinderUploadAdapter';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst url = this.editor.config.get( 'ckfinder.uploadUrl' );\n\n\t\tif ( !url ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Register CKFinderAdapter\n\t\tthis.editor.plugins.get( FileRepository ).createUploadAdapter = loader => new UploadAdapter( loader, url, this.editor.t );\n\t}\n}\n\n/**\n * Upload adapter for CKFinder.\n *\n * @private\n * @implements module:upload/filerepository~UploadAdapter\n */\nclass UploadAdapter {\n\t/**\n\t * Creates a new adapter instance.\n\t *\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t * @param {String} url\n\t * @param {module:utils/locale~Locale#t} t\n\t */\n\tconstructor( loader, url, t ) {\n\t\t/**\n\t\t * FileLoader instance to use during the upload.\n\t\t *\n\t\t * @member {module:upload/filerepository~FileLoader} #loader\n\t\t */\n\t\tthis.loader = loader;\n\n\t\t/**\n\t\t * Upload URL.\n\t\t *\n\t\t * @member {String} #url\n\t\t */\n\t\tthis.url = url;\n\n\t\t/**\n\t\t * Locale translation method.\n\t\t *\n\t\t * @member {module:utils/locale~Locale#t} #t\n\t\t */\n\t\tthis.t = t;\n\t}\n\n\t/**\n\t * Starts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#upload\n\t * @returns {Promise.<Object>}\n\t */\n\tupload() {\n\t\treturn this.loader.file.then( file => {\n\t\t\treturn new Promise( ( resolve, reject ) => {\n\t\t\t\tthis._initRequest();\n\t\t\t\tthis._initListeners( resolve, reject, file );\n\t\t\t\tthis._sendRequest( file );\n\t\t\t} );\n\t\t} );\n\t}\n\n\t/**\n\t * Aborts the upload process.\n\t *\n\t * @see module:upload/filerepository~UploadAdapter#abort\n\t */\n\tabort() {\n\t\tif ( this.xhr ) {\n\t\t\tthis.xhr.abort();\n\t\t}\n\t}\n\n\t/**\n\t * Initializes the XMLHttpRequest object.\n\t *\n\t * @private\n\t */\n\t_initRequest() {\n\t\tconst xhr = this.xhr = new XMLHttpRequest();\n\n\t\txhr.open( 'POST', this.url, true );\n\t\txhr.responseType = 'json';\n\t}\n\n\t/**\n\t * Initializes XMLHttpRequest listeners.\n\t *\n\t * @private\n\t * @param {Function} resolve Callback function to be called when the request is successful.\n\t * @param {Function} reject Callback function to be called when the request cannot be completed.\n\t * @param {File} file File instance to be uploaded.\n\t */\n\t_initListeners( resolve, reject, file ) {\n\t\tconst xhr = this.xhr;\n\t\tconst loader = this.loader;\n\t\tconst t = this.t;\n\t\tconst genericError = t( 'Cannot upload file:' ) + ` ${ file.name }.`;\n\n\t\txhr.addEventListener( 'error', () => reject( genericError ) );\n\t\txhr.addEventListener( 'abort', () => reject() );\n\t\txhr.addEventListener( 'load', () => {\n\t\t\tconst response = xhr.response;\n\n\t\t\tif ( !response || !response.uploaded ) {\n\t\t\t\treturn reject( response && response.error && response.error.message ? response.error.message : genericError );\n\t\t\t}\n\n\t\t\tresolve( {\n\t\t\t\tdefault: response.url\n\t\t\t} );\n\t\t} );\n\n\t\t// Upload progress when it's supported.\n\t\t/* istanbul ignore else */\n\t\tif ( xhr.upload ) {\n\t\t\txhr.upload.addEventListener( 'progress', evt => {\n\t\t\t\tif ( evt.lengthComputable ) {\n\t\t\t\t\tloader.uploadTotal = evt.total;\n\t\t\t\t\tloader.uploaded = evt.loaded;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Prepares the data and sends the request.\n\t *\n\t * @private\n\t * @param {File} file File instance to be uploaded.\n\t */\n\t_sendRequest( file ) {\n\t\t// Prepare form data.\n\t\tconst data = new FormData();\n\t\tdata.append( 'upload', file );\n\t\tdata.append( 'ckCsrfToken', getCsrfToken() );\n\n\t\t// Send request.\n\t\tthis.xhr.send( data );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { LiveRange } from 'ckeditor5/src/engine';\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * The block autoformatting engine. It allows to format various block patterns. For example,\n * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item.\n *\n * The autoformatting operation is integrated with the undo manager,\n * so the autoformatting step can be undone if the user's intention was not to format the text.\n *\n * See the {@link module:autoformat/blockautoformatediting~blockAutoformatEditing `blockAutoformatEditing`} documentation\n * to learn how to create custom block autoformatters. You can also use\n * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters\n * (lists, headings, bold and italic).\n *\n * @module autoformat/blockautoformatediting\n */\n\n/**\n * Creates a listener triggered on {@link module:engine/model/document~Document#event:change:data `change:data`} event in the document.\n * Calls the callback when inserted text matches the regular expression or the command name\n * if provided instead of the callback.\n *\n * Examples of usage:\n *\n * To convert a paragraph to heading 1 when `- ` is typed, using just the command name:\n *\n *\t\tblockAutoformatEditing( editor, plugin, /^\\- $/, 'heading1' );\n *\n * To convert a paragraph to heading 1 when `- ` is typed, using just the callback:\n *\n *\t\tblockAutoformatEditing( editor, plugin, /^\\- $/, ( context ) => {\n *\t\t\tconst { match } = context;\n *\t\t\tconst headingLevel = match[ 1 ].length;\n *\n *\t\t\teditor.execute( 'heading', {\n *\t\t\t\tformatId: `heading${ headingLevel }`\n *\t\t\t} );\n * \t\t} );\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {module:autoformat/autoformat~Autoformat} plugin The autoformat plugin instance.\n * @param {RegExp} pattern The regular expression to execute on just inserted text. The regular expression is tested against the text\n * from the beginning until the caret position.\n * @param {Function|String} callbackOrCommand The callback to execute or the command to run when the text is matched.\n * In case of providing the callback, it receives the following parameter:\n * * {Object} match RegExp.exec() result of matching the pattern to inserted text.\n */\nexport default function blockAutoformatEditing( editor, plugin, pattern, callbackOrCommand ) {\n\tlet callback;\n\tlet command = null;\n\n\tif ( typeof callbackOrCommand == 'function' ) {\n\t\tcallback = callbackOrCommand;\n\t} else {\n\t\t// We assume that the actual command name was provided.\n\t\tcommand = editor.commands.get( callbackOrCommand );\n\n\t\tcallback = () => {\n\t\t\teditor.execute( callbackOrCommand );\n\t\t};\n\t}\n\n\teditor.model.document.on( 'change:data', ( evt, batch ) => {\n\t\tif ( command && !command.isEnabled || !plugin.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst range = first( editor.model.document.selection.getRanges() );\n\n\t\tif ( !range.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( batch.type == 'transparent' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst changes = Array.from( editor.model.document.differ.getChanges() );\n\t\tconst entry = changes[ 0 ];\n\n\t\t// Typing is represented by only a single change.\n\t\tif ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst blockToFormat = entry.position.parent;\n\n\t\t// Block formatting should be disabled in codeBlocks (#5800).\n\t\tif ( blockToFormat.is( 'element', 'codeBlock' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Only list commands and custom callbacks can be applied inside a list.\n\t\tif ( blockToFormat.is( 'element', 'listItem' ) &&\n\t\t\ttypeof callbackOrCommand !== 'function' &&\n\t\t\t![ 'numberedList', 'bulletedList', 'todoList' ].includes( callbackOrCommand )\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\t// In case a command is bound, do not re-execute it over an existing block style which would result with a style removal.\n\t\t// Instead just drop processing so that autoformat trigger text is not lost. E.g. writing \"# \" in a level 1 heading.\n\t\tif ( command && command.value === true ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst firstNode = blockToFormat.getChild( 0 );\n\t\tconst firstNodeRange = editor.model.createRangeOn( firstNode );\n\n\t\t// Range is only expected to be within or at the very end of the first text node.\n\t\tif ( !firstNodeRange.containsRange( range ) && !range.end.isEqual( firstNodeRange.end ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst match = pattern.exec( firstNode.data.substr( 0, range.end.offset ) );\n\n\t\t// ...and this text node's data match the pattern.\n\t\tif ( !match ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.\n\t\teditor.model.enqueueChange( writer => {\n\t\t\t// Matched range.\n\t\t\tconst start = writer.createPositionAt( blockToFormat, 0 );\n\t\t\tconst end = writer.createPositionAt( blockToFormat, match[ 0 ].length );\n\t\t\tconst range = new LiveRange( start, end );\n\n\t\t\tconst wasChanged = callback( { match } );\n\n\t\t\t// Remove matched text.\n\t\t\tif ( wasChanged !== false ) {\n\t\t\t\twriter.remove( range );\n\n\t\t\t\tconst selectionRange = editor.model.document.selection.getFirstRange();\n\t\t\t\tconst blockRange = writer.createRangeIn( blockToFormat );\n\n\t\t\t\t// If the block is empty and the document selection has been moved when\n\t\t\t\t// applying formatting (e.g. is now in newly created block).\n\t\t\t\tif ( blockToFormat.isEmpty && !blockRange.isEqual( selectionRange ) && !blockRange.containsRange( selectionRange, true ) ) {\n\t\t\t\t\twriter.remove( blockToFormat );\n\t\t\t\t}\n\t\t\t}\n\t\t\trange.detach();\n\t\t} );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * The inline autoformatting engine. It allows to format various inline patterns. For example,\n * it can be configured to make \"foo\" bold when typed `**foo**` (the `**` markers will be removed).\n *\n * The autoformatting operation is integrated with the undo manager,\n * so the autoformatting step can be undone if the user's intention was not to format the text.\n *\n * See the {@link module:autoformat/inlineautoformatediting~inlineAutoformatEditing `inlineAutoformatEditing`} documentation\n * to learn how to create custom inline autoformatters. You can also use\n * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters\n * (lists, headings, bold and italic).\n *\n * @module autoformat/inlineautoformatediting\n */\n\n/**\n * Enables autoformatting mechanism for a given {@link module:core/editor/editor~Editor}.\n *\n * It formats the matched text by applying the given model attribute or by running the provided formatting callback.\n * On every {@link module:engine/model/document~Document#event:change:data data change} in the model document\n * the autoformatting engine checks the text on the left of the selection\n * and executes the provided action if the text matches given criteria (regular expression or callback).\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {module:autoformat/autoformat~Autoformat} plugin The autoformat plugin instance.\n * @param {Function|RegExp} testRegexpOrCallback The regular expression or callback to execute on text.\n * Provided regular expression *must* have three capture groups. The first and the third capture group\n * should match opening and closing delimiters. The second capture group should match the text to format.\n *\n *\t\t// Matches the `**bold text**` pattern.\n *\t\t// There are three capturing groups:\n *\t\t// - The first to match the starting `**` delimiter.\n *\t\t// - The second to match the text to format.\n *\t\t// - The third to match the ending `**` delimiter.\n *\t\tinlineAutoformatEditing( editor, plugin, /(\\*\\*)([^\\*]+?)(\\*\\*)$/g, formatCallback );\n *\n * When a function is provided instead of the regular expression, it will be executed with the text to match as a parameter.\n * The function should return proper \"ranges\" to delete and format.\n *\n *\t\t{\n *\t\t\tremove: [\n *\t\t\t\t[ 0, 1 ],\t// Remove the first letter from the given text.\n *\t\t\t\t[ 5, 6 ]\t// Remove the 6th letter from the given text.\n *\t\t\t],\n *\t\t\tformat: [\n *\t\t\t\t[ 1, 5 ]\t// Format all letters from 2nd to 5th.\n *\t\t\t]\n *\t\t}\n *\n * @param {Function} formatCallback A callback to apply actual formatting.\n * It should return `false` if changes should not be applied (e.g. if a command is disabled).\n *\n *\t\tinlineAutoformatEditing( editor, plugin, /(\\*\\*)([^\\*]+?)(\\*\\*)$/g, ( writer, rangesToFormat ) => {\n *\t\t\tconst command = editor.commands.get( 'bold' );\n *\n *\t\t\tif ( !command.isEnabled ) {\n *\t\t\t\treturn false;\n *\t\t\t}\n *\n *\t\t\tconst validRanges = editor.model.schema.getValidRanges( rangesToFormat, 'bold' );\n *\n *\t\t\tfor ( let range of validRanges ) {\n *\t\t\t\twriter.setAttribute( 'bold', true, range );\n *\t\t\t}\n *\t\t} );\n */\nexport default function inlineAutoformatEditing( editor, plugin, testRegexpOrCallback, formatCallback ) {\n\tlet regExp;\n\tlet testCallback;\n\n\tif ( testRegexpOrCallback instanceof RegExp ) {\n\t\tregExp = testRegexpOrCallback;\n\t} else {\n\t\ttestCallback = testRegexpOrCallback;\n\t}\n\n\t// A test callback run on changed text.\n\ttestCallback = testCallback || ( text => {\n\t\tlet result;\n\t\tconst remove = [];\n\t\tconst format = [];\n\n\t\twhile ( ( result = regExp.exec( text ) ) !== null ) {\n\t\t\t// There should be full match and 3 capture groups.\n\t\t\tif ( result && result.length < 4 ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlet {\n\t\t\t\tindex,\n\t\t\t\t'1': leftDel,\n\t\t\t\t'2': content,\n\t\t\t\t'3': rightDel\n\t\t\t} = result;\n\n\t\t\t// Real matched string - there might be some non-capturing groups so we need to recalculate starting index.\n\t\t\tconst found = leftDel + content + rightDel;\n\t\t\tindex += result[ 0 ].length - found.length;\n\n\t\t\t// Start and End offsets of delimiters to remove.\n\t\t\tconst delStart = [\n\t\t\t\tindex,\n\t\t\t\tindex + leftDel.length\n\t\t\t];\n\t\t\tconst delEnd = [\n\t\t\t\tindex + leftDel.length + content.length,\n\t\t\t\tindex + leftDel.length + content.length + rightDel.length\n\t\t\t];\n\n\t\t\tremove.push( delStart );\n\t\t\tremove.push( delEnd );\n\n\t\t\tformat.push( [ index + leftDel.length, index + leftDel.length + content.length ] );\n\t\t}\n\n\t\treturn {\n\t\t\tremove,\n\t\t\tformat\n\t\t};\n\t} );\n\n\teditor.model.document.on( 'change:data', ( evt, batch ) => {\n\t\tif ( batch.type == 'transparent' || !plugin.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = editor.model;\n\t\tconst selection = model.document.selection;\n\n\t\t// Do nothing if selection is not collapsed.\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst changes = Array.from( model.document.differ.getChanges() );\n\t\tconst entry = changes[ 0 ];\n\n\t\t// Typing is represented by only a single change.\n\t\tif ( changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst focus = selection.focus;\n\t\tconst block = focus.parent;\n\t\tconst { text, range } = getTextAfterCode( model.createRange( model.createPositionAt( block, 0 ), focus ), model );\n\t\tconst testOutput = testCallback( text );\n\t\tconst rangesToFormat = testOutputToRanges( range.start, testOutput.format, model );\n\t\tconst rangesToRemove = testOutputToRanges( range.start, testOutput.remove, model );\n\n\t\tif ( !( rangesToFormat.length && rangesToRemove.length ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Use enqueueChange to create new batch to separate typing batch from the auto-format changes.\n\t\tmodel.enqueueChange( writer => {\n\t\t\t// Apply format.\n\t\t\tconst hasChanged = formatCallback( writer, rangesToFormat );\n\n\t\t\t// Strict check on `false` to have backward compatibility (when callbacks were returning `undefined`).\n\t\t\tif ( hasChanged === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Remove delimiters - use reversed order to not mix the offsets while removing.\n\t\t\tfor ( const range of rangesToRemove.reverse() ) {\n\t\t\t\twriter.remove( range );\n\t\t\t}\n\t\t} );\n\t} );\n}\n\n// Converts output of the test function provided to the inlineAutoformatEditing and converts it to the model ranges\n// inside provided block.\n//\n// @private\n// @param {module:engine/model/position~Position} start\n// @param {Array.<Array>} arrays\n// @param {module:engine/model/model~Model} model\nfunction testOutputToRanges( start, arrays, model ) {\n\treturn arrays\n\t\t.filter( array => ( array[ 0 ] !== undefined && array[ 1 ] !== undefined ) )\n\t\t.map( array => {\n\t\t\treturn model.createRange( start.getShiftedBy( array[ 0 ] ), start.getShiftedBy( array[ 1 ] ) );\n\t\t} );\n}\n\n// Returns the last text line after the last code element from the given range.\n// It is similar to {@link module:typing/utils/getlasttextline.getLastTextLine `getLastTextLine()`},\n// but it ignores any text before the last `code`.\n//\n// @param {module:engine/model/range~Range} range\n// @param {module:engine/model/model~Model} model\n// @returns {module:typing/utils/getlasttextline~LastTextLineData}\nfunction getTextAfterCode( range, model ) {\n\tlet start = range.start;\n\n\tconst text = Array.from( range.getItems() ).reduce( ( rangeText, node ) => {\n\t\t// Trim text to a last occurrence of an inline element and update range start.\n\t\tif ( !( node.is( '$text' ) || node.is( '$textProxy' ) ) || node.getAttribute( 'code' ) ) {\n\t\t\tstart = model.createPositionAfter( node );\n\n\t\t\treturn '';\n\t\t}\n\n\t\treturn rangeText + node.data;\n\t}, '' );\n\n\treturn { text, range: model.createRange( start, range.end ) };\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 autoformat/autoformat\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport blockAutoformatEditing from './blockautoformatediting';\nimport inlineAutoformatEditing from './inlineautoformatediting';\n\n/**\n * Enables a set of predefined autoformatting actions.\n *\n * For a detailed overview, check the {@glink features/autoformat Autoformatting feature documentation}\n * and the {@glink api/autoformat package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Autoformat extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Autoformat';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tthis._addListAutoformats();\n\t\tthis._addBasicStylesAutoformats();\n\t\tthis._addHeadingAutoformats();\n\t\tthis._addBlockQuoteAutoformats();\n\t\tthis._addCodeBlockAutoformats();\n\t\tthis._addHorizontalLineAutoformats();\n\t}\n\n\t/**\n\t * Adds autoformatting related to the {@link module:list/list~List}.\n\t *\n\t * When typed:\n\t * - `* ` or `- ` &ndash; A paragraph will be changed to a bulleted list.\n\t * - `1. ` or `1) ` &ndash; A paragraph will be changed to a numbered list (\"1\" can be any digit or a list of digits).\n\t * - `[] ` or `[ ] ` &ndash; A paragraph will be changed to a to-do list.\n\t * - `[x] ` or `[ x ] ` &ndash; A paragraph will be changed to a checked to-do list.\n\t *\n\t * @private\n\t */\n\t_addListAutoformats() {\n\t\tconst commands = this.editor.commands;\n\n\t\tif ( commands.get( 'bulletedList' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^[*-]\\s$/, 'bulletedList' );\n\t\t}\n\n\t\tif ( commands.get( 'numberedList' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^1[.|)]\\s$/, 'numberedList' );\n\t\t}\n\n\t\tif ( commands.get( 'todoList' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^\\[\\s?\\]\\s$/, 'todoList' );\n\t\t}\n\n\t\tif ( commands.get( 'checkTodoList' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^\\[\\s?x\\s?\\]\\s$/, () => {\n\t\t\t\tthis.editor.execute( 'todoList' );\n\t\t\t\tthis.editor.execute( 'checkTodoList' );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to the {@link module:basic-styles/bold~Bold},\n\t * {@link module:basic-styles/italic~Italic}, {@link module:basic-styles/code~Code}\n\t * and {@link module:basic-styles/strikethrough~Strikethrough}\n\t *\n\t * When typed:\n\t * - `**foobar**` &ndash; `**` characters are removed and `foobar` is set to bold,\n\t * - `__foobar__` &ndash; `__` characters are removed and `foobar` is set to bold,\n\t * - `*foobar*` &ndash; `*` characters are removed and `foobar` is set to italic,\n\t * - `_foobar_` &ndash; `_` characters are removed and `foobar` is set to italic,\n\t * - ``` `foobar` &ndash; ``` ` ``` characters are removed and `foobar` is set to code,\n\t * - `~~foobar~~` &ndash; `~~` characters are removed and `foobar` is set to strikethrough.\n\t *\n\t * @private\n\t */\n\t_addBasicStylesAutoformats() {\n\t\tconst commands = this.editor.commands;\n\n\t\tif ( commands.get( 'bold' ) ) {\n\t\t\tconst boldCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'bold' );\n\n\t\t\tinlineAutoformatEditing( this.editor, this, /(?:^|\\s)(\\*\\*)([^*]+)(\\*\\*)$/g, boldCallback );\n\t\t\tinlineAutoformatEditing( this.editor, this, /(?:^|\\s)(__)([^_]+)(__)$/g, boldCallback );\n\t\t}\n\n\t\tif ( commands.get( 'italic' ) ) {\n\t\t\tconst italicCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'italic' );\n\n\t\t\t// The italic autoformatter cannot be triggered by the bold markers, so we need to check the\n\t\t\t// text before the pattern (e.g. `(?:^|[^\\*])`).\n\t\t\tinlineAutoformatEditing( this.editor, this, /(?:^|\\s)(\\*)([^*_]+)(\\*)$/g, italicCallback );\n\t\t\tinlineAutoformatEditing( this.editor, this, /(?:^|\\s)(_)([^_]+)(_)$/g, italicCallback );\n\t\t}\n\n\t\tif ( commands.get( 'code' ) ) {\n\t\t\tconst codeCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'code' );\n\n\t\t\tinlineAutoformatEditing( this.editor, this, /(`)([^`]+)(`)$/g, codeCallback );\n\t\t}\n\n\t\tif ( commands.get( 'strikethrough' ) ) {\n\t\t\tconst strikethroughCallback = getCallbackFunctionForInlineAutoformat( this.editor, 'strikethrough' );\n\n\t\t\tinlineAutoformatEditing( this.editor, this, /(~~)([^~]+)(~~)$/g, strikethroughCallback );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:heading/heading~Heading}.\n\t *\n\t * It is using a number at the end of the command name to associate it with the proper trigger:\n\t *\n\t * * `heading` with value `heading1` will be executed when typing `#`,\n\t * * `heading` with value `heading2` will be executed when typing `##`,\n\t * * ... up to `heading6` and `######`.\n\t *\n\t * @private\n\t */\n\t_addHeadingAutoformats() {\n\t\tconst command = this.editor.commands.get( 'heading' );\n\n\t\tif ( command ) {\n\t\t\tcommand.modelElements\n\t\t\t\t.filter( name => name.match( /^heading[1-6]$/ ) )\n\t\t\t\t.forEach( modelName => {\n\t\t\t\t\tconst level = modelName[ 7 ];\n\t\t\t\t\tconst pattern = new RegExp( `^(#{${ level }})\\\\s$` );\n\n\t\t\t\t\tblockAutoformatEditing( this.editor, this, pattern, () => {\n\t\t\t\t\t\t// Should only be active if command is enabled and heading style associated with pattern is inactive.\n\t\t\t\t\t\tif ( !command.isEnabled || command.value === modelName ) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.editor.execute( 'heading', { value: modelName } );\n\t\t\t\t\t} );\n\t\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:block-quote/blockquote~BlockQuote}.\n\t *\n\t * When typed:\n\t * * `> ` &ndash; A paragraph will be changed to a block quote.\n\t *\n\t * @private\n\t */\n\t_addBlockQuoteAutoformats() {\n\t\tif ( this.editor.commands.get( 'blockQuote' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^>\\s$/, 'blockQuote' );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:code-block/codeblock~CodeBlock}.\n\t *\n\t * When typed:\n\t * - `` ``` `` &ndash; A paragraph will be changed to a code block.\n\t *\n\t * @private\n\t */\n\t_addCodeBlockAutoformats() {\n\t\tif ( this.editor.commands.get( 'codeBlock' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^```$/, 'codeBlock' );\n\t\t}\n\t}\n\n\t/**\n\t * Adds autoformatting related to {@link module:horizontal-line/horizontalline~HorizontalLine}.\n\t *\n\t * When typed:\n\t * - `` --- `` &ndash; Will be replaced with a horizontal line.\n\t *\n\t * @private\n\t */\n\t_addHorizontalLineAutoformats() {\n\t\tif ( this.editor.commands.get( 'horizontalLine' ) ) {\n\t\t\tblockAutoformatEditing( this.editor, this, /^---$/, 'horizontalLine' );\n\t\t}\n\t}\n}\n\n// Helper function for getting `inlineAutoformatEditing` callbacks that checks if command is enabled.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {String} attributeKey\n// @returns {Function}\nfunction getCallbackFunctionForInlineAutoformat( editor, attributeKey ) {\n\treturn ( writer, rangesToFormat ) => {\n\t\tconst command = editor.commands.get( attributeKey );\n\n\t\tif ( !command.isEnabled ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst validRanges = editor.model.schema.getValidRanges( rangesToFormat, attributeKey );\n\n\t\tfor ( const range of validRanges ) {\n\t\t\twriter.setAttribute( attributeKey, true, range );\n\t\t}\n\n\t\t// After applying attribute to the text, remove given attribute from the selection.\n\t\t// This way user is able to type a text without attribute used by auto formatter.\n\t\twriter.removeSelectionAttribute( attributeKey );\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/attributecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\n/**\n * An extension of the base {@link module:core/command~Command} class, which provides utilities for a command\n * that toggles a single attribute on a text or an element.\n *\n * `AttributeCommand` uses {@link module:engine/model/document~Document#selection}\n * to decide which nodes (if any) should be changed, and applies or removes the attribute from them.\n *\n * The command checks the {@link module:engine/model/model~Model#schema} to decide if it can be enabled\n * for the current selection and to which nodes the attribute can be applied.\n *\n * @extends module:core/command~Command\n */\nexport default class AttributeCommand extends Command {\n\t/**\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {String} attributeKey Attribute that will be set by the command.\n\t */\n\tconstructor( editor, attributeKey ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The attribute that will be set by the command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String}\n\t\t */\n\t\tthis.attributeKey = attributeKey;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection#hasAttribute selection has the attribute} which means that:\n\t\t *\n\t\t * * If the selection is not empty &ndash; That the attribute is set on the first node in the selection that allows this attribute.\n\t\t * * If the selection is empty &ndash; That the selection has the attribute itself (which means that newly typed\n\t\t * text will have this attribute, too).\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t}\n\n\t/**\n\t * Updates the command's {@link #value} and {@link #isEnabled} based on the current selection.\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.value = this._getValueFromFirstAllowedNode();\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, this.attributeKey );\n\t}\n\n\t/**\n\t * Executes the command &mdash; applies the attribute to the selection or removes it from the selection.\n\t *\n\t * If the command is active (`value == true`), it will remove attributes. Otherwise, it will set attributes.\n\t *\n\t * The execution result differs, depending on the {@link module:engine/model/document~Document#selection}:\n\t *\n\t * * If the selection is on a range, the command applies the attribute to all nodes in that range\n\t * (if they are allowed to have this attribute by the {@link module:engine/model/schema~Schema schema}).\n\t * * If the selection is collapsed in a non-empty node, the command applies the attribute to the\n\t * {@link module:engine/model/document~Document#selection} itself (note that typed characters copy attributes from the selection).\n\t * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note\n\t * that the selection inherits all attributes from a node if it is in an empty node).\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply the attribute,\n\t * otherwise the command will remove the attribute.\n\t * If not set, the command will look for its current value to decide what it should do.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tif ( value ) {\n\t\t\t\t\twriter.setSelectionAttribute( this.attributeKey, true );\n\t\t\t\t} else {\n\t\t\t\t\twriter.removeSelectionAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), this.attributeKey );\n\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\twriter.setAttribute( this.attributeKey, value, range );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.removeAttribute( this.attributeKey, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the attribute value of the first node in the selection that allows the attribute.\n\t * For the collapsed selection returns the selection attribute.\n\t *\n\t * @private\n\t * @returns {Boolean} The attribute value.\n\t */\n\t_getValueFromFirstAllowedNode() {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst selection = model.document.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn selection.hasAttribute( this.attributeKey );\n\t\t}\n\n\t\tfor ( const range of selection.getRanges() ) {\n\t\t\tfor ( const item of range.getItems() ) {\n\t\t\t\tif ( schema.checkAttribute( item, this.attributeKey ) ) {\n\t\t\t\t\treturn item.hasAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/bold/boldediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport AttributeCommand from '../attributecommand';\n\nconst BOLD = 'bold';\n\n/**\n * The bold editing feature.\n *\n * It registers the `'bold'` command and introduces the `bold` attribute in the model which renders to the view\n * as a `<strong>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BoldEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BoldEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\t// Allow bold attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: BOLD } );\n\t\teditor.model.schema.setAttributeProperties( BOLD, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Build converter from model to view for data and editing pipelines.\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: BOLD,\n\t\t\tview: 'strong',\n\t\t\tupcastAlso: [\n\t\t\t\t'b',\n\t\t\t\tviewElement => {\n\t\t\t\t\tconst fontWeight = viewElement.getStyle( 'font-weight' );\n\n\t\t\t\t\tif ( !fontWeight ) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Value of the `font-weight` attribute can be defined as a string or a number.\n\t\t\t\t\tif ( fontWeight == 'bold' || Number( fontWeight ) >= 600 ) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: true,\n\t\t\t\t\t\t\tstyles: [ 'font-weight' ]\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create bold command.\n\t\teditor.commands.add( BOLD, new AttributeCommand( editor, BOLD ) );\n\n\t\t// Set the Ctrl+B keystroke.\n\t\teditor.keystrokes.set( 'CTRL+B', BOLD );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/bold/boldui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport boldIcon from '../../theme/icons/bold.svg';\n\nconst BOLD = 'bold';\n\n/**\n * The bold UI feature. It introduces the Bold button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BoldUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BoldUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add bold button to feature components.\n\t\teditor.ui.componentFactory.add( BOLD, locale => {\n\t\t\tconst command = editor.commands.get( BOLD );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Bold' ),\n\t\t\t\ticon: boldIcon,\n\t\t\t\tkeystroke: 'CTRL+B',\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( BOLD );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M10.187 17H5.773c-.637 0-1.092-.138-1.364-.415-.273-.277-.409-.718-.409-1.323V4.738c0-.617.14-1.062.419-1.332.279-.27.73-.406 1.354-.406h4.68c.69 0 1.288.041 1.793.124.506.083.96.242 1.36.478.341.197.644.447.906.75a3.262 3.262 0 0 1 .808 2.162c0 1.401-.722 2.426-2.167 3.075C15.05 10.175 16 11.315 16 13.01a3.756 3.756 0 0 1-2.296 3.504 6.1 6.1 0 0 1-1.517.377c-.571.073-1.238.11-2 .11zm-.217-6.217H7v4.087h3.069c1.977 0 2.965-.69 2.965-2.072 0-.707-.256-1.22-.768-1.537-.512-.319-1.277-.478-2.296-.478zM7 5.13v3.619h2.606c.729 0 1.292-.067 1.69-.2a1.6 1.6 0 0 0 .91-.765c.165-.267.247-.566.247-.897 0-.707-.26-1.176-.778-1.409-.519-.232-1.31-.348-2.375-.348H7z\\\"/></svg>\";","/**\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 basic-styles/italic/italicediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport AttributeCommand from '../attributecommand';\n\nconst ITALIC = 'italic';\n\n/**\n * The italic editing feature.\n *\n * It registers the `'italic'` command, the <kbd>Ctrl+I</kbd> keystroke and introduces the `italic` attribute in the model\n * which renders to the view as an `<i>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ItalicEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ItalicEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow italic attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: ITALIC } );\n\t\teditor.model.schema.setAttributeProperties( ITALIC, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: ITALIC,\n\t\t\tview: 'i',\n\t\t\tupcastAlso: [\n\t\t\t\t'em',\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'font-style': 'italic'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create italic command.\n\t\teditor.commands.add( ITALIC, new AttributeCommand( editor, ITALIC ) );\n\n\t\t// Set the Ctrl+I keystroke.\n\t\teditor.keystrokes.set( 'CTRL+I', ITALIC );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/italic/italicui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport italicIcon from '../../theme/icons/italic.svg';\n\nconst ITALIC = 'italic';\n\n/**\n * The italic UI feature. It introduces the Italic button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ItalicUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ItalicUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add bold button to feature components.\n\t\teditor.ui.componentFactory.add( ITALIC, locale => {\n\t\t\tconst command = editor.commands.get( ITALIC );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Italic' ),\n\t\t\t\ticon: italicIcon,\n\t\t\t\tkeystroke: 'CTRL+I',\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( ITALIC );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m9.586 14.633.021.004c-.036.335.095.655.393.962.082.083.173.15.274.201h1.474a.6.6 0 1 1 0 1.2H5.304a.6.6 0 0 1 0-1.2h1.15c.474-.07.809-.182 1.005-.334.157-.122.291-.32.404-.597l2.416-9.55a1.053 1.053 0 0 0-.281-.823 1.12 1.12 0 0 0-.442-.296H8.15a.6.6 0 0 1 0-1.2h6.443a.6.6 0 1 1 0 1.2h-1.195c-.376.056-.65.155-.823.296-.215.175-.423.439-.623.79l-2.366 9.347z\\\"/></svg>\";","/**\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 basic-styles/superscript/superscriptediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport AttributeCommand from '../attributecommand';\n\nconst SUPERSCRIPT = 'superscript';\n\n/**\n * The superscript editing feature.\n *\n * It registers the `super` command and introduces the `super` attribute in the model which renders to the view\n * as a `<super>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SuperscriptEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SuperscriptEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\t// Allow super attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: SUPERSCRIPT } );\n\t\teditor.model.schema.setAttributeProperties( SUPERSCRIPT, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Build converter from model to view for data and editing pipelines.\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: SUPERSCRIPT,\n\t\t\tview: 'sup',\n\t\t\tupcastAlso: [\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'vertical-align': 'super'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create super command.\n\t\teditor.commands.add( SUPERSCRIPT, new AttributeCommand( editor, SUPERSCRIPT ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/superscript/superscriptui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport superscriptIcon from '../../theme/icons/superscript.svg';\n\nconst SUPERSCRIPT = 'superscript';\n\n/**\n * The superscript UI feature. It introduces the Superscript button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SuperscriptUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SuperscriptUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add superscript button to feature components.\n\t\teditor.ui.componentFactory.add( SUPERSCRIPT, locale => {\n\t\t\tconst command = editor.commands.get( SUPERSCRIPT );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Superscript' ),\n\t\t\t\ticon: superscriptIcon,\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( SUPERSCRIPT );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M15.677 8.678h2.549c.254 0 .447.05.58.152a.49.49 0 0 1 .201.413.54.54 0 0 1-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 0 1-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 0 1 .288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 0 0-.554-.917 1.197 1.197 0 0 0-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 0 0-.164.39 1.609 1.609 0 0 1-.258.488c-.096.114-.237.17-.423.17a.558.558 0 0 1-.405-.156.568.568 0 0 1-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 0 1 1.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 0 1 1.004 1.032 1.984 1.984 0 0 1-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 0 0-.24.309zM7.03 10.349l3.818-3.819a.8.8 0 1 1 1.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 1 1-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 1 1-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 1 1 3.212 6.53l3.818 3.82z\\\"/></svg>\";","/**\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 basic-styles/subscript/subscriptediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport AttributeCommand from '../attributecommand';\n\nconst SUBSCRIPT = 'subscript';\n\n/**\n * The subscript editing feature.\n *\n * It registers the `sub` command and introduces the `sub` attribute in the model which renders to the view\n * as a `<sub>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SubscriptEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SubscriptEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\t// Allow sub attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: SUBSCRIPT } );\n\t\teditor.model.schema.setAttributeProperties( SUBSCRIPT, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Build converter from model to view for data and editing pipelines.\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: SUBSCRIPT,\n\t\t\tview: 'sub',\n\t\t\tupcastAlso: [\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'vertical-align': 'sub'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create sub command.\n\t\teditor.commands.add( SUBSCRIPT, new AttributeCommand( editor, SUBSCRIPT ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/subscript/subscriptui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport subscriptIcon from '../../theme/icons/subscript.svg';\n\nconst SUBSCRIPT = 'subscript';\n\n/**\n * The subscript UI feature. It introduces the Subscript button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SubscriptUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SubscriptUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add subscript button to feature components.\n\t\teditor.ui.componentFactory.add( SUBSCRIPT, locale => {\n\t\t\tconst command = editor.commands.get( SUBSCRIPT );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Subscript' ),\n\t\t\t\ticon: subscriptIcon,\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( SUBSCRIPT );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m7.03 10.349 3.818-3.819a.8.8 0 1 1 1.132 1.132L8.16 11.48l3.819 3.818a.8.8 0 1 1-1.132 1.132L7.03 12.61l-3.818 3.82a.8.8 0 1 1-1.132-1.132L5.9 11.48 2.08 7.662A.8.8 0 1 1 3.212 6.53l3.818 3.82zm8.147 7.829h2.549c.254 0 .447.05.58.152a.49.49 0 0 1 .201.413.54.54 0 0 1-.159.393c-.105.108-.266.162-.48.162h-3.594c-.245 0-.435-.066-.572-.197a.621.621 0 0 1-.205-.463c0-.114.044-.265.132-.453a1.62 1.62 0 0 1 .288-.444c.433-.436.824-.81 1.172-1.122.348-.312.597-.517.747-.615.267-.183.49-.368.667-.553.177-.185.312-.375.405-.57.093-.194.139-.384.139-.57a1.008 1.008 0 0 0-.554-.917 1.197 1.197 0 0 0-.56-.133c-.426 0-.761.182-1.005.546a2.332 2.332 0 0 0-.164.39 1.609 1.609 0 0 1-.258.488c-.096.114-.237.17-.423.17a.558.558 0 0 1-.405-.156.568.568 0 0 1-.161-.427c0-.218.05-.446.151-.683.101-.238.252-.453.452-.646s.454-.349.762-.467a2.998 2.998 0 0 1 1.081-.178c.498 0 .923.076 1.274.228a1.916 1.916 0 0 1 1.004 1.032 1.984 1.984 0 0 1-.156 1.794c-.2.32-.405.572-.613.754-.208.182-.558.468-1.048.857-.49.39-.826.691-1.008.906a2.703 2.703 0 0 0-.24.309z\\\"/></svg>\";","/**\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 basic-styles/underline/underlineediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport AttributeCommand from '../attributecommand';\n\nconst UNDERLINE = 'underline';\n\n/**\n * The underline editing feature.\n *\n * It registers the `'underline'` command, the <kbd>Ctrl+U</kbd> keystroke\n * and introduces the `underline` attribute in the model which renders to the view as an `<u>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UnderlineEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'UnderlineEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow strikethrough attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: UNDERLINE } );\n\t\teditor.model.schema.setAttributeProperties( UNDERLINE, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: UNDERLINE,\n\t\t\tview: 'u',\n\t\t\tupcastAlso: {\n\t\t\t\tstyles: {\n\t\t\t\t\t'text-decoration': 'underline'\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Create underline command.\n\t\teditor.commands.add( UNDERLINE, new AttributeCommand( editor, UNDERLINE ) );\n\n\t\t// Set the Ctrl+U keystroke.\n\t\teditor.keystrokes.set( 'CTRL+U', 'underline' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/underline/underlineui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport underlineIcon from '../../theme/icons/underline.svg';\n\nconst UNDERLINE = 'underline';\n\n/**\n * The underline UI feature. It introduces the Underline button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UnderlineUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'UnderlineUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add bold button to feature components.\n\t\teditor.ui.componentFactory.add( UNDERLINE, locale => {\n\t\t\tconst command = editor.commands.get( UNDERLINE );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Underline' ),\n\t\t\t\ticon: underlineIcon,\n\t\t\t\tkeystroke: 'CTRL+U',\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( UNDERLINE );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 18v-1.5h14V18zm2.2-8V3.6c0-.4.4-.6.8-.6.3 0 .7.2.7.6v6.2c0 2 1.3 2.8 3.2 2.8 1.9 0 3.4-.9 3.4-2.9V3.6c0-.3.4-.5.8-.5.3 0 .7.2.7.5V10c0 2.7-2.2 4-4.9 4-2.6 0-4.7-1.2-4.7-4z\\\"/></svg>\";","/**\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 basic-styles/strikethrough/strikethroughediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport AttributeCommand from '../attributecommand';\n\nconst STRIKETHROUGH = 'strikethrough';\n\n/**\n * The strikethrough editing feature.\n *\n * It registers the `'strikethrough'` command, the <kbd>Ctrl+Shift+X</kbd> keystroke and introduces the\n * `strikethroughsthrough` attribute in the model which renders to the view\n * as a `<s>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class StrikethroughEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'StrikethroughEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow strikethrough attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: STRIKETHROUGH } );\n\t\teditor.model.schema.setAttributeProperties( STRIKETHROUGH, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: STRIKETHROUGH,\n\t\t\tview: 's',\n\t\t\tupcastAlso: [\n\t\t\t\t'del',\n\t\t\t\t'strike',\n\t\t\t\t{\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\t'text-decoration': 'line-through'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\t// Create strikethrough command.\n\t\teditor.commands.add( STRIKETHROUGH, new AttributeCommand( editor, STRIKETHROUGH ) );\n\n\t\t// Set the Ctrl+Shift+X keystroke.\n\t\teditor.keystrokes.set( 'CTRL+SHIFT+X', 'strikethrough' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/strikethrough/strikethroughui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport strikethroughIcon from '../../theme/icons/strikethrough.svg';\n\nconst STRIKETHROUGH = 'strikethrough';\n\n/**\n * The strikethrough UI feature. It introduces the Strikethrough button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class StrikethroughUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'StrikethroughUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add strikethrough button to feature components.\n\t\teditor.ui.componentFactory.add( STRIKETHROUGH, locale => {\n\t\t\tconst command = editor.commands.get( STRIKETHROUGH );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Strikethrough' ),\n\t\t\t\ticon: strikethroughIcon,\n\t\t\t\tkeystroke: 'CTRL+SHIFT+X',\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( STRIKETHROUGH );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 16.4c-.8-.4-1.5-.9-2.2-1.5a.6.6 0 0 1-.2-.5l.3-.6h1c1 1.2 2.1 1.7 3.7 1.7 1 0 1.8-.3 2.3-.6.6-.4.6-1.2.6-1.3.2-1.2-.9-2.1-.9-2.1h2.1c.3.7.4 1.2.4 1.7v.8l-.6 1.2c-.6.8-1.1 1-1.6 1.2a6 6 0 0 1-2.4.6c-1 0-1.8-.3-2.5-.6zM6.8 9 6 8.3c-.4-.5-.5-.8-.5-1.6 0-.7.1-1.3.5-1.8.4-.6 1-1 1.6-1.3a6.3 6.3 0 0 1 4.7 0 4 4 0 0 1 1.7 1l.3.7c0 .1.2.4-.2.7-.4.2-.9.1-1 0a3 3 0 0 0-1.2-1c-.4-.2-1-.3-2-.4-.7 0-1.4.2-2 .6-.8.6-1 .8-1 1.5 0 .8.5 1 1.2 1.5.6.4 1.1.7 1.9 1H6.8z\\\"/><path d=\\\"M3 10.5V9h14v1.5z\\\"/></svg>\";","/**\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 typing/utils/changebuffer\n */\n\n/**\n * Change buffer allows to group atomic changes (like characters that have been typed) into\n * {@link module:engine/model/batch~Batch batches}.\n *\n * Batches represent single undo steps, hence changes added to one single batch are undone together.\n *\n * The buffer has a configurable limit of atomic changes that it can accommodate. After the limit was\n * exceeded (see {@link ~ChangeBuffer#input}), a new batch is created in {@link ~ChangeBuffer#batch}.\n *\n * To use the change buffer you need to let it know about the number of changes that were added to the batch:\n *\n *\t\tconst buffer = new ChangeBuffer( model, LIMIT );\n *\n *\t\t// Later on in your feature:\n *\t\tbuffer.batch.insert( pos, insertedCharacters );\n *\t\tbuffer.input( insertedCharacters.length );\n *\n */\nexport default class ChangeBuffer {\n\t/**\n\t * Creates a new instance of the change buffer.\n\t *\n\t * @param {module:engine/model/model~Model} model\n\t * @param {Number} [limit=20] The maximum number of atomic changes which can be contained in one batch.\n\t */\n\tconstructor( model, limit = 20 ) {\n\t\t/**\n\t\t * The model instance.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model} #model\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The number of atomic changes in the buffer. Once it exceeds the {@link #limit},\n\t\t * the {@link #batch batch} is set to a new one.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #size\n\t\t */\n\t\tthis.size = 0;\n\n\t\t/**\n\t\t * The maximum number of atomic changes which can be contained in one batch.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #limit\n\t\t */\n\t\tthis.limit = limit;\n\n\t\t/**\n\t\t * Whether the buffer is locked. A locked buffer cannot be reset unless it gets unlocked.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isLocked\n\t\t */\n\t\tthis.isLocked = false;\n\n\t\t// The function to be called in order to notify the buffer about batches which appeared in the document.\n\t\t// The callback will check whether it is a new batch and in that case the buffer will be flushed.\n\t\t//\n\t\t// The reason why the buffer needs to be flushed whenever a new batch appears is that the changes added afterwards\n\t\t// should be added to a new batch. For instance, when the user types, then inserts an image, and then types again,\n\t\t// the characters typed after inserting the image should be added to a different batch than the characters typed before.\n\t\tthis._changeCallback = ( evt, batch ) => {\n\t\t\tif ( batch.type != 'transparent' && batch !== this._batch ) {\n\t\t\t\tthis._reset( true );\n\t\t\t}\n\t\t};\n\n\t\tthis._selectionChangeCallback = () => {\n\t\t\tthis._reset();\n\t\t};\n\n\t\tthis.model.document.on( 'change', this._changeCallback );\n\n\t\tthis.model.document.selection.on( 'change:range', this._selectionChangeCallback );\n\t\tthis.model.document.selection.on( 'change:attribute', this._selectionChangeCallback );\n\n\t\t/**\n\t\t * The current batch instance.\n\t\t *\n\t\t * @private\n\t\t * @member #_batch\n\t\t */\n\n\t\t/**\n\t\t * The callback to document the change event which later needs to be removed.\n\t\t *\n\t\t * @private\n\t\t * @member #_changeCallback\n\t\t */\n\n\t\t/**\n\t\t * The callback to document selection `change:attribute` and `change:range` events which resets the buffer.\n\t\t *\n\t\t * @private\n\t\t * @member #_selectionChangeCallback\n\t\t */\n\t}\n\n\t/**\n\t * The current batch to which a feature should add its operations. Once the {@link #size}\n\t * is reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.\n\t *\n\t * @type {module:engine/model/batch~Batch}\n\t */\n\tget batch() {\n\t\tif ( !this._batch ) {\n\t\t\tthis._batch = this.model.createBatch();\n\t\t}\n\n\t\treturn this._batch;\n\t}\n\n\t/**\n\t * The input number of changes into the buffer. Once the {@link #size} is\n\t * reached or exceeds the {@link #limit}, the batch is set to a new instance and the size is reset.\n\t *\n\t * @param {Number} changeCount The number of atomic changes to input.\n\t */\n\tinput( changeCount ) {\n\t\tthis.size += changeCount;\n\n\t\tif ( this.size >= this.limit ) {\n\t\t\tthis._reset( true );\n\t\t}\n\t}\n\n\t/**\n\t * Locks the buffer.\n\t */\n\tlock() {\n\t\tthis.isLocked = true;\n\t}\n\n\t/**\n\t * Unlocks the buffer.\n\t */\n\tunlock() {\n\t\tthis.isLocked = false;\n\t}\n\n\t/**\n\t * Destroys the buffer.\n\t */\n\tdestroy() {\n\t\tthis.model.document.off( 'change', this._changeCallback );\n\t\tthis.model.document.selection.off( 'change:range', this._selectionChangeCallback );\n\t\tthis.model.document.selection.off( 'change:attribute', this._selectionChangeCallback );\n\t}\n\n\t/**\n\t * Resets the change buffer.\n\t *\n\t * @private\n\t * @param {Boolean} [ignoreLock] Whether internal lock {@link #isLocked} should be ignored.\n\t */\n\t_reset( ignoreLock ) {\n\t\tif ( !this.isLocked || ignoreLock ) {\n\t\t\tthis._batch = null;\n\t\t\tthis.size = 0;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/inputcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport ChangeBuffer from './utils/changebuffer';\n\n/**\n * The input command. Used by the {@link module:typing/input~Input input feature} to handle typing.\n *\n * @extends module:core/command~Command\n */\nexport default class InputCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Number} undoStepSize The maximum number of atomic changes\n\t * which can be contained in one batch in the command buffer.\n\t */\n\tconstructor( editor, undoStepSize ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Typing's change buffer used to group subsequent changes into batches.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {module:typing/utils/changebuffer~ChangeBuffer} #_buffer\n\t\t */\n\t\tthis._buffer = new ChangeBuffer( editor.model, undoStepSize );\n\n\t\t/**\n\t\t * Stores batches created by the input command. The batches are used to differentiate input batches from other batches using\n\t\t * {@link module:typing/input~Input#isInput} method.\n\t\t *\n\t\t * @type {WeakSet<module:engine/model/batch~Batch>}\n\t\t * @protected\n\t\t */\n\t\tthis._batches = new WeakSet();\n\t}\n\n\t/**\n\t * The current change buffer.\n\t *\n\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t */\n\tget buffer() {\n\t\treturn this._buffer;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis._buffer.destroy();\n\t}\n\n\t/**\n\t * Executes the input command. It replaces the content within the given range with the given text.\n\t * Replacing is a two step process, first the content within the range is removed and then the new text is inserted\n\t * at the beginning of the range (which after the removal is a collapsed range).\n\t *\n\t * @fires execute\n\t * @param {Object} [options] The command options.\n\t * @param {String} [options.text=''] The text to be inserted.\n\t * @param {module:engine/model/range~Range} [options.range] The range in which the text is inserted. Defaults\n\t * to the first range in the current selection.\n\t * @param {module:engine/model/range~Range} [options.resultRange] The range where the selection\n\t * should be placed after the insertion. If not specified, the selection will be placed right after\n\t * the inserted text.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst text = options.text || '';\n\t\tconst textInsertions = text.length;\n\t\tconst selection = options.range ? model.createSelection( options.range ) : doc.selection;\n\t\tconst resultRange = options.resultRange;\n\n\t\tmodel.enqueueChange( this._buffer.batch, writer => {\n\t\t\tthis._buffer.lock();\n\n\t\t\t// Store the batch as an 'input' batch for the Input.isInput( batch ) check.\n\t\t\tthis._batches.add( this._buffer.batch );\n\n\t\t\tmodel.deleteContent( selection );\n\n\t\t\tif ( text ) {\n\t\t\t\tmodel.insertContent( writer.createText( text, doc.selection.getAttributes() ), selection );\n\t\t\t}\n\n\t\t\tif ( resultRange ) {\n\t\t\t\twriter.setSelection( resultRange );\n\t\t\t} else if ( !selection.is( 'documentSelection' ) ) {\n\t\t\t\twriter.setSelection( selection );\n\t\t\t}\n\n\t\t\tthis._buffer.unlock();\n\n\t\t\tthis._buffer.input( textInsertions );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/injectunsafekeystrokeshandling\n */\n\nimport { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Handles keystrokes which are unsafe for typing. This handler's logic is explained\n * in https://github.com/ckeditor/ckeditor5-typing/issues/83#issuecomment-398690251.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport default function injectUnsafeKeystrokesHandling( editor ) {\n\tlet latestCompositionSelection = null;\n\n\tconst model = editor.model;\n\tconst view = editor.editing.view;\n\tconst inputCommand = editor.commands.get( 'input' );\n\n\t// For Android, we want to handle keystrokes on `beforeinput` to be sure that code in `DeleteObserver` already had a chance to be fired.\n\tif ( env.isAndroid ) {\n\t\tview.document.on( 'beforeinput', ( evt, evtData ) => handleUnsafeKeystroke( evtData ), { priority: 'lowest' } );\n\t} else {\n\t\tview.document.on( 'keydown', ( evt, evtData ) => handleUnsafeKeystroke( evtData ), { priority: 'lowest' } );\n\t}\n\n\tview.document.on( 'compositionstart', handleCompositionStart, { priority: 'lowest' } );\n\n\tview.document.on( 'compositionend', () => {\n\t\tlatestCompositionSelection = model.createSelection( model.document.selection );\n\t}, { priority: 'lowest' } );\n\n\t// Handles the keydown event. We need to guess whether such keystroke is going to result\n\t// in typing. If so, then before character insertion happens, any selected content needs\n\t// to be deleted. Otherwise the default browser deletion mechanism would be\n\t// triggered, resulting in:\n\t//\n\t// * Hundreds of mutations which could not be handled.\n\t// * But most importantly, loss of control over how the content is being deleted.\n\t//\n\t// The method is used in a low-priority listener, hence allowing other listeners (e.g. delete or enter features)\n\t// to handle the event.\n\t//\n\t// @param {module:engine/view/observer/keyobserver~KeyEventData} evtData\n\tfunction handleUnsafeKeystroke( evtData ) {\n\t\tconst doc = model.document;\n\t\tconst isComposing = view.document.isComposing;\n\t\tconst isSelectionUnchanged = latestCompositionSelection && latestCompositionSelection.isEqual( doc.selection );\n\n\t\t// Reset stored composition selection.\n\t\tlatestCompositionSelection = null;\n\n\t\t// By relying on the state of the input command we allow disabling the entire input easily\n\t\t// by just disabling the input command. We couldve used here the delete command but that\n\t\t// would mean requiring the delete feature which would block loading one without the other.\n\t\t// We could also check the editor.isReadOnly property, but that wouldn't allow to block\n\t\t// the input without blocking other features.\n\t\tif ( !inputCommand.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( isNonTypingKeystroke( evtData ) || doc.selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If during composition, deletion should be prevented as it may remove composed sequence (#83).\n\t\tif ( isComposing && evtData.keyCode === 229 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there is a `keydown` event fired with '229' keycode it might be related\n\t\t// to recent composition. Check if selection is the same as upon ending recent composition,\n\t\t// if so do not remove selected content as it will remove composed sequence (#83).\n\t\tif ( !isComposing && evtData.keyCode === 229 && isSelectionUnchanged ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdeleteSelectionContent();\n\t}\n\n\t// Handles the `compositionstart` event. It is used only in special cases to remove the contents\n\t// of a non-collapsed selection so composition itself does not result in complex mutations.\n\t//\n\t// The special case mentioned above is a situation in which the `keydown` event is fired after\n\t// `compositionstart` event. In such cases {@link #handleKeydown} cannot clear current selection\n\t// contents (because it is too late and will break the composition) so the composition handler takes care of it.\n\tfunction handleCompositionStart() {\n\t\tconst doc = model.document;\n\t\tconst isFlatSelection = doc.selection.rangeCount === 1 ? doc.selection.getFirstRange().isFlat : true;\n\n\t\t// If on `compositionstart` there is a non-collapsed selection which start and end have different parents\n\t\t// it means the `handleKeydown()` method did not remove its contents. It happens usually because\n\t\t// of different order of events (`compositionstart` before `keydown` - in Safari). In such cases\n\t\t// we need to remove selection contents on composition start (#83).\n\t\tif ( doc.selection.isCollapsed || isFlatSelection ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdeleteSelectionContent();\n\t}\n\n\tfunction deleteSelectionContent() {\n\t\tconst buffer = inputCommand.buffer;\n\n\t\tbuffer.lock();\n\n\t\tconst batch = buffer.batch;\n\t\tinputCommand._batches.add( batch );\n\n\t\tmodel.enqueueChange( batch, () => {\n\t\t\tmodel.deleteContent( model.document.selection );\n\t\t} );\n\n\t\tbuffer.unlock();\n\t}\n}\n\nconst safeKeycodes = [\n\tgetCode( 'arrowUp' ),\n\tgetCode( 'arrowRight' ),\n\tgetCode( 'arrowDown' ),\n\tgetCode( 'arrowLeft' ),\n\t9, // Tab\n\t16, // Shift\n\t17, // Ctrl\n\t18, // Alt\n\t19, // Pause\n\t20, // CapsLock\n\t27, // Escape\n\t33, // PageUp\n\t34, // PageDown\n\t35, // Home\n\t36, // End,\n\t45, // Insert,\n\t91, // Windows,\n\t93, // Menu key,\n\t144, // NumLock\n\t145, // ScrollLock,\n\t173, // Mute/Unmute\n\t174, // Volume up\n\t175, // Volume down,\n\t176, // Next song,\n\t177, // Previous song,\n\t178, // Stop,\n\t179, // Play/Pause,\n\t255 // Display brightness (increase and decrease)\n];\n\n// Function keys.\nfor ( let code = 112; code <= 135; code++ ) {\n\tsafeKeycodes.push( code );\n}\n\n/**\n * Returns `true` if a keystroke will **not** result in \"typing\".\n *\n * For instance, keystrokes that result in typing are letters \"a-zA-Z\", numbers \"0-9\", delete, backspace, etc.\n *\n * Keystrokes that do not cause typing are, for instance, Fn keys (F5, F8, etc.), arrow keys (←, →, ↑, ↓),\n * Tab (↹), \"Windows logo key\" (⊞ Win), etc.\n *\n * Note: This implementation is very simple and will need to be refined with time.\n *\n * @param {module:engine/view/observer/keyobserver~KeyEventData} keyData\n * @returns {Boolean}\n */\nexport function isNonTypingKeystroke( keyData ) {\n\t// Keystrokes which contain Ctrl or Cmd don't represent typing.\n\tif ( keyData.ctrlKey || keyData.metaKey ) {\n\t\treturn true;\n\t}\n\n\treturn safeKeycodes.includes( keyData.keyCode );\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 typing/utils/utils\n */\n\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport diffToChanges from '@ckeditor/ckeditor5-utils/src/difftochanges';\n\n/**\n * Returns true if container children have mutated or more than a single text node was changed.\n *\n * @private\n * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n * module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n * @returns {Boolean}\n */\nexport function containerChildrenMutated( mutations ) {\n\tif ( mutations.length == 0 ) {\n\t\treturn false;\n\t}\n\n\t// Check if there is any mutation of `children` type or any mutation that changes more than one text node.\n\tfor ( const mutation of mutations ) {\n\t\tif ( mutation.type === 'children' && !getSingleTextNodeChange( mutation ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Returns change made to a single text node.\n *\n * @private\n * @param {module:engine/view/observer/mutationobserver~MutatedText|\n * module:engine/view/observer/mutationobserver~MutatedChildren} mutation\n * @returns {Object|undefined} Change object (see {@link module:utils/difftochanges~diffToChanges} output)\n * or undefined if more than a single text node was changed.\n */\nexport function getSingleTextNodeChange( mutation ) {\n\t// One new node.\n\tif ( mutation.newChildren.length - mutation.oldChildren.length != 1 ) {\n\t\treturn;\n\t}\n\n\t// Which is text.\n\tconst diffResult = diff( mutation.oldChildren, mutation.newChildren, compareChildNodes );\n\tconst changes = diffToChanges( diffResult, mutation.newChildren );\n\n\t// In case of [ delete, insert, insert ] the previous check will not exit.\n\tif ( changes.length > 1 ) {\n\t\treturn;\n\t}\n\n\tconst change = changes[ 0 ];\n\n\t// Which is text.\n\tif ( !( !!change.values[ 0 ] && change.values[ 0 ].is( '$text' ) ) ) {\n\t\treturn;\n\t}\n\n\treturn change;\n}\n\n/**\n * Checks whether two view nodes are identical, which means they are the same object\n * or contain exactly same data (in case of text nodes).\n *\n * @private\n * @param {module:engine/view/node~Node} oldChild\n * @param {module:engine/view/node~Node} newChild\n * @returns {Boolean}\n */\nexport function compareChildNodes( oldChild, newChild ) {\n\tif ( !!oldChild && oldChild.is( '$text' ) && !!newChild && newChild.is( '$text' ) ) {\n\t\treturn oldChild.data === newChild.data;\n\t} else {\n\t\treturn oldChild === newChild;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module utils/difftochanges\n */\n\n/**\n * Creates a set of changes which need to be applied to the input in order to transform\n * it into the output. This function can be used with strings or arrays.\n *\n *\t\tconst input = Array.from( 'abc' );\n *\t\tconst output = Array.from( 'xaby' );\n *\t\tconst changes = diffToChanges( diff( input, output ), output );\n *\n *\t\tchanges.forEach( change => {\n *\t\t\tif ( change.type == 'insert' ) {\n *\t\t\t\tinput.splice( change.index, 0, ...change.values );\n *\t\t\t} else if ( change.type == 'delete' ) {\n *\t\t\t\tinput.splice( change.index, change.howMany );\n *\t\t\t}\n *\t\t} );\n *\n *\t\tinput.join( '' ) == output.join( '' ); // -> true\n *\n * @param {Array.<'equal'|'insert'|'delete'>} diff Result of {@link module:utils/diff~diff}.\n * @param {String|Array} output The string or array which was passed as diff's output.\n * @returns {Array.<Object>} Set of changes (insert or delete) which need to be applied to the input\n * in order to transform it into the output.\n */\nexport default function diffToChanges( diff, output ) {\n\tconst changes = [];\n\tlet index = 0;\n\tlet lastOperation;\n\n\tdiff.forEach( change => {\n\t\tif ( change == 'equal' ) {\n\t\t\tpushLast();\n\n\t\t\tindex++;\n\t\t} else if ( change == 'insert' ) {\n\t\t\tif ( isContinuationOf( 'insert' ) ) {\n\t\t\t\tlastOperation.values.push( output[ index ] );\n\t\t\t} else {\n\t\t\t\tpushLast();\n\n\t\t\t\tlastOperation = {\n\t\t\t\t\ttype: 'insert',\n\t\t\t\t\tindex,\n\t\t\t\t\tvalues: [ output[ index ] ]\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tindex++;\n\t\t} else /* if ( change == 'delete' ) */ {\n\t\t\tif ( isContinuationOf( 'delete' ) ) {\n\t\t\t\tlastOperation.howMany++;\n\t\t\t} else {\n\t\t\t\tpushLast();\n\n\t\t\t\tlastOperation = {\n\t\t\t\t\ttype: 'delete',\n\t\t\t\t\tindex,\n\t\t\t\t\thowMany: 1\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t} );\n\n\tpushLast();\n\n\treturn changes;\n\n\tfunction pushLast() {\n\t\tif ( lastOperation ) {\n\t\t\tchanges.push( lastOperation );\n\t\t\tlastOperation = null;\n\t\t}\n\t}\n\n\tfunction isContinuationOf( expected ) {\n\t\treturn lastOperation && lastOperation.type == expected;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/injecttypingmutationshandling\n */\n\nimport diff from '@ckeditor/ckeditor5-utils/src/diff';\nimport DomConverter from '@ckeditor/ckeditor5-engine/src/view/domconverter';\n\nimport { getSingleTextNodeChange, containerChildrenMutated } from './utils';\n\n/**\n * Handles mutations caused by normal typing.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport default function injectTypingMutationsHandling( editor ) {\n\teditor.editing.view.document.on( 'mutations', ( evt, mutations, viewSelection ) => {\n\t\tnew MutationHandler( editor ).handle( mutations, viewSelection );\n\t} );\n}\n\n/**\n * Helper class for translating DOM mutations into model changes.\n *\n * @private\n */\nclass MutationHandler {\n\t/**\n\t * Creates an instance of the mutation handler.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t */\n\tconstructor( editor ) {\n\t\t/**\n\t\t * Editor instance for which mutations are handled.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:core/editor/editor~Editor} #editor\n\t\t */\n\t\tthis.editor = editor;\n\n\t\t/**\n\t\t * The editing controller.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/controller/editingcontroller~EditingController} #editing\n\t\t */\n\t\tthis.editing = this.editor.editing;\n\t}\n\n\t/**\n\t * Handles given mutations.\n\t *\n\t * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n\t * module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n\t * @param {module:engine/view/selection~Selection|null} viewSelection\n\t */\n\thandle( mutations, viewSelection ) {\n\t\tif ( containerChildrenMutated( mutations ) ) {\n\t\t\tthis._handleContainerChildrenMutations( mutations, viewSelection );\n\t\t} else {\n\t\t\tfor ( const mutation of mutations ) {\n\t\t\t\t// Fortunately it will never be both.\n\t\t\t\tthis._handleTextMutation( mutation, viewSelection );\n\t\t\t\tthis._handleTextNodeInsertion( mutation );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handles situations when container's children mutated during input. This can happen when\n\t * the browser is trying to \"fix\" DOM in certain situations. For example, when the user starts to type\n\t * in `<p><a href=\"\"><i>Link{}</i></a></p>`, the browser might change the order of elements\n\t * to `<p><i><a href=\"\">Link</a>x{}</i></p>`. A similar situation happens when the spell checker\n\t * replaces a word wrapped with `<strong>` with a word wrapped with a `<b>` element.\n\t *\n\t * To handle such situations, the common DOM ancestor of all mutations is converted to the model representation\n\t * and then compared with the current model to calculate the proper text change.\n\t *\n\t * Note: Single text node insertion is handled in {@link #_handleTextNodeInsertion} and text node mutation is handled\n\t * in {@link #_handleTextMutation}).\n\t *\n\t * @private\n\t * @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n\t * module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n\t * @param {module:engine/view/selection~Selection|null} viewSelection\n\t */\n\t_handleContainerChildrenMutations( mutations, viewSelection ) {\n\t\t// Get common ancestor of all mutations.\n\t\tconst mutationsCommonAncestor = getMutationsContainer( mutations );\n\n\t\t// Quit if there is no common ancestor.\n\t\tif ( !mutationsCommonAncestor ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst domConverter = this.editor.editing.view.domConverter;\n\n\t\t// Get common ancestor in DOM.\n\t\tconst domMutationCommonAncestor = domConverter.mapViewToDom( mutationsCommonAncestor );\n\n\t\t// Create fresh DomConverter so it will not use existing mapping and convert current DOM to model.\n\t\t// This wouldn't be needed if DomConverter would allow to create fresh view without checking any mappings.\n\t\tconst freshDomConverter = new DomConverter( this.editor.editing.view.document );\n\t\tconst modelFromCurrentDom = this.editor.data.toModel(\n\t\t\tfreshDomConverter.domToView( domMutationCommonAncestor )\n\t\t).getChild( 0 );\n\n\t\t// Current model.\n\t\tconst currentModel = this.editor.editing.mapper.toModelElement( mutationsCommonAncestor );\n\n\t\t// If common ancestor is not mapped, do not do anything. It probably is a parent of another view element.\n\t\t// That means that we would need to diff model elements (see `if` below). Better return early instead of\n\t\t// trying to get a reasonable model ancestor. It will fell into the `if` below anyway.\n\t\t// This situation happens for example for lists. If `<ul>` is a common ancestor, `currentModel` is `undefined`\n\t\t// because `<ul>` is not mapped (`<li>`s are).\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/718.\n\t\tif ( !currentModel ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get children from both ancestors.\n\t\tconst modelFromDomChildren = Array.from( modelFromCurrentDom.getChildren() );\n\t\tconst currentModelChildren = Array.from( currentModel.getChildren() );\n\n\t\t// Remove the last `<softBreak>` from the end of `modelFromDomChildren` if there is no `<softBreak>` in current model.\n\t\t// If the described scenario happened, it means that this is a bogus `<br />` added by a browser.\n\t\tconst lastDomChild = modelFromDomChildren[ modelFromDomChildren.length - 1 ];\n\t\tconst lastCurrentChild = currentModelChildren[ currentModelChildren.length - 1 ];\n\n\t\tconst isLastDomChildSoftBreak = lastDomChild && lastDomChild.is( 'element', 'softBreak' );\n\t\tconst isLastCurrentChildSoftBreak = lastCurrentChild && !lastCurrentChild.is( 'element', 'softBreak' );\n\n\t\tif ( isLastDomChildSoftBreak && isLastCurrentChildSoftBreak ) {\n\t\t\tmodelFromDomChildren.pop();\n\t\t}\n\n\t\tconst schema = this.editor.model.schema;\n\n\t\t// Skip situations when common ancestor has any container elements.\n\t\tif ( !isSafeForTextMutation( modelFromDomChildren, schema ) || !isSafeForTextMutation( currentModelChildren, schema ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Replace &nbsp; inserted by the browser with normal space. See comment in `_handleTextMutation`.\n\t\t// Replace non-texts with any character. This is potentially dangerous but passes in manual tests. The thing is\n\t\t// that we need to take care of proper indexes so we cannot simply remove non-text elements from the content.\n\t\t// By inserting a character we keep all the real texts on their indexes.\n\t\tconst newText = modelFromDomChildren.map( item => item.is( '$text' ) ? item.data : '@' ).join( '' ).replace( /\\u00A0/g, ' ' );\n\t\tconst oldText = currentModelChildren.map( item => item.is( '$text' ) ? item.data : '@' ).join( '' ).replace( /\\u00A0/g, ' ' );\n\n\t\t// Do nothing if mutations created same text.\n\t\tif ( oldText === newText ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst diffResult = diff( oldText, newText );\n\n\t\tconst { firstChangeAt, insertions, deletions } = calculateChanges( diffResult );\n\n\t\t// Try setting new model selection according to passed view selection.\n\t\tlet modelSelectionRange = null;\n\n\t\tif ( viewSelection ) {\n\t\t\tmodelSelectionRange = this.editing.mapper.toModelRange( viewSelection.getFirstRange() );\n\t\t}\n\n\t\tconst insertText = newText.substr( firstChangeAt, insertions );\n\t\tconst removeRange = this.editor.model.createRange(\n\t\t\tthis.editor.model.createPositionAt( currentModel, firstChangeAt ),\n\t\t\tthis.editor.model.createPositionAt( currentModel, firstChangeAt + deletions )\n\t\t);\n\n\t\tthis.editor.execute( 'input', {\n\t\t\ttext: insertText,\n\t\t\trange: removeRange,\n\t\t\tresultRange: modelSelectionRange\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_handleTextMutation( mutation, viewSelection ) {\n\t\tif ( mutation.type != 'text' ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Replace &nbsp; inserted by the browser with normal space.\n\t\t// We want only normal spaces in the model and in the view. Renderer and DOM Converter will be then responsible\n\t\t// for rendering consecutive spaces using &nbsp;, but the model and the view has to be clear.\n\t\t// Other feature may introduce inserting non-breakable space on specific key stroke (for example shift + space).\n\t\t// However then it will be handled outside of mutations, like enter key is.\n\t\t// The replacing is here because it has to be done before `diff` and `diffToChanges` functions, as they\n\t\t// take `newText` and compare it to (cleaned up) view.\n\t\t// It could also be done in mutation observer too, however if any outside plugin would like to\n\t\t// introduce additional events for mutations, they would get already cleaned up version (this may be good or not).\n\t\tconst newText = mutation.newText.replace( /\\u00A0/g, ' ' );\n\t\t// To have correct `diffResult`, we also compare view node text data with &nbsp; replaced by space.\n\t\tconst oldText = mutation.oldText.replace( /\\u00A0/g, ' ' );\n\n\t\t// Do nothing if mutations created same text.\n\t\tif ( oldText === newText ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst diffResult = diff( oldText, newText );\n\n\t\tconst { firstChangeAt, insertions, deletions } = calculateChanges( diffResult );\n\n\t\t// Try setting new model selection according to passed view selection.\n\t\tlet modelSelectionRange = null;\n\n\t\tif ( viewSelection ) {\n\t\t\tmodelSelectionRange = this.editing.mapper.toModelRange( viewSelection.getFirstRange() );\n\t\t}\n\n\t\t// Get the position in view and model where the changes will happen.\n\t\tconst viewPos = this.editing.view.createPositionAt( mutation.node, firstChangeAt );\n\t\tconst modelPos = this.editing.mapper.toModelPosition( viewPos );\n\t\tconst removeRange = this.editor.model.createRange( modelPos, modelPos.getShiftedBy( deletions ) );\n\t\tconst insertText = newText.substr( firstChangeAt, insertions );\n\n\t\tthis.editor.execute( 'input', {\n\t\t\ttext: insertText,\n\t\t\trange: removeRange,\n\t\t\tresultRange: modelSelectionRange\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_handleTextNodeInsertion( mutation ) {\n\t\tif ( mutation.type != 'children' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst change = getSingleTextNodeChange( mutation );\n\t\tconst viewPos = this.editing.view.createPositionAt( mutation.node, change.index );\n\t\tconst modelPos = this.editing.mapper.toModelPosition( viewPos );\n\t\tconst insertedText = change.values[ 0 ].data;\n\n\t\tthis.editor.execute( 'input', {\n\t\t\t// Replace &nbsp; inserted by the browser with normal space.\n\t\t\t// See comment in `_handleTextMutation`.\n\t\t\t// In this case we don't need to do this before `diff` because we diff whole nodes.\n\t\t\t// Just change &nbsp; in case there are some.\n\t\t\ttext: insertedText.replace( /\\u00A0/g, ' ' ),\n\t\t\trange: this.editor.model.createRange( modelPos )\n\t\t} );\n\t}\n}\n\n// Returns first common ancestor of all mutations that is either {@link module:engine/view/containerelement~ContainerElement}\n// or {@link module:engine/view/rootelement~RootElement}.\n//\n// @private\n// @param {Array.<module:engine/view/observer/mutationobserver~MutatedText|\n// module:engine/view/observer/mutationobserver~MutatedChildren>} mutations\n// @returns {module:engine/view/containerelement~ContainerElement|engine/view/rootelement~RootElement|undefined}\nfunction getMutationsContainer( mutations ) {\n\tconst lca = mutations\n\t\t.map( mutation => mutation.node )\n\t\t.reduce( ( commonAncestor, node ) => {\n\t\t\treturn commonAncestor.getCommonAncestor( node, { includeSelf: true } );\n\t\t} );\n\n\tif ( !lca ) {\n\t\treturn;\n\t}\n\n\t// We need to look for container and root elements only, so check all LCA's\n\t// ancestors (starting from itself).\n\treturn lca.getAncestors( { includeSelf: true, parentFirst: true } )\n\t\t.find( element => element.is( 'containerElement' ) || element.is( 'rootElement' ) );\n}\n\n// Returns true if provided array contains content that won't be problematic during diffing and text mutation handling.\n//\n// @param {Array.<module:engine/model/node~Node>} children\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isSafeForTextMutation( children, schema ) {\n\treturn children.every( child => schema.isInline( child ) );\n}\n\n// Calculates first change index and number of characters that should be inserted and deleted starting from that index.\n//\n// @private\n// @param diffResult\n// @returns {{insertions: number, deletions: number, firstChangeAt: *}}\nfunction calculateChanges( diffResult ) {\n\t// Index where the first change happens. Used to set the position from which nodes will be removed and where will be inserted.\n\tlet firstChangeAt = null;\n\t// Index where the last change happens. Used to properly count how many characters have to be removed and inserted.\n\tlet lastChangeAt = null;\n\n\t// Get `firstChangeAt` and `lastChangeAt`.\n\tfor ( let i = 0; i < diffResult.length; i++ ) {\n\t\tconst change = diffResult[ i ];\n\n\t\tif ( change != 'equal' ) {\n\t\t\tfirstChangeAt = firstChangeAt === null ? i : firstChangeAt;\n\t\t\tlastChangeAt = i;\n\t\t}\n\t}\n\n\t// How many characters, starting from `firstChangeAt`, should be removed.\n\tlet deletions = 0;\n\t// How many characters, starting from `firstChangeAt`, should be inserted.\n\tlet insertions = 0;\n\n\tfor ( let i = firstChangeAt; i <= lastChangeAt; i++ ) {\n\t\t// If there is no change (equal) or delete, the character is existing in `oldText`. We count it for removing.\n\t\tif ( diffResult[ i ] != 'insert' ) {\n\t\t\tdeletions++;\n\t\t}\n\n\t\t// If there is no change (equal) or insert, the character is existing in `newText`. We count it for inserting.\n\t\tif ( diffResult[ i ] != 'delete' ) {\n\t\t\tinsertions++;\n\t\t}\n\t}\n\n\treturn { insertions, deletions, firstChangeAt };\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 typing/input\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport InputCommand from './inputcommand';\n\nimport injectUnsafeKeystrokesHandling from './utils/injectunsafekeystrokeshandling';\nimport injectTypingMutationsHandling from './utils/injecttypingmutationshandling';\n\n/**\n * Handles text input coming from the keyboard or other input methods.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Input extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Input';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// TODO The above default configuration value should be defined using editor.config.define() once it's fixed.\n\t\tconst inputCommand = new InputCommand( editor, editor.config.get( 'typing.undoStep' ) || 20 );\n\n\t\teditor.commands.add( 'input', inputCommand );\n\n\t\tinjectUnsafeKeystrokesHandling( editor );\n\t\tinjectTypingMutationsHandling( editor );\n\t}\n\n\t/**\n\t * Checks batch if it is a result of user input - e.g. typing.\n\t *\n\t *\t\tconst input = editor.plugins.get( 'Input' );\n\t *\n\t *\t\teditor.model.document.on( 'change:data', ( evt, batch ) => {\n\t *\t\t\tif ( input.isInput( batch ) ) {\n\t *\t\t\t\tconsole.log( 'The user typed something...' );\n\t *\t\t\t}\n\t *\t\t} );\n\t *\n\t * **Note:** This method checks if the batch was created using {@link module:typing/inputcommand~InputCommand 'input'}\n\t * command as typing changes coming from user input are inserted to the document using that command.\n\t *\n\t * @param {module:engine/model/batch~Batch} batch A batch to check.\n\t * @returns {Boolean}\n\t */\n\tisInput( batch ) {\n\t\tconst inputCommand = this.editor.commands.get( 'input' );\n\n\t\treturn inputCommand._batches.has( batch );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/deletecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport count from '@ckeditor/ckeditor5-utils/src/count';\n\nimport ChangeBuffer from './utils/changebuffer';\n\n/**\n * The delete command. Used by the {@link module:typing/delete~Delete delete feature} to handle the <kbd>Delete</kbd> and\n * <kbd>Backspace</kbd> keys.\n *\n * @extends module:core/command~Command\n */\nexport default class DeleteCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {'forward'|'backward'} direction The directionality of the delete describing in what direction it\n\t * should consume the content when the selection is collapsed.\n\t */\n\tconstructor( editor, direction ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The directionality of the delete describing in what direction it should\n\t\t * consume the content when the selection is collapsed.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'forward'|'backward'} #direction\n\t\t */\n\t\tthis.direction = direction;\n\n\t\t/**\n\t\t * Delete's change buffer used to group subsequent changes into batches.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t\t */\n\t\tthis._buffer = new ChangeBuffer( editor.model, editor.config.get( 'typing.undoStep' ) );\n\t}\n\n\t/**\n\t * The current change buffer.\n\t *\n\t * @type {module:typing/utils/changebuffer~ChangeBuffer}\n\t */\n\tget buffer() {\n\t\treturn this._buffer;\n\t}\n\n\t/**\n\t * Executes the delete command. Depending on whether the selection is collapsed or not, deletes its content\n\t * or a piece of content in the {@link #direction defined direction}.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] The command options.\n\t * @param {'character'} [options.unit='character'] See {@link module:engine/model/utils/modifyselection~modifySelection}'s options.\n\t * @param {Number} [options.sequence=1] A number describing which subsequent delete event it is without the key being released.\n\t * See the {@link module:engine/view/document~Document#event:delete} event data.\n\t * @param {module:engine/model/selection~Selection} [options.selection] Selection to remove. If not set, current model selection\n\t * will be used.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.enqueueChange( this._buffer.batch, writer => {\n\t\t\tthis._buffer.lock();\n\n\t\t\tconst selection = writer.createSelection( options.selection || doc.selection );\n\t\t\tconst sequence = options.sequence || 1;\n\n\t\t\t// Do not replace the whole selected content if selection was collapsed.\n\t\t\t// This prevents such situation:\n\t\t\t//\n\t\t\t// <h1></h1><p>[]</p>\t--> <h1>[</h1><p>]</p> \t\t--> <p></p>\n\t\t\t// starting content\t\t--> after `modifySelection`\t--> after `deleteContent`.\n\t\t\tconst doNotResetEntireContent = selection.isCollapsed;\n\n\t\t\t// Try to extend the selection in the specified direction.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tmodel.modifySelection( selection, { direction: this.direction, unit: options.unit } );\n\t\t\t}\n\n\t\t\t// Check if deleting in an empty editor. See #61.\n\t\t\tif ( this._shouldEntireContentBeReplacedWithParagraph( sequence ) ) {\n\t\t\t\tthis._replaceEntireContentWithParagraph( writer );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Check if deleting in the first empty block.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/8137.\n\t\t\tif ( this._shouldReplaceFirstBlockWithParagraph( selection, sequence ) ) {\n\t\t\t\tthis.editor.execute( 'paragraph', { selection } );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If selection is still collapsed, then there's nothing to delete.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet changeCount = 0;\n\n\t\t\tselection.getFirstRange().getMinimalFlatRanges().forEach( range => {\n\t\t\t\tchangeCount += count(\n\t\t\t\t\trange.getWalker( { singleCharacters: true, ignoreElementEnd: true, shallow: true } )\n\t\t\t\t);\n\t\t\t} );\n\n\t\t\tmodel.deleteContent( selection, {\n\t\t\t\tdoNotResetEntireContent,\n\t\t\t\tdirection: this.direction\n\t\t\t} );\n\n\t\t\tthis._buffer.input( changeCount );\n\n\t\t\twriter.setSelection( selection );\n\n\t\t\tthis._buffer.unlock();\n\t\t} );\n\t}\n\n\t/**\n\t * If the user keeps <kbd>Backspace</kbd> or <kbd>Delete</kbd> key pressed, the content of the current\n\t * editable will be cleared. However, this will not yet lead to resetting the remaining block to a paragraph\n\t * (which happens e.g. when the user does <kbd>Ctrl</kbd> + <kbd>A</kbd>, <kbd>Backspace</kbd>).\n\t *\n\t * But, if the user pressed the key in an empty editable for the first time,\n\t * we want to replace the entire content with a paragraph if:\n\t *\n\t * * the current limit element is empty,\n\t * * the paragraph is allowed in the limit element,\n\t * * the limit doesn't already have a paragraph inside.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5-typing/issues/61.\n\t *\n\t * @private\n\t * @param {Number} sequence A number describing which subsequent delete event it is without the key being released.\n\t * @returns {Boolean}\n\t */\n\t_shouldEntireContentBeReplacedWithParagraph( sequence ) {\n\t\t// Does nothing if user pressed and held the \"Backspace\" or \"Delete\" key.\n\t\tif ( sequence > 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst limitElement = model.schema.getLimitElement( selection );\n\n\t\t// If a collapsed selection contains the whole content it means that the content is empty\n\t\t// (from the user perspective).\n\t\tconst limitElementIsEmpty = selection.isCollapsed && selection.containsEntireContent( limitElement );\n\n\t\tif ( !limitElementIsEmpty ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !model.schema.checkChild( limitElement, 'paragraph' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst limitElementFirstChild = limitElement.getChild( 0 );\n\n\t\t// Does nothing if the limit element already contains only a paragraph.\n\t\t// We ignore the case when paragraph might have some inline elements (<p><inlineWidget>[]</inlineWidget></p>)\n\t\t// because we don't support such cases yet and it's unclear whether inlineWidget shouldn't be a limit itself.\n\t\tif ( limitElementFirstChild && limitElementFirstChild.name === 'paragraph' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * The entire content is replaced with the paragraph. Selection is moved inside the paragraph.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The model writer.\n\t */\n\t_replaceEntireContentWithParagraph( writer ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst selection = doc.selection;\n\t\tconst limitElement = model.schema.getLimitElement( selection );\n\t\tconst paragraph = writer.createElement( 'paragraph' );\n\n\t\twriter.remove( writer.createRangeIn( limitElement ) );\n\t\twriter.insert( paragraph, limitElement );\n\n\t\twriter.setSelection( paragraph, 0 );\n\t}\n\n\t/**\n\t * Checks if the selection is inside an empty element that is the first child of the limit element\n\t * and should be replaced with a paragraph.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The selection.\n\t * @param {Number} sequence A number describing which subsequent delete event it is without the key being released.\n\t * @returns {Boolean}\n\t */\n\t_shouldReplaceFirstBlockWithParagraph( selection, sequence ) {\n\t\tconst model = this.editor.model;\n\n\t\t// Does nothing if user pressed and held the \"Backspace\" key or it was a \"Delete\" button.\n\t\tif ( sequence > 1 || this.direction != 'backward' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst position = selection.getFirstPosition();\n\t\tconst limitElement = model.schema.getLimitElement( position );\n\t\tconst limitElementFirstChild = limitElement.getChild( 0 );\n\n\t\t// Only elements that are direct children of the limit element can be replaced.\n\t\t// Unwrapping from a block quote should be handled in a dedicated feature.\n\t\tif ( position.parent != limitElementFirstChild ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// A block should be replaced only if it was empty.\n\t\tif ( !selection.containsEntireContent( limitElementFirstChild ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Replace with a paragraph only if it's allowed there.\n\t\tif ( !model.schema.checkChild( limitElement, 'paragraph' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Does nothing if the limit element already contains only a paragraph.\n\t\tif ( limitElementFirstChild.name == 'paragraph' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/deleteobserver\n */\n\nimport Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';\nimport DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';\nimport BubblingEventInfo from '@ckeditor/ckeditor5-engine/src/view/observer/bubblingeventinfo';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * Delete observer introduces the {@link module:engine/view/document~Document#event:delete} event.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class DeleteObserver extends Observer {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst document = view.document;\n\t\tlet sequence = 0;\n\n\t\tdocument.on( 'keyup', ( evt, data ) => {\n\t\t\tif ( data.keyCode == keyCodes.delete || data.keyCode == keyCodes.backspace ) {\n\t\t\t\tsequence = 0;\n\t\t\t}\n\t\t} );\n\n\t\tdocument.on( 'keydown', ( evt, data ) => {\n\t\t\tconst deleteData = {};\n\n\t\t\tif ( data.keyCode == keyCodes.delete ) {\n\t\t\t\tdeleteData.direction = 'forward';\n\t\t\t\tdeleteData.unit = 'character';\n\t\t\t} else if ( data.keyCode == keyCodes.backspace ) {\n\t\t\t\tdeleteData.direction = 'backward';\n\t\t\t\tdeleteData.unit = 'codePoint';\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst hasWordModifier = env.isMac ? data.altKey : data.ctrlKey;\n\t\t\tdeleteData.unit = hasWordModifier ? 'word' : deleteData.unit;\n\t\t\tdeleteData.sequence = ++sequence;\n\n\t\t\tfireViewDeleteEvent( evt, data.domEvent, deleteData );\n\t\t} );\n\n\t\t// `beforeinput` is handled only for Android devices. Desktop Chrome and iOS are skipped because they are working fine now.\n\t\tif ( env.isAndroid ) {\n\t\t\tdocument.on( 'beforeinput', ( evt, data ) => {\n\t\t\t\t// If event type is other than `deleteContentBackward` then this is not deleting.\n\t\t\t\tif ( data.domEvent.inputType != 'deleteContentBackward' ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst deleteData = {\n\t\t\t\t\tunit: 'codepoint',\n\t\t\t\t\tdirection: 'backward',\n\t\t\t\t\tsequence: 1\n\t\t\t\t};\n\n\t\t\t\t// Android IMEs may change the DOM selection on `beforeinput` event so that the selection contains all the text\n\t\t\t\t// that the IME wants to remove. We will pass this information to `delete` event so proper part of the content is removed.\n\t\t\t\t//\n\t\t\t\t// Sometimes it is only expanding by a one character (in case of collapsed selection). In this case we don't need to\n\t\t\t\t// set a different selection to remove, it will work just fine.\n\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\tif ( domSelection.anchorNode == domSelection.focusNode && domSelection.anchorOffset + 1 != domSelection.focusOffset ) {\n\t\t\t\t\tdeleteData.selectionToRemove = view.domConverter.domSelectionToView( domSelection );\n\t\t\t\t}\n\n\t\t\t\tfireViewDeleteEvent( evt, data.domEvent, deleteData );\n\t\t\t} );\n\t\t}\n\n\t\tfunction fireViewDeleteEvent( originalEvent, domEvent, deleteData ) {\n\t\t\tconst event = new BubblingEventInfo( document, 'delete', document.selection.getFirstRange() );\n\n\t\t\tdocument.fire( event, new DomEventData( document, domEvent, deleteData ) );\n\n\t\t\t// Stop the original event if `delete` event was stopped.\n\t\t\t// https://github.com/ckeditor/ckeditor5/issues/753\n\t\t\tif ( event.stop.called ) {\n\t\t\t\toriginalEvent.stop();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {}\n}\n\n/**\n * Event fired when the user tries to delete content (e.g. presses <kbd>Delete</kbd> or <kbd>Backspace</kbd>).\n *\n * Note: This event is fired by the {@link module:typing/deleteobserver~DeleteObserver observer}\n * (usually registered by the {@link module:typing/delete~Delete delete feature}).\n *\n * @event module:engine/view/document~Document#event:delete\n * @param {module:engine/view/observer/domeventdata~DomEventData} data\n * @param {'forward'|'delete'} data.direction The direction in which the deletion should happen.\n * @param {'character'|'word'} data.unit The \"amount\" of content that should be deleted.\n * @param {Number} data.sequence A number describing which subsequent delete event it is without the key being released.\n * If it's 2 or more it means that the key was pressed and hold.\n * @param {module:engine/view/selection~Selection} [data.selectionToRemove] View selection which content should be removed. If not set,\n * current selection should be used.\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 typing/delete\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport DeleteCommand from './deletecommand';\nimport DeleteObserver from './deleteobserver';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\n/**\n * The delete and backspace feature. Handles the <kbd>Delete</kbd> and <kbd>Backspace</kbd> keys in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Delete extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Delete';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\tview.addObserver( DeleteObserver );\n\n\t\tconst deleteForwardCommand = new DeleteCommand( editor, 'forward' );\n\n\t\t// Register `deleteForward` command and add `forwardDelete` command as an alias for backward compatibility.\n\t\teditor.commands.add( 'deleteForward', deleteForwardCommand );\n\t\teditor.commands.add( 'forwardDelete', deleteForwardCommand );\n\n\t\teditor.commands.add( 'delete', new DeleteCommand( editor, 'backward' ) );\n\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\tconst deleteCommandParams = { unit: data.unit, sequence: data.sequence };\n\n\t\t\t// If a specific (view) selection to remove was set, convert it to a model selection and set as a parameter for `DeleteCommand`.\n\t\t\tif ( data.selectionToRemove ) {\n\t\t\t\tconst modelSelection = editor.model.createSelection();\n\t\t\t\tconst ranges = [];\n\n\t\t\t\tfor ( const viewRange of data.selectionToRemove.getRanges() ) {\n\t\t\t\t\tranges.push( editor.editing.mapper.toModelRange( viewRange ) );\n\t\t\t\t}\n\n\t\t\t\tmodelSelection.setTo( ranges );\n\n\t\t\t\tdeleteCommandParams.selection = modelSelection;\n\t\t\t}\n\n\t\t\teditor.execute( data.direction == 'forward' ? 'deleteForward' : 'delete', deleteCommandParams );\n\n\t\t\tdata.preventDefault();\n\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\n\t\t// Android IMEs have a quirk - they change DOM selection after the input changes were performed by the browser.\n\t\t// This happens on `keyup` event. Android doesn't know anything about our deletion and selection handling. Even if the selection\n\t\t// was changed during input events, IME remembers the position where the selection \"should\" be placed and moves it there.\n\t\t//\n\t\t// To prevent incorrect selection, we save the selection after deleting here and then re-set it on `keyup`. This has to be done\n\t\t// on DOM selection level, because on `keyup` the model selection is still the same as it was just after deletion, so it\n\t\t// wouldn't be changed and the fix would do nothing.\n\t\t//\n\t\tif ( env.isAndroid ) {\n\t\t\tlet domSelectionAfterDeletion = null;\n\n\t\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\tdomSelectionAfterDeletion = {\n\t\t\t\t\tanchorNode: domSelection.anchorNode,\n\t\t\t\t\tanchorOffset: domSelection.anchorOffset,\n\t\t\t\t\tfocusNode: domSelection.focusNode,\n\t\t\t\t\tfocusOffset: domSelection.focusOffset\n\t\t\t\t};\n\t\t\t}, { priority: 'lowest' } );\n\n\t\t\tthis.listenTo( viewDocument, 'keyup', ( evt, data ) => {\n\t\t\t\tif ( domSelectionAfterDeletion ) {\n\t\t\t\t\tconst domSelection = data.domTarget.ownerDocument.defaultView.getSelection();\n\n\t\t\t\t\tdomSelection.collapse( domSelectionAfterDeletion.anchorNode, domSelectionAfterDeletion.anchorOffset );\n\t\t\t\t\tdomSelection.extend( domSelectionAfterDeletion.focusNode, domSelectionAfterDeletion.focusOffset );\n\n\t\t\t\t\tdomSelectionAfterDeletion = null;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module typing/utils/getlasttextline\n */\n\n/**\n * Returns the last text line from the given range.\n *\n * \"The last text line\" is understood as text (from one or more text nodes) which is limited either by a parent block\n * or by inline elements (e.g. `<softBreak>`).\n *\n *\t\tconst rangeToCheck = model.createRange(\n *\t\t\tmodel.createPositionAt( paragraph, 0 ),\n *\t\t\tmodel.createPositionAt( paragraph, 'end' )\n *\t\t);\n *\n *\t\tconst { text, range } = getLastTextLine( rangeToCheck, model );\n *\n * For model below, the returned `text` will be \"Foo bar baz\" and `range` will be set on whole `<paragraph>` content:\n *\n *\t\t<paragraph>Foo bar baz<paragraph>\n *\n * However, in below case, `text` will be set to \"baz\" and `range` will be set only on \"baz\".\n *\n *\t\t<paragraph>Foo<softBreak></softBreak>bar<softBreak></softBreak>baz<paragraph>\n *\n * @protected\n * @param {module:engine/model/range~Range} range\n * @param {module:engine/model/model~Model} model\n * @returns {module:typing/utils/getlasttextline~LastTextLineData}\n */\nexport default function getLastTextLine( range, model ) {\n\tlet start = range.start;\n\n\tconst text = Array.from( range.getItems() ).reduce( ( rangeText, node ) => {\n\t\t// Trim text to a last occurrence of an inline element and update range start.\n\t\tif ( !( node.is( '$text' ) || node.is( '$textProxy' ) ) ) {\n\t\t\tstart = model.createPositionAfter( node );\n\n\t\t\treturn '';\n\t\t}\n\n\t\treturn rangeText + node.data;\n\t}, '' );\n\n\treturn { text, range: model.createRange( start, range.end ) };\n}\n\n/**\n * The value returned by {@link module:typing/utils/getlasttextline~getLastTextLine}.\n *\n * @typedef {Object} module:typing/utils/getlasttextline~LastTextLineData\n *\n * @property {String} text The text from the text nodes in the last text line.\n * @property {module:engine/model/range~Range} range The range set on the text nodes in the last text line.\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 typing/textwatcher\n */\n\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport getLastTextLine from './utils/getlasttextline';\n\n/**\n * The text watcher feature.\n *\n * Fires the {@link module:typing/textwatcher~TextWatcher#event:matched:data `matched:data`},\n * {@link module:typing/textwatcher~TextWatcher#event:matched:selection `matched:selection`} and\n * {@link module:typing/textwatcher~TextWatcher#event:unmatched `unmatched`} events on typing or selection changes.\n *\n * @private\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class TextWatcher {\n\t/**\n\t * Creates a text watcher instance.\n\t *\n\t * @param {module:engine/model/model~Model} model\n\t * @param {Function} testCallback See {@link module:typing/textwatcher~TextWatcher#testCallback}.\n\t */\n\tconstructor( model, testCallback ) {\n\t\t/**\n\t\t * The editor's model.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/model~Model}\n\t\t */\n\t\tthis.model = model;\n\n\t\t/**\n\t\t * The function used to match the text.\n\t\t *\n\t\t * The test callback can return 3 values:\n\t\t *\n\t\t * * `false` if there is no match,\n\t\t * * `true` if there is a match,\n\t\t * * an object if there is a match and we want to pass some additional information to the {@link #event:matched:data} event.\n\t\t *\n\t\t * @member {Function} #testCallback\n\t\t * @returns {Object} testResult\n\t\t */\n\t\tthis.testCallback = testCallback;\n\n\t\t/**\n\t\t * Whether there is a match currently.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis.hasMatch = false;\n\n\t\t/**\n\t\t * Flag indicating whether the `TextWatcher` instance is enabled or disabled.\n\t\t * A disabled TextWatcher will not evaluate text.\n\t\t *\n\t\t * To disable TextWatcher:\n\t\t *\n\t\t *\t\tconst watcher = new TextWatcher( editor.model, testCallback );\n\t\t *\n\t\t *\t\t// After this a testCallback will not be called.\n\t\t *\t\twatcher.isEnabled = false;\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\t// Toggle text watching on isEnabled state change.\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tif ( this.isEnabled ) {\n\t\t\t\tthis._startListening();\n\t\t\t} else {\n\t\t\t\tthis.stopListening( model.document.selection );\n\t\t\t\tthis.stopListening( model.document );\n\t\t\t}\n\t\t} );\n\n\t\tthis._startListening();\n\t}\n\n\t/**\n\t * Starts listening to the editor for typing and selection events.\n\t *\n\t * @private\n\t */\n\t_startListening() {\n\t\tconst model = this.model;\n\t\tconst document = model.document;\n\n\t\tthis.listenTo( document.selection, 'change:range', ( evt, { directChange } ) => {\n\t\t\t// Indirect changes (i.e. when the user types or external changes are applied) are handled in the document's change event.\n\t\t\tif ( !directChange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Act only on collapsed selection.\n\t\t\tif ( !document.selection.isCollapsed ) {\n\t\t\t\tif ( this.hasMatch ) {\n\t\t\t\t\tthis.fire( 'unmatched' );\n\t\t\t\t\tthis.hasMatch = false;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._evaluateTextBeforeSelection( 'selection' );\n\t\t} );\n\n\t\tthis.listenTo( document, 'change:data', ( evt, batch ) => {\n\t\t\tif ( batch.type == 'transparent' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._evaluateTextBeforeSelection( 'data', { batch } );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the editor content for matched text.\n\t *\n\t * @fires matched:data\n\t * @fires matched:selection\n\t * @fires unmatched\n\t *\n\t * @private\n\t * @param {'data'|'selection'} suffix A suffix used for generating the event name.\n\t * @param {Object} data Data object for event.\n\t */\n\t_evaluateTextBeforeSelection( suffix, data = {} ) {\n\t\tconst model = this.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst rangeBeforeSelection = model.createRange( model.createPositionAt( selection.focus.parent, 0 ), selection.focus );\n\n\t\tconst { text, range } = getLastTextLine( rangeBeforeSelection, model );\n\n\t\tconst testResult = this.testCallback( text );\n\n\t\tif ( !testResult && this.hasMatch ) {\n\t\t\tthis.fire( 'unmatched' );\n\t\t}\n\n\t\tthis.hasMatch = !!testResult;\n\n\t\tif ( testResult ) {\n\t\t\tconst eventData = Object.assign( data, { text, range } );\n\n\t\t\t// If the test callback returns an object with additional data, assign the data as well.\n\t\t\tif ( typeof testResult == 'object' ) {\n\t\t\t\tObject.assign( eventData, testResult );\n\t\t\t}\n\n\t\t\tthis.fire( `matched:${ suffix }`, eventData );\n\t\t}\n\t}\n}\n\nmix( TextWatcher, ObservableMixin );\n\n/**\n * Fired whenever the text watcher found a match for data changes.\n *\n * @event matched:data\n * @param {Object} data Event data.\n * @param {String} data.text The full text before selection to which the regexp was applied.\n * @param {module:engine/model/range~Range} data.range The range representing the position of the `data.text`.\n * @param {Object} [data.testResult] The additional data returned from the {@link module:typing/textwatcher~TextWatcher#testCallback}.\n */\n\n/**\n * Fired whenever the text watcher found a match for selection changes.\n *\n * @event matched:selection\n * @param {Object} data Event data.\n * @param {String} data.text The full text before selection.\n * @param {module:engine/model/range~Range} data.range The range representing the position of the `data.text`.\n * @param {Object} [data.testResult] The additional data returned from the {@link module:typing/textwatcher~TextWatcher#testCallback}.\n */\n\n/**\n * Fired whenever the text does not match anymore. Fired only when the text watcher found a match.\n *\n * @event unmatched\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 typing/twostepcaretmovement\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * This plugin enables the two-step caret (phantom) movement behavior for\n * {@link module:typing/twostepcaretmovement~TwoStepCaretMovement#registerAttribute registered attributes}\n * on arrow right (<kbd>→</kbd>) and left (<kbd>←</kbd>) key press.\n *\n * Thanks to this (phantom) caret movement the user is able to type before/after as well as at the\n * beginning/end of an attribute.\n *\n * **Note:** This plugin support righttoleft (Arabic, Hebrew, etc.) content by mirroring its behavior\n * but for the sake of simplicity examples showcase only lefttoright usecases.\n *\n * # Forward movement\n *\n * ## \"Entering\" an attribute:\n *\n * When this plugin is enabled and registered for the `a` attribute and the selection is right before it\n * (at the attribute boundary), pressing the right arrow key will not move the selection but update its\n * attributes accordingly:\n *\n * * When enabled:\n *\n * \t\tfoo{}<$text a=\"true\">bar</$text>\n *\n * <kbd>→</kbd>\n *\n * \t\tfoo<$text a=\"true\">{}bar</$text>\n *\n * * When disabled:\n *\n * \t\tfoo{}<$text a=\"true\">bar</$text>\n *\n * <kbd>→</kbd>\n *\n * \t\tfoo<$text a=\"true\">b{}ar</$text>\n *\n *\n * ## \"Leaving\" an attribute:\n *\n * * When enabled:\n *\n * \t\t<$text a=\"true\">bar{}</$text>baz\n *\n * <kbd>→</kbd>\n *\n * \t\t<$text a=\"true\">bar</$text>{}baz\n *\n * * When disabled:\n *\n * \t\t<$text a=\"true\">bar{}</$text>baz\n *\n * <kbd>→</kbd>\n *\n * \t\t<$text a=\"true\">bar</$text>b{}az\n *\n * # Backward movement\n *\n * * When enabled:\n *\n * \t\t<$text a=\"true\">bar</$text>{}baz\n *\n * <kbd>←</kbd>\n *\n * \t\t<$text a=\"true\">bar{}</$text>baz\n *\n * * When disabled:\n *\n * \t\t<$text a=\"true\">bar</$text>{}baz\n *\n * <kbd>←</kbd>\n *\n * \t\t<$text a=\"true\">ba{}r</$text>b{}az\n *\n * # Multiple attributes\n *\n * * When enabled and many attributes starts or ends at the same position:\n *\n * \t\t<$text a=\"true\" b=\"true\">bar</$text>{}baz\n *\n * <kbd>←</kbd>\n *\n * \t\t<$text a=\"true\" b=\"true\">bar{}</$text>baz\n *\n * * When enabled and one procedes another:\n *\n * \t\t<$text a=\"true\">bar</$text><$text b=\"true\">{}bar</$text>\n *\n * <kbd>←</kbd>\n *\n * \t\t<$text a=\"true\">bar{}</$text><$text b=\"true\">bar</$text>\n *\n */\nexport default class TwoStepCaretMovement extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TwoStepCaretMovement';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A set of attributes to handle.\n\t\t *\n\t\t * @protected\n\t\t * @property {module:typing/twostepcaretmovement~TwoStepCaretMovement}\n\t\t */\n\t\tthis.attributes = new Set();\n\n\t\t/**\n\t\t * The current UID of the overridden gravity, as returned by\n\t\t * {@link module:engine/model/writer~Writer#overrideSelectionGravity}.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._overrideUid = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\t\tconst locale = editor.locale;\n\n\t\tconst modelSelection = model.document.selection;\n\n\t\t// Listen to keyboard events and handle the caret movement according to the 2-step caret logic.\n\t\tthis.listenTo( view.document, 'arrowKey', ( evt, data ) => {\n\t\t\t// This implementation works only for collapsed selection.\n\t\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When user tries to expand the selection or jump over the whole word or to the beginning/end then\n\t\t\t// two-steps movement is not necessary.\n\t\t\tif ( data.shiftKey || data.altKey || data.ctrlKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst arrowRightPressed = data.keyCode == keyCodes.arrowright;\n\t\t\tconst arrowLeftPressed = data.keyCode == keyCodes.arrowleft;\n\n\t\t\t// When neither left or right arrow has been pressed then do noting.\n\t\t\tif ( !arrowRightPressed && !arrowLeftPressed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst contentDirection = locale.contentLanguageDirection;\n\t\t\tlet isMovementHandled = false;\n\n\t\t\tif ( ( contentDirection === 'ltr' && arrowRightPressed ) || ( contentDirection === 'rtl' && arrowLeftPressed ) ) {\n\t\t\t\tisMovementHandled = this._handleForwardMovement( data );\n\t\t\t} else {\n\t\t\t\tisMovementHandled = this._handleBackwardMovement( data );\n\t\t\t}\n\n\t\t\t// Stop the keydown event if the two-step caret movement handled it. Avoid collisions\n\t\t\t// with other features which may also take over the caret movement (e.g. Widget).\n\t\t\tif ( isMovementHandled === true ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { context: '$text', priority: 'highest' } );\n\n\t\t/**\n\t\t * A flag indicating that the automatic gravity restoration should not happen upon the next\n\t\t * gravity restoration.\n\t\t * {@link module:engine/model/selection~Selection#event:change:range} event.\n\t\t *\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._isNextGravityRestorationSkipped = false;\n\n\t\t// The automatic gravity restoration logic.\n\t\tthis.listenTo( modelSelection, 'change:range', ( evt, data ) => {\n\t\t\t// Skipping the automatic restoration is needed if the selection should change\n\t\t\t// but the gravity must remain overridden afterwards. See the #handleBackwardMovement\n\t\t\t// to learn more.\n\t\t\tif ( this._isNextGravityRestorationSkipped ) {\n\t\t\t\tthis._isNextGravityRestorationSkipped = false;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip automatic restore when the gravity is not overridden — simply, there's nothing to restore\n\t\t\t// at this moment.\n\t\t\tif ( !this._isGravityOverridden ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip automatic restore when the change is indirect AND the selection is at the attribute boundary.\n\t\t\t// It means that e.g. if the change was external (collaboration) and the user had their\n\t\t\t// selection around the link, its gravity should remain intact in this change:range event.\n\t\t\tif ( !data.directChange && isBetweenDifferentAttributes( modelSelection.getFirstPosition(), this.attributes ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._restoreGravity();\n\t\t} );\n\t}\n\n\t/**\n\t * Registers a given attribute for the two-step caret movement.\n\t *\n\t * @param {String} attribute Name of the attribute to handle.\n\t */\n\tregisterAttribute( attribute ) {\n\t\tthis.attributes.add( attribute );\n\t}\n\n\t/**\n\t * Updates the document selection and the view according to the twostep caret movement state\n\t * when moving **forwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.\n\t * @returns {Boolean} `true` when the handler prevented caret movement\n\t */\n\t_handleForwardMovement( data ) {\n\t\tconst attributes = this.attributes;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst position = selection.getFirstPosition();\n\t\t// DON'T ENGAGE 2-SCM if gravity is already overridden. It means that we just entered\n\t\t//\n\t\t// \t\t<paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\n\t\t// or left the attribute\n\t\t//\n\t\t// \t\t<paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>\n\t\t//\n\t\t// and the gravity will be restored automatically.\n\t\tif ( this._isGravityOverridden ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// DON'T ENGAGE 2-SCM when the selection is at the beginning of the block AND already has the\n\t\t// attribute:\n\t\t// * when the selection was initially set there using the mouse,\n\t\t// * when the editor has just started\n\t\t//\n\t\t//\t\t<paragraph><$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\n\t\tif ( position.isAtStart && hasAnyAttribute( selection, attributes ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// ENGAGE 2-SCM When at least one of the observed attributes changes its value (incl. starts, ends).\n\t\t//\n\t\t//\t\t<paragraph>foo<$text attribute>bar{}</$text>baz</paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>bar{}</$text><$text otherAttribute>baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute=1>bar{}</$text><$text attribute=2>baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo{}<$text attribute>bar</$text>baz</paragraph>\n\t\t//\n\t\tif ( isBetweenDifferentAttributes( position, attributes ) ) {\n\t\t\tpreventCaretMovement( data );\n\t\t\tthis._overrideGravity();\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Updates the document selection and the view according to the twostep caret movement state\n\t * when moving **backwards**. Executed upon `keypress` in the {@link module:engine/view/view~View}.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} data Data of the key press.\n\t * @returns {Boolean} `true` when the handler prevented caret movement\n\t */\n\t_handleBackwardMovement( data ) {\n\t\tconst attributes = this.attributes;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst position = selection.getFirstPosition();\n\n\t\t// When the gravity is already overridden (by this plugin), it means we are on the two-step position.\n\t\t// Prevent the movement, restore the gravity and update selection attributes.\n\t\t//\n\t\t//\t\t<paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>{}baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>bar</$text><$text otherAttribute>{}baz</$text></paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>{}bar</$text>baz</paragraph>\n\t\t//\t\t<paragraph>foo<$text attribute>bar</$text>{}baz</paragraph>\n\t\t//\n\t\tif ( this._isGravityOverridden ) {\n\t\t\tpreventCaretMovement( data );\n\t\t\tthis._restoreGravity();\n\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\t// REMOVE SELECTION ATTRIBUTE when restoring gravity towards a non-existent content at the\n\t\t\t// beginning of the block.\n\t\t\t//\n\t\t\t// \t\t<paragraph>{}<$text attribute>bar</$text></paragraph>\n\t\t\t//\n\t\t\tif ( position.isAtStart ) {\n\t\t\t\tif ( hasAnyAttribute( selection, attributes ) ) {\n\t\t\t\t\tpreventCaretMovement( data );\n\t\t\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// When we are moving from natural gravity, to the position of the 2SCM, we need to override the gravity,\n\t\t\t// and make sure it won't be restored. Unless it's at the end of the block and an observed attribute.\n\t\t\t// We need to check if the caret is a one position before the attribute boundary:\n\t\t\t//\n\t\t\t//\t\t<paragraph>foo<$text attribute=1>bar</$text><$text attribute=2>b{}az</$text></paragraph>\n\t\t\t//\t\t<paragraph>foo<$text attribute>bar</$text><$text otherAttribute>b{}az</$text></paragraph>\n\t\t\t//\t\t<paragraph>foo<$text attribute>b{}ar</$text>baz</paragraph>\n\t\t\t//\t\t<paragraph>foo<$text attribute>bar</$text>b{}az</paragraph>\n\t\t\t//\n\t\t\tif ( isStepAfterAnyAttributeBoundary( position, attributes ) ) {\n\t\t\t\t// ENGAGE 2-SCM if the selection has no attribute. This may happen when the user\n\t\t\t\t// left the attribute using a FORWARD 2-SCM.\n\t\t\t\t//\n\t\t\t\t// \t\t<paragraph><$text attribute>bar</$text>{}</paragraph>\n\t\t\t\t//\n\t\t\t\tif (\n\t\t\t\t\tposition.isAtEnd &&\n\t\t\t\t\t!hasAnyAttribute( selection, attributes ) &&\n\t\t\t\t\tisBetweenDifferentAttributes( position, attributes )\n\t\t\t\t) {\n\t\t\t\t\tpreventCaretMovement( data );\n\t\t\t\t\tsetSelectionAttributesFromTheNodeBefore( model, attributes, position );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// Skip the automatic gravity restore upon the next selection#change:range event.\n\t\t\t\t// If not skipped, it would automatically restore the gravity, which should remain\n\t\t\t\t// overridden.\n\t\t\t\tthis._isNextGravityRestorationSkipped = true;\n\t\t\t\tthis._overrideGravity();\n\n\t\t\t\t// Don't return \"true\" here because we didn't call _preventCaretMovement.\n\t\t\t\t// Returning here will destabilize the filler logic, which also listens to\n\t\t\t\t// keydown (and the event would be stopped).\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * `true` when the gravity is overridden for the plugin.\n\t *\n\t * @readonly\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isGravityOverridden() {\n\t\treturn !!this._overrideUid;\n\t}\n\n\t/**\n\t * Overrides the gravity using the {@link module:engine/model/writer~Writer model writer}\n\t * and stores the information about this fact in the {@link #_overrideUid}.\n\t *\n\t * A shorthand for {@link module:engine/model/writer~Writer#overrideSelectionGravity}.\n\t *\n\t * @private\n\t */\n\t_overrideGravity() {\n\t\tthis._overrideUid = this.editor.model.change( writer => {\n\t\t\treturn writer.overrideSelectionGravity();\n\t\t} );\n\t}\n\n\t/**\n\t * Restores the gravity using the {@link module:engine/model/writer~Writer model writer}.\n\t *\n\t * A shorthand for {@link module:engine/model/writer~Writer#restoreSelectionGravity}.\n\t *\n\t * @private\n\t */\n\t_restoreGravity() {\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.restoreSelectionGravity( this._overrideUid );\n\t\t\tthis._overrideUid = null;\n\t\t} );\n\t}\n}\n\n// Checks whether the selection has any of given attributes.\n//\n// @param {module:engine/model/documentselection~DocumentSelection} selection\n// @param {Iterable.<String>} attributes\nfunction hasAnyAttribute( selection, attributes ) {\n\tfor ( const observedAttribute of attributes ) {\n\t\tif ( selection.hasAttribute( observedAttribute ) ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n// Applies the given attributes to the current selection using using the\n// values from the node before the current position. Uses\n// the {@link module:engine/model/writer~Writer model writer}.\n//\n// @param {module:engine/model/model~Model}\n// @param {Iterable.<String>} attributess\n// @param {module:engine/model/position~Position} position\nfunction setSelectionAttributesFromTheNodeBefore( model, attributes, position ) {\n\tconst nodeBefore = position.nodeBefore;\n\tmodel.change( writer => {\n\t\tif ( nodeBefore ) {\n\t\t\twriter.setSelectionAttribute( nodeBefore.getAttributes() );\n\t\t} else {\n\t\t\twriter.removeSelectionAttribute( attributes );\n\t\t}\n\t} );\n}\n\n// Prevents the caret movement in the view by calling `preventDefault` on the event data.\n//\n// @alias data.preventDefault\nfunction preventCaretMovement( data ) {\n\tdata.preventDefault();\n}\n\n// Checks whether the step before `isBetweenDifferentAttributes()`.\n//\n// @param {module:engine/model/position~Position} position\n// @param {String} attribute\nfunction isStepAfterAnyAttributeBoundary( position, attributes ) {\n\tconst positionBefore = position.getShiftedBy( -1 );\n\treturn isBetweenDifferentAttributes( positionBefore, attributes );\n}\n\n// Checks whether the given position is between different values of given attributes.\n//\n// @param {module:engine/model/position~Position} position\n// @param {Iterable.<String>} attributes\nfunction isBetweenDifferentAttributes( position, attributes ) {\n\tconst { nodeBefore, nodeAfter } = position;\n\tfor ( const observedAttribute of attributes ) {\n\t\tconst attrBefore = nodeBefore ? nodeBefore.getAttribute( observedAttribute ) : undefined;\n\t\tconst attrAfter = nodeAfter ? nodeAfter.getAttribute( observedAttribute ) : undefined;\n\n\t\tif ( attrAfter !== attrBefore ) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n","import toString from './toString.js';\n\n/**\n * Used to match `RegExp`\n * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).\n */\nvar reRegExpChar = /[\\\\^$.*+?()[\\]{}|]/g,\n reHasRegExpChar = RegExp(reRegExpChar.source);\n\n/**\n * Escapes the `RegExp` special characters \"^\", \"$\", \"\\\", \".\", \"*\", \"+\",\n * \"?\", \"(\", \")\", \"[\", \"]\", \"{\", \"}\", and \"|\" in `string`.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to escape.\n * @returns {string} Returns the escaped string.\n * @example\n *\n * _.escapeRegExp('[lodash](https://lodash.com/)');\n * // => '\\[lodash\\]\\(https://lodash\\.com/\\)'\n */\nfunction escapeRegExp(string) {\n string = toString(string);\n return (string && reHasRegExpChar.test(string))\n ? string.replace(reRegExpChar, '\\\\$&')\n : string;\n}\n\nexport default escapeRegExp;\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 typing/texttransformation\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport TextWatcher from './textwatcher';\nimport { escapeRegExp } from 'lodash-es';\n\n// All named transformations.\nconst TRANSFORMATIONS = {\n\t// Common symbols:\n\tcopyright: { from: '(c)', to: '©' },\n\tregisteredTrademark: { from: '(r)', to: '®' },\n\ttrademark: { from: '(tm)', to: '™' },\n\n\t// Mathematical:\n\toneHalf: { from: '1/2', to: '½' },\n\toneThird: { from: '1/3', to: '⅓' },\n\ttwoThirds: { from: '2/3', to: '⅔' },\n\toneForth: { from: '1/4', to: '¼' },\n\tthreeQuarters: { from: '3/4', to: '¾' },\n\tlessThanOrEqual: { from: '<=', to: '≤' },\n\tgreaterThanOrEqual: { from: '>=', to: '≥' },\n\tnotEqual: { from: '!=', to: '≠' },\n\tarrowLeft: { from: '<-', to: '←' },\n\tarrowRight: { from: '->', to: '→' },\n\n\t// Typography:\n\thorizontalEllipsis: { from: '...', to: '…' },\n\tenDash: { from: /(^| )(--)( )$/, to: [ null, '', null ] },\n\temDash: { from: /(^| )(---)( )$/, to: [ null, '—', null ] },\n\t// Quotations:\n\t// English, US\n\tquotesPrimary: { from: buildQuotesRegExp( '\"' ), to: [ null, '“', null, '”' ] },\n\tquotesSecondary: { from: buildQuotesRegExp( '\\'' ), to: [ null, '', null, '' ] },\n\n\t// English, UK\n\tquotesPrimaryEnGb: { from: buildQuotesRegExp( '\\'' ), to: [ null, '', null, '' ] },\n\tquotesSecondaryEnGb: { from: buildQuotesRegExp( '\"' ), to: [ null, '“', null, '”' ] },\n\n\t// Polish\n\tquotesPrimaryPl: { from: buildQuotesRegExp( '\"' ), to: [ null, '„', null, '”' ] },\n\tquotesSecondaryPl: { from: buildQuotesRegExp( '\\'' ), to: [ null, '', null, '' ] }\n};\n\n// Transformation groups.\nconst TRANSFORMATION_GROUPS = {\n\tsymbols: [ 'copyright', 'registeredTrademark', 'trademark' ],\n\tmathematical: [\n\t\t'oneHalf', 'oneThird', 'twoThirds', 'oneForth', 'threeQuarters',\n\t\t'lessThanOrEqual', 'greaterThanOrEqual', 'notEqual',\n\t\t'arrowLeft', 'arrowRight'\n\t],\n\ttypography: [ 'horizontalEllipsis', 'enDash', 'emDash' ],\n\tquotes: [ 'quotesPrimary', 'quotesSecondary' ]\n};\n\n// A set of default transformations provided by the feature.\nconst DEFAULT_TRANSFORMATIONS = [\n\t'symbols',\n\t'mathematical',\n\t'typography',\n\t'quotes'\n];\n\n/**\n * The text transformation plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TextTransformation extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TextTransformation';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'typing', {\n\t\t\ttransformations: {\n\t\t\t\tinclude: DEFAULT_TRANSFORMATIONS\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst model = this.editor.model;\n\t\tconst modelSelection = model.document.selection;\n\n\t\tmodelSelection.on( 'change:range', () => {\n\t\t\t// Disable plugin when selection is inside a code block.\n\t\t\tthis.isEnabled = !modelSelection.anchor.parent.is( 'element', 'codeBlock' );\n\t\t} );\n\n\t\tthis._enableTransformationWatchers();\n\t}\n\n\t/**\n\t * Create new TextWatcher listening to the editor for typing and selection events.\n\t *\n\t * @private\n\t */\n\t_enableTransformationWatchers() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst input = editor.plugins.get( 'Input' );\n\t\tconst normalizedTransformations = normalizeTransformations( editor.config.get( 'typing.transformations' ) );\n\n\t\tconst testCallback = text => {\n\t\t\tfor ( const normalizedTransformation of normalizedTransformations ) {\n\t\t\t\tconst from = normalizedTransformation.from;\n\t\t\t\tconst match = from.test( text );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\treturn { normalizedTransformation };\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst watcherCallback = ( evt, data ) => {\n\t\t\tif ( !input.isInput( data.batch ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { from, to } = data.normalizedTransformation;\n\n\t\t\tconst matches = from.exec( data.text );\n\t\t\tconst replaces = to( matches.slice( 1 ) );\n\n\t\t\tconst matchedRange = data.range;\n\n\t\t\tlet changeIndex = matches.index;\n\n\t\t\tmodel.enqueueChange( writer => {\n\t\t\t\tfor ( let i = 1; i < matches.length; i++ ) {\n\t\t\t\t\tconst match = matches[ i ];\n\t\t\t\t\tconst replaceWith = replaces[ i - 1 ];\n\n\t\t\t\t\tif ( replaceWith == null ) {\n\t\t\t\t\t\tchangeIndex += match.length;\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst replacePosition = matchedRange.start.getShiftedBy( changeIndex );\n\t\t\t\t\tconst replaceRange = model.createRange( replacePosition, replacePosition.getShiftedBy( match.length ) );\n\t\t\t\t\tconst attributes = getTextAttributesAfterPosition( replacePosition );\n\n\t\t\t\t\tmodel.insertContent( writer.createText( replaceWith, attributes ), replaceRange );\n\n\t\t\t\t\tchangeIndex += replaceWith.length;\n\t\t\t\t}\n\t\t\t} );\n\t\t};\n\n\t\tconst watcher = new TextWatcher( editor.model, testCallback );\n\n\t\twatcher.on( 'matched:data', watcherCallback );\n\t\twatcher.bind( 'isEnabled' ).to( this );\n\t}\n}\n\n// Normalizes the configuration `from` parameter value.\n// The normalized value for the `from` parameter is a RegExp instance. If the passed `from` is already a RegExp instance,\n// it is returned unchanged.\n//\n// @param {String|RegExp} from\n// @returns {RegExp}\nfunction normalizeFrom( from ) {\n\tif ( typeof from == 'string' ) {\n\t\treturn new RegExp( `(${ escapeRegExp( from ) })$` );\n\t}\n\n\t// `from` is already a regular expression.\n\treturn from;\n}\n\n// Normalizes the configuration `to` parameter value.\n// The normalized value for the `to` parameter is a function that takes an array and returns an array. See more in the\n// configuration description. If the passed `to` is already a function, it is returned unchanged.\n//\n// @param {String|Array.<null|String>|Function} to\n// @returns {Function}\nfunction normalizeTo( to ) {\n\tif ( typeof to == 'string' ) {\n\t\treturn () => [ to ];\n\t} else if ( to instanceof Array ) {\n\t\treturn () => to;\n\t}\n\n\t// `to` is already a function.\n\treturn to;\n}\n\n// For given `position` returns attributes for the text that is after that position.\n// The text can be in the same text node as the position (`foo[]bar`) or in the next text node (`foo[]<$text bold=\"true\">bar</$text>`).\n//\n// @param {module:engine/model/position~Position} position\n// @returns {Iterable.<*>}\nfunction getTextAttributesAfterPosition( position ) {\n\tconst textNode = position.textNode ? position.textNode : position.nodeAfter;\n\n\treturn textNode.getAttributes();\n}\n\n// Returns a RegExp pattern string that detects a sentence inside a quote.\n//\n// @param {String} quoteCharacter The character to create a pattern for.\n// @returns {String}\nfunction buildQuotesRegExp( quoteCharacter ) {\n\treturn new RegExp( `(^|\\\\s)(${ quoteCharacter })([^${ quoteCharacter }]*)(${ quoteCharacter })$` );\n}\n\n// Reads text transformation config and returns normalized array of transformations objects.\n//\n// @param {module:typing/texttransformation~TextTransformationDescription} config\n// @returns {Array.<{from:String,to:Function}>}\nfunction normalizeTransformations( config ) {\n\tconst extra = config.extra || [];\n\tconst remove = config.remove || [];\n\tconst isNotRemoved = transformation => !remove.includes( transformation );\n\n\tconst configured = config.include.concat( extra ).filter( isNotRemoved );\n\n\treturn expandGroupsAndRemoveDuplicates( configured )\n\t\t.filter( isNotRemoved ) // Filter out 'remove' transformations as they might be set in group\n\t\t.map( transformation => TRANSFORMATIONS[ transformation ] || transformation )\n\t\t.map( transformation => ( {\n\t\t\tfrom: normalizeFrom( transformation.from ),\n\t\t\tto: normalizeTo( transformation.to )\n\t\t} ) );\n}\n\n// Reads definitions and expands named groups if needed to transformation names.\n// This method also removes duplicated named transformations if any.\n//\n// @param {Array.<String|Object>} definitions\n// @returns {Array.<String|Object>}\nfunction expandGroupsAndRemoveDuplicates( definitions ) {\n\t// Set is using to make sure that transformation names are not duplicated.\n\tconst definedTransformations = new Set();\n\n\tfor ( const transformationOrGroup of definitions ) {\n\t\tif ( TRANSFORMATION_GROUPS[ transformationOrGroup ] ) {\n\t\t\tfor ( const transformation of TRANSFORMATION_GROUPS[ transformationOrGroup ] ) {\n\t\t\t\tdefinedTransformations.add( transformation );\n\t\t\t}\n\t\t} else {\n\t\t\tdefinedTransformations.add( transformationOrGroup );\n\t\t}\n\t}\n\n\treturn Array.from( definedTransformations );\n}\n\n/**\n * The text transformation definition object. It describes what should be replaced with what.\n *\n * The input value (`from`) can be passed either as a string or as a regular expression.\n *\n * * If a string is passed, it will be simply checked if the end of the input matches it.\n * * If a regular expression is passed, its entire length must be covered with capturing groups (e.g. `/(foo)(bar)$/`).\n * Also, since it is compared against the end of the input, it has to end with `$` to be correctly matched.\n * See examples below.\n *\n * The output value (`to`) can be passed as a string, as an array or as a function.\n *\n * * If a string is passed, it will be used as a replacement value as-is. Note that a string output value can be used only if\n * the input value is a string, too.\n * * If an array is passed, it has to have the same number of elements as there are capturing groups in the input value regular expression.\n * Each capture group will be replaced with a corresponding string from the passed array. If a given capturing group should not be replaced,\n * use `null` instead of passing a string.\n * * If a function is used, it should return an array as described above. The function is passed one parameter &mdash; an array with matches\n * by the regular expression. See the examples below.\n *\n * A simple string-to-string replacement:\n *\n *\t\t{ from: '(c)', to: '©' }\n *\n * Change quote styles using a regular expression. Note how all the parts are in separate capturing groups and the space at the beginning\n * and the text inside quotes are not replaced (`null` passed as the first and the third value in the `to` parameter):\n *\n *\t\t{\n *\t\t\tfrom: /(^|\\s)(\")([^\"]*)(\")$/,\n *\t\t\tto: [ null, '“', null, '”' ]\n *\t\t}\n *\n * Automatic uppercase after a dot using a callback:\n *\n *\t\t{\n *\t\t\tfrom: /(\\. )([a-z])$/,\n *\t\t\tto: matches => [ null, matches[ 1 ].toUpperCase() ]\n *\t\t}\n *\n * @typedef {Object} module:typing/texttransformation~TextTransformationDescription\n * @property {String|RegExp} from The string or regular expression to transform.\n * @property {String} to The text to transform compatible with `String.replace()`.\n */\n\n/**\n * The configuration of the {@link module:typing/texttransformation~TextTransformation} feature.\n *\n * Read more in {@link module:typing/texttransformation~TextTransformationConfig}.\n *\n * @member {module:typing/texttransformation~TextTransformationConfig} module:typing/typing~TypingConfig#transformations\n */\n\n/**\n * The configuration of the text transformation feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\ttyping: {\n *\t\t\t\t\ttransformations: ... // Text transformation feature options.\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * By default, the feature comes pre-configured\n * (via {@link module:typing/texttransformation~TextTransformationConfig#include `config.typing.transformations.include`}) with the\n * following groups of transformations:\n *\n * * Typography (group name: `typography`)\n * - `ellipsis`: transforms `...` to `…`\n * - `enDash`: transforms ` -- ` to ` `\n * - `emDash`: transforms ` --- ` to ` — `\n * * Quotations (group name: `quotes`)\n * - `quotesPrimary`: transforms `\"Foo bar\"` to `“Foo bar”`\n * - `quotesSecondary`: transforms `'Foo bar'` to `Foo bar`\n * * Symbols (group name: `symbols`)\n * - `trademark`: transforms `(tm)` to `™`\n * - `registeredTrademark`: transforms `(r)` to `®`\n * - `copyright`: transforms `(c)` to `©`\n * * Mathematical (group name: `mathematical`)\n * - `oneHalf`: transforms `1/2` to: `½`\n * - `oneThird`: transforms `1/3` to: `⅓`\n * - `twoThirds`: transforms `2/3` to: `⅔`\n * - `oneForth`: transforms `1/4` to: `¼`\n * - `threeQuarters`: transforms `3/4` to: `¾`\n * - `lessThanOrEqual`: transforms `<=` to: `≤`\n * - `greaterThanOrEqual`: transforms `>=` to: `≥`\n * - `notEqual`: transforms `!=` to: `≠`\n * - `arrowLeft`: transforms `<-` to: `←`\n * - `arrowRight`: transforms `->` to: `→`\n * * Misc:\n * - `quotesPrimaryEnGb`: transforms `'Foo bar'` to `Foo bar`\n * - `quotesSecondaryEnGb`: transforms `\"Foo bar\"` to `“Foo bar”`\n * - `quotesPrimaryPl`: transforms `\"Foo bar\"` to `„Foo bar”`\n * - `quotesSecondaryPl`: transforms `'Foo bar'` to `Foo bar`\n *\n * In order to load additional transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra` option}.\n *\n * In order to narrow down the list of transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#remove `transformations.remove` option}.\n *\n * In order to completely override the supported transformations, use the\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include` option}.\n *\n * Examples:\n *\n *\t\tconst transformationsConfig = {\n *\t\t\tinclude: [\n *\t\t\t\t// Use only the 'quotes' and 'typography' groups.\n *\t\t\t\t'quotes',\n *\t\t\t\t'typography',\n *\n *\t\t\t\t// Plus, some custom transformation.\n *\t\t\t\t{ from: 'CKE', to: 'CKEditor' }\n *\t\t\t]\n *\t\t};\n *\n *\t\tconst transformationsConfig = {\n *\t\t\t// Remove the 'ellipsis' transformation loaded by the 'typography' group.\n *\t\t\tremove: [ 'ellipsis' ]\n *\t\t}\n *\n * @interface TextTransformationConfig\n */\n\n/* eslint-disable max-len */\n/**\n * The standard list of text transformations supported by the editor. By default it comes pre-configured with a couple dozen of them\n * (see {@link module:typing/texttransformation~TextTransformationConfig} for the full list). You can override this list completely\n * by setting this option or use the other two options\n * ({@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra`},\n * {@link module:typing/texttransformation~TextTransformationConfig#remove `transformations.remove`}) to fine-tune the default list.\n *\n * @member {Array.<module:typing/texttransformation~TextTransformationDescription>} module:typing/texttransformation~TextTransformationConfig#include\n */\n\n/**\n * Additional text transformations that are added to the transformations defined in\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include`}.\n *\n *\t\tconst transformationsConfig = {\n *\t\t\textra: [\n *\t\t\t\t{ from: 'CKE', to: 'CKEditor' }\n *\t\t\t]\n *\t\t};\n *\n * @member {Array.<module:typing/texttransformation~TextTransformationDescription>} module:typing/texttransformation~TextTransformationConfig#extra\n */\n\n/**\n * The text transformation names that are removed from transformations defined in\n * {@link module:typing/texttransformation~TextTransformationConfig#include `transformations.include`} or\n * {@link module:typing/texttransformation~TextTransformationConfig#extra `transformations.extra`}.\n *\n *\t\tconst transformationsConfig = {\n *\t\t\tremove: [\n *\t\t\t\t'ellipsis', // Remove only 'ellipsis' from the 'typography' group.\n *\t\t\t\t'mathematical' // Remove all transformations from the 'mathematical' group.\n *\t\t\t]\n *\t\t}\n *\n * @member {Array.<module:typing/texttransformation~TextTransformationDescription>} module:typing/texttransformation~TextTransformationConfig#remove\n */\n/* eslint-enable max-len */\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 typing/utils/findattributerange\n */\n\n/**\n * Returns a model range that covers all consecutive nodes with the same `attributeName` and its `value`\n * that intersect the given `position`.\n *\n * It can be used e.g. to get the entire range on which the `linkHref` attribute needs to be changed when having a\n * selection inside a link.\n *\n * @param {module:engine/model/position~Position} position The start position.\n * @param {String} attributeName The attribute name.\n * @param {String} value The attribute value.\n * @param {module:engine/model/model~Model} model The model instance.\n * @returns {module:engine/model/range~Range} The link range.\n */\nexport default function findAttributeRange( position, attributeName, value, model ) {\n\treturn model.createRange(\n\t\t_findBound( position, attributeName, value, true, model ),\n\t\t_findBound( position, attributeName, value, false, model )\n\t);\n}\n\n// Walks forward or backward (depends on the `lookBack` flag), node by node, as long as they have the same attribute value\n// and returns a position just before or after (depends on the `lookBack` flag) the last matched node.\n//\n// @param {module:engine/model/position~Position} position The start position.\n// @param {String} attributeName The attribute name.\n// @param {String} value The attribute value.\n// @param {Boolean} lookBack Whether the walk direction is forward (`false`) or backward (`true`).\n// @returns {module:engine/model/position~Position} The position just before the last matched node.\nfunction _findBound( position, attributeName, value, lookBack, model ) {\n\t// Get node before or after position (depends on `lookBack` flag).\n\t// When position is inside text node then start searching from text node.\n\tlet node = position.textNode || ( lookBack ? position.nodeBefore : position.nodeAfter );\n\n\tlet lastNode = null;\n\n\twhile ( node && node.getAttribute( attributeName ) == value ) {\n\t\tlastNode = node;\n\t\tnode = lookBack ? node.previousSibling : node.nextSibling;\n\t}\n\n\treturn lastNode ? model.createPositionAt( lastNode, lookBack ? 'before' : 'after' ) : position;\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\nimport findAttributeRange from './findattributerange';\n\n/**\n * @module typing/utils/inlinehighlight\n */\n\n/**\n * Adds a visual highlight style to an attribute element in which the selection is anchored.\n * Together with two-step caret movement, they indicate that the user is typing inside the element.\n *\n * Highlight is turned on by adding the given class to the attribute element in the view:\n *\n * * The class is removed before the conversion has started, as callbacks added with the `'highest'` priority\n * to {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} events.\n * * The class is added in the view post fixer, after other changes in the model tree were converted to the view.\n *\n * This way, adding and removing the highlight does not interfere with conversion.\n *\n * Usage:\n *\n *\t\timport inlineHighlight from '@ckeditor/ckeditor5-typing/src/utils/inlinehighlight';\n *\n *\t\t// Make `ck-link_selected` class be applied on an `a` element\n *\t\t// whenever the corresponding `linkHref` attribute element is selected.\n *\t\tinlineHighlight( editor, 'linkHref', 'a', 'ck-link_selected' );\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {String} attributeName The attribute name to check.\n * @param {String} tagName The tagName of a view item.\n * @param {String} className The class name to apply in the view.\n */\nexport default function inlineHighlight( editor, attributeName, tagName, className ) {\n\tconst view = editor.editing.view;\n\tconst highlightedElements = new Set();\n\n\t// Adding the class.\n\tview.document.registerPostFixer( writer => {\n\t\tconst selection = editor.model.document.selection;\n\t\tlet changed = false;\n\n\t\tif ( selection.hasAttribute( attributeName ) ) {\n\t\t\tconst modelRange = findAttributeRange(\n\t\t\t\tselection.getFirstPosition(),\n\t\t\t\tattributeName,\n\t\t\t\tselection.getAttribute( attributeName ),\n\t\t\t\teditor.model\n\t\t\t);\n\t\t\tconst viewRange = editor.editing.mapper.toViewRange( modelRange );\n\n\t\t\t// There might be multiple view elements in the `viewRange`, for example, when the `a` element is\n\t\t\t// broken by a UIElement.\n\t\t\tfor ( const item of viewRange.getItems() ) {\n\t\t\t\tif ( item.is( 'element', tagName ) && !item.hasClass( className ) ) {\n\t\t\t\t\twriter.addClass( className, item );\n\t\t\t\t\thighlightedElements.add( item );\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn changed;\n\t} );\n\n\t// Removing the class.\n\teditor.conversion.for( 'editingDowncast' ).add( dispatcher => {\n\t\t// Make sure the highlight is removed on every possible event, before conversion is started.\n\t\tdispatcher.on( 'insert', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'remove', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'attribute', removeHighlight, { priority: 'highest' } );\n\t\tdispatcher.on( 'selection', removeHighlight, { priority: 'highest' } );\n\n\t\tfunction removeHighlight() {\n\t\t\tview.change( writer => {\n\t\t\t\tfor ( const item of highlightedElements.values() ) {\n\t\t\t\t\twriter.removeClass( className, item );\n\t\t\t\t\thighlightedElements.delete( item );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/code/codeediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { TwoStepCaretMovement, inlineHighlight } from 'ckeditor5/src/typing';\n\nimport AttributeCommand from '../attributecommand';\n\nconst CODE = 'code';\nconst HIGHLIGHT_CLASS = 'ck-code_selected';\n\n/**\n * The code editing feature.\n *\n * It registers the `'code'` command and introduces the `code` attribute in the model which renders to the view\n * as a `<code>` element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CodeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CodeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TwoStepCaretMovement ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow code attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: CODE } );\n\t\teditor.model.schema.setAttributeProperties( CODE, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: false\n\t\t} );\n\n\t\teditor.conversion.attributeToElement( {\n\t\t\tmodel: CODE,\n\t\t\tview: 'code',\n\t\t\tupcastAlso: {\n\t\t\t\tstyles: {\n\t\t\t\t\t'word-wrap': 'break-word'\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Create code command.\n\t\teditor.commands.add( CODE, new AttributeCommand( editor, CODE ) );\n\n\t\t// Enable two-step caret movement for `code` attribute.\n\t\teditor.plugins.get( TwoStepCaretMovement ).registerAttribute( CODE );\n\n\t\t// Setup highlight over selected element.\n\t\tinlineHighlight( editor, CODE, 'code', HIGHLIGHT_CLASS );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/code/codeui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport codeIcon from '../../theme/icons/code.svg';\n\nimport '../../theme/code.css';\n\nconst CODE = 'code';\n\n/**\n * The code UI feature. It introduces the Code button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CodeUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CodeUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add code button to feature components.\n\t\teditor.ui.componentFactory.add( CODE, locale => {\n\t\t\tconst command = editor.commands.get( CODE );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Code' ),\n\t\t\t\ticon: codeIcon,\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( CODE );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m12.5 5.7 5.2 3.9v1.3l-5.6 4c-.1.2-.3.2-.5.2-.3-.1-.6-.7-.6-1l.3-.4 4.7-3.5L11.5 7l-.2-.2c-.1-.3-.1-.6 0-.8.2-.2.5-.4.8-.4a.8.8 0 0 1 .4.1zm-5.2 0L2 9.6v1.3l5.6 4c.1.2.3.2.5.2.3-.1.7-.7.6-1 0-.1 0-.3-.2-.4l-5-3.5L8.2 7l.2-.2c.1-.3.1-.6 0-.8-.2-.2-.5-.4-.8-.4a.8.8 0 0 0-.3.1z\\\"/></svg>\";","/**\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 enter/utils\n */\n\n/**\n * Returns attributes that should be preserved on the enter key.\n *\n * Filtering is realized based on `copyOnEnter` attribute property. Read more about attribute properties\n * {@link module:engine/model/schema~Schema#setAttributeProperties here}.\n *\n * @param {module:engine/model/schema~Schema} schema\n * @param {Iterable.<*>} allAttributes attributes to filter.\n * @returns {Iterable.<*>}\n */\nexport function* getCopyOnEnterAttributes( schema, allAttributes ) {\n\tfor ( const attribute of allAttributes ) {\n\t\tif ( attribute && schema.getAttributeProperties( attribute[ 0 ] ).copyOnEnter ) {\n\t\t\tyield attribute;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/entercommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getCopyOnEnterAttributes } from './utils';\n\n/**\n * Enter command. It is used by the {@link module:enter/enter~Enter Enter feature} to handle the <kbd>Enter</kbd> key.\n *\n * @extends module:core/command~Command\n */\nexport default class EnterCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tenterBlock( this.editor.model, writer, doc.selection, model.schema );\n\t\t\tthis.fire( 'afterExecute', { writer } );\n\t\t} );\n\t}\n}\n\n// Creates a new block in the way that the <kbd>Enter</kbd> key is expected to work.\n//\n// @param {module:engine/model~Model} model\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// Selection on which the action should be performed.\n// @param {module:engine/model/schema~Schema} schema\nfunction enterBlock( model, writer, selection, schema ) {\n\tconst isSelectionEmpty = selection.isCollapsed;\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\n\t// Don't touch the roots and other limit elements.\n\tif ( schema.isLimit( startElement ) || schema.isLimit( endElement ) ) {\n\t\t// Delete the selected content but only if inside a single limit element.\n\t\t// Abort, when crossing limit elements boundary (e.g. <limit1>x[x</limit1>donttouchme<limit2>y]y</limit2>).\n\t\t// This is an edge case and it's hard to tell what should actually happen because such a selection\n\t\t// is not entirely valid.\n\t\tif ( !isSelectionEmpty && startElement == endElement ) {\n\t\t\tmodel.deleteContent( selection );\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif ( isSelectionEmpty ) {\n\t\tconst attributesToCopy = getCopyOnEnterAttributes( writer.model.schema, selection.getAttributes() );\n\t\tsplitBlock( writer, range.start );\n\t\twriter.setSelectionAttribute( attributesToCopy );\n\t} else {\n\t\tconst leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd );\n\t\tconst isContainedWithinOneElement = ( startElement == endElement );\n\n\t\tmodel.deleteContent( selection, { leaveUnmerged } );\n\n\t\tif ( leaveUnmerged ) {\n\t\t\t// Partially selected elements.\n\t\t\t//\n\t\t\t// <h>x[xx]x</h>\t\t-> <h>x^x</h>\t\t\t-> <h>x</h><h>^x</h>\n\t\t\tif ( isContainedWithinOneElement ) {\n\t\t\t\tsplitBlock( writer, selection.focus );\n\t\t\t}\n\t\t\t// Selection over multiple elements.\n\t\t\t//\n\t\t\t// <h>x[x</h><p>y]y<p>\t-> <h>x^</h><p>y</p>\t-> <h>x</h><p>^y</p>\n\t\t\telse {\n\t\t\t\twriter.setSelection( endElement, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction splitBlock( writer, splitPos ) {\n\twriter.split( splitPos );\n\twriter.setSelection( splitPos.parent.nextSibling, 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 enter/enterobserver\n */\n\nimport Observer from '@ckeditor/ckeditor5-engine/src/view/observer/observer';\nimport DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';\nimport BubblingEventInfo from '@ckeditor/ckeditor5-engine/src/view/observer/bubblingeventinfo';\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\n\n/**\n * Enter observer introduces the {@link module:engine/view/document~Document#event:enter} event.\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class EnterObserver extends Observer {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst doc = this.document;\n\n\t\tdoc.on( 'keydown', ( evt, data ) => {\n\t\t\tif ( this.isEnabled && data.keyCode == keyCodes.enter ) {\n\t\t\t\tconst event = new BubblingEventInfo( doc, 'enter', doc.selection.getFirstRange() );\n\n\t\t\t\tdoc.fire( event, new DomEventData( doc, data.domEvent, {\n\t\t\t\t\tisSoft: data.shiftKey\n\t\t\t\t} ) );\n\n\t\t\t\t// Stop `keydown` event if `enter` event was stopped.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5/issues/753\n\t\t\t\tif ( event.stop.called ) {\n\t\t\t\t\tevt.stop();\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve() {}\n}\n\n/**\n * Event fired when the user presses the <kbd>Enter</kbd> key.\n *\n * Note: This event is fired by the {@link module:enter/enterobserver~EnterObserver observer}\n * (usually registered by the {@link module:enter/enter~Enter Enter feature} and\n * {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature}).\n *\n * @event module:engine/view/document~Document#event:enter\n * @param {module:engine/view/observer/domeventdata~DomEventData} data\n * @param {Boolean} data.isSoft Whether it's a soft enter (<kbd>Shift</kbd>+<kbd>Enter</kbd>) or hard enter (<kbd>Enter</kbd>).\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 enter/enter\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport EnterCommand from './entercommand';\nimport EnterObserver from './enterobserver';\n\n/**\n * This plugin handles the <kbd>Enter</kbd> key (hard line break) in the editor.\n *\n * See also the {@link module:enter/shiftenter~ShiftEnter} plugin.\n *\n * For more information about this feature see the {@glink api/enter package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Enter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Enter';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\tview.addObserver( EnterObserver );\n\n\t\teditor.commands.add( 'enter', new EnterCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\n\t\t\t// The soft enter key is handled by the ShiftEnter plugin.\n\t\t\tif ( data.isSoft ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.execute( 'enter' );\n\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module enter/shiftentercommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { getCopyOnEnterAttributes } from './utils';\n\n/**\n * ShiftEnter command. It is used by the {@link module:enter/shiftenter~ShiftEnter ShiftEnter feature} to handle\n * the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke.\n *\n * @extends module:core/command~Command\n */\nexport default class ShiftEnterCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tsoftBreakAction( model, writer, doc.selection );\n\t\t\tthis.fire( 'afterExecute', { writer } );\n\t\t} );\n\t}\n\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.isEnabled = isEnabled( model.schema, doc.selection );\n\t}\n}\n\n// Checks whether the ShiftEnter command should be enabled in the specified selection.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\nfunction isEnabled( schema, selection ) {\n\t// At this moment it is okay to support single range selections only.\n\t// But in the future we may need to change that.\n\tif ( selection.rangeCount > 1 ) {\n\t\treturn false;\n\t}\n\n\tconst anchorPos = selection.anchor;\n\n\t// Check whether the break element can be inserted in the current selection anchor.\n\tif ( !anchorPos || !schema.checkChild( anchorPos, 'softBreak' ) ) {\n\t\treturn false;\n\t}\n\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\n\t// Do not modify the content if selection is cross-limit elements.\n\tif ( ( isInsideLimitElement( startElement, schema ) || isInsideLimitElement( endElement, schema ) ) && startElement !== endElement ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Creates a break in the way that the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke is expected to work.\n//\n// @param {module:engine/model~Model} model\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// Selection on which the action should be performed.\nfunction softBreakAction( model, writer, selection ) {\n\tconst isSelectionEmpty = selection.isCollapsed;\n\tconst range = selection.getFirstRange();\n\tconst startElement = range.start.parent;\n\tconst endElement = range.end.parent;\n\tconst isContainedWithinOneElement = ( startElement == endElement );\n\n\tif ( isSelectionEmpty ) {\n\t\tconst attributesToCopy = getCopyOnEnterAttributes( model.schema, selection.getAttributes() );\n\t\tinsertBreak( model, writer, range.end );\n\n\t\twriter.removeSelectionAttribute( selection.getAttributeKeys() );\n\t\twriter.setSelectionAttribute( attributesToCopy );\n\t} else {\n\t\tconst leaveUnmerged = !( range.start.isAtStart && range.end.isAtEnd );\n\t\tmodel.deleteContent( selection, { leaveUnmerged } );\n\n\t\t// Selection within one element:\n\t\t//\n\t\t// <h>x[xx]x</h>\t\t-> <h>x^x</h>\t\t\t-> <h>x<br>^x</h>\n\t\tif ( isContainedWithinOneElement ) {\n\t\t\tinsertBreak( model, writer, selection.focus );\n\t\t}\n\t\t// Selection over multiple elements.\n\t\t//\n\t\t// <h>x[x</h><p>y]y<p>\t-> <h>x^</h><p>y</p>\t-> <h>x</h><p>^y</p>\n\t\t//\n\t\t// We chose not to insert a line break in this case because:\n\t\t//\n\t\t// * it's not a very common scenario,\n\t\t// * it actually surprised me when I saw the \"expected behavior\" in real life.\n\t\t//\n\t\t// It's ok if the user will need to be more specific where they want the <br> to be inserted.\n\t\telse {\n\t\t\t// Move the selection to the 2nd element (last step of the example above).\n\t\t\tif ( leaveUnmerged ) {\n\t\t\t\twriter.setSelection( endElement, 0 );\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction insertBreak( model, writer, position ) {\n\tconst breakLineElement = writer.createElement( 'softBreak' );\n\n\tmodel.insertContent( breakLineElement, position );\n\twriter.setSelection( breakLineElement, 'after' );\n}\n\n// Checks whether the specified `element` is a child of the limit element.\n//\n// Checking whether the `<p>` element is inside a limit element:\n// - <$root><p>Text.</p></$root> => false\n// - <$root><limitElement><p>Text</p></limitElement></$root> => true\n//\n// @param {module:engine/model/element~Element} element\n// @param {module:engine/schema~Schema} schema\n// @returns {Boolean}\nfunction isInsideLimitElement( element, schema ) {\n\t// `$root` is a limit element but in this case is an invalid element.\n\tif ( element.is( 'rootElement' ) ) {\n\t\treturn false;\n\t}\n\n\treturn schema.isLimit( element ) || isInsideLimitElement( element.parent, schema );\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 enter/shiftenter\n */\n\nimport ShiftEnterCommand from './shiftentercommand';\nimport EnterObserver from './enterobserver';\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * This plugin handles the <kbd>Shift</kbd>+<kbd>Enter</kbd> keystroke (soft line break) in the editor.\n *\n * See also the {@link module:enter/enter~Enter} plugin.\n *\n * For more information about this feature see the {@glink api/enter package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ShiftEnter extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ShiftEnter';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Configure the schema.\n\t\tschema.register( 'softBreak', {\n\t\t\tallowWhere: '$text',\n\t\t\tisInline: true\n\t\t} );\n\n\t\t// Configure converters.\n\t\tconversion.for( 'upcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'softBreak',\n\t\t\t\tview: 'br'\n\t\t\t} );\n\n\t\tconversion.for( 'downcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'softBreak',\n\t\t\t\tview: ( modelElement, { writer } ) => writer.createEmptyElement( 'br' )\n\t\t\t} );\n\n\t\tview.addObserver( EnterObserver );\n\n\t\teditor.commands.add( 'shiftEnter', new ShiftEnterCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\n\t\t\t// The hard enter key is handled by the Enter plugin.\n\t\t\tif ( !data.isSoft ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.execute( 'shiftEnter' );\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module block-quote/blockquotecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * The block quote command plugin.\n *\n * @extends module:core/command~Command\n */\nexport default class BlockQuoteCommand extends Command {\n\t/**\n\t * Whether the selection starts in a block quote.\n\t *\n\t * @observable\n\t * @readonly\n\t * @member {Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command. When the command {@link #value is on}, all top-most block quotes within\n\t * the selection will be removed. If it is off, all selected blocks will be wrapped with\n\t * a block quote.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply a block quote,\n\t * otherwise the command will remove the block quote. If not set, the command will act basing on its current value.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst selection = model.document.selection;\n\n\t\tconst blocks = Array.from( selection.getSelectedBlocks() );\n\n\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( !value ) {\n\t\t\t\tthis._removeQuote( writer, blocks.filter( findQuote ) );\n\t\t\t} else {\n\t\t\t\tconst blocksToQuote = blocks.filter( block => {\n\t\t\t\t\t// Already quoted blocks needs to be considered while quoting too\n\t\t\t\t\t// in order to reuse their <bQ> elements.\n\t\t\t\t\treturn findQuote( block ) || checkCanBeQuoted( schema, block );\n\t\t\t\t} );\n\n\t\t\t\tthis._applyQuote( writer, blocksToQuote );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {Boolean} The current value.\n\t */\n\t_getValue() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\t// In the current implementation, the block quote must be an immediate parent of a block element.\n\t\treturn !!( firstBlock && findQuote( firstBlock ) );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\tif ( this.value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\tif ( !firstBlock ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn checkCanBeQuoted( schema, firstBlock );\n\t}\n\n\t/**\n\t * Removes the quote from given blocks.\n\t *\n\t * If blocks which are supposed to be \"unquoted\" are in the middle of a quote,\n\t * start it or end it, then the quote will be split (if needed) and the blocks\n\t * will be moved out of it, so other quoted blocks remained quoted.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t */\n\t_removeQuote( writer, blocks ) {\n\t\t// Unquote all groups of block. Iterate in the reverse order to not break following ranges.\n\t\tgetRangesOfBlockGroups( writer, blocks ).reverse().forEach( groupRange => {\n\t\t\tif ( groupRange.start.isAtStart && groupRange.end.isAtEnd ) {\n\t\t\t\twriter.unwrap( groupRange.start.parent );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The group of blocks are at the beginning of an <bQ> so let's move them left (out of the <bQ>).\n\t\t\tif ( groupRange.start.isAtStart ) {\n\t\t\t\tconst positionBefore = writer.createPositionBefore( groupRange.start.parent );\n\n\t\t\t\twriter.move( groupRange, positionBefore );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// The blocks are in the middle of an <bQ> so we need to split the <bQ> after the last block\n\t\t\t// so we move the items there.\n\t\t\tif ( !groupRange.end.isAtEnd ) {\n\t\t\t\twriter.split( groupRange.end );\n\t\t\t}\n\n\t\t\t// Now we are sure that groupRange.end.isAtEnd is true, so let's move the blocks right.\n\n\t\t\tconst positionAfter = writer.createPositionAfter( groupRange.end.parent );\n\n\t\t\twriter.move( groupRange, positionAfter );\n\t\t} );\n\t}\n\n\t/**\n\t * Applies the quote to given blocks.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t */\n\t_applyQuote( writer, blocks ) {\n\t\tconst quotesToMerge = [];\n\n\t\t// Quote all groups of block. Iterate in the reverse order to not break following ranges.\n\t\tgetRangesOfBlockGroups( writer, blocks ).reverse().forEach( groupRange => {\n\t\t\tlet quote = findQuote( groupRange.start );\n\n\t\t\tif ( !quote ) {\n\t\t\t\tquote = writer.createElement( 'blockQuote' );\n\n\t\t\t\twriter.wrap( groupRange, quote );\n\t\t\t}\n\n\t\t\tquotesToMerge.push( quote );\n\t\t} );\n\n\t\t// Merge subsequent <bQ> elements. Reverse the order again because this time we want to go through\n\t\t// the <bQ> elements in the source order (due to how merge works it moves the right element's content\n\t\t// to the first element and removes the right one. Since we may need to merge a couple of subsequent `<bQ>` elements\n\t\t// we want to keep the reference to the first (furthest left) one.\n\t\tquotesToMerge.reverse().reduce( ( currentQuote, nextQuote ) => {\n\t\t\tif ( currentQuote.nextSibling == nextQuote ) {\n\t\t\t\twriter.merge( writer.createPositionAfter( currentQuote ) );\n\n\t\t\t\treturn currentQuote;\n\t\t\t}\n\n\t\t\treturn nextQuote;\n\t\t} );\n\t}\n}\n\nfunction findQuote( elementOrPosition ) {\n\treturn elementOrPosition.parent.name == 'blockQuote' ? elementOrPosition.parent : null;\n}\n\n// Returns a minimal array of ranges containing groups of subsequent blocks.\n//\n// content: abcdefgh\n// blocks: [ a, b, d, f, g, h ]\n// output ranges: [ab]c[d]e[fgh]\n//\n// @param {Array.<module:engine/model/element~Element>} blocks\n// @returns {Array.<module:engine/model/range~Range>}\nfunction getRangesOfBlockGroups( writer, blocks ) {\n\tlet startPosition;\n\tlet i = 0;\n\tconst ranges = [];\n\n\twhile ( i < blocks.length ) {\n\t\tconst block = blocks[ i ];\n\t\tconst nextBlock = blocks[ i + 1 ];\n\n\t\tif ( !startPosition ) {\n\t\t\tstartPosition = writer.createPositionBefore( block );\n\t\t}\n\n\t\tif ( !nextBlock || block.nextSibling != nextBlock ) {\n\t\t\tranges.push( writer.createRange( startPosition, writer.createPositionAfter( block ) ) );\n\t\t\tstartPosition = null;\n\t\t}\n\n\t\ti++;\n\t}\n\n\treturn ranges;\n}\n\n// Checks whether <bQ> can wrap the block.\nfunction checkCanBeQuoted( schema, block ) {\n\t// TMP will be replaced with schema.checkWrap().\n\tconst isBQAllowed = schema.checkChild( block.parent, 'blockQuote' );\n\tconst isBlockAllowedInBQ = schema.checkChild( [ '$root', 'blockQuote' ], block );\n\n\treturn isBQAllowed && isBlockAllowedInBQ;\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 block-quote/blockquoteediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Enter } from 'ckeditor5/src/enter';\nimport { Delete } from 'ckeditor5/src/typing';\n\nimport BlockQuoteCommand from './blockquotecommand';\n\n/**\n * The block quote editing.\n *\n * Introduces the `'blockQuote'` command and the `'blockQuote'` model element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuoteEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockQuoteEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Enter, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\n\t\teditor.commands.add( 'blockQuote', new BlockQuoteCommand( editor ) );\n\n\t\tschema.register( 'blockQuote', {\n\t\t\tallowWhere: '$block',\n\t\t\tallowContentOf: '$root'\n\t\t} );\n\n\t\teditor.conversion.elementToElement( { model: 'blockQuote', view: 'blockquote' } );\n\n\t\t// Postfixer which cleans incorrect model states connected with block quotes.\n\t\teditor.model.document.registerPostFixer( writer => {\n\t\t\tconst changes = editor.model.document.differ.getChanges();\n\n\t\t\tfor ( const entry of changes ) {\n\t\t\t\tif ( entry.type == 'insert' ) {\n\t\t\t\t\tconst element = entry.position.nodeAfter;\n\n\t\t\t\t\tif ( !element ) {\n\t\t\t\t\t\t// We are inside a text node.\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( element.is( 'element', 'blockQuote' ) && element.isEmpty ) {\n\t\t\t\t\t\t// Added an empty blockQuote - remove it.\n\t\t\t\t\t\twriter.remove( element );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( element.is( 'element', 'blockQuote' ) && !schema.checkChild( entry.position, element ) ) {\n\t\t\t\t\t\t// Added a blockQuote in incorrect place. Unwrap it so the content inside is not lost.\n\t\t\t\t\t\twriter.unwrap( element );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t} else if ( element.is( 'element' ) ) {\n\t\t\t\t\t\t// Just added an element. Check that all children meet the scheme rules.\n\t\t\t\t\t\tconst range = writer.createRangeIn( element );\n\n\t\t\t\t\t\tfor ( const child of range.getItems() ) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tchild.is( 'element', 'blockQuote' ) &&\n\t\t\t\t\t\t\t\t!schema.checkChild( writer.createPositionBefore( child ), child )\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\twriter.unwrap( child );\n\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if ( entry.type == 'remove' ) {\n\t\t\t\t\tconst parent = entry.position.parent;\n\n\t\t\t\t\tif ( parent.is( 'element', 'blockQuote' ) && parent.isEmpty ) {\n\t\t\t\t\t\t// Something got removed and now blockQuote is empty. Remove the blockQuote as well.\n\t\t\t\t\t\twriter.remove( parent );\n\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} );\n\n\t\tconst viewDocument = this.editor.editing.view.document;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst blockQuoteCommand = editor.commands.get( 'blockQuote' );\n\n\t\t// Overwrite default Enter key behavior.\n\t\t// If Enter key is pressed with selection collapsed in empty block inside a quote, break the quote.\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tif ( !selection.isCollapsed || !blockQuoteCommand.value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst positionParent = selection.getLastPosition().parent;\n\n\t\t\tif ( positionParent.isEmpty ) {\n\t\t\t\teditor.execute( 'blockQuote' );\n\t\t\t\teditor.editing.view.scrollToTheSelection();\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { context: 'blockquote' } );\n\n\t\t// Overwrite default Backspace key behavior.\n\t\t// If Backspace key is pressed with selection collapsed in first empty block inside a quote, break the quote.\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\tif ( data.direction != 'backward' || !selection.isCollapsed || !blockQuoteCommand.value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst positionParent = selection.getLastPosition().parent;\n\n\t\t\tif ( positionParent.isEmpty && !positionParent.previousSibling ) {\n\t\t\t\teditor.execute( 'blockQuote' );\n\t\t\t\teditor.editing.view.scrollToTheSelection();\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { context: 'blockquote' } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module block-quote/blockquoteui\n */\n\nimport { Plugin, icons } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport '../theme/blockquote.css';\n\n/**\n * The block quote UI plugin.\n *\n * It introduces the `'blockQuote'` button.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuoteUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockQuoteUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\teditor.ui.componentFactory.add( 'blockQuote', locale => {\n\t\t\tconst command = editor.commands.get( 'blockQuote' );\n\t\t\tconst buttonView = new ButtonView( locale );\n\n\t\t\tbuttonView.set( {\n\t\t\t\tlabel: t( 'Block quote' ),\n\t\t\t\ticon: icons.quote,\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\t// Bind button model to command.\n\t\t\tbuttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute command.\n\t\t\tthis.listenTo( buttonView, 'execute', () => {\n\t\t\t\teditor.execute( 'blockQuote' );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn buttonView;\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paragraph/paragraphcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport first from '@ckeditor/ckeditor5-utils/src/first';\n\n/**\n * The paragraph command.\n *\n * @extends module:core/command~Command\n */\nexport default class ParagraphCommand extends Command {\n\t/**\n\t * The value of the command. Indicates whether the selection start is placed in a paragraph.\n\t *\n\t * @readonly\n\t * @observable\n\t * @member {Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst block = first( document.selection.getSelectedBlocks() );\n\n\t\tthis.value = !!block && block.is( 'element', 'paragraph' );\n\t\tthis.isEnabled = !!block && checkCanBecomeParagraph( block, model.schema );\n\t}\n\n\t/**\n\t * Executes the command. All the blocks (see {@link module:engine/model/schema~Schema}) in the selection\n\t * will be turned to paragraphs.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} [options.selection]\n\t * The selection that the command should be applied to.\n\t * By default, if not provided, the command is applied to the {@link module:engine/model/document~Document#selection}.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\tmodel.change( writer => {\n\t\t\tconst blocks = ( options.selection || document.selection ).getSelectedBlocks();\n\n\t\t\tfor ( const block of blocks ) {\n\t\t\t\tif ( !block.is( 'element', 'paragraph' ) && checkCanBecomeParagraph( block, model.schema ) ) {\n\t\t\t\t\twriter.rename( block, 'paragraph' );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks whether the given block can be replaced by a paragraph.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeParagraph( block, schema ) {\n\treturn schema.checkChild( block.parent, 'paragraph' ) && !schema.isObject( block );\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 paragraph/insertparagraphcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\n/**\n * The insert paragraph command. It inserts a new paragraph at a specific\n * {@link module:engine/model/position~Position document position}.\n *\n *\t\t// Insert a new paragraph before an element in the document.\n *\t\teditor.execute( 'insertParagraph', {\n *\t\t\tposition: editor.model.createPositionBefore( element )\n *\t\t} );\n *\n * If a paragraph is disallowed in the context of the specific position, the command\n * will attempt to split position ancestors to find a place where it is possible\n * to insert a paragraph.\n *\n * **Note**: This command moves the selection to the inserted paragraph.\n *\n * @extends module:core/command~Command\n */\nexport default class InsertParagraphCommand extends Command {\n\t/**\n\t * Executes the command.\n\t *\n\t * @param {Object} options Options for the executed command.\n\t * @param {module:engine/model/position~Position} options.position The model position at which\n\t * the new paragraph will be inserted.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tlet position = options.position;\n\n\t\tmodel.change( writer => {\n\t\t\tconst paragraph = writer.createElement( 'paragraph' );\n\n\t\t\tif ( !model.schema.checkChild( position.parent, paragraph ) ) {\n\t\t\t\tconst allowedParent = model.schema.findAllowedParent( position, paragraph );\n\n\t\t\t\t// It could be there's no ancestor limit that would allow paragraph.\n\t\t\t\t// In theory, \"paragraph\" could be disallowed even in the \"$root\".\n\t\t\t\tif ( !allowedParent ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tposition = writer.split( position, allowedParent ).position;\n\t\t\t}\n\n\t\t\tmodel.insertContent( paragraph, position );\n\n\t\t\twriter.setSelection( paragraph, 'in' );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paragraph/paragraph\n */\n\nimport ParagraphCommand from './paragraphcommand';\nimport InsertParagraphCommand from './insertparagraphcommand';\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\n/**\n * The paragraph feature for the editor.\n *\n * It introduces the `<paragraph>` element in the model which renders as a `<p>` element in the DOM and data.\n *\n * It also brings two editors commands:\n *\n * * The {@link module:paragraph/paragraphcommand~ParagraphCommand `'paragraph'`} command that converts all\n * blocks in the model selection into paragraphs.\n * * The {@link module:paragraph/insertparagraphcommand~InsertParagraphCommand `'insertParagraph'`} command\n * that inserts a new paragraph at a specified location in the model.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Paragraph extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Paragraph';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\teditor.commands.add( 'paragraph', new ParagraphCommand( editor ) );\n\t\teditor.commands.add( 'insertParagraph', new InsertParagraphCommand( editor ) );\n\n\t\t// Schema.\n\t\tmodel.schema.register( 'paragraph', { inheritAllFrom: '$block' } );\n\n\t\teditor.conversion.elementToElement( { model: 'paragraph', view: 'p' } );\n\n\t\t// Conversion for paragraph-like elements which has not been converted by any plugin.\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tmodel: ( viewElement, { writer } ) => {\n\t\t\t\tif ( !Paragraph.paragraphLikeElements.has( viewElement.name ) ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t// Do not auto-paragraph empty elements.\n\t\t\t\tif ( viewElement.isEmpty ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\treturn writer.createElement( 'paragraph' );\n\t\t\t},\n\t\t\tview: /.+/,\n\t\t\tconverterPriority: 'low'\n\t\t} );\n\t}\n}\n\n/**\n * A list of element names which should be treated by the autoparagraphing algorithms as\n * paragraph-like. This means that e.g. the following content:\n *\n *\t\t<h1>Foo</h1>\n *\t\t<table>\n *\t\t\t<tr>\n *\t\t\t\t<td>X</td>\n *\t\t\t\t<td>\n *\t\t\t\t\t<ul>\n *\t\t\t\t\t\t<li>Y</li>\n *\t\t\t\t\t\t<li>Z</li>\n *\t\t\t\t\t</ul>\n *\t\t\t\t</td>\n *\t\t\t</tr>\n *\t\t</table>\n *\n * contains five paragraph-like elements: `<h1>`, two `<td>`s and two `<li>`s.\n * Hence, if none of the features is going to convert those elements the above content will be automatically handled\n * by the paragraph feature and converted to:\n *\n *\t\t<p>Foo</p>\n *\t\t<p>X</p>\n *\t\t<p>Y</p>\n *\t\t<p>Z</p>\n *\n * Note: The `<td>` containing two `<li>` elements was ignored as the innermost paragraph-like elements\n * have a priority upon conversion.\n *\n * @member {Set.<String>} module:paragraph/paragraph~Paragraph.paragraphLikeElements\n */\nParagraph.paragraphLikeElements = new Set( [\n\t'blockquote',\n\t'dd',\n\t'div',\n\t'dt',\n\t'h1',\n\t'h2',\n\t'h3',\n\t'h4',\n\t'h5',\n\t'h6',\n\t'li',\n\t'p',\n\t'td',\n\t'th'\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 heading/headingcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * The heading command. It is used by the {@link module:heading/heading~Heading heading feature} to apply headings.\n *\n * @extends module:core/command~Command\n */\nexport default class HeadingCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor instance.\n\t * @param {Array.<String>} modelElements Names of the element which this command can apply in the model.\n\t */\n\tconstructor( editor, modelElements ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * If the selection starts in a heading (which {@link #modelElements is supported by this command})\n\t\t * the value is set to the name of that heading model element.\n\t\t * It is set to `false` otherwise.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean|String} #value\n\t\t */\n\n\t\t/**\n\t\t * Set of defined model's elements names that this command support.\n\t\t * See {@link module:heading/heading~HeadingOption}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<String>}\n\t\t */\n\t\tthis.modelElements = modelElements;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst block = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\tthis.value = !!block && this.modelElements.includes( block.name ) && block.name;\n\t\tthis.isEnabled = !!block && this.modelElements.some( heading => checkCanBecomeHeading( block, heading, this.editor.model.schema ) );\n\t}\n\n\t/**\n\t * Executes the command. Applies the heading to the selected blocks or, if the first selected\n\t * block is a heading already, turns selected headings (of this level only) to paragraphs.\n\t *\n\t * @param {Object} options\n\t * @param {String} options.value Name of the element which this command will apply in the model.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\tconst modelElement = options.value;\n\n\t\tmodel.change( writer => {\n\t\t\tconst blocks = Array.from( document.selection.getSelectedBlocks() )\n\t\t\t\t.filter( block => {\n\t\t\t\t\treturn checkCanBecomeHeading( block, modelElement, model.schema );\n\t\t\t\t} );\n\n\t\t\tfor ( const block of blocks ) {\n\t\t\t\tif ( !block.is( 'element', modelElement ) ) {\n\t\t\t\t\twriter.rename( block, modelElement );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks whether the given block can be replaced by a specific heading.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:heading/headingcommand~HeadingCommand#modelElement} heading Command element name in the model.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeHeading( block, heading, schema ) {\n\treturn schema.checkChild( block.parent, heading ) && !schema.isObject( block );\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 heading/headingediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Paragraph } from 'ckeditor5/src/paragraph';\nimport { priorities } from 'ckeditor5/src/utils';\n\nimport HeadingCommand from './headingcommand';\n\nconst defaultModelElement = 'paragraph';\n\n/**\n * The headings engine feature. It handles switching between block formats &ndash; headings and paragraph.\n * This class represents the engine part of the heading feature. See also {@link module:heading/heading~Heading}.\n * It introduces `heading1`-`headingN` commands which allow to convert paragraphs into headings.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HeadingEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HeadingEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'heading', {\n\t\t\toptions: [\n\t\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n\t\t\t\t{ model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },\n\t\t\t\t{ model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },\n\t\t\t\t{ model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Paragraph ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst options = editor.config.get( 'heading.options' );\n\n\t\tconst modelElements = [];\n\n\t\tfor ( const option of options ) {\n\t\t\t// Skip paragraph - it is defined in required Paragraph feature.\n\t\t\tif ( option.model !== defaultModelElement ) {\n\t\t\t\t// Schema.\n\t\t\t\teditor.model.schema.register( option.model, {\n\t\t\t\t\tinheritAllFrom: '$block'\n\t\t\t\t} );\n\n\t\t\t\teditor.conversion.elementToElement( option );\n\n\t\t\t\tmodelElements.push( option.model );\n\t\t\t}\n\t\t}\n\n\t\tthis._addDefaultH1Conversion( editor );\n\n\t\t// Register the heading command for this option.\n\t\teditor.commands.add( 'heading', new HeadingCommand( editor, modelElements ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\t// If the enter command is added to the editor, alter its behavior.\n\t\t// Enter at the end of a heading element should create a paragraph.\n\t\tconst editor = this.editor;\n\t\tconst enterCommand = editor.commands.get( 'enter' );\n\t\tconst options = editor.config.get( 'heading.options' );\n\n\t\tif ( enterCommand ) {\n\t\t\tthis.listenTo( enterCommand, 'afterExecute', ( evt, data ) => {\n\t\t\t\tconst positionParent = editor.model.document.selection.getFirstPosition().parent;\n\t\t\t\tconst isHeading = options.some( option => positionParent.is( 'element', option.model ) );\n\n\t\t\t\tif ( isHeading && !positionParent.is( 'element', defaultModelElement ) && positionParent.childCount === 0 ) {\n\t\t\t\t\tdata.writer.rename( positionParent, defaultModelElement );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Adds default conversion for `h1` -> `heading1` with a low priority.\n\t *\n\t * @private\n\t * @param {module:core/editor/editor~Editor} editor Editor instance on which to add the `h1` conversion.\n\t */\n\t_addDefaultH1Conversion( editor ) {\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tmodel: 'heading1',\n\t\t\tview: 'h1',\n\t\t\t// With a `low` priority, `paragraph` plugin autoparagraphing mechanism is executed. Make sure\n\t\t\t// this listener is called before it. If not, `h1` will be transformed into a paragraph.\n\t\t\tconverterPriority: priorities.get( 'low' ) + 1\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/utils\n */\n\n/**\n * Returns heading options as defined in `config.heading.options` but processed to consider\n * the editor localization, i.e. to display {@link module:heading/heading~HeadingOption}\n * in the correct language.\n *\n * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n * when the user configuration is defined because the editor does not exist yet.\n *\n * @param {module:core/editor/editor~Editor} editor\n * @returns {Array.<module:heading/heading~HeadingOption>}.\n */\nexport function getLocalizedOptions( editor ) {\n\tconst t = editor.t;\n\tconst localizedTitles = {\n\t\tParagraph: t( 'Paragraph' ),\n\t\t'Heading 1': t( 'Heading 1' ),\n\t\t'Heading 2': t( 'Heading 2' ),\n\t\t'Heading 3': t( 'Heading 3' ),\n\t\t'Heading 4': t( 'Heading 4' ),\n\t\t'Heading 5': t( 'Heading 5' ),\n\t\t'Heading 6': t( 'Heading 6' )\n\t};\n\n\treturn editor.config.get( 'heading.options' ).map( option => {\n\t\tconst title = localizedTitles[ option.title ];\n\n\t\tif ( title && title != option.title ) {\n\t\t\toption.title = title;\n\t\t}\n\n\t\treturn option;\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/headingui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui';\nimport { Collection } from 'ckeditor5/src/utils';\n\nimport { getLocalizedOptions } from './utils';\n\nimport '../theme/heading.css';\n\n/**\n * The headings UI feature. It introduces the `headings` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HeadingUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HeadingUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst options = getLocalizedOptions( editor );\n\t\tconst defaultTitle = t( 'Choose heading' );\n\t\tconst dropdownTooltip = t( 'Heading' );\n\n\t\t// Register UI component.\n\t\teditor.ui.componentFactory.add( 'heading', locale => {\n\t\t\tconst titles = {};\n\t\t\tconst itemDefinitions = new Collection();\n\n\t\t\tconst headingCommand = editor.commands.get( 'heading' );\n\t\t\tconst paragraphCommand = editor.commands.get( 'paragraph' );\n\n\t\t\tconst commands = [ headingCommand ];\n\n\t\t\tfor ( const option of options ) {\n\t\t\t\tconst def = {\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: new Model( {\n\t\t\t\t\t\tlabel: option.title,\n\t\t\t\t\t\tclass: option.class,\n\t\t\t\t\t\twithText: true\n\t\t\t\t\t} )\n\t\t\t\t};\n\n\t\t\t\tif ( option.model === 'paragraph' ) {\n\t\t\t\t\tdef.model.bind( 'isOn' ).to( paragraphCommand, 'value' );\n\t\t\t\t\tdef.model.set( 'commandName', 'paragraph' );\n\t\t\t\t\tcommands.push( paragraphCommand );\n\t\t\t\t} else {\n\t\t\t\t\tdef.model.bind( 'isOn' ).to( headingCommand, 'value', value => value === option.model );\n\t\t\t\t\tdef.model.set( {\n\t\t\t\t\t\tcommandName: 'heading',\n\t\t\t\t\t\tcommandValue: option.model\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\t// Add the option to the collection.\n\t\t\t\titemDefinitions.add( def );\n\n\t\t\t\ttitles[ option.model ] = option.title;\n\t\t\t}\n\n\t\t\tconst dropdownView = createDropdown( locale );\n\t\t\taddListToDropdown( dropdownView, itemDefinitions );\n\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\tisOn: false,\n\t\t\t\twithText: true,\n\t\t\t\ttooltip: dropdownTooltip\n\t\t\t} );\n\n\t\t\tdropdownView.extendTemplate( {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck-heading-dropdown'\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => {\n\t\t\t\treturn areEnabled.some( isEnabled => isEnabled );\n\t\t\t} );\n\n\t\t\tdropdownView.buttonView.bind( 'label' ).to( headingCommand, 'value', paragraphCommand, 'value', ( value, para ) => {\n\t\t\t\tconst whichModel = value || para && 'paragraph';\n\t\t\t\t// If none of the commands is active, display default title.\n\t\t\t\treturn titles[ whichModel ] ? titles[ whichModel ] : defaultTitle;\n\t\t\t} );\n\n\t\t\t// Execute command when an item from the dropdown is selected.\n\t\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\t\teditor.execute( evt.source.commandName, evt.source.commandValue ? { value: evt.source.commandValue } : undefined );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module widget/highlightstack\n */\n\nimport EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Class used to handle correct order of highlights on elements.\n *\n * When different highlights are applied to same element correct order should be preserved:\n *\n * * highlight with highest priority should be applied,\n * * if two highlights have same priority - sort by CSS class provided in\n * {@link module:engine/conversion/downcasthelpers~HighlightDescriptor}.\n *\n * This way, highlight will be applied with the same rules it is applied on texts.\n */\nexport default class HighlightStack {\n\t/**\n\t * Creates class instance.\n\t */\n\tconstructor() {\n\t\tthis._stack = [];\n\t}\n\n\t/**\n\t * Adds highlight descriptor to the stack.\n\t *\n\t * @fires change:top\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\tadd( descriptor, writer ) {\n\t\tconst stack = this._stack;\n\n\t\t// Save top descriptor and insert new one. If top is changed - fire event.\n\t\tconst oldTop = stack[ 0 ];\n\t\tthis._insertDescriptor( descriptor );\n\t\tconst newTop = stack[ 0 ];\n\n\t\t// When new object is at the top and stores different information.\n\t\tif ( oldTop !== newTop && !compareDescriptors( oldTop, newTop ) ) {\n\t\t\tthis.fire( 'change:top', {\n\t\t\t\toldDescriptor: oldTop,\n\t\t\t\tnewDescriptor: newTop,\n\t\t\t\twriter\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Removes highlight descriptor from the stack.\n\t *\n\t * @fires change:top\n\t * @param {String} id Id of the descriptor to remove.\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\tremove( id, writer ) {\n\t\tconst stack = this._stack;\n\n\t\tconst oldTop = stack[ 0 ];\n\t\tthis._removeDescriptor( id );\n\t\tconst newTop = stack[ 0 ];\n\n\t\t// When new object is at the top and stores different information.\n\t\tif ( oldTop !== newTop && !compareDescriptors( oldTop, newTop ) ) {\n\t\t\tthis.fire( 'change:top', {\n\t\t\t\toldDescriptor: oldTop,\n\t\t\t\tnewDescriptor: newTop,\n\t\t\t\twriter\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Inserts given descriptor in correct place in the stack. It also takes care about updating information when\n\t * descriptor with same id is already present.\n\t *\n\t * @private\n\t * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n\t */\n\t_insertDescriptor( descriptor ) {\n\t\tconst stack = this._stack;\n\t\tconst index = stack.findIndex( item => item.id === descriptor.id );\n\n\t\t// Inserting exact same descriptor - do nothing.\n\t\tif ( compareDescriptors( descriptor, stack[ index ] ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If descriptor with same id but with different information is on the stack - remove it.\n\t\tif ( index > -1 ) {\n\t\t\tstack.splice( index, 1 );\n\t\t}\n\n\t\t// Find correct place to insert descriptor in the stack.\n\t\t// It have different information (for example priority) so it must be re-inserted in correct place.\n\t\tlet i = 0;\n\n\t\twhile ( stack[ i ] && shouldABeBeforeB( stack[ i ], descriptor ) ) {\n\t\t\ti++;\n\t\t}\n\n\t\tstack.splice( i, 0, descriptor );\n\t}\n\n\t/**\n\t * Removes descriptor with given id from the stack.\n\t *\n\t * @private\n\t * @param {String} id Descriptor's id.\n\t */\n\t_removeDescriptor( id ) {\n\t\tconst stack = this._stack;\n\t\tconst index = stack.findIndex( item => item.id === id );\n\n\t\t// If descriptor with same id is on the list - remove it.\n\t\tif ( index > -1 ) {\n\t\t\tstack.splice( index, 1 );\n\t\t}\n\t}\n}\n\nmix( HighlightStack, EmitterMixin );\n\n// Compares two descriptors by checking their priority and class list.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} a\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} b\n// @returns {Boolean} Returns true if both descriptors are defined and have same priority and classes.\nfunction compareDescriptors( a, b ) {\n\treturn a && b && a.priority == b.priority && classesToString( a.classes ) == classesToString( b.classes );\n}\n\n// Checks whenever first descriptor should be placed in the stack before second one.\n//\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} a\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} b\n// @returns {Boolean}\nfunction shouldABeBeforeB( a, b ) {\n\tif ( a.priority > b.priority ) {\n\t\treturn true;\n\t} else if ( a.priority < b.priority ) {\n\t\treturn false;\n\t}\n\n\t// When priorities are equal and names are different - use classes to compare.\n\treturn classesToString( a.classes ) > classesToString( b.classes );\n}\n\n// Converts CSS classes passed with {@link module:engine/conversion/downcasthelpers~HighlightDescriptor} to\n// sorted string.\n//\n// @param {String|Array<String>} descriptor\n// @returns {String}\nfunction classesToString( classes ) {\n\treturn Array.isArray( classes ) ? classes.sort().join( ',' ) : classes;\n}\n\n/**\n * Fired when top element on {@link module:widget/highlightstack~HighlightStack} has been changed\n *\n * @event change:top\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} [data.newDescriptor] New highlight\n * descriptor. It will be `undefined` when last descriptor is removed from the stack.\n * @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} [data.oldDescriptor] Old highlight\n * descriptor. It will be `undefined` when first descriptor is added to the stack.\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer View writer that can be used to modify element.\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 widget/utils\n */\n\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\n\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\nimport toArray from '@ckeditor/ckeditor5-utils/src/toarray';\n\nimport HighlightStack from './highlightstack';\nimport { getTypeAroundFakeCaretPosition } from './widgettypearound/utils';\n\nimport IconView from '@ckeditor/ckeditor5-ui/src/icon/iconview';\nimport dragHandleIcon from '../theme/icons/drag-handle.svg';\n\n/**\n * CSS class added to each widget element.\n *\n * @const {String}\n */\nexport const WIDGET_CLASS_NAME = 'ck-widget';\n\n/**\n * CSS class added to currently selected widget element.\n *\n * @const {String}\n */\nexport const WIDGET_SELECTED_CLASS_NAME = 'ck-widget_selected';\n\n/**\n * Returns `true` if given {@link module:engine/view/node~Node} is an {@link module:engine/view/element~Element} and a widget.\n *\n * @param {module:engine/view/node~Node} node\n * @returns {Boolean}\n */\nexport function isWidget( node ) {\n\tif ( !node.is( 'element' ) ) {\n\t\treturn false;\n\t}\n\n\treturn !!node.getCustomProperty( 'widget' );\n}\n\n/**\n * Converts the given {@link module:engine/view/element~Element} to a widget in the following way:\n *\n * * sets the `contenteditable` attribute to `\"false\"`,\n * * adds the `ck-widget` CSS class,\n * * adds a custom {@link module:engine/view/element~Element#getFillerOffset `getFillerOffset()`} method returning `null`,\n * * adds a custom property allowing to recognize widget elements by using {@link ~isWidget `isWidget()`},\n * * implements the {@link ~setHighlightHandling view highlight on widgets}.\n *\n * This function needs to be used in conjunction with\n * {@link module:engine/conversion/downcasthelpers~DowncastHelpers downcast conversion helpers}\n * like {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`}.\n * Moreover, typically you will want to use `toWidget()` only for `editingDowncast`, while keeping the `dataDowncast` clean.\n *\n * For example, in order to convert a `<widget>` model element to `<div class=\"widget\">` in the view, you can define\n * such converters:\n *\n *\t\teditor.conversion.for( 'editingDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'widget',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\tconst div = writer.createContainerElement( 'div', { class: 'widget' } );\n *\n *\t\t\t\t\treturn toWidget( div, writer, { label: 'some widget' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n *\t\teditor.conversion.for( 'dataDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'widget',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\treturn writer.createContainerElement( 'div', { class: 'widget' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n * See the full source code of the widget (with a nested editable) schema definition and converters in\n * [this sample](https://github.com/ckeditor/ckeditor5-widget/blob/master/tests/manual/widget-with-nestededitable.js).\n *\n * @param {module:engine/view/element~Element} element\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {Object} [options={}]\n * @param {String|Function} [options.label] Element's label provided to the {@link ~setLabel} function. It can be passed as\n * a plain string or a function returning a string. It represents the widget for assistive technologies (like screen readers).\n * @param {Boolean} [options.hasSelectionHandle=false] If `true`, the widget will have a selection handle added.\n * @returns {module:engine/view/element~Element} Returns the same element.\n */\nexport function toWidget( element, writer, options = {} ) {\n\tif ( !element.is( 'containerElement' ) ) {\n\t\t/**\n\t\t * The element passed to `toWidget()` must be a {@link module:engine/view/containerelement~ContainerElement}\n\t\t * instance.\n\t\t *\n\t\t * @error widget-to-widget-wrong-element-type\n\t\t * @param {String} element The view element passed to `toWidget()`.\n\t\t */\n\t\tthrow new CKEditorError(\n\t\t\t'widget-to-widget-wrong-element-type',\n\t\t\tnull,\n\t\t\t{ element }\n\t\t);\n\t}\n\n\twriter.setAttribute( 'contenteditable', 'false', element );\n\n\twriter.addClass( WIDGET_CLASS_NAME, element );\n\twriter.setCustomProperty( 'widget', true, element );\n\telement.getFillerOffset = getFillerOffset;\n\n\tif ( options.label ) {\n\t\tsetLabel( element, options.label, writer );\n\t}\n\n\tif ( options.hasSelectionHandle ) {\n\t\taddSelectionHandle( element, writer );\n\t}\n\n\tsetHighlightHandling( element, writer, addHighlight, removeHighlight );\n\n\treturn element;\n}\n\n// Default handler for adding a highlight on a widget.\n// It adds CSS class and attributes basing on the given highlight descriptor.\n//\n// @param {module:engine/view/element~Element} element\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction addHighlight( element, descriptor, writer ) {\n\tif ( descriptor.classes ) {\n\t\twriter.addClass( toArray( descriptor.classes ), element );\n\t}\n\n\tif ( descriptor.attributes ) {\n\t\tfor ( const key in descriptor.attributes ) {\n\t\t\twriter.setAttribute( key, descriptor.attributes[ key ], element );\n\t\t}\n\t}\n}\n\n// Default handler for removing a highlight from a widget.\n// It removes CSS class and attributes basing on the given highlight descriptor.\n//\n// @param {module:engine/view/element~Element} element\n// @param {module:engine/conversion/downcasthelpers~HighlightDescriptor} descriptor\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction removeHighlight( element, descriptor, writer ) {\n\tif ( descriptor.classes ) {\n\t\twriter.removeClass( toArray( descriptor.classes ), element );\n\t}\n\n\tif ( descriptor.attributes ) {\n\t\tfor ( const key in descriptor.attributes ) {\n\t\t\twriter.removeAttribute( key, element );\n\t\t}\n\t}\n}\n\n/**\n * Sets highlight handling methods. Uses {@link module:widget/highlightstack~HighlightStack} to\n * properly determine which highlight descriptor should be used at given time.\n *\n * @param {module:engine/view/element~Element} element\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @param {Function} add\n * @param {Function} remove\n */\nexport function setHighlightHandling( element, writer, add, remove ) {\n\tconst stack = new HighlightStack();\n\n\tstack.on( 'change:top', ( evt, data ) => {\n\t\tif ( data.oldDescriptor ) {\n\t\t\tremove( element, data.oldDescriptor, data.writer );\n\t\t}\n\n\t\tif ( data.newDescriptor ) {\n\t\t\tadd( element, data.newDescriptor, data.writer );\n\t\t}\n\t} );\n\n\twriter.setCustomProperty( 'addHighlight', ( element, descriptor, writer ) => stack.add( descriptor, writer ), element );\n\twriter.setCustomProperty( 'removeHighlight', ( element, id, writer ) => stack.remove( id, writer ), element );\n}\n\n/**\n * Sets label for given element.\n * It can be passed as a plain string or a function returning a string. Function will be called each time label is retrieved by\n * {@link ~getLabel `getLabel()`}.\n *\n * @param {module:engine/view/element~Element} element\n * @param {String|Function} labelOrCreator\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n */\nexport function setLabel( element, labelOrCreator, writer ) {\n\twriter.setCustomProperty( 'widgetLabel', labelOrCreator, element );\n}\n\n/**\n * Returns the label of the provided element.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {String}\n */\nexport function getLabel( element ) {\n\tconst labelCreator = element.getCustomProperty( 'widgetLabel' );\n\n\tif ( !labelCreator ) {\n\t\treturn '';\n\t}\n\n\treturn typeof labelCreator == 'function' ? labelCreator() : labelCreator;\n}\n\n/**\n * Adds functionality to the provided {@link module:engine/view/editableelement~EditableElement} to act as a widget's editable:\n *\n * * sets the `contenteditable` attribute to `true` when {@link module:engine/view/editableelement~EditableElement#isReadOnly} is `false`,\n * otherwise sets it to `false`,\n * * adds the `ck-editor__editable` and `ck-editor__nested-editable` CSS classes,\n * * adds the `ck-editor__nested-editable_focused` CSS class when the editable is focused and removes it when it is blurred.\n *\n * Similarly to {@link ~toWidget `toWidget()`} this function should be used in `editingDowncast` only and it is usually\n * used together with {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `elementToElement()`}.\n *\n * For example, in order to convert a `<nested>` model element to `<div class=\"nested\">` in the view, you can define\n * such converters:\n *\n *\t\teditor.conversion.for( 'editingDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'nested',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\tconst div = writer.createEditableElement( 'div', { class: 'nested' } );\n *\n *\t\t\t\t\treturn toWidgetEditable( nested, writer );\n *\t\t\t\t}\n *\t\t\t} );\n *\n *\t\teditor.conversion.for( 'dataDowncast' )\n *\t\t\t.elementToElement( {\n *\t\t\t\tmodel: 'nested',\n *\t\t\t\tview: ( modelItem, { writer } ) => {\n *\t\t\t\t\treturn writer.createContainerElement( 'div', { class: 'nested' } );\n *\t\t\t\t}\n *\t\t\t} );\n *\n * See the full source code of the widget (with nested editable) schema definition and converters in\n * [this sample](https://github.com/ckeditor/ckeditor5-widget/blob/master/tests/manual/widget-with-nestededitable.js).\n *\n * @param {module:engine/view/editableelement~EditableElement} editable\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n * @returns {module:engine/view/editableelement~EditableElement} Returns the same element that was provided in the `editable` parameter\n */\nexport function toWidgetEditable( editable, writer ) {\n\twriter.addClass( [ 'ck-editor__editable', 'ck-editor__nested-editable' ], editable );\n\n\t// Set initial contenteditable value.\n\twriter.setAttribute( 'contenteditable', editable.isReadOnly ? 'false' : 'true', editable );\n\n\t// Bind the contenteditable property to element#isReadOnly.\n\teditable.on( 'change:isReadOnly', ( evt, property, is ) => {\n\t\twriter.setAttribute( 'contenteditable', is ? 'false' : 'true', editable );\n\t} );\n\n\teditable.on( 'change:isFocused', ( evt, property, is ) => {\n\t\tif ( is ) {\n\t\t\twriter.addClass( 'ck-editor__nested-editable_focused', editable );\n\t\t} else {\n\t\t\twriter.removeClass( 'ck-editor__nested-editable_focused', editable );\n\t\t}\n\t} );\n\n\treturn editable;\n}\n\n/**\n * Returns a model position which is optimal (in terms of UX) for inserting a widget block.\n *\n * For instance, if a selection is in the middle of a paragraph, the position before this paragraph\n * will be returned so that it is not split. If the selection is at the end of a paragraph,\n * the position after this paragraph will be returned.\n *\n * Note: If the selection is placed in an empty block, that block will be returned. If that position\n * is then passed to {@link module:engine/model/model~Model#insertContent},\n * the block will be fully replaced by the image.\n *\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * The selection based on which the insertion position should be calculated.\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {module:engine/model/position~Position} The optimal position.\n */\nexport function findOptimalInsertionPosition( selection, model ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\tif ( selectedElement ) {\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( selection );\n\n\t\t// If the WidgetTypeAround \"fake caret\" is displayed, use its position for the insertion\n\t\t// to provide the most predictable UX (https://github.com/ckeditor/ckeditor5/issues/7438).\n\t\tif ( typeAroundFakeCaretPosition ) {\n\t\t\treturn model.createPositionAt( selectedElement, typeAroundFakeCaretPosition );\n\t\t}\n\n\t\tif ( model.schema.isBlock( selectedElement ) ) {\n\t\t\treturn model.createPositionAfter( selectedElement );\n\t\t}\n\t}\n\n\tconst firstBlock = selection.getSelectedBlocks().next().value;\n\n\tif ( firstBlock ) {\n\t\t// If inserting into an empty block return position in that block. It will get\n\t\t// replaced with the image by insertContent(). #42.\n\t\tif ( firstBlock.isEmpty ) {\n\t\t\treturn model.createPositionAt( firstBlock, 0 );\n\t\t}\n\n\t\tconst positionAfter = model.createPositionAfter( firstBlock );\n\n\t\t// If selection is at the end of the block - return position after the block.\n\t\tif ( selection.focus.isTouching( positionAfter ) ) {\n\t\t\treturn positionAfter;\n\t\t}\n\n\t\t// Otherwise return position before the block.\n\t\treturn model.createPositionBefore( firstBlock );\n\t}\n\n\treturn selection.focus;\n}\n\n/**\n * Checks if the selection is on an object.\n *\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * @param {module:engine/model/schema~Schema} schema\n * @returns {Boolean}\n*/\nexport function checkSelectionOnObject( selection, schema ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\treturn !!selectedElement && schema.isObject( selectedElement );\n}\n\n/**\n * A util to be used in order to map view positions to correct model positions when implementing a widget\n * which renders non-empty view element for an empty model element.\n *\n * For example:\n *\n *\t\t// Model:\n *\t\t<placeholder type=\"name\"></placeholder>\n *\n *\t\t// View:\n *\t\t<span class=\"placeholder\">name</span>\n *\n * In such case, view positions inside `<span>` cannot be correct mapped to the model (because the model element is empty).\n * To handle mapping positions inside `<span class=\"placeholder\">` to the model use this util as follows:\n *\n *\t\teditor.editing.mapper.on(\n *\t\t\t'viewToModelPosition',\n *\t\t\tviewToModelPositionOutsideModelElement( model, viewElement => viewElement.hasClass( 'placeholder' ) )\n *\t\t);\n *\n * The callback will try to map the view offset of selection to an expected model position.\n *\n * 1. When the position is at the end (or in the middle) of the inline widget:\n *\n *\t\t// View:\n *\t\t<p>foo <span class=\"placeholder\">name|</span> bar</p>\n *\n *\t\t// Model:\n *\t\t<paragraph>foo <placeholder type=\"name\"></placeholder>| bar</paragraph>\n *\n * 2. When the position is at the beginning of the inline widget:\n *\n *\t\t// View:\n *\t\t<p>foo <span class=\"placeholder\">|name</span> bar</p>\n *\n *\t\t// Model:\n *\t\t<paragraph>foo |<placeholder type=\"name\"></placeholder> bar</paragraph>\n *\n * @param {module:engine/model/model~Model} model Model instance on which the callback operates.\n * @param {Function} viewElementMatcher Function that is passed a view element and should return `true` if the custom mapping\n * should be applied to the given view element.\n * @return {Function}\n */\nexport function viewToModelPositionOutsideModelElement( model, viewElementMatcher ) {\n\treturn ( evt, data ) => {\n\t\tconst { mapper, viewPosition } = data;\n\n\t\tconst viewParent = mapper.findMappedViewAncestor( viewPosition );\n\n\t\tif ( !viewElementMatcher( viewParent ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelParent = mapper.toModelElement( viewParent );\n\n\t\tdata.modelPosition = model.createPositionAt( modelParent, viewPosition.isAtStart ? 'before' : 'after' );\n\t};\n}\n\n/**\n * A positioning function passed to the {@link module:utils/dom/position~getOptimalPosition} helper as a last resort\n * when attaching {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView balloon UI} to widgets.\n * It comes in handy when a widget is longer than the visual viewport of the web browser and/or upper/lower boundaries\n * of a widget are off screen because of the web page scroll.\n *\n *\t ┌─┄┄┄┄┄┄┄┄┄Widget┄┄┄┄┄┄┄┄┄┐\n *\t ┊ ┊\n *\t┌────────────Viewport───────────┐ ┌──╁─────────Viewport────────╁──┐\n *\t│ ┏━━━━━━━━━━Widget━━━━━━━━━┓ │ │ ┃ ^ ┃ │\n *\t│ ┃ ^ ┃ │ │ ┃ ╭───────/ \\───────╮ ┃ │\n *\t│ ┃ ╭───────/ \\───────╮ ┃ │ │ ┃ │ Balloon │ ┃ │\n *\t│ ┃ │ Balloon │ ┃ │ │ ┃ ╰─────────────────╯ ┃ │\n *\t│ ┃ ╰─────────────────╯ ┃ │ │ ┃ ┃ │\n *\t│ ┃ ┃ │ │ ┃ ┃ │\n *\t│ ┃ ┃ │ │ ┃ ┃ │\n *\t│ ┃ ┃ │ │ ┃ ┃ │\n *\t│ ┃ ┃ │ │ ┃ ┃ │\n *\t│ ┃ ┃ │ │ ┃ ┃ │\n *\t│ ┃ ┃ │ │ ┃ ┃ │\n *\t└──╀─────────────────────────╀──┘ └──╀─────────────────────────╀──┘\n *\t ┊ ┊ ┊ ┊\n *\t ┊ ┊ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘\n *\t ┊ ┊\n *\t └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘\n *\n * **Note**: Works best if used together with\n * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions default `BalloonPanelView` positions}\n * like `northArrowSouth` and `southArrowNorth`; the transition between these two and this position is smooth.\n *\n * @param {module:utils/dom/rect~Rect} widgetRect A rect of the widget.\n * @param {module:utils/dom/rect~Rect} balloonRect A rect of the balloon.\n * @returns {module:utils/dom/position~Position|null}\n */\nexport function centeredBalloonPositionForLongWidgets( widgetRect, balloonRect ) {\n\tconst viewportRect = new Rect( global.window );\n\tconst viewportWidgetInsersectionRect = viewportRect.getIntersection( widgetRect );\n\n\tconst balloonTotalHeight = balloonRect.height + BalloonPanelView.arrowVerticalOffset;\n\n\t// If there is enough space above or below the widget then this position should not be used.\n\tif ( widgetRect.top - balloonTotalHeight > viewportRect.top || widgetRect.bottom + balloonTotalHeight < viewportRect.bottom ) {\n\t\treturn null;\n\t}\n\n\t// Because this is a last resort positioning, to keep things simple we're not playing with positions of the arrow\n\t// like, for instance, \"south west\" or whatever. Just try to keep the balloon in the middle of the visible area of\n\t// the widget for as long as it is possible. If the widgets becomes invisible (because cropped by the viewport),\n\t// just... place the balloon in the middle of it (because why not?).\n\tconst targetRect = viewportWidgetInsersectionRect || widgetRect;\n\tconst left = targetRect.left + targetRect.width / 2 - balloonRect.width / 2;\n\n\treturn {\n\t\ttop: Math.max( widgetRect.top, 0 ) + BalloonPanelView.arrowVerticalOffset,\n\t\tleft,\n\t\tname: 'arrow_n'\n\t};\n}\n\n// Default filler offset function applied to all widget elements.\n//\n// @returns {null}\nfunction getFillerOffset() {\n\treturn null;\n}\n\n// Adds a drag handle to the widget.\n//\n// @param {module:engine/view/containerelement~ContainerElement}\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction addSelectionHandle( widgetElement, writer ) {\n\tconst selectionHandle = writer.createUIElement( 'div', { class: 'ck ck-widget__selection-handle' }, function( domDocument ) {\n\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t// Use the IconView from the ui library.\n\t\tconst icon = new IconView();\n\t\ticon.set( 'content', dragHandleIcon );\n\n\t\t// Render the icon view right away to append its #element to the selectionHandle DOM element.\n\t\ticon.render();\n\n\t\tdomElement.appendChild( icon.element );\n\n\t\treturn domElement;\n\t} );\n\n\t// Append the selection handle into the widget wrapper.\n\twriter.insert( writer.createPositionAt( widgetElement, 0 ), selectionHandle );\n\twriter.addClass( [ 'ck-widget_with-selection-handle' ], widgetElement );\n}\n","export default \"<svg viewBox=\\\"0 0 16 16\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M4 0v1H1v3H0V.5A.5.5 0 0 1 .5 0H4zm8 0h3.5a.5.5 0 0 1 .5.5V4h-1V1h-3V0zM4 16H.5a.5.5 0 0 1-.5-.5V12h1v3h3v1zm8 0v-1h3v-3h1v3.5a.5.5 0 0 1-.5.5H12z\\\"/><path fill-opacity=\\\".256\\\" d=\\\"M1 1h14v14H1z\\\"/><g class=\\\"ck-icon__selected-indicator\\\"><path d=\\\"M7 0h2v1H7V0zM0 7h1v2H0V7zm15 0h1v2h-1V7zm-8 8h2v1H7v-1z\\\"/><path fill-opacity=\\\".254\\\" d=\\\"M1 1h14v14H1z\\\"/></g></svg>\";","/**\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 widget/widgettypearound/utils\n */\n\nimport { isWidget } from '../utils';\n\n/**\n * The name of the type around model selection attribute responsible for\n * displaying a fake caret next to a selected widget.\n */\nexport const TYPE_AROUND_SELECTION_ATTRIBUTE = 'widget-type-around';\n\n/**\n * Checks if an element is a widget that qualifies to get the widget type around UI.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/model/element~Element} modelElement\n * @param {module:engine/model/schema~Schema} schema\n * @returns {Boolean}\n */\nexport function isTypeAroundWidget( viewElement, modelElement, schema ) {\n\treturn viewElement && isWidget( viewElement ) && !schema.isInline( modelElement );\n}\n\n/**\n * For the passed HTML element, this helper finds the closest widget type around button ancestor.\n *\n * @param {HTMLElement} domElement\n * @returns {HTMLElement|null}\n */\nexport function getClosestTypeAroundDomButton( domElement ) {\n\treturn domElement.closest( '.ck-widget__type-around__button' );\n}\n\n/**\n * For the passed widget type around button element, this helper determines at which position\n * the paragraph would be inserted into the content if, for instance, the button was\n * clicked by the user.\n *\n * @param {HTMLElement} domElement\n * @returns {'before'|'after'} The position of the button.\n */\nexport function getTypeAroundButtonPosition( domElement ) {\n\treturn domElement.classList.contains( 'ck-widget__type-around__button_before' ) ? 'before' : 'after';\n}\n\n/**\n * For the passed HTML element, this helper returns the closest view widget ancestor.\n *\n * @param {HTMLElement} domElement\n * @param {module:engine/view/domconverter~DomConverter} domConverter\n * @returns {module:engine/view/element~Element}\n */\nexport function getClosestWidgetViewElement( domElement, domConverter ) {\n\tconst widgetDomElement = domElement.closest( '.ck-widget' );\n\n\treturn domConverter.mapDomToView( widgetDomElement );\n}\n\n/**\n * For the passed selection instance, it returns the position of the fake caret displayed next to a widget.\n *\n * **Note**: If the fake caret is not currently displayed, `null` is returned.\n *\n * @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n * @returns {'before'|'after'|null} The position of the fake caret or `null` when none is present.\n */\nexport function getTypeAroundFakeCaretPosition( selection ) {\n\treturn selection.getAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\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/* global DOMParser */\n\n/**\n * @module widget/widgettypearound\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport Enter from '@ckeditor/ckeditor5-enter/src/enter';\nimport Delete from '@ckeditor/ckeditor5-typing/src/delete';\nimport {\n\tisForwardArrowKeyCode,\n\tkeyCodes\n} from '@ckeditor/ckeditor5-utils/src/keyboard';\n\nimport {\n\tisTypeAroundWidget,\n\tgetClosestTypeAroundDomButton,\n\tgetTypeAroundButtonPosition,\n\tgetClosestWidgetViewElement,\n\tgetTypeAroundFakeCaretPosition,\n\tTYPE_AROUND_SELECTION_ATTRIBUTE\n} from './utils';\n\nimport {\n\tisNonTypingKeystroke\n} from '@ckeditor/ckeditor5-typing/src/utils/injectunsafekeystrokeshandling';\n\nimport { isWidget } from '../utils';\n\nimport returnIcon from '../../theme/icons/return-arrow.svg';\nimport '../../theme/widgettypearound.css';\n\nconst POSSIBLE_INSERTION_POSITIONS = [ 'before', 'after' ];\n\n// Do the SVG parsing once and then clone the result <svg> DOM element for each new button.\nconst RETURN_ARROW_ICON_ELEMENT = new DOMParser().parseFromString( returnIcon, 'image/svg+xml' ).firstChild;\n\nconst PLUGIN_DISABLED_EDITING_ROOT_CLASS = 'ck-widget__type-around_disabled';\n\n/**\n * A plugin that allows users to type around widgets where normally it is impossible to place the caret due\n * to limitations of web browsers. These \"tight spots\" occur, for instance, before (or after) a widget being\n * the first (or last) child of its parent or between two block widgets.\n *\n * This plugin extends the {@link module:widget/widget~Widget `Widget`} plugin and injects the user interface\n * with two buttons into each widget instance in the editor. Each of the buttons can be clicked by the\n * user if the widget is next to the \"tight spot\". Once clicked, a paragraph is created with the selection anchored\n * in it so that users can type (or insert content, paste, etc.) straight away.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class WidgetTypeAround extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'WidgetTypeAround';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Enter, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A reference to the model widget element that has the fake caret active\n\t\t * on either side of it. It is later used to remove CSS classes associated with the fake caret\n\t\t * when the widget no longer needs it.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/model/element~Element|null}\n\t\t */\n\t\tthis._currentFakeCaretModelElement = null;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// Set a CSS class on the view editing root when the plugin is disabled so all the buttons\n\t\t// and lines visually disappear. All the interactions are disabled in individual plugin methods.\n\t\tthis.on( 'change:isEnabled', ( evt, data, isEnabled ) => {\n\t\t\teditingView.change( writer => {\n\t\t\t\tfor ( const root of editingView.document.roots ) {\n\t\t\t\t\tif ( isEnabled ) {\n\t\t\t\t\t\twriter.removeClass( PLUGIN_DISABLED_EDITING_ROOT_CLASS, root );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.addClass( PLUGIN_DISABLED_EDITING_ROOT_CLASS, root );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tif ( !isEnabled ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tthis._enableTypeAroundUIInjection();\n\t\tthis._enableInsertingParagraphsOnButtonClick();\n\t\tthis._enableInsertingParagraphsOnEnterKeypress();\n\t\tthis._enableInsertingParagraphsOnTypingKeystroke();\n\t\tthis._enableTypeAroundFakeCaretActivationUsingKeyboardArrows();\n\t\tthis._enableDeleteIntegration();\n\t\tthis._enableInsertContentIntegration();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._currentFakeCaretModelElement = null;\n\t}\n\n\t/**\n\t * Inserts a new paragraph next to a widget element with the selection anchored in it.\n\t *\n\t * **Note**: This method is heavily user-oriented and will both focus the editing view and scroll\n\t * the viewport to the selection in the inserted paragraph.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} widgetModelElement The model widget element next to which a paragraph is inserted.\n\t * @param {'before'|'after'} position The position where the paragraph is inserted. Either `'before'` or `'after'` the widget.\n\t */\n\t_insertParagraph( widgetModelElement, position ) {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\teditor.execute( 'insertParagraph', {\n\t\t\tposition: editor.model.createPositionAt( widgetModelElement, position )\n\t\t} );\n\n\t\teditingView.focus();\n\t\teditingView.scrollToTheSelection();\n\t}\n\n\t/**\n\t * A wrapper for the {@link module:utils/emittermixin~EmitterMixin#listenTo} method that executes the callbacks only\n\t * when the plugin {@link #isEnabled is enabled}.\n\t *\n\t * @private\n\t * @param {module:utils/emittermixin~Emitter} emitter The object that fires the event.\n\t * @param {String} event The name of the event.\n\t * @param {Function} callback The function to be called on event.\n\t * @param {Object} [options={}] Additional options.\n\t * @param {module:utils/priorities~PriorityString|Number} [options.priority='normal'] The priority of this event callback. The higher\n\t * the priority value the sooner the callback will be fired. Events having the same priority are called in the\n\t * order they were added.\n\t */\n\t_listenToIfEnabled( emitter, event, callback, options ) {\n\t\tthis.listenTo( emitter, event, ( ...args ) => {\n\t\t\t// Do not respond if the plugin is disabled.\n\t\t\tif ( this.isEnabled ) {\n\t\t\t\tcallback( ...args );\n\t\t\t}\n\t\t}, options );\n\t}\n\n\t/**\n\t * Similar to {@link #_insertParagraph}, this method inserts a paragraph except that it\n\t * does not expect a position. Instead, it performs the insertion next to a selected widget\n\t * according to the `widget-type-around` model selection attribute value (fake caret position).\n\t *\n\t * Because this method requires the `widget-type-around` attribute to be set,\n\t * the insertion can only happen when the widget's fake caret is active (e.g. activated\n\t * using the keyboard).\n\t *\n\t * @private\n\t * @returns {Boolean} Returns `true` when the paragraph was inserted (the attribute was present) and `false` otherwise.\n\t */\n\t_insertParagraphAccordingToFakeCaretPosition() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( modelSelection );\n\n\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst selectedModelElement = modelSelection.getSelectedElement();\n\n\t\tthis._insertParagraph( selectedModelElement, typeAroundFakeCaretPosition );\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Creates a listener in the editing conversion pipeline that injects the widget type around\n\t * UI into every single widget instance created in the editor.\n\t *\n\t * The UI is delivered as a {@link module:engine/view/uielement~UIElement}\n\t * wrapper which renders DOM buttons that users can use to insert paragraphs.\n\t *\n\t * @private\n\t */\n\t_enableTypeAroundUIInjection() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.locale.t;\n\t\tconst buttonTitles = {\n\t\t\tbefore: t( 'Insert paragraph before block' ),\n\t\t\tafter: t( 'Insert paragraph after block' )\n\t\t};\n\n\t\teditor.editing.downcastDispatcher.on( 'insert', ( evt, data, conversionApi ) => {\n\t\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\n\t\t\t// Filter out non-widgets and inline widgets.\n\t\t\tif ( isTypeAroundWidget( viewElement, data.item, schema ) ) {\n\t\t\t\tinjectUIIntoWidget( conversionApi.writer, buttonTitles, viewElement );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Brings support for the fake caret that appears when either:\n\t *\n\t * * the selection moves to a widget from a position next to it using arrow keys,\n\t * * the arrow key is pressed when the widget is already selected.\n\t *\n\t * The fake caret lets the user know that they can start typing or just press\n\t * <kbd>Enter</kbd> to insert a paragraph at the position next to a widget as suggested by the fake caret.\n\t *\n\t * The fake caret disappears when the user changes the selection or the editor\n\t * gets blurred.\n\t *\n\t * The whole idea is as follows:\n\t *\n\t * 1. A user does one of the 2 scenarios described at the beginning.\n\t * 2. The \"keydown\" listener is executed and the decision is made whether to show or hide the fake caret.\n\t * 3. If it should show up, the `widget-type-around` model selection attribute is set indicating\n\t * on which side of the widget it should appear.\n\t * 4. The selection dispatcher reacts to the selection attribute and sets CSS classes responsible for the\n\t * fake caret on the view widget.\n\t * 5. If the fake caret should disappear, the selection attribute is removed and the dispatcher\n\t * does the CSS class clean-up in the view.\n\t * 6. Additionally, `change:range` and `FocusTracker#isFocused` listeners also remove the selection\n\t * attribute (the former also removes widget CSS classes).\n\t *\n\t * @private\n\t */\n\t_enableTypeAroundFakeCaretActivationUsingKeyboardArrows() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst editingView = editor.editing.view;\n\n\t\t// This is the main listener responsible for the fake caret.\n\t\t// Note: The priority must precede the default Widget class keydown handler (\"high\").\n\t\tthis._listenToIfEnabled( editingView.document, 'arrowKey', ( evt, domEventData ) => {\n\t\t\tthis._handleArrowKeyPress( evt, domEventData );\n\t\t}, { context: [ isWidget, '$text' ], priority: 'high' } );\n\n\t\t// This listener makes sure the widget type around selection attribute will be gone from the model\n\t\t// selection as soon as the model range changes. This attribute only makes sense when a widget is selected\n\t\t// (and the \"fake horizontal caret\" is visible) so whenever the range changes (e.g. selection moved somewhere else),\n\t\t// let's get rid of the attribute so that the selection downcast dispatcher isn't even bothered.\n\t\tthis._listenToIfEnabled( modelSelection, 'change:range', ( evt, data ) => {\n\t\t\t// Do not reset the selection attribute when the change was indirect.\n\t\t\tif ( !data.directChange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Get rid of the widget type around attribute of the selection on every change:range.\n\t\t\t// If the range changes, it means for sure, the user is no longer in the active (\"fake horizontal caret\") mode.\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t} );\n\t\t} );\n\n\t\t// Get rid of the widget type around attribute of the selection on every document change\n\t\t// that makes widget not selected any more (i.e. widget was removed).\n\t\tthis._listenToIfEnabled( model.document, 'change:data', () => {\n\t\t\tconst selectedModelElement = modelSelection.getSelectedElement();\n\n\t\t\tif ( selectedModelElement ) {\n\t\t\t\tconst selectedViewElement = editor.editing.mapper.toViewElement( selectedModelElement );\n\n\t\t\t\tif ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t} );\n\t\t} );\n\n\t\t// React to changes of the model selection attribute made by the arrow keys listener.\n\t\t// If the block widget is selected and the attribute changes, downcast the attribute to special\n\t\t// CSS classes associated with the active (\"fake horizontal caret\") mode of the widget.\n\t\tthis._listenToIfEnabled( editor.editing.downcastDispatcher, 'selection', ( evt, data, conversionApi ) => {\n\t\t\tconst writer = conversionApi.writer;\n\n\t\t\tif ( this._currentFakeCaretModelElement ) {\n\t\t\t\tconst selectedViewElement = conversionApi.mapper.toViewElement( this._currentFakeCaretModelElement );\n\n\t\t\t\tif ( selectedViewElement ) {\n\t\t\t\t\t// Get rid of CSS classes associated with the active (\"fake horizontal caret\") mode from the view widget.\n\t\t\t\t\twriter.removeClass( POSSIBLE_INSERTION_POSITIONS.map( positionToWidgetCssClass ), selectedViewElement );\n\n\t\t\t\t\tthis._currentFakeCaretModelElement = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst selectedModelElement = data.selection.getSelectedElement();\n\n\t\t\tif ( !selectedModelElement ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectedViewElement = conversionApi.mapper.toViewElement( selectedModelElement );\n\n\t\t\tif ( !isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( data.selection );\n\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twriter.addClass( positionToWidgetCssClass( typeAroundFakeCaretPosition ), selectedViewElement );\n\n\t\t\t// Remember the view widget that got the \"fake-caret\" CSS class. This class should be removed ASAP when the\n\t\t\t// selection changes\n\t\t\tthis._currentFakeCaretModelElement = selectedModelElement;\n\t\t} );\n\n\t\tthis._listenToIfEnabled( editor.ui.focusTracker, 'change:isFocused', ( evt, name, isFocused ) => {\n\t\t\tif ( !isFocused ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tfunction positionToWidgetCssClass( position ) {\n\t\t\treturn `ck-widget_type-around_show-fake-caret_${ position }`;\n\t\t}\n\t}\n\n\t/**\n\t * A listener executed on each \"keydown\" in the view document, a part of\n\t * {@link #_enableTypeAroundFakeCaretActivationUsingKeyboardArrows}.\n\t *\n\t * It decides whether the arrow keypress should activate the fake caret or not (also whether it should\n\t * be deactivated).\n\t *\n\t * The fake caret activation is done by setting the `widget-type-around` model selection attribute\n\t * in this listener, and stopping and preventing the event that would normally be handled by the widget\n\t * plugin that is responsible for the regular keyboard navigation near/across all widgets (that\n\t * includes inline widgets, which are ignored by the widget type around plugin).\n\t *\n\t * @private\n\t */\n\t_handleArrowKeyPress( evt, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst schema = model.schema;\n\t\tconst editingView = editor.editing.view;\n\n\t\tconst keyCode = domEventData.keyCode;\n\t\tconst isForward = isForwardArrowKeyCode( keyCode, editor.locale.contentLanguageDirection );\n\t\tconst selectedViewElement = editingView.document.selection.getSelectedElement();\n\t\tconst selectedModelElement = editor.editing.mapper.toModelElement( selectedViewElement );\n\t\tlet shouldStopAndPreventDefault;\n\n\t\t// Handle keyboard navigation when a type-around-compatible widget is currently selected.\n\t\tif ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\tshouldStopAndPreventDefault = this._handleArrowKeyPressOnSelectedWidget( isForward );\n\t\t}\n\t\t// Handle keyboard arrow navigation when the selection is next to a type-around-compatible widget\n\t\t// and the widget is about to be selected.\n\t\telse if ( modelSelection.isCollapsed ) {\n\t\t\tshouldStopAndPreventDefault = this._handleArrowKeyPressWhenSelectionNextToAWidget( isForward );\n\t\t}\n\n\t\tif ( shouldStopAndPreventDefault ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles the keyboard navigation on \"keydown\" when a widget is currently selected and activates or deactivates\n\t * the fake caret for that widget, depending on the current value of the `widget-type-around` model\n\t * selection attribute and the direction of the pressed arrow key.\n\t *\n\t * @private\n\t * @param {Boolean} isForward `true` when the pressed arrow key was responsible for the forward model selection movement\n\t * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.\n\t * @returns {Boolean} Returns `true` when the keypress was handled and no other keydown listener of the editor should\n\t * process the event any further. Returns `false` otherwise.\n\t */\n\t_handleArrowKeyPressOnSelectedWidget( isForward ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( modelSelection );\n\n\t\treturn model.change( writer => {\n\t\t\t// If the fake caret is displayed...\n\t\t\tif ( typeAroundFakeCaretPosition ) {\n\t\t\t\tconst isLeavingWidget = typeAroundFakeCaretPosition === ( isForward ? 'after' : 'before' );\n\n\t\t\t\t// If the keyboard arrow works against the value of the selection attribute...\n\t\t\t\t// then remove the selection attribute but prevent default DOM actions\n\t\t\t\t// and do not let the Widget plugin listener move the selection. This brings\n\t\t\t\t// the widget back to the state, for instance, like if was selected using the mouse.\n\t\t\t\t//\n\t\t\t\t// **Note**: If leaving the widget when the fake caret is active, then the default\n\t\t\t\t// Widget handler will change the selection and, in turn, this will automatically discard\n\t\t\t\t// the selection attribute.\n\t\t\t\tif ( !isLeavingWidget ) {\n\t\t\t\t\twriter.removeSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If the fake caret wasn't displayed, let's set it now according to the direction of the arrow\n\t\t\t// key press. This also means we cannot let the Widget plugin listener move the selection.\n\t\t\telse {\n\t\t\t\twriter.setSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE, isForward ? 'after' : 'before' );\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t} );\n\t}\n\n\t/**\n\t * Handles the keyboard navigation on \"keydown\" when **no** widget is selected but the selection is **directly** next\n\t * to one and upon the fake caret should become active for this widget upon arrow keypress\n\t * (AKA entering/selecting the widget).\n\t *\n\t * **Note**: This code mirrors the implementation from the widget plugin but also adds the selection attribute.\n\t * Unfortunately, there is no safe way to let the widget plugin do the selection part first and then just set the\n\t * selection attribute here in the widget type around plugin. This is why this code must duplicate some from the widget plugin.\n\t *\n\t * @private\n\t * @param {Boolean} isForward `true` when the pressed arrow key was responsible for the forward model selection movement\n\t * as in {@link module:utils/keyboard~isForwardArrowKeyCode}.\n\t * @returns {Boolean} Returns `true` when the keypress was handled and no other keydown listener of the editor should\n\t * process the event any further. Returns `false` otherwise.\n\t */\n\t_handleArrowKeyPressWhenSelectionNextToAWidget( isForward ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\t\tconst widgetPlugin = editor.plugins.get( 'Widget' );\n\n\t\t// This is the widget the selection is about to be set on.\n\t\tconst modelElementNextToSelection = widgetPlugin._getObjectElementNextToSelection( isForward );\n\t\tconst viewElementNextToSelection = editor.editing.mapper.toViewElement( modelElementNextToSelection );\n\n\t\tif ( isTypeAroundWidget( viewElementNextToSelection, modelElementNextToSelection, schema ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twidgetPlugin._setSelectionOverElement( modelElementNextToSelection );\n\t\t\t\twriter.setSelectionAttribute( TYPE_AROUND_SELECTION_ATTRIBUTE, isForward ? 'before' : 'after' );\n\t\t\t} );\n\n\t\t\t// The change() block above does the same job as the Widget plugin. The event can\n\t\t\t// be safely canceled.\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Registers a `mousedown` listener for the view document which intercepts events\n\t * coming from the widget type around UI, which happens when a user clicks one of the buttons\n\t * that insert a paragraph next to a widget.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnButtonClick() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tconst button = getClosestTypeAroundDomButton( domEventData.domTarget );\n\n\t\t\tif ( !button ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst buttonPosition = getTypeAroundButtonPosition( button );\n\t\t\tconst widgetViewElement = getClosestWidgetViewElement( button, editingView.domConverter );\n\t\t\tconst widgetModelElement = editor.editing.mapper.toModelElement( widgetViewElement );\n\n\t\t\tthis._insertParagraph( widgetModelElement, buttonPosition );\n\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t} );\n\t}\n\n\t/**\n\t * Creates the <kbd>Enter</kbd> key listener on the view document that allows the user to insert a paragraph\n\t * near the widget when either:\n\t *\n\t * * The fake caret was first activated using the arrow keys,\n\t * * The entire widget is selected in the model.\n\t *\n\t * In the first case, the new paragraph is inserted according to the `widget-type-around` selection\n\t * attribute (see {@link #_handleArrowKeyPress}).\n\t *\n\t * In the second case, the new paragraph is inserted based on whether a soft (<kbd>Shift</kbd>+<kbd>Enter</kbd>) keystroke\n\t * was pressed or not.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnEnterKeypress() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst editingView = editor.editing.view;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'enter', ( evt, domEventData ) => {\n\t\t\t// This event could be triggered from inside the widget but we are interested\n\t\t\t// only when the widget is selected itself.\n\t\t\tif ( evt.eventPhase != 'atTarget' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selectedModelElement = selection.getSelectedElement();\n\t\t\tconst selectedViewElement = editor.editing.mapper.toViewElement( selectedModelElement );\n\n\t\t\tconst schema = editor.model.schema;\n\t\t\tlet wasHandled;\n\n\t\t\t// First check if the widget is selected and there's a type around selection attribute associated\n\t\t\t// with the fake caret that would tell where to insert a new paragraph.\n\t\t\tif ( this._insertParagraphAccordingToFakeCaretPosition() ) {\n\t\t\t\twasHandled = true;\n\t\t\t}\n\t\t\t// Then, if there is no selection attribute associated with the fake caret, check if the widget\n\t\t\t// simply is selected and create a new paragraph according to the keystroke (Shift+)Enter.\n\t\t\telse if ( isTypeAroundWidget( selectedViewElement, selectedModelElement, schema ) ) {\n\t\t\t\tthis._insertParagraph( selectedModelElement, domEventData.isSoft ? 'before' : 'after' );\n\n\t\t\t\twasHandled = true;\n\t\t\t}\n\n\t\t\tif ( wasHandled ) {\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { context: isWidget } );\n\t}\n\n\t/**\n\t * Similar to the {@link #_enableInsertingParagraphsOnEnterKeypress}, it allows the user\n\t * to insert a paragraph next to a widget when the fake caret was activated using arrow\n\t * keys but it responds to typing keystrokes instead of <kbd>Enter</kbd>.\n\t *\n\t * \"Typing keystrokes\" are keystrokes that insert new content into the document,\n\t * for instance, letters (\"a\") or numbers (\"4\"). The \"keydown\" listener enabled by this method\n\t * will insert a new paragraph according to the `widget-type-around` model selection attribute\n\t * as the user simply starts typing, which creates the impression that the fake caret\n\t * behaves like a real one rendered by the browser (AKA your text appears where the caret was).\n\t *\n\t * **Note**: At the moment this listener creates 2 undo steps: one for the `insertParagraph` command\n\t * and another one for actual typing. It is not a disaster but this may need to be fixed\n\t * sooner or later.\n\t *\n\t * Learn more in {@link module:typing/utils/injectunsafekeystrokeshandling}.\n\t *\n\t * @private\n\t */\n\t_enableInsertingParagraphsOnTypingKeystroke() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst keyCodesHandledSomewhereElse = [\n\t\t\tkeyCodes.enter,\n\t\t\tkeyCodes.delete,\n\t\t\tkeyCodes.backspace\n\t\t];\n\n\t\t// Note: The priority must precede the default observers.\n\t\tthis._listenToIfEnabled( editingView.document, 'keydown', ( evt, domEventData ) => {\n\t\t\t// Don't handle enter/backspace/delete here. They are handled in dedicated listeners.\n\t\t\tif ( !keyCodesHandledSomewhereElse.includes( domEventData.keyCode ) && !isNonTypingKeystroke( domEventData ) ) {\n\t\t\t\tthis._insertParagraphAccordingToFakeCaretPosition();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * It creates a \"delete\" event listener on the view document to handle cases when the <kbd>Delete</kbd> or <kbd>Backspace</kbd>\n\t * is pressed and the fake caret is currently active.\n\t *\n\t * The fake caret should create an illusion of a real browser caret so that when it appears before or after\n\t * a widget, pressing <kbd>Delete</kbd> or <kbd>Backspace</kbd> should remove a widget or delete the content\n\t * before or after a widget (depending on the content surrounding the widget).\n\t *\n\t * @private\n\t */\n\t_enableDeleteIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\n\t\tthis._listenToIfEnabled( editingView.document, 'delete', ( evt, domEventData ) => {\n\t\t\t// This event could be triggered from inside the widget but we are interested\n\t\t\t// only when the widget is selected itself.\n\t\t\tif ( evt.eventPhase != 'atTarget' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( model.document.selection );\n\n\t\t\t// This listener handles only these cases when the fake caret is active.\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst direction = domEventData.direction;\n\t\t\tconst selectedModelWidget = model.document.selection.getSelectedElement();\n\n\t\t\tconst isFakeCaretBefore = typeAroundFakeCaretPosition === 'before';\n\t\t\tconst isDeleteForward = direction == 'forward';\n\t\t\tconst shouldDeleteEntireWidget = isFakeCaretBefore === isDeleteForward;\n\n\t\t\tif ( shouldDeleteEntireWidget ) {\n\t\t\t\teditor.execute( 'delete', {\n\t\t\t\t\tselection: model.createSelection( selectedModelWidget, 'on' )\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\tconst range = schema.getNearestSelectionRange(\n\t\t\t\t\tmodel.createPositionAt( selectedModelWidget, typeAroundFakeCaretPosition ),\n\t\t\t\t\tdirection\n\t\t\t\t);\n\n\t\t\t\t// If there is somewhere to move selection to, then there will be something to delete.\n\t\t\t\tif ( range ) {\n\t\t\t\t\t// If the range is NOT collapsed, then we know that the range contains an object (see getNearestSelectionRange() docs).\n\t\t\t\t\tif ( !range.isCollapsed ) {\n\t\t\t\t\t\tmodel.change( writer => {\n\t\t\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t\t\t\teditor.execute( isDeleteForward ? 'deleteForward' : 'delete' );\n\t\t\t\t\t\t} );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst probe = model.createSelection( range.start );\n\t\t\t\t\t\tmodel.modifySelection( probe, { direction } );\n\n\t\t\t\t\t\t// If the range is collapsed, let's see if a non-collapsed range exists that can could be deleted.\n\t\t\t\t\t\t// If such range exists, use the editor command because it it safe for collaboration (it merges where it can).\n\t\t\t\t\t\tif ( !probe.focus.isEqual( range.start ) ) {\n\t\t\t\t\t\t\tmodel.change( writer => {\n\t\t\t\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t\t\t\t\teditor.execute( isDeleteForward ? 'deleteForward' : 'delete' );\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// If there is no non-collapsed range to be deleted then we are sure that there is an empty element\n\t\t\t\t\t\t// next to a widget that should be removed. \"delete\" and \"deleteForward\" commands cannot get rid of it\n\t\t\t\t\t\t// so calling Model#deleteContent here manually.\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tconst deepestEmptyRangeAncestor = getDeepestEmptyElementAncestor( schema, range.start.parent );\n\n\t\t\t\t\t\t\tmodel.deleteContent( model.createSelection( deepestEmptyRangeAncestor, 'on' ), {\n\t\t\t\t\t\t\t\tdoNotAutoparagraph: true\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If some content was deleted, don't let the handler from the Widget plugin kick in.\n\t\t\t// If nothing was deleted, then the default handler will have nothing to do anyway.\n\t\t\tdomEventData.preventDefault();\n\t\t\tevt.stop();\n\t\t}, { context: isWidget } );\n\t}\n\n\t/**\n\t * Attaches the {@link module:engine/model/model~Model#event:insertContent} event listener that, for instance, allows the user to paste\n\t * content near a widget when the fake caret is first activated using the arrow keys.\n\t *\n\t * The content is inserted according to the `widget-type-around` selection attribute (see {@link #_handleArrowKeyPress}).\n\t *\n\t * @private\n\t */\n\t_enableInsertContentIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst model = this.editor.model;\n\t\tconst documentSelection = model.document.selection;\n\n\t\tthis._listenToIfEnabled( editor.model, 'insertContent', ( evt, [ content, selectable ] ) => {\n\t\t\tif ( selectable && !selectable.is( 'documentSelection' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeAroundFakeCaretPosition = getTypeAroundFakeCaretPosition( documentSelection );\n\n\t\t\tif ( !typeAroundFakeCaretPosition ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevt.stop();\n\n\t\t\treturn model.change( writer => {\n\t\t\t\tconst selectedElement = documentSelection.getSelectedElement();\n\t\t\t\tconst position = model.createPositionAt( selectedElement, typeAroundFakeCaretPosition );\n\t\t\t\tconst selection = writer.createSelection( position );\n\n\t\t\t\tconst result = model.insertContent( content, selection );\n\n\t\t\t\twriter.setSelection( selection );\n\n\t\t\t\treturn result;\n\t\t\t} );\n\t\t}, { priority: 'high' } );\n\t}\n}\n\n// Injects the type around UI into a view widget instance.\n//\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {Object.<String,String>} buttonTitles\n// @param {module:engine/view/element~Element} widgetViewElement\nfunction injectUIIntoWidget( viewWriter, buttonTitles, widgetViewElement ) {\n\tconst typeAroundWrapper = viewWriter.createUIElement( 'div', {\n\t\tclass: 'ck ck-reset_all ck-widget__type-around'\n\t}, function( domDocument ) {\n\t\tconst wrapperDomElement = this.toDomElement( domDocument );\n\n\t\tinjectButtons( wrapperDomElement, buttonTitles );\n\t\tinjectFakeCaret( wrapperDomElement );\n\n\t\treturn wrapperDomElement;\n\t} );\n\n\t// Inject the type around wrapper into the widget's wrapper.\n\tviewWriter.insert( viewWriter.createPositionAt( widgetViewElement, 'end' ), typeAroundWrapper );\n}\n\n// FYI: Not using the IconView class because each instance would need to be destroyed to avoid memory leaks\n// and it's pretty hard to figure out when a view (widget) is gone for good so it's cheaper to use raw\n// <svg> here.\n//\n// @param {HTMLElement} wrapperDomElement\n// @param {Object.<String,String>} buttonTitles\nfunction injectButtons( wrapperDomElement, buttonTitles ) {\n\tfor ( const position of POSSIBLE_INSERTION_POSITIONS ) {\n\t\tconst buttonTemplate = new Template( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-widget__type-around__button',\n\t\t\t\t\t`ck-widget__type-around__button_${ position }`\n\t\t\t\t],\n\t\t\t\ttitle: buttonTitles[ position ]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\twrapperDomElement.ownerDocument.importNode( RETURN_ARROW_ICON_ELEMENT, true )\n\t\t\t]\n\t\t} );\n\n\t\twrapperDomElement.appendChild( buttonTemplate.render() );\n\t}\n}\n\n// @param {HTMLElement} wrapperDomElement\nfunction injectFakeCaret( wrapperDomElement ) {\n\tconst caretTemplate = new Template( {\n\t\ttag: 'div',\n\t\tattributes: {\n\t\t\tclass: [\n\t\t\t\t'ck',\n\t\t\t\t'ck-widget__type-around__fake-caret'\n\t\t\t]\n\t\t}\n\t} );\n\n\twrapperDomElement.appendChild( caretTemplate.render() );\n}\n\n// Returns the ancestor of an element closest to the root which is empty. For instance,\n// for `<baz>`:\n//\n//\t\t<foo>abc<bar><baz></baz></bar></foo>\n//\n// it returns `<bar>`.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/element~Element} element\n// @returns {module:engine/model/element~Element|null}\nfunction getDeepestEmptyElementAncestor( schema, element ) {\n\tlet deepestEmptyAncestor = element;\n\n\tfor ( const ancestor of element.getAncestors( { parentFirst: true } ) ) {\n\t\tif ( ancestor.childCount > 1 || schema.isLimit( ancestor ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tdeepestEmptyAncestor = ancestor;\n\t}\n\n\treturn deepestEmptyAncestor;\n}\n","export default \"<svg viewBox=\\\"0 0 10 8\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M9.055.263v3.972h-6.77M1 4.216l2-2.038m-2 2 2 2.038\\\"/></svg>\";","/**\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\nimport { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\n/**\n * @module widget/verticalnavigationhandler\n */\n\n/**\n * Returns 'keydown' handler for up/down arrow keys that modifies the caret movement if it's in a text line next to an object.\n *\n * @param {module:engine/controller/editingcontroller~EditingController} editing The editing controller.\n * @returns {Function}\n */\nexport default function verticalNavigationHandler( editing ) {\n\tconst model = editing.model;\n\n\treturn ( evt, data ) => {\n\t\tconst arrowUpPressed = data.keyCode == keyCodes.arrowup;\n\t\tconst arrowDownPressed = data.keyCode == keyCodes.arrowdown;\n\t\tconst expandSelection = data.shiftKey;\n\t\tconst selection = model.document.selection;\n\n\t\tif ( !arrowUpPressed && !arrowDownPressed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isForward = arrowDownPressed;\n\n\t\t// Navigation is in the opposite direction than the selection direction so this is shrinking of the selection.\n\t\t// Selection for sure will not approach any object.\n\t\tif ( expandSelection && selectionWillShrink( selection, isForward ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Find a range between selection and closest limit element.\n\t\tconst range = findTextRangeFromSelection( editing, selection, isForward );\n\n\t\tif ( !range || range.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the range is a single line (there is no word wrapping) then move the selection to the position closest to the limit element.\n\t\t//\n\t\t// We can't move the selection directly to the isObject element (eg. table cell) because of dual position at the end/beginning\n\t\t// of wrapped line (it's at the same time at the end of one line and at the start of the next line).\n\t\tif ( isSingleLineRange( editing, range, isForward ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\tconst newPosition = isForward ? range.end : range.start;\n\n\t\t\t\tif ( expandSelection ) {\n\t\t\t\t\tconst newSelection = model.createSelection( selection.anchor );\n\t\t\t\t\tnewSelection.setFocus( newPosition );\n\n\t\t\t\t\twriter.setSelection( newSelection );\n\t\t\t\t} else {\n\t\t\t\t\twriter.setSelection( newPosition );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tevt.stop();\n\t\t\tdata.preventDefault();\n\t\t\tdata.stopPropagation();\n\t\t}\n\t};\n}\n\n// Finds the range between selection and closest limit element (in the direction of navigation).\n// The position next to limit element is adjusted to the closest allowed `$text` position.\n//\n// Returns `null` if, according to the schema, the resulting range cannot contain a `$text` element.\n//\n// @param {module:engine/controller/editingcontroller~EditingController} editing The editing controller.\n// @param {module:engine/model/selection~Selection} selection The current selection.\n// @param {Boolean} isForward The expected navigation direction.\n// @returns {module:engine/model/range~Range|null}\n//\nfunction findTextRangeFromSelection( editing, selection, isForward ) {\n\tconst model = editing.model;\n\n\tif ( isForward ) {\n\t\tconst startPosition = selection.isCollapsed ? selection.focus : selection.getLastPosition();\n\t\tconst endPosition = getNearestNonInlineLimit( model, startPosition, 'forward' );\n\n\t\t// There is no limit element, browser should handle this.\n\t\tif ( !endPosition ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst range = model.createRange( startPosition, endPosition );\n\t\tconst lastRangePosition = getNearestTextPosition( model.schema, range, 'backward' );\n\n\t\tif ( lastRangePosition && startPosition.isBefore( lastRangePosition ) ) {\n\t\t\treturn model.createRange( startPosition, lastRangePosition );\n\t\t}\n\n\t\treturn null;\n\t} else {\n\t\tconst endPosition = selection.isCollapsed ? selection.focus : selection.getFirstPosition();\n\t\tconst startPosition = getNearestNonInlineLimit( model, endPosition, 'backward' );\n\n\t\t// There is no limit element, browser should handle this.\n\t\tif ( !startPosition ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst range = model.createRange( startPosition, endPosition );\n\t\tconst firstRangePosition = getNearestTextPosition( model.schema, range, 'forward' );\n\n\t\tif ( firstRangePosition && endPosition.isAfter( firstRangePosition ) ) {\n\t\t\treturn model.createRange( firstRangePosition, endPosition );\n\t\t}\n\n\t\treturn null;\n\t}\n}\n\n// Finds the limit element position that is closest to startPosition.\n//\n// @param {module:engine/model/model~Model} model\n// @param {<module:engine/model/position~Position>} startPosition\n// @param {'forward'|'backward'} direction Search direction.\n// @returns {<module:engine/model/position~Position>|null}\n//\nfunction getNearestNonInlineLimit( model, startPosition, direction ) {\n\tconst schema = model.schema;\n\tconst range = model.createRangeIn( startPosition.root );\n\n\tconst walkerValueType = direction == 'forward' ? 'elementStart' : 'elementEnd';\n\n\tfor ( const { previousPosition, item, type } of range.getWalker( { startPosition, direction } ) ) {\n\t\tif ( schema.isLimit( item ) && !schema.isInline( item ) ) {\n\t\t\treturn previousPosition;\n\t\t}\n\n\t\t// Stop looking for isLimit element if the next element is a block element (it is for sure not single line).\n\t\tif ( type == walkerValueType && schema.isBlock( item ) ) {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Basing on the provided range, finds the first or last (depending on `direction`) position inside the range\n// that can contain `$text` (according to schema).\n//\n// @param {module:engine/model/schema~Schema} schema The schema.\n// @param {module:engine/model/range~Range} range The range to find the position in.\n// @param {'forward'|'backward'} direction Search direction.\n// @returns {module:engine/model/position~Position} The nearest selection range.\n//\nfunction getNearestTextPosition( schema, range, direction ) {\n\tconst position = direction == 'backward' ? range.end : range.start;\n\n\tif ( schema.checkChild( position, '$text' ) ) {\n\t\treturn position;\n\t}\n\n\tfor ( const { nextPosition } of range.getWalker( { direction } ) ) {\n\t\tif ( schema.checkChild( nextPosition, '$text' ) ) {\n\t\t\treturn nextPosition;\n\t\t}\n\t}\n}\n\n// Checks if the DOM range corresponding to the provided model range renders as a single line by analyzing DOMRects\n// (verifying if they visually wrap content to the next line).\n//\n// @param {module:engine/controller/editingcontroller~EditingController} editing The editing controller.\n// @param {module:engine/model/range~Range} modelRange The current table cell content range.\n// @param {Boolean} isForward The expected navigation direction.\n// @returns {Boolean}\n//\nfunction isSingleLineRange( editing, modelRange, isForward ) {\n\tconst model = editing.model;\n\tconst domConverter = editing.view.domConverter;\n\n\t// Wrapped lines contain exactly the same position at the end of current line\n\t// and at the beginning of next line. That position's client rect is at the end\n\t// of current line. In case of caret at first position of the last line that 'dual'\n\t// position would be detected as it's not the last line.\n\tif ( isForward ) {\n\t\tconst probe = model.createSelection( modelRange.start );\n\n\t\tmodel.modifySelection( probe );\n\n\t\t// If the new position is at the end of the container then we can't use this position\n\t\t// because it would provide incorrect result for eg caption of image and selection\n\t\t// just before end of it. Also in this case there is no \"dual\" position.\n\t\tif ( !probe.focus.isAtEnd && !modelRange.start.isEqual( probe.focus ) ) {\n\t\t\tmodelRange = model.createRange( probe.focus, modelRange.end );\n\t\t}\n\t}\n\n\tconst viewRange = editing.mapper.toViewRange( modelRange );\n\tconst domRange = domConverter.viewRangeToDom( viewRange );\n\tconst rects = Rect.getDomRangeRects( domRange );\n\n\tlet boundaryVerticalPosition;\n\n\tfor ( const rect of rects ) {\n\t\tif ( boundaryVerticalPosition === undefined ) {\n\t\t\tboundaryVerticalPosition = Math.round( rect.bottom );\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Let's check if this rect is in new line.\n\t\tif ( Math.round( rect.top ) >= boundaryVerticalPosition ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tboundaryVerticalPosition = Math.max( boundaryVerticalPosition, Math.round( rect.bottom ) );\n\t}\n\n\treturn true;\n}\n\nfunction selectionWillShrink( selection, isForward ) {\n\treturn !selection.isCollapsed && selection.isBackward == isForward;\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 widget/widget\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';\nimport WidgetTypeAround from './widgettypearound/widgettypearound';\nimport Delete from '@ckeditor/ckeditor5-typing/src/delete';\nimport { getLabel, isWidget, WIDGET_SELECTED_CLASS_NAME } from './utils';\nimport { isForwardArrowKeyCode } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\n\nimport '../theme/widget.css';\nimport verticalNavigationHandler from './verticalnavigation';\n\n/**\n * The widget plugin. It enables base support for widgets.\n *\n * See {@glink api/widget package page} for more details and documentation.\n *\n * This plugin enables multiple behaviors required by widgets:\n *\n * * The model to view selection converter for the editing pipeline (it handles widget custom selection rendering).\n * If a converted selection wraps around a widget element, that selection is marked as\n * {@link module:engine/view/selection~Selection#isFake fake}. Additionally, the `ck-widget_selected` CSS class\n * is added to indicate that widget has been selected.\n * * The mouse and keyboard events handling on and around widget elements.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Widget extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Widget';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetTypeAround, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t/**\n\t\t * Holds previously selected widgets.\n\t\t *\n\t\t * @private\n\t\t * @type {Set.<module:engine/view/element~Element>}\n\t\t */\n\t\tthis._previouslySelected = new Set();\n\n\t\t// Model to view selection converter.\n\t\t// Converts selection placed over widget element to fake selection\n\t\tthis.editor.editing.downcastDispatcher.on( 'selection', ( evt, data, conversionApi ) => {\n\t\t\t// Remove selected class from previously selected widgets.\n\t\t\tthis._clearPreviouslySelectedWidgets( conversionApi.writer );\n\n\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\tconst viewSelection = viewWriter.document.selection;\n\t\t\tconst selectedElement = viewSelection.getSelectedElement();\n\t\t\tlet lastMarked = null;\n\n\t\t\tfor ( const range of viewSelection.getRanges() ) {\n\t\t\t\tfor ( const value of range ) {\n\t\t\t\t\tconst node = value.item;\n\n\t\t\t\t\t// Do not mark nested widgets in selected one. See: #57.\n\t\t\t\t\tif ( isWidget( node ) && !isChild( node, lastMarked ) ) {\n\t\t\t\t\t\tviewWriter.addClass( WIDGET_SELECTED_CLASS_NAME, node );\n\n\t\t\t\t\t\tthis._previouslySelected.add( node );\n\t\t\t\t\t\tlastMarked = node;\n\n\t\t\t\t\t\t// Check if widget is a single element selected.\n\t\t\t\t\t\tif ( node == selectedElement ) {\n\t\t\t\t\t\t\tviewWriter.setSelection( viewSelection.getRanges(), { fake: true, label: getLabel( selectedElement ) } );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// If mouse down is pressed on widget - create selection over whole widget.\n\t\tview.addObserver( MouseObserver );\n\t\tthis.listenTo( viewDocument, 'mousedown', ( ...args ) => this._onMousedown( ...args ) );\n\n\t\t// There are two keydown listeners working on different priorities. This allows other\n\t\t// features such as WidgetTypeAround or TableKeyboard to attach their listeners in between\n\t\t// and customize the behavior even further in different content/selection scenarios.\n\t\t//\n\t\t// * The first listener handles changing the selection on arrow key press\n\t\t// if the widget is selected or if the selection is next to a widget and the widget\n\t\t// should become selected upon the arrow key press.\n\t\t//\n\t\t// * The second (late) listener makes sure the default browser action on arrow key press is\n\t\t// prevented when a widget is selected. This prevents the selection from being moved\n\t\t// from a fake selection container.\n\t\tthis.listenTo( viewDocument, 'arrowKey', ( ...args ) => {\n\t\t\tthis._handleSelectionChangeOnArrowKeyPress( ...args );\n\t\t}, { context: [ isWidget, '$text' ] } );\n\n\t\tthis.listenTo( viewDocument, 'arrowKey', ( ...args ) => {\n\t\t\tthis._preventDefaultOnArrowKeyPress( ...args );\n\t\t}, { context: '$root' } );\n\n\t\tthis.listenTo( viewDocument, 'arrowKey', verticalNavigationHandler( this.editor.editing ), { context: '$text' } );\n\n\t\t// Handle custom delete behaviour.\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\tif ( this._handleDelete( data.direction == 'forward' ) ) {\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { context: '$root' } );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:mousedown mousedown} events on widget elements.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_onMousedown( eventInfo, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\t\tlet element = domEventData.target;\n\n\t\t// Do nothing for single or double click inside nested editable.\n\t\tif ( isInsideNestedEditable( element ) ) {\n\t\t\t// But at least triple click inside nested editable causes broken selection in Safari.\n\t\t\t// For such event, we select the entire nested editable element.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5/issues/1463.\n\t\t\tif ( ( env.isSafari || env.isGecko ) && domEventData.domEvent.detail >= 3 ) {\n\t\t\t\tconst mapper = editor.editing.mapper;\n\t\t\t\tconst viewElement = element.is( 'attributeElement' ) ?\n\t\t\t\t\telement.findAncestor( element => !element.is( 'attributeElement' ) ) : element;\n\t\t\t\tconst modelElement = mapper.toModelElement( viewElement );\n\n\t\t\t\tdomEventData.preventDefault();\n\n\t\t\t\tthis.editor.model.change( writer => {\n\t\t\t\t\twriter.setSelection( modelElement, 'in' );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If target is not a widget element - check if one of the ancestors is.\n\t\tif ( !isWidget( element ) ) {\n\t\t\telement = element.findAncestor( isWidget );\n\n\t\t\tif ( !element ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// On Android selection would jump to the first table cell, on other devices\n\t\t// we can't block it (and don't need to) because of drag and drop support.\n\t\tif ( env.isAndroid ) {\n\t\t\tdomEventData.preventDefault();\n\t\t}\n\n\t\t// Focus editor if is not focused already.\n\t\tif ( !viewDocument.isFocused ) {\n\t\t\tview.focus();\n\t\t}\n\n\t\t// Create model selection over widget.\n\t\tconst modelElement = editor.editing.mapper.toModelElement( element );\n\n\t\tthis._setSelectionOverElement( modelElement );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and changes\n\t * the model selection when:\n\t *\n\t * * arrow key is pressed when the widget is selected,\n\t * * the selection is next to a widget and the widget should become selected upon the arrow key press.\n\t *\n\t * See {@link #_preventDefaultOnArrowKeyPress}.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_handleSelectionChangeOnArrowKeyPress( eventInfo, domEventData ) {\n\t\tconst keyCode = domEventData.keyCode;\n\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst modelSelection = model.document.selection;\n\t\tconst objectElement = modelSelection.getSelectedElement();\n\t\tconst isForward = isForwardArrowKeyCode( keyCode, this.editor.locale.contentLanguageDirection );\n\n\t\t// If object element is selected.\n\t\tif ( objectElement && schema.isObject( objectElement ) ) {\n\t\t\tconst position = isForward ? modelSelection.getLastPosition() : modelSelection.getFirstPosition();\n\t\t\tconst newRange = schema.getNearestSelectionRange( position, isForward ? 'forward' : 'backward' );\n\n\t\t\tif ( newRange ) {\n\t\t\t\tmodel.change( writer => {\n\t\t\t\t\twriter.setSelection( newRange );\n\t\t\t\t} );\n\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t\teventInfo.stop();\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\t// If selection is next to object element.\n\t\t// Return if not collapsed.\n\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectElementNextToSelection = this._getObjectElementNextToSelection( isForward );\n\n\t\tif ( objectElementNextToSelection && schema.isObject( objectElementNextToSelection ) ) {\n\t\t\tthis._setSelectionOverElement( objectElementNextToSelection );\n\n\t\t\tdomEventData.preventDefault();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events and prevents\n\t * the default browser behavior to make sure the fake selection is not being moved from a fake selection\n\t * container.\n\t *\n\t * See {@link #_handleSelectionChangeOnArrowKeyPress}.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_preventDefaultOnArrowKeyPress( eventInfo, domEventData ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst objectElement = model.document.selection.getSelectedElement();\n\n\t\t// If object element is selected.\n\t\tif ( objectElement && schema.isObject( objectElement ) ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles delete keys: backspace and delete.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Set to true if delete was performed in forward direction.\n\t * @returns {Boolean|undefined} Returns `true` if keys were handled correctly.\n\t */\n\t_handleDelete( isForward ) {\n\t\t// Do nothing when the read only mode is enabled.\n\t\tif ( this.editor.isReadOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelDocument = this.editor.model.document;\n\t\tconst modelSelection = modelDocument.selection;\n\n\t\t// Do nothing on non-collapsed selection.\n\t\tif ( !modelSelection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst objectElement = this._getObjectElementNextToSelection( isForward );\n\n\t\tif ( objectElement ) {\n\t\t\tthis.editor.model.change( writer => {\n\t\t\t\tlet previousNode = modelSelection.anchor.parent;\n\n\t\t\t\t// Remove previous element if empty.\n\t\t\t\twhile ( previousNode.isEmpty ) {\n\t\t\t\t\tconst nodeToRemove = previousNode;\n\t\t\t\t\tpreviousNode = nodeToRemove.parent;\n\n\t\t\t\t\twriter.remove( nodeToRemove );\n\t\t\t\t}\n\n\t\t\t\tthis._setSelectionOverElement( objectElement );\n\t\t\t} );\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t/**\n\t * Sets {@link module:engine/model/selection~Selection document's selection} over given element.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} element\n\t */\n\t_setSelectionOverElement( element ) {\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.setSelection( writer.createRangeOn( element ) );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if {@link module:engine/model/element~Element element} placed next to the current\n\t * {@link module:engine/model/selection~Selection model selection} exists and is marked in\n\t * {@link module:engine/model/schema~Schema schema} as `object`.\n\t *\n\t * @protected\n\t * @param {Boolean} forward Direction of checking.\n\t * @returns {module:engine/model/element~Element|null}\n\t */\n\t_getObjectElementNextToSelection( forward ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\t\tconst modelSelection = model.document.selection;\n\n\t\t// Clone current selection to use it as a probe. We must leave default selection as it is so it can return\n\t\t// to its current state after undo.\n\t\tconst probe = model.createSelection( modelSelection );\n\t\tmodel.modifySelection( probe, { direction: forward ? 'forward' : 'backward' } );\n\t\tconst objectElement = forward ? probe.focus.nodeBefore : probe.focus.nodeAfter;\n\n\t\tif ( !!objectElement && schema.isObject( objectElement ) ) {\n\t\t\treturn objectElement;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Removes CSS class from previously selected widgets.\n\t *\n\t * @private\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t */\n\t_clearPreviouslySelectedWidgets( writer ) {\n\t\tfor ( const widget of this._previouslySelected ) {\n\t\t\twriter.removeClass( WIDGET_SELECTED_CLASS_NAME, widget );\n\t\t}\n\n\t\tthis._previouslySelected.clear();\n\t}\n}\n\n// Returns `true` when element is a nested editable or is placed inside one.\n//\n// @param {module:engine/view/element~Element}\n// @returns {Boolean}\nfunction isInsideNestedEditable( element ) {\n\twhile ( element ) {\n\t\tif ( element.is( 'editableElement' ) && !element.is( 'rootElement' ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Click on nested widget should select it.\n\t\tif ( isWidget( element ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\telement = element.parent;\n\t}\n\n\treturn false;\n}\n\n// Checks whether the specified `element` is a child of the `parent` element.\n//\n// @param {module:engine/view/element~Element} element An element to check.\n// @param {module:engine/view/element~Element|null} parent A parent for the element.\n// @returns {Boolean}\nfunction isChild( element, parent ) {\n\tif ( !parent ) {\n\t\treturn false;\n\t}\n\n\treturn Array.from( element.getAncestors() ).includes( parent );\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 widget/widgettoolbarrepository\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\nimport ToolbarView from '@ckeditor/ckeditor5-ui/src/toolbar/toolbarview';\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\nimport {\n\tisWidget,\n\tcenteredBalloonPositionForLongWidgets\n} from './utils';\nimport CKEditorError, { logWarning } from '@ckeditor/ckeditor5-utils/src/ckeditorerror';\n\n/**\n * Widget toolbar repository plugin. A central point for registering widget toolbars. This plugin handles the whole\n * toolbar rendering process and exposes a concise API.\n *\n * To add a toolbar for your widget use the {@link ~WidgetToolbarRepository#register `WidgetToolbarRepository#register()`} method.\n *\n * The following example comes from the {@link module:image/imagetoolbar~ImageToolbar} plugin:\n *\n * \t\tclass ImageToolbar extends Plugin {\n *\t\t\tstatic get requires() {\n *\t\t\t\treturn [ WidgetToolbarRepository ];\n *\t\t\t}\n *\n *\t\t\tafterInit() {\n *\t\t\t\tconst editor = this.editor;\n *\t\t\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n *\n *\t\t\t\twidgetToolbarRepository.register( 'image', {\n *\t\t\t\t\titems: editor.config.get( 'image.toolbar' ),\n *\t\t\t\t\tgetRelatedElement: getSelectedImageWidget\n *\t\t\t\t} );\n *\t\t\t}\n *\t\t}\n */\nexport default class WidgetToolbarRepository extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'WidgetToolbarRepository';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Disables the default balloon toolbar for all widgets.\n\t\tif ( editor.plugins.has( 'BalloonToolbar' ) ) {\n\t\t\tconst balloonToolbar = editor.plugins.get( 'BalloonToolbar' );\n\n\t\t\tthis.listenTo( balloonToolbar, 'show', evt => {\n\t\t\t\tif ( isWidgetSelected( editor.editing.view.document.selection ) ) {\n\t\t\t\t\tevt.stop();\n\t\t\t\t}\n\t\t\t}, { priority: 'high' } );\n\t\t}\n\n\t\t/**\n\t\t * A map of toolbar definitions.\n\t\t *\n\t\t * @protected\n\t\t * @member {Map.<String,module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition>} #_toolbarDefinitions\n\t\t */\n\t\tthis._toolbarDefinitions = new Map();\n\n\t\t/**\n\t\t * @private\n\t\t */\n\t\tthis._balloon = this.editor.plugins.get( 'ContextualBalloon' );\n\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tthis._updateToolbarsVisibility();\n\t\t} );\n\n\t\tthis.listenTo( editor.ui, 'update', () => {\n\t\t\tthis._updateToolbarsVisibility();\n\t\t} );\n\n\t\t// UI#update is not fired after focus is back in editor, we need to check if balloon panel should be visible.\n\t\tthis.listenTo( editor.ui.focusTracker, 'change:isFocused', () => {\n\t\t\tthis._updateToolbarsVisibility();\n\t\t}, { priority: 'low' } );\n\t}\n\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tfor ( const toolbarConfig of this._toolbarDefinitions.values() ) {\n\t\t\ttoolbarConfig.view.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * Registers toolbar in the WidgetToolbarRepository. It renders it in the `ContextualBalloon` based on the value of the invoked\n\t * `getRelatedElement` function. Toolbar items are gathered from `items` array.\n\t * The balloon's CSS class is by default `ck-toolbar-container` and may be override with the `balloonClassName` option.\n\t *\n\t * Note: This method should be called in the {@link module:core/plugin~PluginInterface#afterInit `Plugin#afterInit()`}\n\t * callback (or later) to make sure that the given toolbar items were already registered by other plugins.\n\t *\n\t * @param {String} toolbarId An id for the toolbar. Used to\n\t * @param {Object} options\n\t * @param {String} [options.ariaLabel] Label used by assistive technologies to describe this toolbar element.\n\t * @param {Array.<String>} options.items Array of toolbar items.\n\t * @param {Function} options.getRelatedElement Callback which returns an element the toolbar should be attached to.\n\t * @param {String} [options.balloonClassName='ck-toolbar-container'] CSS class for the widget balloon.\n\t */\n\tregister( toolbarId, { ariaLabel, items, getRelatedElement, balloonClassName = 'ck-toolbar-container' } ) {\n\t\t// Trying to register a toolbar without any item.\n\t\tif ( !items.length ) {\n\t\t\t/**\n\t\t\t * When {@link #register} a new toolbar, you need to provide a non-empty array with\n\t\t\t * the items that will be inserted into the toolbar.\n\t\t\t *\n\t\t\t * @error widget-toolbar-no-items\n\t\t\t */\n\t\t\tlogWarning( 'widget-toolbar-no-items', { toolbarId } );\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst toolbarView = new ToolbarView( editor.locale );\n\n\t\ttoolbarView.ariaLabel = ariaLabel || t( 'Widget toolbar' );\n\n\t\tif ( this._toolbarDefinitions.has( toolbarId ) ) {\n\t\t\t/**\n\t\t\t * Toolbar with the given id was already added.\n\t\t\t *\n\t\t\t * @error widget-toolbar-duplicated\n\t\t\t * @param toolbarId Toolbar id.\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'widget-toolbar-duplicated', this, { toolbarId } );\n\t\t}\n\n\t\ttoolbarView.fillFromConfig( items, editor.ui.componentFactory );\n\n\t\tthis._toolbarDefinitions.set( toolbarId, {\n\t\t\tview: toolbarView,\n\t\t\tgetRelatedElement,\n\t\t\tballoonClassName\n\t\t} );\n\t}\n\n\t/**\n\t * Iterates over stored toolbars and makes them visible or hidden.\n\t *\n\t * @private\n\t */\n\t_updateToolbarsVisibility() {\n\t\tlet maxRelatedElementDepth = 0;\n\t\tlet deepestRelatedElement = null;\n\t\tlet deepestToolbarDefinition = null;\n\n\t\tfor ( const definition of this._toolbarDefinitions.values() ) {\n\t\t\tconst relatedElement = definition.getRelatedElement( this.editor.editing.view.document.selection );\n\n\t\t\tif ( !this.isEnabled || !relatedElement ) {\n\t\t\t\tif ( this._isToolbarInBalloon( definition ) ) {\n\t\t\t\t\tthis._hideToolbar( definition );\n\t\t\t\t}\n\t\t\t} else if ( !this.editor.ui.focusTracker.isFocused ) {\n\t\t\t\tif ( this._isToolbarVisible( definition ) ) {\n\t\t\t\t\tthis._hideToolbar( definition );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst relatedElementDepth = relatedElement.getAncestors().length;\n\n\t\t\t\t// Many toolbars can express willingness to be displayed but they do not know about\n\t\t\t\t// each other. Figure out which toolbar is deepest in the view tree to decide which\n\t\t\t\t// should be displayed. For instance, if a selected image is inside a table cell, display\n\t\t\t\t// the ImageToolbar rather than the TableToolbar (#60).\n\t\t\t\tif ( relatedElementDepth > maxRelatedElementDepth ) {\n\t\t\t\t\tmaxRelatedElementDepth = relatedElementDepth;\n\t\t\t\t\tdeepestRelatedElement = relatedElement;\n\t\t\t\t\tdeepestToolbarDefinition = definition;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( deepestToolbarDefinition ) {\n\t\t\tthis._showToolbar( deepestToolbarDefinition, deepestRelatedElement );\n\t\t}\n\t}\n\n\t/**\n\t * Hides the given toolbar.\n\t *\n\t * @private\n\t * @param {module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition} toolbarDefinition\n\t */\n\t_hideToolbar( toolbarDefinition ) {\n\t\tthis._balloon.remove( toolbarDefinition.view );\n\t\tthis.stopListening( this._balloon, 'change:visibleView' );\n\t}\n\n\t/**\n\t * Shows up the toolbar if the toolbar is not visible.\n\t * Otherwise, repositions the toolbar's balloon when toolbar's view is the most top view in balloon stack.\n\t *\n\t * It might happen here that the toolbar's view is under another view. Then do nothing as the other toolbar view\n\t * should be still visible after the {@link module:core/editor/editorui~EditorUI#event:update}.\n\t *\n\t * @private\n\t * @param {module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition} toolbarDefinition\n\t * @param {module:engine/view/element~Element} relatedElement\n\t */\n\t_showToolbar( toolbarDefinition, relatedElement ) {\n\t\tif ( this._isToolbarVisible( toolbarDefinition ) ) {\n\t\t\trepositionContextualBalloon( this.editor, relatedElement );\n\t\t} else if ( !this._isToolbarInBalloon( toolbarDefinition ) ) {\n\t\t\tthis._balloon.add( {\n\t\t\t\tview: toolbarDefinition.view,\n\t\t\t\tposition: getBalloonPositionData( this.editor, relatedElement ),\n\t\t\t\tballoonClassName: toolbarDefinition.balloonClassName\n\t\t\t} );\n\n\t\t\t// Update toolbar position each time stack with toolbar view is switched to visible.\n\t\t\t// This is in a case target element has changed when toolbar was in invisible stack\n\t\t\t// e.g. target image was wrapped by a block quote.\n\t\t\t// See https://github.com/ckeditor/ckeditor5-widget/issues/92.\n\t\t\tthis.listenTo( this._balloon, 'change:visibleView', () => {\n\t\t\t\tfor ( const definition of this._toolbarDefinitions.values() ) {\n\t\t\t\t\tif ( this._isToolbarVisible( definition ) ) {\n\t\t\t\t\t\tconst relatedElement = definition.getRelatedElement( this.editor.editing.view.document.selection );\n\t\t\t\t\t\trepositionContextualBalloon( this.editor, relatedElement );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * @private\n\t * @param {Object} toolbar\n\t * @returns {Boolean}\n\t */\n\t_isToolbarVisible( toolbar ) {\n\t\treturn this._balloon.visibleView === toolbar.view;\n\t}\n\n\t/**\n\t * @private\n\t * @param {Object} toolbar\n\t * @returns {Boolean}\n\t */\n\t_isToolbarInBalloon( toolbar ) {\n\t\treturn this._balloon.hasView( toolbar.view );\n\t}\n}\n\nfunction repositionContextualBalloon( editor, relatedElement ) {\n\tconst balloon = editor.plugins.get( 'ContextualBalloon' );\n\tconst position = getBalloonPositionData( editor, relatedElement );\n\n\tballoon.updatePosition( position );\n}\n\nfunction getBalloonPositionData( editor, relatedElement ) {\n\tconst editingView = editor.editing.view;\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\treturn {\n\t\ttarget: editingView.domConverter.mapViewToDom( relatedElement ),\n\t\tpositions: [\n\t\t\tdefaultPositions.northArrowSouth,\n\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\tdefaultPositions.northArrowSouthEast,\n\t\t\tdefaultPositions.southArrowNorth,\n\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\tdefaultPositions.southArrowNorthEast,\n\t\t\tcenteredBalloonPositionForLongWidgets\n\t\t]\n\t};\n}\n\nfunction isWidgetSelected( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\treturn !!( viewElement && isWidget( viewElement ) );\n}\n\n/**\n * The toolbar definition object used by the toolbar repository to manage toolbars.\n * It contains information necessary to display the toolbar in the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} and\n * update it during its life (display) cycle.\n *\n * @typedef {Object} module:widget/widgettoolbarrepository~WidgetRepositoryToolbarDefinition\n *\n * @property {module:ui/view~View} view The UI view of the toolbar.\n * @property {Function} getRelatedElement A function that returns an engine {@link module:engine/view/view~View}\n * element the toolbar is to be attached to. For instance, an image widget or a table widget (or `null` when\n * there is no such element). The function accepts an instance of {@link module:engine/view/selection~Selection}.\n * @property {String} balloonClassName CSS class for the widget balloon when a toolbar is displayed.\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 widget/widgetresize/resizerstate\n */\n\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\n/**\n * Stores the internal state of a single resizable object.\n *\n */\nexport default class ResizeState {\n\t/**\n\t * @param {module:widget/widgetresize~ResizerOptions} options Resizer options.\n\t */\n\tconstructor( options ) {\n\t\t/**\n\t\t * The original width (pixels) of the resized object when the resize process was started.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #originalWidth\n\t\t */\n\n\t\t/**\n\t\t * The original height (pixels) of the resized object when the resize process was started.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #originalHeight\n\t\t */\n\n\t\t/**\n\t\t * The original width (percents) of the resized object when the resize process was started.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #originalWidthPercents\n\t\t */\n\n\t\t/**\n\t\t * The position of the handle that initiated the resizing. E.g. `\"top-left\"`, `\"bottom-right\"` etc. or `null`\n\t\t * if unknown.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {String|null} #activeHandlePosition\n\t\t */\n\t\tthis.set( 'activeHandlePosition', null );\n\n\t\t/**\n\t\t * The width (percents) proposed, but not committed yet, in the current resize process.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #proposedWidthPercents\n\t\t */\n\t\tthis.set( 'proposedWidthPercents', null );\n\n\t\t/**\n\t\t * The width (pixels) proposed, but not committed yet, in the current resize process.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #proposedWidthPixels\n\t\t */\n\t\tthis.set( 'proposedWidth', null );\n\n\t\t/**\n\t\t * The height (pixels) proposed, but not committed yet, in the current resize process.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Number|null} #proposedHeightPixels\n\t\t */\n\t\tthis.set( 'proposedHeight', null );\n\n\t\tthis.set( 'proposedHandleHostWidth', null );\n\t\tthis.set( 'proposedHandleHostHeight', null );\n\n\t\t/**\n\t\t * A width to height ratio of the resized image.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number} #aspectRatio\n\t\t */\n\n\t\t/**\n\t\t * @private\n\t\t * @type {module:widget/widgetresize~ResizerOptions}\n\t\t */\n\t\tthis._options = options;\n\n\t\t/**\n\t\t * The reference point of the resizer where the dragging started. It is used to measure the distance the user cursor\n\t\t * traveled, so how much the image should be enlarged.\n\t\t * This information is only known after the DOM was rendered, so it will be updated later.\n\t\t *\n\t\t * @private\n\t\t * @type {Object}\n\t\t */\n\t\tthis._referenceCoordinates = null;\n\t}\n\n\t/**\n\t *\n\t * @param {HTMLElement} domResizeHandle The handle used to calculate the reference point.\n\t * @param {HTMLElement} domHandleHost\n\t * @param {HTMLElement} domResizeHost\n\t */\n\tbegin( domResizeHandle, domHandleHost, domResizeHost ) {\n\t\tconst clientRect = new Rect( domHandleHost );\n\n\t\tthis.activeHandlePosition = getHandlePosition( domResizeHandle );\n\n\t\tthis._referenceCoordinates = getAbsoluteBoundaryPoint( domHandleHost, getOppositePosition( this.activeHandlePosition ) );\n\n\t\tthis.originalWidth = clientRect.width;\n\t\tthis.originalHeight = clientRect.height;\n\n\t\tthis.aspectRatio = clientRect.width / clientRect.height;\n\n\t\tconst widthStyle = domResizeHost.style.width;\n\n\t\tif ( widthStyle && widthStyle.match( /^\\d+(\\.\\d*)?%$/ ) ) {\n\t\t\tthis.originalWidthPercents = parseFloat( widthStyle );\n\t\t} else {\n\t\t\tthis.originalWidthPercents = calculateHostPercentageWidth( domResizeHost, clientRect );\n\t\t}\n\t}\n\n\tupdate( newSize ) {\n\t\tthis.proposedWidth = newSize.width;\n\t\tthis.proposedHeight = newSize.height;\n\t\tthis.proposedWidthPercents = newSize.widthPercents;\n\n\t\tthis.proposedHandleHostWidth = newSize.handleHostWidth;\n\t\tthis.proposedHandleHostHeight = newSize.handleHostHeight;\n\t}\n}\n\nmix( ResizeState, ObservableMixin );\n\n// Calculates a relative width of a `domResizeHost` compared to it's parent in percents.\n//\n// @private\n// @param {HTMLElement} domResizeHost\n// @param {module:utils/dom/rect~Rect} resizeHostRect\n// @returns {Number}\nfunction calculateHostPercentageWidth( domResizeHost, resizeHostRect ) {\n\tconst domResizeHostParent = domResizeHost.parentElement;\n\t// Need to use computed style as it properly excludes parent's paddings from the returned value.\n\tconst parentWidth = parseFloat( domResizeHostParent.ownerDocument.defaultView.getComputedStyle( domResizeHostParent ).width );\n\n\treturn resizeHostRect.width / parentWidth * 100;\n}\n\n// Returns coordinates of the top-left corner of an element, relative to the document's top-left corner.\n//\n// @private\n// @param {HTMLElement} element\n// @param {String} resizerPosition The position of the resize handle, e.g. `\"top-left\"`, `\"bottom-right\"`.\n// @returns {Object} return\n// @returns {Number} return.x\n// @returns {Number} return.y\nfunction getAbsoluteBoundaryPoint( element, resizerPosition ) {\n\tconst elementRect = new Rect( element );\n\tconst positionParts = resizerPosition.split( '-' );\n\tconst ret = {\n\t\tx: positionParts[ 1 ] == 'right' ? elementRect.right : elementRect.left,\n\t\ty: positionParts[ 0 ] == 'bottom' ? elementRect.bottom : elementRect.top\n\t};\n\n\tret.x += element.ownerDocument.defaultView.scrollX;\n\tret.y += element.ownerDocument.defaultView.scrollY;\n\n\treturn ret;\n}\n\n// @private\n// @param {String} resizerPosition The expected resizer position, like `\"top-left\"`, `\"bottom-right\"`.\n// @returns {String} A prefixed HTML class name for the resizer element.\nfunction getResizerHandleClass( resizerPosition ) {\n\treturn `ck-widget__resizer__handle-${ resizerPosition }`;\n}\n\n// Determines the position of a given resize handle.\n//\n// @private\n// @param {HTMLElement} domHandle Handle used to calculate the reference point.\n// @returns {String|undefined} Returns a string like `\"top-left\"` or `undefined` if not matched.\nfunction getHandlePosition( domHandle ) {\n\tconst resizerPositions = [ 'top-left', 'top-right', 'bottom-right', 'bottom-left' ];\n\n\tfor ( const position of resizerPositions ) {\n\t\tif ( domHandle.classList.contains( getResizerHandleClass( position ) ) ) {\n\t\t\treturn position;\n\t\t}\n\t}\n}\n\n// @private\n// @param {String} position Like `\"top-left\"`.\n// @returns {String} Inverted `position`, e.g. it returns `\"bottom-right\"` if `\"top-left\"` was given as `position`.\nfunction getOppositePosition( position ) {\n\tconst parts = position.split( '-' );\n\tconst replacements = {\n\t\ttop: 'bottom',\n\t\tbottom: 'top',\n\t\tleft: 'right',\n\t\tright: 'left'\n\t};\n\n\treturn `${ replacements[ parts[ 0 ] ] }-${ replacements[ parts[ 1 ] ] }`;\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 widget/widgetresize/resizer\n */\n\nimport View from '@ckeditor/ckeditor5-ui/src/view';\nimport Template from '@ckeditor/ckeditor5-ui/src/template';\nimport Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';\nimport compareArrays from '@ckeditor/ckeditor5-utils/src/comparearrays';\n\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\n\nimport ResizeState from './resizerstate';\n\n/**\n * Represents a resizer for a single resizable object.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class Resizer {\n\t/**\n\t * @param {module:widget/widgetresize~ResizerOptions} options Resizer options.\n\t */\n\tconstructor( options ) {\n\t\t/**\n\t\t * Stores the state of the resizable host geometry, such as the original width, the currently proposed height, etc.\n\t\t *\n\t\t * Note that a new state is created for each resize transaction.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:widget/widgetresize/resizerstate~ResizerState} #state\n\t\t */\n\n\t\t/**\n\t\t * A view displaying the proposed new element size during the resizing.\n\t\t *\n\t\t * @protected\n\t\t * @readonly\n\t\t * @member {module:widget/widgetresize/resizer~SizeView} #_sizeUI\n\t\t */\n\n\t\t/**\n\t\t * Options passed to the {@link #constructor}.\n\t\t *\n\t\t * @private\n\t\t * @type {module:widget/widgetresize~ResizerOptions}\n\t\t */\n\t\tthis._options = options;\n\n\t\t/**\n\t\t * Container of the entire resize UI.\n\t\t *\n\t\t * Note that this property is initialized only after the element bound with the resizer is drawn\n\t\t * so it will be a `null` when uninitialized.\n\t\t *\n\t\t * @private\n\t\t * @type {HTMLElement|null}\n\t\t */\n\t\tthis._domResizerWrapper = null;\n\n\t\t/**\n\t\t * A wrapper that is controlled by the resizer. This is usually a widget element.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/view/element~Element|null}\n\t\t */\n\t\tthis._viewResizerWrapper = null;\n\n\t\t/**\n\t\t * The width of the resized {@link module:widget/widgetresize~ResizerOptions#viewElement viewElement} before the resizing started.\n\t\t *\n\t\t * @private\n\t\t * @member {Number|String|undefined} #_initialViewWidth\n\t\t */\n\n\t\t/**\n\t\t * @observable\n\t\t */\n\t\tthis.set( 'isEnabled', true );\n\n\t\tthis.decorate( 'begin' );\n\t\tthis.decorate( 'cancel' );\n\t\tthis.decorate( 'commit' );\n\t\tthis.decorate( 'updateSize' );\n\n\t\tthis.on( 'commit', event => {\n\t\t\t// State might not be initialized yet. In this case, prevent further handling and make sure that the resizer is\n\t\t\t// cleaned up (#5195).\n\t\t\tif ( !this.state.proposedWidth && !this.state.proposedWidthPercents ) {\n\t\t\t\tthis._cleanup();\n\t\t\t\tevent.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\t// We should redraw the resize handles when the plugin is enabled again.\n\t\t\t// Otherwise they won't show up.\n\t\t\tif ( this.isEnabled ) {\n\t\t\t\tthis.redraw();\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Attaches the resizer to the DOM.\n\t */\n\tattach() {\n\t\tconst that = this;\n\t\tconst widgetElement = this._options.viewElement;\n\t\tconst editingView = this._options.editor.editing.view;\n\n\t\teditingView.change( writer => {\n\t\t\tconst viewResizerWrapper = writer.createUIElement( 'div', {\n\t\t\t\tclass: 'ck ck-reset_all ck-widget__resizer'\n\t\t\t}, function( domDocument ) {\n\t\t\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t\t\tthat._appendHandles( domElement );\n\t\t\t\tthat._appendSizeUI( domElement );\n\n\t\t\t\tthat._domResizerWrapper = domElement;\n\n\t\t\t\tthat.on( 'change:isEnabled', ( evt, propName, newValue ) => {\n\t\t\t\t\tdomElement.style.display = newValue ? '' : 'none';\n\t\t\t\t} );\n\n\t\t\t\tdomElement.style.display = that.isEnabled ? '' : 'none';\n\n\t\t\t\treturn domElement;\n\t\t\t} );\n\n\t\t\t// Append the resizer wrapper to the widget's wrapper.\n\t\t\twriter.insert( writer.createPositionAt( widgetElement, 'end' ), viewResizerWrapper );\n\t\t\twriter.addClass( 'ck-widget_with-resizer', widgetElement );\n\n\t\t\tthis._viewResizerWrapper = viewResizerWrapper;\n\t\t} );\n\t}\n\n\t/**\n\t * Starts the resizing process.\n\t *\n\t * Creates a new {@link #state} for the current process.\n\t *\n\t * @fires begin\n\t * @param {HTMLElement} domResizeHandle Clicked handle.\n\t */\n\tbegin( domResizeHandle ) {\n\t\tthis.state = new ResizeState( this._options );\n\n\t\tthis._sizeUI.bindToState( this._options, this.state );\n\n\t\tthis._initialViewWidth = this._options.viewElement.getStyle( 'width' );\n\n\t\tthis.state.begin( domResizeHandle, this._getHandleHost(), this._getResizeHost() );\n\t}\n\n\t/**\n\t * Updates the proposed size based on `domEventData`.\n\t *\n\t * @fires updateSize\n\t * @param {Event} domEventData\n\t */\n\tupdateSize( domEventData ) {\n\t\tconst newSize = this._proposeNewSize( domEventData );\n\t\tconst editingView = this._options.editor.editing.view;\n\n\t\teditingView.change( writer => {\n\t\t\tconst unit = this._options.unit || '%';\n\t\t\tconst newWidth = ( unit === '%' ? newSize.widthPercents : newSize.width ) + unit;\n\n\t\t\twriter.setStyle( 'width', newWidth, this._options.viewElement );\n\t\t} );\n\n\t\t// Get an actual image width, and:\n\t\t// * reflect this size to the resize wrapper\n\t\t// * apply this **real** size to the state\n\t\tconst domHandleHost = this._getHandleHost();\n\t\tconst domHandleHostRect = new Rect( domHandleHost );\n\n\t\tnewSize.handleHostWidth = Math.round( domHandleHostRect.width );\n\t\tnewSize.handleHostHeight = Math.round( domHandleHostRect.height );\n\n\t\t// Handle max-width limitation.\n\t\tconst domResizeHostRect = new Rect( domHandleHost );\n\n\t\tnewSize.width = Math.round( domResizeHostRect.width );\n\t\tnewSize.height = Math.round( domResizeHostRect.height );\n\n\t\tthis.redraw( domHandleHostRect );\n\n\t\tthis.state.update( newSize );\n\t}\n\n\t/**\n\t * Applies the geometry proposed with the resizer.\n\t *\n\t * @fires commit\n\t */\n\tcommit() {\n\t\tconst unit = this._options.unit || '%';\n\t\tconst newValue = ( unit === '%' ? this.state.proposedWidthPercents : this.state.proposedWidth ) + unit;\n\n\t\t// Both cleanup and onCommit callback are very likely to make view changes. Ensure that it is made in a single step.\n\t\tthis._options.editor.editing.view.change( () => {\n\t\t\tthis._cleanup();\n\t\t\tthis._options.onCommit( newValue );\n\t\t} );\n\t}\n\n\t/**\n\t * Cancels and rejects the proposed resize dimensions, hiding the UI.\n\t *\n\t * @fires cancel\n\t */\n\tcancel() {\n\t\tthis._cleanup();\n\t}\n\n\t/**\n\t * Destroys the resizer.\n\t */\n\tdestroy() {\n\t\tthis.cancel();\n\t}\n\n\t/**\n\t * Redraws the resizer.\n\t *\n\t * @param {module:utils/dom/rect~Rect} [handleHostRect] Handle host rectangle might be given to improve performance.\n\t */\n\tredraw( handleHostRect ) {\n\t\tconst domWrapper = this._domResizerWrapper;\n\n\t\t// Refresh only if resizer exists in the DOM.\n\t\tif ( !existsInDom( domWrapper ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst widgetWrapper = domWrapper.parentElement;\n\t\tconst handleHost = this._getHandleHost();\n\t\tconst resizerWrapper = this._viewResizerWrapper;\n\t\tconst currentDimensions = [\n\t\t\tresizerWrapper.getStyle( 'width' ),\n\t\t\tresizerWrapper.getStyle( 'height' ),\n\t\t\tresizerWrapper.getStyle( 'left' ),\n\t\t\tresizerWrapper.getStyle( 'top' )\n\t\t];\n\t\tlet newDimensions;\n\n\t\tif ( widgetWrapper.isSameNode( handleHost ) ) {\n\t\t\tconst clientRect = handleHostRect || new Rect( handleHost );\n\n\t\t\tnewDimensions = [\n\t\t\t\tclientRect.width + 'px',\n\t\t\t\tclientRect.height + 'px',\n\t\t\t\tundefined,\n\t\t\t\tundefined\n\t\t\t];\n\t\t}\n\t\t// In case a resizing host is not a widget wrapper, we need to compensate\n\t\t// for any additional offsets the resize host might have. E.g. wrapper padding\n\t\t// or simply another editable. By doing that the border and resizers are shown\n\t\t// only around the resize host.\n\t\telse {\n\t\t\tnewDimensions = [\n\t\t\t\thandleHost.offsetWidth + 'px',\n\t\t\t\thandleHost.offsetHeight + 'px',\n\t\t\t\thandleHost.offsetLeft + 'px',\n\t\t\t\thandleHost.offsetTop + 'px'\n\t\t\t];\n\t\t}\n\n\t\t// Make changes to the view only if the resizer should actually get new dimensions.\n\t\t// Otherwise, if View#change() was always called, this would cause EditorUI#update\n\t\t// loops because the WidgetResize plugin listens to EditorUI#update and updates\n\t\t// the resizer.\n\t\t// https://github.com/ckeditor/ckeditor5/issues/7633\n\t\tif ( compareArrays( currentDimensions, newDimensions ) !== 'same' ) {\n\t\t\tthis._options.editor.editing.view.change( writer => {\n\t\t\t\twriter.setStyle( {\n\t\t\t\t\twidth: newDimensions[ 0 ],\n\t\t\t\t\theight: newDimensions[ 1 ],\n\t\t\t\t\tleft: newDimensions[ 2 ],\n\t\t\t\t\ttop: newDimensions[ 3 ]\n\t\t\t\t}, resizerWrapper );\n\t\t\t} );\n\t\t}\n\t}\n\n\tcontainsHandle( domElement ) {\n\t\treturn this._domResizerWrapper.contains( domElement );\n\t}\n\n\tstatic isResizeHandle( domElement ) {\n\t\treturn domElement.classList.contains( 'ck-widget__resizer__handle' );\n\t}\n\n\t/**\n\t * Cleans up the context state.\n\t *\n\t * @protected\n\t */\n\t_cleanup() {\n\t\tthis._sizeUI.dismiss();\n\t\tthis._sizeUI.isVisible = false;\n\n\t\tconst editingView = this._options.editor.editing.view;\n\n\t\teditingView.change( writer => {\n\t\t\twriter.setStyle( 'width', this._initialViewWidth, this._options.viewElement );\n\t\t} );\n\t}\n\n\t/**\n\t * Calculates the proposed size as the resize handles are dragged.\n\t *\n\t * @private\n\t * @param {Event} domEventData Event data that caused the size update request. It should be used to calculate the proposed size.\n\t * @returns {Object} return\n\t * @returns {Number} return.width Proposed width.\n\t * @returns {Number} return.height Proposed height.\n\t */\n\t_proposeNewSize( domEventData ) {\n\t\tconst state = this.state;\n\t\tconst currentCoordinates = extractCoordinates( domEventData );\n\t\tconst isCentered = this._options.isCentered ? this._options.isCentered( this ) : true;\n\n\t\t// Enlargement defines how much the resize host has changed in a given axis. Naturally it could be a negative number\n\t\t// meaning that it has been shrunk.\n\t\t//\n\t\t// +----------------+--+\n\t\t// | | |\n\t\t// | img | |\n\t\t// | /handle host | |\n\t\t// +----------------+ | ^\n\t\t// | | | - enlarge y\n\t\t// +-------------------+ v\n\t\t// \t\t\t\t\t<-->\n\t\t// \t\t\t\t\t enlarge x\n\t\tconst enlargement = {\n\t\t\tx: state._referenceCoordinates.x - ( currentCoordinates.x + state.originalWidth ),\n\t\t\ty: ( currentCoordinates.y - state.originalHeight ) - state._referenceCoordinates.y\n\t\t};\n\n\t\tif ( isCentered && state.activeHandlePosition.endsWith( '-right' ) ) {\n\t\t\tenlargement.x = currentCoordinates.x - ( state._referenceCoordinates.x + state.originalWidth );\n\t\t}\n\n\t\t// Objects needs to be resized twice as much in horizontal axis if centered, since enlargement is counted from\n\t\t// one resized corner to your cursor. It needs to be duplicated to compensate for the other side too.\n\t\tif ( isCentered ) {\n\t\t\tenlargement.x *= 2;\n\t\t}\n\n\t\t// const resizeHost = this._getResizeHost();\n\n\t\t// The size proposed by the user. It does not consider the aspect ratio.\n\t\tconst proposedSize = {\n\t\t\twidth: Math.abs( state.originalWidth + enlargement.x ),\n\t\t\theight: Math.abs( state.originalHeight + enlargement.y )\n\t\t};\n\n\t\t// Dominant determination must take the ratio into account.\n\t\tproposedSize.dominant = proposedSize.width / state.aspectRatio > proposedSize.height ? 'width' : 'height';\n\t\tproposedSize.max = proposedSize[ proposedSize.dominant ];\n\n\t\t// Proposed size, respecting the aspect ratio.\n\t\tconst targetSize = {\n\t\t\twidth: proposedSize.width,\n\t\t\theight: proposedSize.height\n\t\t};\n\n\t\tif ( proposedSize.dominant == 'width' ) {\n\t\t\ttargetSize.height = targetSize.width / state.aspectRatio;\n\t\t} else {\n\t\t\ttargetSize.width = targetSize.height * state.aspectRatio;\n\t\t}\n\n\t\treturn {\n\t\t\twidth: Math.round( targetSize.width ),\n\t\t\theight: Math.round( targetSize.height ),\n\t\t\twidthPercents: Math.min( Math.round( state.originalWidthPercents / state.originalWidth * targetSize.width * 100 ) / 100, 100 )\n\t\t};\n\t}\n\n\t/**\n\t * Obtains the resize host.\n\t *\n\t * Resize host is an object that receives dimensions which are the result of resizing.\n\t *\n\t * @protected\n\t * @returns {HTMLElement}\n\t */\n\t_getResizeHost() {\n\t\tconst widgetWrapper = this._domResizerWrapper.parentElement;\n\n\t\treturn this._options.getResizeHost( widgetWrapper );\n\t}\n\n\t/**\n\t * Obtains the handle host.\n\t *\n\t * Handle host is an object that the handles are aligned to.\n\t *\n\t * Handle host will not always be an entire widget itself. Take an image as an example. The image widget\n\t * contains an image and a caption. Only the image should be surrounded with handles.\n\t *\n\t * @protected\n\t * @returns {HTMLElement}\n\t */\n\t_getHandleHost() {\n\t\tconst widgetWrapper = this._domResizerWrapper.parentElement;\n\n\t\treturn this._options.getHandleHost( widgetWrapper );\n\t}\n\n\t/**\n\t * Renders the resize handles in the DOM.\n\t *\n\t * @private\n\t * @param {HTMLElement} domElement The resizer wrapper.\n\t */\n\t_appendHandles( domElement ) {\n\t\tconst resizerPositions = [ 'top-left', 'top-right', 'bottom-right', 'bottom-left' ];\n\n\t\tfor ( const currentPosition of resizerPositions ) {\n\t\t\tdomElement.appendChild( ( new Template( {\n\t\t\t\ttag: 'div',\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: `ck-widget__resizer__handle ${ getResizerClass( currentPosition ) }`\n\t\t\t\t}\n\t\t\t} ).render() ) );\n\t\t}\n\t}\n\n\t/**\n\t * Sets up the {@link #_sizeUI} property and adds it to the passed `domElement`.\n\t *\n\t * @private\n\t * @param {HTMLElement} domElement\n\t */\n\t_appendSizeUI( domElement ) {\n\t\tconst sizeUI = new SizeView();\n\n\t\t// Make sure icon#element is rendered before passing to appendChild().\n\t\tsizeUI.render();\n\n\t\tthis._sizeUI = sizeUI;\n\n\t\tdomElement.appendChild( sizeUI.element );\n\t}\n\n\t/**\n\t * @event begin\n\t */\n\n\t/**\n\t * @event updateSize\n\t */\n\n\t/**\n\t * @event commit\n\t */\n\n\t/**\n\t * @event cancel\n\t */\n}\n\nmix( Resizer, ObservableMixin );\n\n/**\n * A view displaying the proposed new element size during the resizing.\n *\n * @extends {module:ui/view~View}\n */\nclass SizeView extends View {\n\tconstructor() {\n\t\tsuper();\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-size-view',\n\t\t\t\t\tbind.to( 'activeHandlePosition', value => value ? `ck-orientation-${ value }` : '' )\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\tdisplay: bind.if( 'isVisible', 'none', visible => !visible )\n\t\t\t\t}\n\t\t\t},\n\t\t\tchildren: [ {\n\t\t\t\ttext: bind.to( 'label' )\n\t\t\t} ]\n\t\t} );\n\t}\n\n\tbindToState( options, resizerState ) {\n\t\tthis.bind( 'isVisible' ).to( resizerState, 'proposedWidth', resizerState, 'proposedHeight', ( width, height ) =>\n\t\t\twidth !== null && height !== null );\n\n\t\tthis.bind( 'label' ).to(\n\t\t\tresizerState, 'proposedHandleHostWidth',\n\t\t\tresizerState, 'proposedHandleHostHeight',\n\t\t\tresizerState, 'proposedWidthPercents',\n\t\t\t( width, height, widthPercents ) => {\n\t\t\t\tif ( options.unit === 'px' ) {\n\t\t\t\t\treturn `${ width }×${ height }`;\n\t\t\t\t} else {\n\t\t\t\t\treturn `${ widthPercents }%`;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\n\t\tthis.bind( 'activeHandlePosition' ).to( resizerState );\n\t}\n\n\tdismiss() {\n\t\tthis.unbind();\n\t\tthis.isVisible = false;\n\t}\n}\n\n// @private\n// @param {String} resizerPosition Expected resizer position like `\"top-left\"`, `\"bottom-right\"`.\n// @returns {String} A prefixed HTML class name for the resizer element\nfunction getResizerClass( resizerPosition ) {\n\treturn `ck-widget__resizer__handle-${ resizerPosition }`;\n}\n\nfunction extractCoordinates( event ) {\n\treturn {\n\t\tx: event.pageX,\n\t\ty: event.pageY\n\t};\n}\n\nfunction existsInDom( element ) {\n\treturn element && element.ownerDocument && element.ownerDocument.contains( element );\n}\n","import debounce from './debounce.js';\nimport isObject from './isObject.js';\n\n/** Error message constants. */\nvar FUNC_ERROR_TEXT = 'Expected a function';\n\n/**\n * Creates a throttled function that only invokes `func` at most once per\n * every `wait` milliseconds. The throttled function comes with a `cancel`\n * method to cancel delayed `func` invocations and a `flush` method to\n * immediately invoke them. Provide `options` to indicate whether `func`\n * should be invoked on the leading and/or trailing edge of the `wait`\n * timeout. The `func` is invoked with the last arguments provided to the\n * throttled function. Subsequent calls to the throttled function return the\n * result of the last `func` invocation.\n *\n * **Note:** If `leading` and `trailing` options are `true`, `func` is\n * invoked on the trailing edge of the timeout only if the throttled function\n * is invoked more than once during the `wait` timeout.\n *\n * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred\n * until to the next tick, similar to `setTimeout` with a timeout of `0`.\n *\n * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)\n * for details over the differences between `_.throttle` and `_.debounce`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Function\n * @param {Function} func The function to throttle.\n * @param {number} [wait=0] The number of milliseconds to throttle invocations to.\n * @param {Object} [options={}] The options object.\n * @param {boolean} [options.leading=true]\n * Specify invoking on the leading edge of the timeout.\n * @param {boolean} [options.trailing=true]\n * Specify invoking on the trailing edge of the timeout.\n * @returns {Function} Returns the new throttled function.\n * @example\n *\n * // Avoid excessively updating the position while scrolling.\n * jQuery(window).on('scroll', _.throttle(updatePosition, 100));\n *\n * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.\n * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });\n * jQuery(element).on('click', throttled);\n *\n * // Cancel the trailing throttled invocation.\n * jQuery(window).on('popstate', throttled.cancel);\n */\nfunction throttle(func, wait, options) {\n var leading = true,\n trailing = true;\n\n if (typeof func != 'function') {\n throw new TypeError(FUNC_ERROR_TEXT);\n }\n if (isObject(options)) {\n leading = 'leading' in options ? !!options.leading : leading;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n return debounce(func, wait, {\n 'leading': leading,\n 'maxWait': wait,\n 'trailing': trailing\n });\n}\n\nexport default throttle;\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 widget/widgetresize\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Resizer from './widgetresize/resizer';\nimport DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';\nimport MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';\nimport mix from '@ckeditor/ckeditor5-utils/src/mix';\nimport { throttle } from 'lodash-es';\n\nimport '../theme/widgetresize.css';\n\n/**\n * The widget resize feature plugin.\n *\n * Use the {@link module:widget/widgetresize~WidgetResize#attachTo} method to create a resizer for the specified widget.\n *\n * @extends module:core/plugin~Plugin\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class WidgetResize extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'WidgetResize';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\t/**\n\t\t * The currently visible resizer.\n\t\t *\n\t\t * @observable\n\t\t * @member {module:widget/widgetresize/resizer~Resizer|null} #visibleResizer\n\t\t */\n\t\tthis.set( 'visibleResizer', null );\n\n\t\t/**\n\t\t * References an active resizer.\n\t\t *\n\t\t * Active resizer means a resizer which handle is actively used by the end user.\n\t\t *\n\t\t * @protected\n\t\t * @observable\n\t\t * @member {module:widget/widgetresize/resizer~Resizer|null} #_activeResizer\n\t\t */\n\t\tthis.set( '_activeResizer', null );\n\n\t\t/**\n\t\t * A map of resizers created using this plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @type {Map.<module:engine/view/containerelement~ContainerElement, module:widget/widgetresize/resizer~Resizer>}\n\t\t */\n\t\tthis._resizers = new Map();\n\n\t\tconst domDocument = global.window.document;\n\n\t\tthis.editor.model.schema.setAttributeProperties( 'width', {\n\t\t\tisFormatting: true\n\t\t} );\n\n\t\tthis.editor.editing.view.addObserver( MouseObserver );\n\n\t\tthis._observer = Object.create( DomEmitterMixin );\n\n\t\tthis.listenTo( this.editor.editing.view.document, 'mousedown', this._mouseDownListener.bind( this ), { priority: 'high' } );\n\n\t\tthis._observer.listenTo( domDocument, 'mousemove', this._mouseMoveListener.bind( this ) );\n\t\tthis._observer.listenTo( domDocument, 'mouseup', this._mouseUpListener.bind( this ) );\n\n\t\tconst redrawFocusedResizer = () => {\n\t\t\tif ( this.visibleResizer ) {\n\t\t\t\tthis.visibleResizer.redraw();\n\t\t\t}\n\t\t};\n\n\t\tconst redrawFocusedResizerThrottled = throttle( redrawFocusedResizer, 200 );\n\n\t\t// Redraws occurring upon a change of visible resizer must not be throttled, as it is crucial for the initial\n\t\t// render. Without it the resizer frame would be misaligned with resizing host for a fraction of second.\n\t\tthis.on( 'change:visibleResizer', redrawFocusedResizer );\n\n\t\t// Redrawing on any change of the UI of the editor (including content changes).\n\t\tthis.editor.ui.on( 'update', redrawFocusedResizerThrottled );\n\n\t\t// Resizers need to be redrawn upon window resize, because new window might shrink resize host.\n\t\tthis._observer.listenTo( global.window, 'resize', redrawFocusedResizerThrottled );\n\n\t\tconst viewSelection = this.editor.editing.view.document.selection;\n\n\t\tviewSelection.on( 'change', () => {\n\t\t\tconst selectedElement = viewSelection.getSelectedElement();\n\n\t\t\tthis.visibleResizer = this.getResizerByViewElement( selectedElement ) || null;\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tthis._observer.stopListening();\n\n\t\tfor ( const resizer of this._resizers.values() ) {\n\t\t\tresizer.destroy();\n\t\t}\n\t}\n\n\t/**\n\t * @param {module:widget/widgetresize~ResizerOptions} [options] Resizer options.\n\t * @returns {module:widget/widgetresize/resizer~Resizer}\n\t */\n\tattachTo( options ) {\n\t\tconst resizer = new Resizer( options );\n\t\tconst plugins = this.editor.plugins;\n\n\t\tresizer.attach();\n\n\t\tif ( plugins.has( 'WidgetToolbarRepository' ) ) {\n\t\t\t// Hiding widget toolbar to improve the performance\n\t\t\t// (https://github.com/ckeditor/ckeditor5-widget/pull/112#issuecomment-564528765).\n\t\t\tconst widgetToolbarRepository = plugins.get( 'WidgetToolbarRepository' );\n\n\t\t\tresizer.on( 'begin', () => {\n\t\t\t\twidgetToolbarRepository.forceDisabled( 'resize' );\n\t\t\t}, { priority: 'lowest' } );\n\n\t\t\tresizer.on( 'cancel', () => {\n\t\t\t\twidgetToolbarRepository.clearForceDisabled( 'resize' );\n\t\t\t}, { priority: 'highest' } );\n\n\t\t\tresizer.on( 'commit', () => {\n\t\t\t\twidgetToolbarRepository.clearForceDisabled( 'resize' );\n\t\t\t}, { priority: 'highest' } );\n\t\t}\n\n\t\tthis._resizers.set( options.viewElement, resizer );\n\n\t\tconst viewSelection = this.editor.editing.view.document.selection;\n\t\tconst selectedElement = viewSelection.getSelectedElement();\n\n\t\t// If the element the resizer is created for is currently focused, it should become visible.\n\t\tif ( this.getResizerByViewElement( selectedElement ) == resizer ) {\n\t\t\tthis.visibleResizer = resizer;\n\t\t}\n\n\t\treturn resizer;\n\t}\n\n\t/**\n\t * Returns a resizer created for a given view element (widget element).\n\t *\n\t * @param {module:engine/view/containerelement~ContainerElement} viewElement View element associated with the resizer.\n\t * @returns {module:widget/widgetresize/resizer~Resizer|undefined}\n\t */\n\tgetResizerByViewElement( viewElement ) {\n\t\treturn this._resizers.get( viewElement );\n\t}\n\n\t/**\n\t * Returns a resizer that contains a given resize handle.\n\t *\n\t * @protected\n\t * @param {HTMLElement} domResizeHandle\n\t * @returns {module:widget/widgetresize/resizer~Resizer}\n\t */\n\t_getResizerByHandle( domResizeHandle ) {\n\t\tfor ( const resizer of this._resizers.values() ) {\n\t\t\tif ( resizer.containsHandle( domResizeHandle ) ) {\n\t\t\t\treturn resizer;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * @protected\n\t * @param {module:utils/eventinfo~EventInfo} event\n\t * @param {Event} domEventData Native DOM event.\n\t */\n\t_mouseDownListener( event, domEventData ) {\n\t\tconst resizeHandle = domEventData.domTarget;\n\n\t\tif ( !Resizer.isResizeHandle( resizeHandle ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._activeResizer = this._getResizerByHandle( resizeHandle );\n\n\t\tif ( this._activeResizer ) {\n\t\t\tthis._activeResizer.begin( resizeHandle );\n\n\t\t\t// Do not call other events when resizing. See: #6755.\n\t\t\tevent.stop();\n\t\t\tdomEventData.preventDefault();\n\t\t}\n\t}\n\n\t/**\n\t * @protected\n\t * @param {module:utils/eventinfo~EventInfo} event\n\t * @param {Event} domEventData Native DOM event.\n\t */\n\t_mouseMoveListener( event, domEventData ) {\n\t\tif ( this._activeResizer ) {\n\t\t\tthis._activeResizer.updateSize( domEventData );\n\t\t}\n\t}\n\n\t/**\n\t * @protected\n\t */\n\t_mouseUpListener() {\n\t\tif ( this._activeResizer ) {\n\t\t\tthis._activeResizer.commit();\n\t\t\tthis._activeResizer = null;\n\t\t}\n\t}\n}\n\nmix( WidgetResize, ObservableMixin );\n\n/**\n * Interface describing a resizer. It allows to specify the resizing host, custom logic for calculating aspect ratio, etc.\n *\n * @interface ResizerOptions\n */\n\n/**\n * Editor instance associated with the resizer.\n *\n * @member {module:core/editor/editor~Editor} module:widget/widgetresize~ResizerOptions#editor\n */\n\n/**\n * @member {module:engine/model/element~Element} module:widget/widgetresize~ResizerOptions#modelElement\n */\n\n/**\n * A view of an element to be resized. Typically it's the main widget's view instance.\n *\n * @member {module:engine/view/containerelement~ContainerElement} module:widget/widgetresize~ResizerOptions#viewElement\n */\n\n/**\n * A callback to be executed once the resizing process is done.\n *\n * It receives a `Number` (`newValue`) as a parameter.\n *\n * For example, {@link module:image/imageresize~ImageResize} uses it to execute the resize image command\n * which puts the new value into the model.\n *\n * ```js\n * {\n *\teditor,\n *\tmodelElement: data.item,\n *\tviewElement: widget,\n *\n *\tonCommit( newValue ) {\n *\t\teditor.execute( 'resizeImage', { width: newValue } );\n *\t}\n * };\n * ```\n *\n *\n * @member {Function} module:widget/widgetresize~ResizerOptions#onCommit\n */\n\n/**\n * @member {Function} module:widget/widgetresize~ResizerOptions#getResizeHost\n */\n\n/**\n * @member {Function} module:widget/widgetresize~ResizerOptions#isCentered\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 image/image/imageloadobserver\n */\n\nimport { Observer } from 'ckeditor5/src/engine';\n\n/**\n * Observes all new images added to the {@link module:engine/view/document~Document},\n * fires {@link module:engine/view/document~Document#event:imageLoaded} and\n * {@link module:engine/view/document~Document#event:layoutChanged} event every time when the new image\n * has been loaded.\n *\n * **Note:** This event is not fired for images that has been added to the document and rendered as `complete` (already loaded).\n *\n * @extends module:engine/view/observer/observer~Observer\n */\nexport default class ImageLoadObserver extends Observer {\n\t/**\n\t * @inheritDoc\n\t */\n\tobserve( domRoot ) {\n\t\tthis.listenTo( domRoot, 'load', ( event, domEvent ) => {\n\t\t\tconst domElement = domEvent.target;\n\n\t\t\tif ( this.checkShouldIgnoreEventFromTarget( domElement ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( domElement.tagName == 'IMG' ) {\n\t\t\t\tthis._fireEvents( domEvent );\n\t\t\t}\n\t\t\t// Use capture phase for better performance (#4504).\n\t\t}, { useCapture: true } );\n\t}\n\n\t/**\n\t * Fires {@link module:engine/view/document~Document#event:layoutChanged} and\n\t * {@link module:engine/view/document~Document#event:imageLoaded}\n\t * if observer {@link #isEnabled is enabled}.\n\t *\n\t * @protected\n\t * @param {Event} domEvent The DOM event.\n\t */\n\t_fireEvents( domEvent ) {\n\t\tif ( this.isEnabled ) {\n\t\t\tthis.document.fire( 'layoutChanged' );\n\t\t\tthis.document.fire( 'imageLoaded', domEvent );\n\t\t}\n\t}\n}\n\n/**\n * Fired when an <img/> DOM element has been loaded in the DOM root.\n *\n * Introduced by {@link module:image/image/imageloadobserver~ImageLoadObserver}.\n *\n * @see module:image/image/imageloadobserver~ImageLoadObserver\n * @event module:engine/view/document~Document#event:imageLoaded\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\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 image/image/utils\n */\n\nimport { findOptimalInsertionPosition, checkSelectionOnObject, isWidget, toWidget } from 'ckeditor5/src/widget';\n\n/**\n * Converts a given {@link module:engine/view/element~Element} to an image widget:\n * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the image widget element.\n * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n * @param {String} label The element's label. It will be concatenated with the image `alt` attribute if one is present.\n * @returns {module:engine/view/element~Element}\n */\nexport function toImageWidget( viewElement, writer, label ) {\n\twriter.setCustomProperty( 'image', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { label: labelCreator } );\n\n\tfunction labelCreator() {\n\t\tconst imgElement = getViewImgFromWidget( viewElement );\n\t\tconst altText = imgElement.getAttribute( 'alt' );\n\n\t\treturn altText ? `${ altText } ${ label }` : label;\n\t}\n}\n\n/**\n * Checks if a given view element is an image widget.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isImageWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'image' ) && isWidget( viewElement );\n}\n\n/**\n * Returns an image widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedImageWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isImageWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Checks if the provided model element is an `image`.\n *\n * @param {module:engine/model/element~Element} modelElement\n * @returns {Boolean}\n */\nexport function isImage( modelElement ) {\n\treturn !!modelElement && modelElement.is( 'element', 'image' );\n}\n\n/**\n * Handles inserting single file. This method unifies image insertion using {@link module:widget/utils~findOptimalInsertionPosition} method.\n *\n *\t\tinsertImage( model, { src: 'path/to/image.jpg' } );\n *\n * @param {module:engine/model/model~Model} model\n * @param {Object} [attributes={}] Attributes of inserted image\n * @param {module:engine/model/position~Position} [insertPosition] Position to insert the image. If not specified,\n * the {@link module:widget/utils~findOptimalInsertionPosition} logic will be applied.\n */\nexport function insertImage( model, attributes = {}, insertPosition = null ) {\n\tmodel.change( writer => {\n\t\tconst imageElement = writer.createElement( 'image', attributes );\n\n\t\tconst insertAtSelection = insertPosition || findOptimalInsertionPosition( model.document.selection, model );\n\n\t\tmodel.insertContent( imageElement, insertAtSelection );\n\n\t\t// Inserting an image might've failed due to schema regulations.\n\t\tif ( imageElement.parent ) {\n\t\t\twriter.setSelection( imageElement, 'on' );\n\t\t}\n\t} );\n}\n\n/**\n * Checks if image can be inserted at current model selection.\n *\n * @param {module:engine/model/model~Model} model\n * @returns {Boolean}\n */\nexport function isImageAllowed( model ) {\n\tconst schema = model.schema;\n\tconst selection = model.document.selection;\n\n\treturn isImageAllowedInParent( selection, schema, model ) &&\n\t\t!checkSelectionOnObject( selection, schema ) &&\n\t\tisInOtherImage( selection );\n}\n\n/**\n * Get view `<img>` element from the view widget (`<figure>`).\n *\n * Assuming that image is always a first child of a widget (ie. `figureView.getChild( 0 )`) is unsafe as other features might\n * inject their own elements to the widget.\n *\n * The `<img>` can be wrapped to other elements, e.g. `<a>`. Nested check required.\n *\n * @param {module:engine/view/element~Element} figureView\n * @returns {module:engine/view/element~Element}\n */\nexport function getViewImgFromWidget( figureView ) {\n\tconst figureChildren = [];\n\n\tfor ( const figureChild of figureView.getChildren() ) {\n\t\tfigureChildren.push( figureChild );\n\n\t\tif ( figureChild.is( 'element' ) ) {\n\t\t\tfigureChildren.push( ...figureChild.getChildren() );\n\t\t}\n\t}\n\n\treturn figureChildren.find( viewChild => viewChild.is( 'element', 'img' ) );\n}\n\n// Checks if image is allowed by schema in optimal insertion parent.\n//\n// @returns {Boolean}\nfunction isImageAllowedInParent( selection, schema, model ) {\n\tconst parent = getInsertImageParent( selection, model );\n\n\treturn schema.checkChild( parent, 'image' );\n}\n\n// Checks if selection is placed in other image (ie. in caption).\nfunction isInOtherImage( selection ) {\n\treturn [ ...selection.focus.getAncestors() ].every( ancestor => !ancestor.is( 'element', 'image' ) );\n}\n\n// Returns a node that will be used to insert image with `model.insertContent` to check if image can be placed there.\nfunction getInsertImageParent( selection, model ) {\n\tconst insertAt = findOptimalInsertionPosition( selection, model );\n\n\tconst parent = insertAt.parent;\n\n\tif ( parent.isEmpty && !parent.is( 'element', '$root' ) ) {\n\t\treturn parent.parent;\n\t}\n\n\treturn parent;\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 image/image/converters\n */\n\nimport { first } from 'ckeditor5/src/utils';\nimport { getViewImgFromWidget } from './utils';\n\n/**\n * Returns a function that converts the image view representation:\n *\n *\t\t<figure class=\"image\"><img src=\"...\" alt=\"...\"></img></figure>\n *\n * to the model representation:\n *\n *\t\t<image src=\"...\" alt=\"...\"></image>\n *\n * The entire content of the `<figure>` element except the first `<img>` is being converted as children\n * of the `<image>` model element.\n *\n * @returns {Function}\n */\nexport function viewFigureToModel() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:figure', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\t// Do not convert if this is not an \"image figure\".\n\t\tif ( !conversionApi.consumable.test( data.viewItem, { name: true, classes: 'image' } ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Find an image element inside the figure element.\n\t\tconst viewImage = getViewImgFromWidget( data.viewItem );\n\n\t\t// Do not convert if image element is absent, is missing src attribute or was already converted.\n\t\tif ( !viewImage || !viewImage.hasAttribute( 'src' ) || !conversionApi.consumable.test( viewImage, { name: true } ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert view image to model image.\n\t\tconst conversionResult = conversionApi.convertItem( viewImage, data.modelCursor );\n\n\t\t// Get image element from conversion result.\n\t\tconst modelImage = first( conversionResult.modelRange.getItems() );\n\n\t\t// When image wasn't successfully converted then finish conversion.\n\t\tif ( !modelImage ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert rest of the figure element's children as an image children.\n\t\tconversionApi.convertChildren( data.viewItem, modelImage );\n\n\t\tconversionApi.updateConversionResult( modelImage, data );\n\t}\n}\n\n/**\n * Converter used to convert the `srcset` model image attribute to the `srcset`, `sizes` and `width` attributes in the view.\n *\n * @returns {Function}\n */\nexport function srcsetAttributeConverter() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'attribute:srcset:image', converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst writer = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\t\tconst img = getViewImgFromWidget( figure );\n\n\t\tif ( data.attributeNewValue === null ) {\n\t\t\tconst srcset = data.attributeOldValue;\n\n\t\t\tif ( srcset.data ) {\n\t\t\t\twriter.removeAttribute( 'srcset', img );\n\t\t\t\twriter.removeAttribute( 'sizes', img );\n\n\t\t\t\tif ( srcset.width ) {\n\t\t\t\t\twriter.removeAttribute( 'width', img );\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tconst srcset = data.attributeNewValue;\n\n\t\t\tif ( srcset.data ) {\n\t\t\t\twriter.setAttribute( 'srcset', srcset.data, img );\n\t\t\t\t// Always outputting `100vw`. See https://github.com/ckeditor/ckeditor5-image/issues/2.\n\t\t\t\twriter.setAttribute( 'sizes', '100vw', img );\n\n\t\t\t\tif ( srcset.width ) {\n\t\t\t\t\twriter.setAttribute( 'width', srcset.width, img );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function modelToViewAttributeConverter( attributeKey ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( `attribute:${ attributeKey }:image`, converter );\n\t};\n\n\tfunction converter( evt, data, conversionApi ) {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\t\tconst img = getViewImgFromWidget( figure );\n\n\t\tviewWriter.setAttribute( data.attributeKey, data.attributeNewValue || '', img );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { toArray } from 'ckeditor5/src/utils';\n\nimport { insertImage, isImageAllowed } from './utils';\n\n/**\n * @module image/image/insertimagecommand\n */\n\n/**\n * Insert image command.\n *\n * The command is registered by the {@link module:image/image/imageediting~ImageEditing} plugin as `insertImage`\n * and it is also available via aliased `imageInsert` name.\n *\n * In order to insert an image at the current selection position\n * (according to the {@link module:widget/utils~findOptimalInsertionPosition} algorithm),\n * execute the command and specify the image source:\n *\n *\t\teditor.execute( 'insertImage', { source: 'http://url.to.the/image' } );\n *\n * It is also possible to insert multiple images at once:\n *\n *\t\teditor.execute( 'insertImage', {\n *\t\t\tsource: [\n *\t\t\t\t'path/to/image.jpg',\n *\t\t\t\t'path/to/other-image.jpg'\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertImageCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = isImageAllowed( this.editor.model );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options Options for the executed command.\n\t * @param {String|Array.<String>} options.source The image source or an array of image sources to insert.\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\n\t\tfor ( const src of toArray( options.source ) ) {\n\t\t\tinsertImage( model, { src } );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image/imageediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ImageLoadObserver from './imageloadobserver';\n\nimport {\n\tviewFigureToModel,\n\tmodelToViewAttributeConverter,\n\tsrcsetAttributeConverter\n} from './converters';\n\nimport { toImageWidget } from './utils';\n\nimport InsertImageCommand from './insertimagecommand';\n\n/**\n * The image engine plugin.\n *\n * It registers:\n *\n * * `<image>` as a block element in the document schema, and allows `alt`, `src` and `srcset` attributes.\n * * converters for editing and data pipelines.\n * * `'insertImage'` command.\n * * `'imageInsert'` command as an alias for `insertImage` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.t;\n\t\tconst conversion = editor.conversion;\n\n\t\t// See https://github.com/ckeditor/ckeditor5-image/issues/142.\n\t\teditor.editing.view.addObserver( ImageLoadObserver );\n\n\t\t// Configure schema.\n\t\tschema.register( 'image', {\n\t\t\tisObject: true,\n\t\t\tisBlock: true,\n\t\t\tallowWhere: '$block',\n\t\t\tallowAttributes: [ 'alt', 'src', 'srcset' ]\n\t\t} );\n\n\t\tconversion.for( 'dataDowncast' ).elementToElement( {\n\t\t\tmodel: 'image',\n\t\t\tview: ( modelElement, { writer } ) => createImageViewElement( writer )\n\t\t} );\n\n\t\tconversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'image',\n\t\t\tview: ( modelElement, { writer } ) => toImageWidget( createImageViewElement( writer ), writer, t( 'image widget' ) )\n\t\t} );\n\n\t\tconversion.for( 'downcast' )\n\t\t\t.add( modelToViewAttributeConverter( 'src' ) )\n\t\t\t.add( modelToViewAttributeConverter( 'alt' ) )\n\t\t\t.add( srcsetAttributeConverter() );\n\n\t\tconversion.for( 'upcast' )\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tsrc: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: ( viewImage, { writer } ) => writer.createElement( 'image', { src: viewImage.getAttribute( 'src' ) } )\n\t\t\t} )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tkey: 'alt'\n\t\t\t\t},\n\t\t\t\tmodel: 'alt'\n\t\t\t} )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tkey: 'srcset'\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: 'srcset',\n\t\t\t\t\tvalue: viewImage => {\n\t\t\t\t\t\tconst value = {\n\t\t\t\t\t\t\tdata: viewImage.getAttribute( 'srcset' )\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif ( viewImage.hasAttribute( 'width' ) ) {\n\t\t\t\t\t\t\tvalue.width = viewImage.getAttribute( 'width' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.add( viewFigureToModel() );\n\n\t\tconst insertImageCommand = new InsertImageCommand( editor );\n\n\t\t// Register `insertImage` command and add `imageInsert` command as an alias for backward compatibility.\n\t\teditor.commands.add( 'insertImage', insertImageCommand );\n\t\teditor.commands.add( 'imageInsert', insertImageCommand );\n\t}\n}\n\n// Creates a view element representing the image.\n//\n//\t\t<figure class=\"image\"><img></img></figure>\n//\n// Note that `alt` and `src` attributes are converted separately, so they are not included.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/containerelement~ContainerElement}\nexport function createImageViewElement( writer ) {\n\tconst emptyElement = writer.createEmptyElement( 'img' );\n\tconst figure = writer.createContainerElement( 'figure', { class: 'image' } );\n\n\twriter.insert( writer.createPositionAt( figure, 0 ), emptyElement );\n\n\treturn figure;\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 image/imagetextalternative/imagetextalternativecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { isImage } from '../image/utils';\n\n/**\n * The image text alternative command. It is used to change the `alt` attribute of `<image>` elements.\n *\n * @extends module:core/command~Command\n */\nexport default class ImageTextAlternativeCommand extends Command {\n\t/**\n\t * The command value: `false` if there is no `alt` attribute, otherwise the value of the `alt` attribute.\n\t *\n\t * @readonly\n\t * @observable\n\t * @member {String|Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( isImage( element ) && element.hasAttribute( 'alt' ) ) {\n\t\t\tthis.value = element.getAttribute( 'alt' );\n\t\t} else {\n\t\t\tthis.value = false;\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options\n\t * @param {String} options.newValue The new value of the `alt` attribute to set.\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setAttribute( 'alt', options.newValue, imageElement );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative/imagetextalternativeediting\n */\n\nimport ImageTextAlternativeCommand from './imagetextalternativecommand';\nimport { Plugin } from 'ckeditor5/src/core';\n\n/**\n * The image text alternative editing plugin.\n *\n * Registers the `'imageTextAlternative'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternativeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternativeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis.editor.commands.add( 'imageTextAlternative', new ImageTextAlternativeCommand( this.editor ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative/ui/textalternativeformview\n */\n\nimport {\n\tButtonView,\n\tFocusCycler,\n\tLabeledFieldView,\n\tView,\n\tViewCollection,\n\tcreateLabeledInputText,\n\tinjectCssTransitionDisabler,\n\tsubmitHandler\n} from 'ckeditor5/src/ui';\nimport { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\nimport '../../../theme/textalternativeform.css';\n\n// See: #8833.\n// eslint-disable-next-line ckeditor5-rules/ckeditor-imports\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\n\n/**\n * The TextAlternativeFormView class.\n *\n * @extends module:ui/view~View\n */\nexport default class TextAlternativeFormView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = this.locale.t;\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * An input with a label.\n\t\t *\n\t\t * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView} #labeledInput\n\t\t */\n\t\tthis.labeledInput = this._createLabeledInputView();\n\n\t\t/**\n\t\t * A button used to submit the form.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView} #saveButtonView\n\t\t */\n\t\tthis.saveButtonView = this._createButton( t( 'Save' ), icons.check, 'ck-button-save' );\n\t\tthis.saveButtonView.type = 'submit';\n\n\t\t/**\n\t\t * A button used to cancel the form.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView} #cancelButtonView\n\t\t */\n\t\tthis.cancelButtonView = this._createButton( t( 'Cancel' ), icons.cancel, 'ck-button-cancel', 'cancel' );\n\n\t\t/**\n\t\t * A collection of views which can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-text-alternative-form',\n\t\t\t\t\t'ck-responsive-form'\n\t\t\t\t],\n\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-image/issues/40\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tthis.labeledInput,\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t]\n\t\t} );\n\n\t\tinjectCssTransitionDisabler( this );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.keystrokes.listenTo( this.element );\n\n\t\tsubmitHandler( { view: this } );\n\n\t\t[ this.labeledInput, this.saveButtonView, this.cancelButtonView ]\n\t\t\t.forEach( v => {\n\t\t\t\t// Register the view as focusable.\n\t\t\t\tthis._focusables.add( v );\n\n\t\t\t\t// Register the view in the focus tracker.\n\t\t\t\tthis.focusTracker.add( v.element );\n\t\t\t} );\n\t}\n\n\t/**\n\t * Creates the button view.\n\t *\n\t * @private\n\t * @param {String} label The button label\n\t * @param {String} icon The button's icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] The event name that the ButtonView#execute event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, className, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: className\n\t\t\t}\n\t\t} );\n\n\t\tif ( eventName ) {\n\t\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\t\t}\n\n\t\treturn button;\n\t}\n\n\t/**\n\t * Creates an input with a label.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView} Labeled field view instance.\n\t */\n\t_createLabeledInputView() {\n\t\tconst t = this.locale.t;\n\t\tconst labeledInput = new LabeledFieldView( this.locale, createLabeledInputText );\n\n\t\tlabeledInput.label = t( 'Text alternative' );\n\n\t\treturn labeledInput;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/image/ui/utils\n */\n\nimport { BalloonPanelView } from 'ckeditor5/src/ui';\nimport { getSelectedImageWidget } from '../utils';\n\n/**\n * A helper utility that positions the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} instance\n * with respect to the image in the editor content, if one is selected.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n */\nexport function repositionContextualBalloon( editor ) {\n\tconst balloon = editor.plugins.get( 'ContextualBalloon' );\n\n\tif ( getSelectedImageWidget( editor.editing.view.document.selection ) ) {\n\t\tconst position = getBalloonPositionData( editor );\n\n\t\tballoon.updatePosition( position );\n\t}\n}\n\n/**\n * Returns the positioning options that control the geometry of the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} with respect\n * to the selected element in the editor content.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @returns {module:utils/dom/position~Options}\n */\nexport function getBalloonPositionData( editor ) {\n\tconst editingView = editor.editing.view;\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\treturn {\n\t\ttarget: editingView.domConverter.viewToDom( editingView.document.selection.getSelectedElement() ),\n\t\tpositions: [\n\t\t\tdefaultPositions.northArrowSouth,\n\t\t\tdefaultPositions.northArrowSouthWest,\n\t\t\tdefaultPositions.northArrowSouthEast,\n\t\t\tdefaultPositions.southArrowNorth,\n\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\tdefaultPositions.southArrowNorthEast\n\t\t]\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative/imagetextalternativeui\n */\n\nimport { Plugin, icons } from 'ckeditor5/src/core';\nimport { ButtonView, ContextualBalloon, clickOutsideHandler } from 'ckeditor5/src/ui';\n\nimport TextAlternativeFormView from './ui/textalternativeformview';\nimport { repositionContextualBalloon, getBalloonPositionData } from '../image/ui/utils';\nimport { getSelectedImageWidget } from '../image/utils';\n\n/**\n * The image text alternative UI plugin.\n *\n * The plugin uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternativeUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternativeUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis._createButton();\n\t\tthis._createForm();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis._form.destroy();\n\t}\n\n\t/**\n\t * Creates a button showing the balloon panel for changing the image text alternative and\n\t * registers it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.\n\t *\n\t * @private\n\t */\n\t_createButton() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\teditor.ui.componentFactory.add( 'imageTextAlternative', locale => {\n\t\t\tconst command = editor.commands.get( 'imageTextAlternative' );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Change image text alternative' ),\n\t\t\t\ticon: icons.lowVision,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isEnabled' ).to( command, 'isEnabled' );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\tthis._showForm();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n\n\t/**\n\t * Creates the {@link module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}\n\t * form.\n\t *\n\t * @private\n\t */\n\t_createForm() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = this.editor.plugins.get( 'ContextualBalloon' );\n\n\t\t/**\n\t\t * A form containing a textarea and buttons, used to change the `alt` text value.\n\t\t *\n\t\t * @member {module:image/imagetextalternative/ui/textalternativeformview~TextAlternativeFormView}\n\t\t */\n\t\tthis._form = new TextAlternativeFormView( editor.locale );\n\n\t\t// Render the form so its #element is available for clickOutsideHandler.\n\t\tthis._form.render();\n\n\t\tthis.listenTo( this._form, 'submit', () => {\n\t\t\teditor.execute( 'imageTextAlternative', {\n\t\t\t\tnewValue: this._form.labeledInput.fieldView.element.value\n\t\t\t} );\n\n\t\t\tthis._hideForm( true );\n\t\t} );\n\n\t\tthis.listenTo( this._form, 'cancel', () => {\n\t\t\tthis._hideForm( true );\n\t\t} );\n\n\t\t// Close the form on Esc key press.\n\t\tthis._form.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._hideForm( true );\n\t\t\tcancel();\n\t\t} );\n\n\t\t// Reposition the balloon or hide the form if an image widget is no longer selected.\n\t\tthis.listenTo( editor.ui, 'update', () => {\n\t\t\tif ( !getSelectedImageWidget( viewDocument.selection ) ) {\n\t\t\t\tthis._hideForm( true );\n\t\t\t} else if ( this._isVisible ) {\n\t\t\t\trepositionContextualBalloon( editor );\n\t\t\t}\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this._form,\n\t\t\tactivator: () => this._isVisible,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideForm()\n\t\t} );\n\t}\n\n\t/**\n\t * Shows the {@link #_form} in the {@link #_balloon}.\n\t *\n\t * @private\n\t */\n\t_showForm() {\n\t\tif ( this._isVisible ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'imageTextAlternative' );\n\t\tconst labeledInput = this._form.labeledInput;\n\n\t\tthis._form.disableCssTransitions();\n\n\t\tif ( !this._isInBalloon ) {\n\t\t\tthis._balloon.add( {\n\t\t\t\tview: this._form,\n\t\t\t\tposition: getBalloonPositionData( editor )\n\t\t\t} );\n\t\t}\n\n\t\t// Make sure that each time the panel shows up, the field remains in sync with the value of\n\t\t// the command. If the user typed in the input, then canceled the balloon (`labeledInput#value`\n\t\t// stays unaltered) and re-opened it without changing the value of the command, they would see the\n\t\t// old value instead of the actual value of the command.\n\t\t// https://github.com/ckeditor/ckeditor5-image/issues/114\n\t\tlabeledInput.fieldView.value = labeledInput.fieldView.element.value = command.value || '';\n\n\t\tthis._form.labeledInput.fieldView.select();\n\n\t\tthis._form.enableCssTransitions();\n\t}\n\n\t/**\n\t * Removes the {@link #_form} from the {@link #_balloon}.\n\t *\n\t * @param {Boolean} [focusEditable=false] Controls whether the editing view is focused afterwards.\n\t * @private\n\t */\n\t_hideForm( focusEditable ) {\n\t\tif ( !this._isInBalloon ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Blur the input element before removing it from DOM to prevent issues in some browsers.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1501.\n\t\tif ( this._form.focusTracker.isFocused ) {\n\t\t\tthis._form.saveButtonView.focus();\n\t\t}\n\n\t\tthis._balloon.remove( this._form );\n\n\t\tif ( focusEditable ) {\n\t\t\tthis.editor.editing.view.focus();\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #_form} is the visible view in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isVisible() {\n\t\treturn this._balloon.visibleView === this._form;\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #_form} is in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isInBalloon() {\n\t\treturn this._balloon.hasView( this._form );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagetextalternative\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ImageTextAlternativeEditing from './imagetextalternative/imagetextalternativeediting';\nimport ImageTextAlternativeUI from './imagetextalternative/imagetextalternativeui';\n\n/**\n * The image text alternative plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-styles image styles} documentation.\n *\n * This is a \"glue\" plugin which loads the\n * {@link module:image/imagetextalternative/imagetextalternativeediting~ImageTextAlternativeEditing}\n * and {@link module:image/imagetextalternative/imagetextalternativeui~ImageTextAlternativeUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageTextAlternative extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageTextAlternativeEditing, ImageTextAlternativeUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageTextAlternative';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagecaption/utils\n */\n\nimport { enablePlaceholder } from 'ckeditor5/src/engine';\nimport { toWidgetEditable } from 'ckeditor5/src/widget';\n\n/**\n * Returns a function that creates a caption editable element for the given {@link module:engine/view/document~Document}.\n *\n * @param {module:engine/view/view~View} view\n * @param {String} placeholderText The text to be displayed when the caption is empty.\n * @returns {Function}\n */\nexport function captionElementCreator( view, placeholderText ) {\n\treturn writer => {\n\t\tconst editable = writer.createEditableElement( 'figcaption' );\n\t\twriter.setCustomProperty( 'imageCaption', true, editable );\n\n\t\tenablePlaceholder( {\n\t\t\tview,\n\t\t\telement: editable,\n\t\t\ttext: placeholderText\n\t\t} );\n\n\t\treturn toWidgetEditable( editable, writer );\n\t};\n}\n\n/**\n * Returns `true` if a given view element is the image caption editable.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @returns {Boolean}\n */\nexport function isCaption( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'imageCaption' );\n}\n\n/**\n * Returns the caption model element from a given image element. Returns `null` if no caption is found.\n *\n * @param {module:engine/model/element~Element} imageModelElement\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getCaptionFromImage( imageModelElement ) {\n\tfor ( const node of imageModelElement.getChildren() ) {\n\t\tif ( !!node && node.is( 'element', 'caption' ) ) {\n\t\t\treturn node;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * {@link module:engine/view/matcher~Matcher} pattern. Checks if a given element is a `<figcaption>` element that is placed\n * inside the image `<figure>` element.\n *\n * @param {module:engine/view/element~Element} element\n * @returns {Object|null} Returns the object accepted by {@link module:engine/view/matcher~Matcher} or `null` if the element\n * cannot be matched.\n */\nexport function matchImageCaption( element ) {\n\tconst parent = element.parent;\n\n\t// Convert only captions for images.\n\tif ( element.name == 'figcaption' && parent && parent.name == 'figure' && parent.hasClass( 'image' ) ) {\n\t\treturn { name: true };\n\t}\n\n\treturn null;\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 image/imagecaption/imagecaptionediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { isImage } from '../image/utils';\nimport { captionElementCreator, getCaptionFromImage, matchImageCaption } from './utils';\n\n/**\n * The image caption engine plugin.\n *\n * It registers proper converters. It takes care of adding a caption element if the image without it is inserted\n * to the model document.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageCaptionEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageCaptionEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst schema = editor.model.schema;\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\t\tconst t = editor.t;\n\n\t\t/**\n\t\t * The last selected caption editable.\n\t\t * It is used for hiding the editable when it is empty and the image widget is no longer selected.\n\t\t *\n\t\t * @private\n\t\t * @member {module:engine/view/editableelement~EditableElement} #_lastSelectedCaption\n\t\t */\n\n\t\t// Schema configuration.\n\t\tschema.register( 'caption', {\n\t\t\tallowIn: 'image',\n\t\t\tallowContentOf: '$block',\n\t\t\tisLimit: true\n\t\t} );\n\n\t\t// Add caption element to each image inserted without it.\n\t\teditor.model.document.registerPostFixer( writer => this._insertMissingModelCaptionElement( writer ) );\n\n\t\t// View to model converter for the data pipeline.\n\t\teditor.conversion.for( 'upcast' ).elementToElement( {\n\t\t\tview: matchImageCaption,\n\t\t\tmodel: 'caption'\n\t\t} );\n\n\t\t// Model to view converter for the data pipeline.\n\t\tconst createCaptionForData = writer => writer.createContainerElement( 'figcaption' );\n\t\tdata.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForData, false ) );\n\n\t\t// Model to view converter for the editing pipeline.\n\t\tconst createCaptionForEditing = captionElementCreator( view, t( 'Enter image caption' ) );\n\t\tediting.downcastDispatcher.on( 'insert:caption', captionModelToView( createCaptionForEditing ) );\n\n\t\t// Always show caption in view when something is inserted in model.\n\t\tediting.downcastDispatcher.on(\n\t\t\t'insert',\n\t\t\tthis._fixCaptionVisibility( data => data.item ),\n\t\t\t{ priority: 'high' }\n\t\t);\n\n\t\t// Hide caption when everything is removed from it.\n\t\tediting.downcastDispatcher.on( 'remove', this._fixCaptionVisibility( data => data.position.parent ), { priority: 'high' } );\n\n\t\t// Update caption visibility on view in post fixer.\n\t\tview.document.registerPostFixer( writer => this._updateCaptionVisibility( writer ) );\n\t}\n\n\t/**\n\t * Updates the view before each rendering, making sure that empty captions (so unnecessary ones) are hidden\n\t * and then visible when the image is selected.\n\t *\n\t * @private\n\t * @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n\t * @returns {Boolean} Returns `true` when the view is updated.\n\t */\n\t_updateCaptionVisibility( viewWriter ) {\n\t\tconst mapper = this.editor.editing.mapper;\n\t\tconst lastCaption = this._lastSelectedCaption;\n\t\tlet viewCaption;\n\n\t\t// If whole image is selected.\n\t\tconst modelSelection = this.editor.model.document.selection;\n\t\tconst selectedElement = modelSelection.getSelectedElement();\n\n\t\tif ( selectedElement && selectedElement.is( 'element', 'image' ) ) {\n\t\t\tconst modelCaption = getCaptionFromImage( selectedElement );\n\t\t\tviewCaption = mapper.toViewElement( modelCaption );\n\t\t}\n\n\t\t// If selection is placed inside caption.\n\t\tconst position = modelSelection.getFirstPosition();\n\t\tconst modelCaption = getParentCaption( position.parent );\n\n\t\tif ( modelCaption ) {\n\t\t\tviewCaption = mapper.toViewElement( modelCaption );\n\t\t}\n\n\t\t// Is currently any caption selected?\n\t\tif ( viewCaption && !this.editor.isReadOnly ) {\n\t\t\t// Was any caption selected before?\n\t\t\tif ( lastCaption ) {\n\t\t\t\t// Same caption as before?\n\t\t\t\tif ( lastCaption === viewCaption ) {\n\t\t\t\t\treturn showCaption( viewCaption, viewWriter );\n\t\t\t\t} else {\n\t\t\t\t\thideCaptionIfEmpty( lastCaption, viewWriter );\n\t\t\t\t\tthis._lastSelectedCaption = viewCaption;\n\n\t\t\t\t\treturn showCaption( viewCaption, viewWriter );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._lastSelectedCaption = viewCaption;\n\t\t\t\treturn showCaption( viewCaption, viewWriter );\n\t\t\t}\n\t\t} else {\n\t\t\t// Was any caption selected before?\n\t\t\tif ( lastCaption ) {\n\t\t\t\tconst viewModified = hideCaptionIfEmpty( lastCaption, viewWriter );\n\t\t\t\tthis._lastSelectedCaption = null;\n\n\t\t\t\treturn viewModified;\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns a converter that fixes caption visibility during the model-to-view conversion.\n\t * Checks if the changed node is placed inside the caption element and fixes its visibility in the view.\n\t *\n\t * @private\n\t * @param {Function} nodeFinder\n\t * @returns {Function}\n\t */\n\t_fixCaptionVisibility( nodeFinder ) {\n\t\treturn ( evt, data, conversionApi ) => {\n\t\t\tconst node = nodeFinder( data );\n\t\t\tconst modelCaption = getParentCaption( node );\n\t\t\tconst mapper = this.editor.editing.mapper;\n\t\t\tconst viewWriter = conversionApi.writer;\n\n\t\t\tif ( modelCaption ) {\n\t\t\t\tconst viewCaption = mapper.toViewElement( modelCaption );\n\n\t\t\t\tif ( viewCaption ) {\n\t\t\t\t\tif ( modelCaption.childCount ) {\n\t\t\t\t\t\tviewWriter.removeClass( 'ck-hidden', viewCaption );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tviewWriter.addClass( 'ck-hidden', viewCaption );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Checks whether the data inserted to the model document have an image element that has no caption element inside it.\n\t * If there is none, it adds it to the image element.\n\t *\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer The writer to make changes with.\n\t * @returns {Boolean} `true` if any change was applied, `false` otherwise.\n\t */\n\t_insertMissingModelCaptionElement( writer ) {\n\t\tconst model = this.editor.model;\n\t\tconst changes = model.document.differ.getChanges();\n\n\t\tconst imagesWithoutCaption = [];\n\n\t\tfor ( const entry of changes ) {\n\t\t\tif ( entry.type == 'insert' && entry.name != '$text' ) {\n\t\t\t\tconst item = entry.position.nodeAfter;\n\n\t\t\t\tif ( item.is( 'element', 'image' ) && !getCaptionFromImage( item ) ) {\n\t\t\t\t\timagesWithoutCaption.push( item );\n\t\t\t\t}\n\n\t\t\t\t// Check elements with children for nested images.\n\t\t\t\tif ( !item.is( 'element', 'image' ) && item.childCount ) {\n\t\t\t\t\tfor ( const nestedItem of model.createRangeIn( item ).getItems() ) {\n\t\t\t\t\t\tif ( nestedItem.is( 'element', 'image' ) && !getCaptionFromImage( nestedItem ) ) {\n\t\t\t\t\t\t\timagesWithoutCaption.push( nestedItem );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor ( const image of imagesWithoutCaption ) {\n\t\t\twriter.appendElement( 'caption', image );\n\t\t}\n\n\t\treturn !!imagesWithoutCaption.length;\n\t}\n}\n\n// Creates a converter that converts image caption model element to view element.\n//\n// @private\n// @param {Function} elementCreator\n// @param {Boolean} [hide=true] When set to `false` view element will not be inserted when it's empty.\n// @returns {Function}\nfunction captionModelToView( elementCreator, hide = true ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst captionElement = data.item;\n\n\t\t// Return if element shouldn't be present when empty.\n\t\tif ( !captionElement.childCount && !hide ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( isImage( captionElement.parent ) ) {\n\t\t\tif ( !conversionApi.consumable.consume( data.item, 'insert' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst viewImage = conversionApi.mapper.toViewElement( data.range.start.parent );\n\t\t\tconst viewCaption = elementCreator( conversionApi.writer );\n\t\t\tconst viewWriter = conversionApi.writer;\n\n\t\t\t// Hide if empty.\n\t\t\tif ( !captionElement.childCount ) {\n\t\t\t\tviewWriter.addClass( 'ck-hidden', viewCaption );\n\t\t\t}\n\n\t\t\tinsertViewCaptionAndBind( viewCaption, data.item, viewImage, conversionApi );\n\t\t}\n\t};\n}\n\n// Inserts `viewCaption` at the end of `viewImage` and binds it to `modelCaption`.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} viewCaption\n// @param {module:engine/model/element~Element} modelCaption\n// @param {module:engine/view/containerelement~ContainerElement} viewImage\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction insertViewCaptionAndBind( viewCaption, modelCaption, viewImage, conversionApi ) {\n\tconst viewPosition = conversionApi.writer.createPositionAt( viewImage, 'end' );\n\n\tconversionApi.writer.insert( viewPosition, viewCaption );\n\tconversionApi.mapper.bindElements( modelCaption, viewCaption );\n}\n\n// Checks if the provided node or one of its ancestors is a caption element, and returns it.\n//\n// @private\n// @param {module:engine/model/node~Node} node\n// @returns {module:engine/model/element~Element|null}\nfunction getParentCaption( node ) {\n\tconst ancestors = node.getAncestors( { includeSelf: true } );\n\tconst caption = ancestors.find( ancestor => ancestor.name == 'caption' );\n\n\tif ( caption && caption.parent && caption.parent.name == 'image' ) {\n\t\treturn caption;\n\t}\n\n\treturn null;\n}\n\n// Hides a given caption in the view if it is empty.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} caption\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @returns {Boolean} Returns `true` if the view was modified.\nfunction hideCaptionIfEmpty( caption, viewWriter ) {\n\tif ( !caption.childCount && !caption.hasClass( 'ck-hidden' ) ) {\n\t\tviewWriter.addClass( 'ck-hidden', caption );\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// Shows the caption.\n//\n// @private\n// @param {module:engine/view/containerelement~ContainerElement} caption\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @returns {Boolean} Returns `true` if the view was modified.\nfunction showCaption( caption, viewWriter ) {\n\tif ( caption.hasClass( 'ck-hidden' ) ) {\n\t\tviewWriter.removeClass( 'ck-hidden', caption );\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle/imagestylecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { isImage } from '../image/utils';\n\n/**\n * The image style command. It is used to apply different image styles.\n *\n * @extends module:core/command~Command\n */\nexport default class ImageStyleCommand extends Command {\n\t/**\n\t * Creates an instance of the image style command. Each command instance is handling one style.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles that this command supports.\n\t */\n\tconstructor( editor, styles ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The name of the default style, if it is present. If there is no default style, it defaults to `false`.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Boolean|String}\n\t\t */\n\t\tthis.defaultStyle = false;\n\n\t\t/**\n\t\t * A style handled by this command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} #styles\n\t\t */\n\t\tthis.styles = styles.reduce( ( styles, style ) => {\n\t\t\tstyles[ style.name ] = style;\n\n\t\t\tif ( style.isDefault ) {\n\t\t\t\tthis.defaultStyle = style.name;\n\t\t\t}\n\n\t\t\treturn styles;\n\t\t}, {} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( !element ) {\n\t\t\tthis.value = false;\n\t\t} else if ( element.hasAttribute( 'imageStyle' ) ) {\n\t\t\tconst attributeValue = element.getAttribute( 'imageStyle' );\n\t\t\tthis.value = this.styles[ attributeValue ] ? attributeValue : false;\n\t\t} else {\n\t\t\tthis.value = this.defaultStyle;\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t *\t\teditor.execute( 'imageStyle', { value: 'side' } );\n\t *\n\t * @param {Object} options\n\t * @param {String} options.value The name of the style (based on the\n\t * {@link module:image/image~ImageConfig#styles `image.styles`} configuration option).\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst styleName = options.value;\n\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\t// Default style means that there is no `imageStyle` attribute in the model.\n\t\t\t// https://github.com/ckeditor/ckeditor5-image/issues/147\n\t\t\tif ( this.styles[ styleName ].isDefault ) {\n\t\t\t\twriter.removeAttribute( 'imageStyle', imageElement );\n\t\t\t} else {\n\t\t\t\twriter.setAttribute( 'imageStyle', styleName, imageElement );\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * @module image/imagestyle/converters\n */\n\n/**\n * Returns a converter for the `imageStyle` attribute. It can be used for adding, changing and removing the attribute.\n *\n * @param {Object} styles An object containing available styles. See {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}\n * for more details.\n * @returns {Function} A model-to-view attribute converter.\n */\nexport function modelToViewStyleAttribute( styles ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if there is class name associated with given value.\n\t\tconst newStyle = getStyleByName( data.attributeNewValue, styles );\n\t\tconst oldStyle = getStyleByName( data.attributeOldValue, styles );\n\n\t\tconst viewElement = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\tif ( oldStyle ) {\n\t\t\tviewWriter.removeClass( oldStyle.className, viewElement );\n\t\t}\n\n\t\tif ( newStyle ) {\n\t\t\tviewWriter.addClass( newStyle.className, viewElement );\n\t\t}\n\t};\n}\n\n/**\n * Returns a view-to-model converter converting image CSS classes to a proper value in the model.\n *\n * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles The styles for which the converter is created.\n * @returns {Function} A view-to-model converter.\n */\nexport function viewToModelStyleAttribute( styles ) {\n\t// Convert only nondefault styles.\n\tconst filteredStyles = styles.filter( style => !style.isDefault );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !data.modelRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewFigureElement = data.viewItem;\n\t\tconst modelImageElement = first( data.modelRange.getItems() );\n\n\t\t// Check if `modelImageElement` exists (see: https://github.com/ckeditor/ckeditor5/issues/8270)\n\t\t// and `imageStyle` attribute is allowed for that element, otherwise stop conversion early.\n\t\tif ( modelImageElement && !conversionApi.schema.checkAttribute( modelImageElement, 'imageStyle' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Convert style one by one.\n\t\tfor ( const style of filteredStyles ) {\n\t\t\t// Try to consume class corresponding with style.\n\t\t\tif ( conversionApi.consumable.consume( viewFigureElement, { classes: style.className } ) ) {\n\t\t\t\t// And convert this style to model attribute.\n\t\t\t\tconversionApi.writer.setAttribute( 'imageStyle', style.name, modelImageElement );\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Returns the style with a given `name` from an array of styles.\n//\n// @param {String} name\n// @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat> } styles\n// @returns {module:image/imagestyle/imagestyleediting~ImageStyleFormat|undefined}\nfunction getStyleByName( name, styles ) {\n\tfor ( const style of styles ) {\n\t\tif ( style.name === name ) {\n\t\t\treturn style;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle/utils\n */\n\nimport { logWarning } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\n/**\n * Default image styles provided by the plugin that can be referred in the\n * {@link module:image/image~ImageConfig#styles} configuration.\n *\n * Among them, 2 default semantic content styles are available:\n *\n * * `full` is a fullwidth image without any CSS class,\n * * `side` is a side image styled with the `image-style-side` CSS class.\n *\n * There are also 3 styles focused on formatting:\n *\n * * `alignLeft` aligns the image to the left using the `image-style-align-left` class,\n * * `alignCenter` centers the image using the `image-style-align-center` class,\n * * `alignRight` aligns the image to the right using the `image-style-align-right` class,\n *\n * @member {Object.<String,Object>}\n */\nconst defaultStyles = {\n\t// This option is equal to the situation when no style is applied.\n\tfull: {\n\t\tname: 'full',\n\t\ttitle: 'Full size image',\n\t\ticon: icons.objectFullWidth,\n\t\tisDefault: true\n\t},\n\n\t// This represents a side image.\n\tside: {\n\t\tname: 'side',\n\t\ttitle: 'Side image',\n\t\ticon: icons.objectRight,\n\t\tclassName: 'image-style-side'\n\t},\n\n\t// This style represents an image aligned to the left.\n\talignLeft: {\n\t\tname: 'alignLeft',\n\t\ttitle: 'Left aligned image',\n\t\ticon: icons.objectLeft,\n\t\tclassName: 'image-style-align-left'\n\t},\n\n\t// This style represents a centered image.\n\talignCenter: {\n\t\tname: 'alignCenter',\n\t\ttitle: 'Centered image',\n\t\ticon: icons.objectCenter,\n\t\tclassName: 'image-style-align-center'\n\t},\n\n\t// This style represents an image aligned to the right.\n\talignRight: {\n\t\tname: 'alignRight',\n\t\ttitle: 'Right aligned image',\n\t\ticon: icons.objectRight,\n\t\tclassName: 'image-style-align-right'\n\t}\n};\n\n/**\n * Default image style icons provided by the plugin that can be referred in the\n * {@link module:image/image~ImageConfig#styles} configuration.\n *\n * There are 4 icons available: `'full'`, `'left'`, `'center'` and `'right'`.\n *\n * @member {Object.<String, String>}\n */\nconst defaultIcons = {\n\tfull: icons.objectFullWidth,\n\tleft: icons.objectLeft,\n\tright: icons.objectRight,\n\tcenter: icons.objectCenter\n};\n\n/**\n * Returns a {@link module:image/image~ImageConfig#styles} array with items normalized in the\n * {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat} format and a complete `icon` markup for each style.\n *\n * @returns {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}\n */\nexport function normalizeImageStyles( configuredStyles = [] ) {\n\treturn configuredStyles.map( _normalizeStyle );\n}\n\n// Normalizes an image style provided in the {@link module:image/image~ImageConfig#styles}\n// and returns it in a {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}.\n//\n// @param {Object} style\n// @returns {@link module:image/imagestyle/imagestyleediting~ImageStyleFormat}\nfunction _normalizeStyle( style ) {\n\t// Just the name of the style has been passed.\n\tif ( typeof style == 'string' ) {\n\t\tconst styleName = style;\n\n\t\t// If it's one of the defaults, just use it.\n\t\tif ( defaultStyles[ styleName ] ) {\n\t\t\t// Clone the style to avoid overriding defaults.\n\t\t\tstyle = Object.assign( {}, defaultStyles[ styleName ] );\n\t\t}\n\t\t// If it's just a name but none of the defaults, warn because probably it's a mistake.\n\t\telse {\n\t\t\t/**\n\t\t\t * There is no such image style of given name.\n\t\t\t *\n\t\t\t * @error image-style-not-found\n\t\t\t * @param {String} name Name of a missing style name.\n\t\t\t */\n\t\t\tlogWarning( 'image-style-not-found', { name: styleName } );\n\n\t\t\t// Normalize the style anyway to prevent errors.\n\t\t\tstyle = {\n\t\t\t\tname: styleName\n\t\t\t};\n\t\t}\n\t}\n\t// If an object style has been passed and if the name matches one of the defaults,\n\t// extend it with defaults the user wants to customize a default style.\n\t// Note: Don't override the userdefined style object, clone it instead.\n\telse if ( defaultStyles[ style.name ] ) {\n\t\tconst defaultStyle = defaultStyles[ style.name ];\n\t\tconst extendedStyle = Object.assign( {}, style );\n\n\t\tfor ( const prop in defaultStyle ) {\n\t\t\tif ( !Object.prototype.hasOwnProperty.call( style, prop ) ) {\n\t\t\t\textendedStyle[ prop ] = defaultStyle[ prop ];\n\t\t\t}\n\t\t}\n\n\t\tstyle = extendedStyle;\n\t}\n\n\t// If an icon is defined as a string and correspond with a name\n\t// in default icons, use the default icon provided by the plugin.\n\tif ( typeof style.icon == 'string' && defaultIcons[ style.icon ] ) {\n\t\tstyle.icon = defaultIcons[ style.icon ];\n\t}\n\n\treturn style;\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 image/imagestyle/imagestyleediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ImageStyleCommand from './imagestylecommand';\nimport { viewToModelStyleAttribute, modelToViewStyleAttribute } from './converters';\nimport { normalizeImageStyles } from './utils';\n\n/**\n * The image style engine plugin. It sets the default configuration, creates converters and registers\n * {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand ImageStyleCommand}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyleEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyleEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\n\t\t// Define default configuration.\n\t\teditor.config.define( 'image.styles', [ 'full', 'side' ] );\n\n\t\t// Get configuration.\n\t\tconst styles = normalizeImageStyles( editor.config.get( 'image.styles' ) );\n\n\t\t// Allow imageStyle attribute in image.\n\t\t// We could call it 'style' but https://github.com/ckeditor/ckeditor5-engine/issues/559.\n\t\tschema.extend( 'image', { allowAttributes: 'imageStyle' } );\n\n\t\t// Converters for imageStyle attribute from model to view.\n\t\tconst modelToViewConverter = modelToViewStyleAttribute( styles );\n\t\tediting.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );\n\t\tdata.downcastDispatcher.on( 'attribute:imageStyle:image', modelToViewConverter );\n\n\t\t// Converter for figure element from view to model.\n\t\tdata.upcastDispatcher.on( 'element:figure', viewToModelStyleAttribute( styles ), { priority: 'low' } );\n\n\t\t// Register imageStyle command.\n\t\teditor.commands.add( 'imageStyle', new ImageStyleCommand( editor, styles ) );\n\t}\n}\n\n/**\n * The image style format descriptor.\n *\n *\t\timport fullSizeIcon from 'path/to/icon.svg';\n *\n *\t\tconst imageStyleFormat = {\n *\t\t\tname: 'fullSize',\n *\t\t\ticon: fullSizeIcon,\n *\t\t\ttitle: 'Full size image',\n *\t\t\tclassName: 'image-full-size'\n *\t\t}\n *\n * @typedef {Object} module:image/imagestyle/imagestyleediting~ImageStyleFormat\n *\n * @property {String} name The unique name of the style. It will be used to:\n *\n * * Store the chosen style in the model by setting the `imageStyle` attribute of the `<image>` element.\n * * As a value of the {@link module:image/imagestyle/imagestylecommand~ImageStyleCommand#execute `imageStyle` command},\n * * when registering a button for each of the styles (`'imageStyle:{name}'`) in the\n * {@link module:ui/componentfactory~ComponentFactory UI components factory} (this functionality is provided by the\n * {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugin).\n *\n * @property {Boolean} [isDefault] When set, the style will be used as the default one.\n * A default style does not apply any CSS class to the view element.\n *\n * @property {String} icon One of the following to be used when creating the style's button:\n *\n * * An SVG icon source (as an XML string).\n * * One of {@link module:image/imagestyle/utils~defaultIcons} to use a default icon provided by the plugin.\n *\n * @property {String} title The style's title.\n *\n * @property {String} className The CSS class used to represent the style in the view.\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 image/imagestyle/imagestyleui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport { normalizeImageStyles } from './utils';\n\nimport '../../theme/imagestyle.css';\n\n/**\n * The image style UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyleUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyleUI';\n\t}\n\n\t/**\n\t * Returns the default localized style titles provided by the plugin.\n\t *\n\t * The following localized titles corresponding with\n\t * {@link module:image/imagestyle/utils~defaultStyles} are available:\n\t *\n\t * * `'Full size image'`,\n\t * * `'Side image'`,\n\t * * `'Left aligned image'`,\n\t * * `'Centered image'`,\n\t * * `'Right aligned image'`\n\t *\n\t * @returns {Object.<String,String>}\n\t */\n\tget localizedDefaultStylesTitles() {\n\t\tconst t = this.editor.t;\n\n\t\treturn {\n\t\t\t'Full size image': t( 'Full size image' ),\n\t\t\t'Side image': t( 'Side image' ),\n\t\t\t'Left aligned image': t( 'Left aligned image' ),\n\t\t\t'Centered image': t( 'Centered image' ),\n\t\t\t'Right aligned image': t( 'Right aligned image' )\n\t\t};\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst configuredStyles = editor.config.get( 'image.styles' );\n\n\t\tconst translatedStyles = translateStyles( normalizeImageStyles( configuredStyles ), this.localizedDefaultStylesTitles );\n\n\t\tfor ( const style of translatedStyles ) {\n\t\t\tthis._createButton( style );\n\t\t}\n\t}\n\n\t/**\n\t * Creates a button for each style and stores it in the editor {@link module:ui/componentfactory~ComponentFactory ComponentFactory}.\n\t *\n\t * @private\n\t * @param {module:image/imagestyle/imagestyleediting~ImageStyleFormat} style\n\t */\n\t_createButton( style ) {\n\t\tconst editor = this.editor;\n\n\t\tconst componentName = `imageStyle:${ style.name }`;\n\n\t\teditor.ui.componentFactory.add( componentName, locale => {\n\t\t\tconst command = editor.commands.get( 'imageStyle' );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: style.title,\n\t\t\t\ticon: style.icon,\n\t\t\t\ttooltip: true,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isEnabled' ).to( command, 'isEnabled' );\n\t\t\tview.bind( 'isOn' ).to( command, 'value', value => value === style.name );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( 'imageStyle', { value: style.name } );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n\n/**\n * Returns the translated `title` from the passed styles array.\n *\n * @param {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} styles\n * @param titles\n * @returns {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>}\n */\nfunction translateStyles( styles, titles ) {\n\tfor ( const style of styles ) {\n\t\t// Localize the titles of the styles, if a title corresponds with\n\t\t// a localized default provided by the plugin.\n\t\tif ( titles[ style.title ] ) {\n\t\t\tstyle.title = titles[ style.title ];\n\t\t}\n\t}\n\n\treturn styles;\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 image/imageupload/utils\n */\n\n/* global fetch, File */\n\nimport { global } from 'ckeditor5/src/utils';\n\n/**\n * Creates a regular expression used to test for image files.\n *\n *\t\tconst imageType = createImageTypeRegExp( [ 'png', 'jpeg', 'svg+xml', 'vnd.microsoft.icon' ] );\n *\n *\t\tconsole.log( 'is supported image', imageType.test( file.type ) );\n *\n * @param {Array.<String>} types\n * @returns {RegExp}\n */\nexport function createImageTypeRegExp( types ) {\n\t// Sanitize the MIME type name which may include: \"+\", \"-\" or \".\".\n\tconst regExpSafeNames = types.map( type => type.replace( '+', '\\\\+' ) );\n\n\treturn new RegExp( `^image\\\\/(${ regExpSafeNames.join( '|' ) })$` );\n}\n\n/**\n * Creates a promise that fetches the image local source (Base64 or blob) and resolves with a `File` object.\n *\n * @param {module:engine/view/element~Element} image Image whose source to fetch.\n * @returns {Promise.<File>} A promise which resolves when an image source is fetched and converted to a `File` instance.\n * It resolves with a `File` object. If there were any errors during file processing, the promise will be rejected.\n */\nexport function fetchLocalImage( image ) {\n\treturn new Promise( ( resolve, reject ) => {\n\t\tconst imageSrc = image.getAttribute( 'src' );\n\n\t\t// Fetch works asynchronously and so does not block browser UI when processing data.\n\t\tfetch( imageSrc )\n\t\t\t.then( resource => resource.blob() )\n\t\t\t.then( blob => {\n\t\t\t\tconst mimeType = getImageMimeType( blob, imageSrc );\n\t\t\t\tconst ext = mimeType.replace( 'image/', '' );\n\t\t\t\tconst filename = `image.${ ext }`;\n\t\t\t\tconst file = new File( [ blob ], filename, { type: mimeType } );\n\n\t\t\t\tresolve( file );\n\t\t\t} )\n\t\t\t.catch( err => {\n\t\t\t\t// Fetch fails only, if it can't make a request due to a network failure or if anything prevented the request\n\t\t\t\t// from completing, i.e. the Content Security Policy rules. It is not possible to detect the exact cause of failure,\n\t\t\t\t// so we are just trying the fallback solution, if general TypeError is thrown.\n\t\t\t\treturn err && err.name === 'TypeError' ?\n\t\t\t\t\tconvertLocalImageOnCanvas( imageSrc ).then( resolve ).catch( reject ) :\n\t\t\t\t\treject( err );\n\t\t\t} );\n\t} );\n}\n\n/**\n * Checks whether a given node is an image element with a local source (Base64 or blob).\n *\n * @param {module:engine/view/node~Node} node The node to check.\n * @returns {Boolean}\n */\nexport function isLocalImage( node ) {\n\tif ( !node.is( 'element', 'img' ) || !node.getAttribute( 'src' ) ) {\n\t\treturn false;\n\t}\n\n\treturn node.getAttribute( 'src' ).match( /^data:image\\/\\w+;base64,/g ) ||\n\t\tnode.getAttribute( 'src' ).match( /^blob:/g );\n}\n\n// Extracts an image type based on its blob representation or its source.\n//\n// @param {String} src Image `src` attribute value.\n// @param {Blob} blob Image blob representation.\n// @returns {String}\nfunction getImageMimeType( blob, src ) {\n\tif ( blob.type ) {\n\t\treturn blob.type;\n\t} else if ( src.match( /data:(image\\/\\w+);base64/ ) ) {\n\t\treturn src.match( /data:(image\\/\\w+);base64/ )[ 1 ].toLowerCase();\n\t} else {\n\t\t// Fallback to 'jpeg' as common extension.\n\t\treturn 'image/jpeg';\n\t}\n}\n\n// Creates a promise that converts the image local source (Base64 or blob) to a blob using canvas and resolves\n// with a `File` object.\n//\n// @param {String} imageSrc Image `src` attribute value.\n// @returns {Promise.<File>} A promise which resolves when an image source is converted to a `File` instance.\n// It resolves with a `File` object. If there were any errors during file processing, the promise will be rejected.\nfunction convertLocalImageOnCanvas( imageSrc ) {\n\treturn getBlobFromCanvas( imageSrc ).then( blob => {\n\t\tconst mimeType = getImageMimeType( blob, imageSrc );\n\t\tconst ext = mimeType.replace( 'image/', '' );\n\t\tconst filename = `image.${ ext }`;\n\n\t\treturn new File( [ blob ], filename, { type: mimeType } );\n\t} );\n}\n\n// Creates a promise that resolves with a `Blob` object converted from the image source (Base64 or blob).\n//\n// @param {String} imageSrc Image `src` attribute value.\n// @returns {Promise.<Blob>}\nfunction getBlobFromCanvas( imageSrc ) {\n\treturn new Promise( ( resolve, reject ) => {\n\t\tconst image = global.document.createElement( 'img' );\n\n\t\timage.addEventListener( 'load', () => {\n\t\t\tconst canvas = global.document.createElement( 'canvas' );\n\n\t\t\tcanvas.width = image.width;\n\t\t\tcanvas.height = image.height;\n\n\t\t\tconst ctx = canvas.getContext( '2d' );\n\n\t\t\tctx.drawImage( image, 0, 0 );\n\n\t\t\tcanvas.toBlob( blob => blob ? resolve( blob ) : reject() );\n\t\t} );\n\n\t\timage.addEventListener( 'error', () => reject() );\n\n\t\timage.src = imageSrc;\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageupload/imageuploadui\n */\n\nimport { Plugin, icons } from 'ckeditor5/src/core';\nimport { FileDialogButtonView } from 'ckeditor5/src/upload';\nimport { createImageTypeRegExp } from './utils';\n\n/**\n * The image upload button plugin.\n *\n * For a detailed overview, check the {@glink features/image-upload/image-upload Image upload feature} documentation.\n *\n * Adds the `'uploadImage'` button to the {@link module:ui/componentfactory~ComponentFactory UI component factory}\n * and also the `imageUpload` button as an alias for backward compatibility.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageUploadUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst componentCreator = locale => {\n\t\t\tconst view = new FileDialogButtonView( locale );\n\t\t\tconst command = editor.commands.get( 'uploadImage' );\n\t\t\tconst imageTypes = editor.config.get( 'image.upload.types' );\n\t\t\tconst imageTypesRegExp = createImageTypeRegExp( imageTypes );\n\n\t\t\tview.set( {\n\t\t\t\tacceptedType: imageTypes.map( type => `image/${ type }` ).join( ',' ),\n\t\t\t\tallowMultipleFiles: true\n\t\t\t} );\n\n\t\t\tview.buttonView.set( {\n\t\t\t\tlabel: t( 'Insert image' ),\n\t\t\t\ticon: icons.image,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.buttonView.bind( 'isEnabled' ).to( command );\n\n\t\t\tview.on( 'done', ( evt, files ) => {\n\t\t\t\tconst imagesToUpload = Array.from( files ).filter( file => imageTypesRegExp.test( file.type ) );\n\n\t\t\t\tif ( imagesToUpload.length ) {\n\t\t\t\t\teditor.execute( 'uploadImage', { file: imagesToUpload } );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t};\n\n\t\t// Setup `uploadImage` button and add `imageUpload` button as an alias for backward compatibility.\n\t\teditor.ui.componentFactory.add( 'uploadImage', componentCreator );\n\t\teditor.ui.componentFactory.add( 'imageUpload', componentCreator );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageupload/imageuploadprogress\n */\n\n/* globals setTimeout */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { FileRepository } from 'ckeditor5/src/upload';\nimport { getViewImgFromWidget } from '../image/utils';\n\nimport uploadingPlaceholder from '../../theme/icons/image_placeholder.svg';\n\nimport '../../theme/imageuploadprogress.css';\nimport '../../theme/imageuploadicon.css';\nimport '../../theme/imageuploadloader.css';\n\n/**\n * The image upload progress plugin.\n * It shows a placeholder when the image is read from the disk and a progress bar while the image is uploading.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadProgress extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageUploadProgress';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The image placeholder that is displayed before real image data can be accessed.\n\t\t *\n\t\t * @protected\n\t\t * @member {String} #placeholder\n\t\t */\n\t\tthis.placeholder = 'data:image/svg+xml;utf8,' + encodeURIComponent( uploadingPlaceholder );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Upload status change - update image's view according to that status.\n\t\teditor.editing.downcastDispatcher.on( 'attribute:uploadStatus:image', ( ...args ) => this.uploadStatusChange( ...args ) );\n\t}\n\n\t/**\n\t * This method is called each time the image `uploadStatus` attribute is changed.\n\t *\n\t * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n\t * @param {Object} data Additional information about the change.\n\t * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n\t */\n\tuploadStatusChange( evt, data, conversionApi ) {\n\t\tconst editor = this.editor;\n\t\tconst modelImage = data.item;\n\t\tconst uploadId = modelImage.getAttribute( 'uploadId' );\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\t\tconst status = uploadId ? data.attributeNewValue : null;\n\t\tconst placeholder = this.placeholder;\n\t\tconst viewFigure = editor.editing.mapper.toViewElement( modelImage );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\tif ( status == 'reading' ) {\n\t\t\t// Start \"appearing\" effect and show placeholder with infinite progress bar on the top\n\t\t\t// while image is read from disk.\n\t\t\t_startAppearEffect( viewFigure, viewWriter );\n\t\t\t_showPlaceholder( placeholder, viewFigure, viewWriter );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Show progress bar on the top of the image when image is uploading.\n\t\tif ( status == 'uploading' ) {\n\t\t\tconst loader = fileRepository.loaders.get( uploadId );\n\n\t\t\t// Start appear effect if needed - see https://github.com/ckeditor/ckeditor5-image/issues/191.\n\t\t\t_startAppearEffect( viewFigure, viewWriter );\n\n\t\t\tif ( !loader ) {\n\t\t\t\t// There is no loader associated with uploadId - this means that image came from external changes.\n\t\t\t\t// In such cases we still want to show the placeholder until image is fully uploaded.\n\t\t\t\t// Show placeholder if needed - see https://github.com/ckeditor/ckeditor5-image/issues/191.\n\t\t\t\t_showPlaceholder( placeholder, viewFigure, viewWriter );\n\t\t\t} else {\n\t\t\t\t// Hide placeholder and initialize progress bar showing upload progress.\n\t\t\t\t_hidePlaceholder( viewFigure, viewWriter );\n\t\t\t\t_showProgressBar( viewFigure, viewWriter, loader, editor.editing.view );\n\t\t\t\t_displayLocalImage( viewFigure, viewWriter, loader );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( status == 'complete' && fileRepository.loaders.get( uploadId ) ) {\n\t\t\t_showCompleteIcon( viewFigure, viewWriter, editor.editing.view );\n\t\t}\n\n\t\t// Clean up.\n\t\t_hideProgressBar( viewFigure, viewWriter );\n\t\t_hidePlaceholder( viewFigure, viewWriter );\n\t\t_stopAppearEffect( viewFigure, viewWriter );\n\t}\n}\n\n// Adds ck-appear class to the image figure if one is not already applied.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _startAppearEffect( viewFigure, writer ) {\n\tif ( !viewFigure.hasClass( 'ck-appear' ) ) {\n\t\twriter.addClass( 'ck-appear', viewFigure );\n\t}\n}\n\n// Removes ck-appear class to the image figure if one is not already removed.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _stopAppearEffect( viewFigure, writer ) {\n\twriter.removeClass( 'ck-appear', viewFigure );\n}\n\n// Shows placeholder together with infinite progress bar on given image figure.\n//\n// @param {String} Data-uri with a svg placeholder.\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _showPlaceholder( placeholder, viewFigure, writer ) {\n\tif ( !viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {\n\t\twriter.addClass( 'ck-image-upload-placeholder', viewFigure );\n\t}\n\n\tconst viewImg = getViewImgFromWidget( viewFigure );\n\n\tif ( viewImg.getAttribute( 'src' ) !== placeholder ) {\n\t\twriter.setAttribute( 'src', placeholder, viewImg );\n\t}\n\n\tif ( !_getUIElement( viewFigure, 'placeholder' ) ) {\n\t\twriter.insert( writer.createPositionAfter( viewImg ), _createPlaceholder( writer ) );\n\t}\n}\n\n// Removes placeholder together with infinite progress bar on given image figure.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _hidePlaceholder( viewFigure, writer ) {\n\tif ( viewFigure.hasClass( 'ck-image-upload-placeholder' ) ) {\n\t\twriter.removeClass( 'ck-image-upload-placeholder', viewFigure );\n\t}\n\n\t_removeUIElement( viewFigure, writer, 'placeholder' );\n}\n\n// Shows progress bar displaying upload progress.\n// Attaches it to the file loader to update when upload percentace is changed.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:upload/filerepository~FileLoader} loader\n// @param {module:engine/view/view~View} view\nfunction _showProgressBar( viewFigure, writer, loader, view ) {\n\tconst progressBar = _createProgressBar( writer );\n\twriter.insert( writer.createPositionAt( viewFigure, 'end' ), progressBar );\n\n\t// Update progress bar width when uploadedPercent is changed.\n\tloader.on( 'change:uploadedPercent', ( evt, name, value ) => {\n\t\tview.change( writer => {\n\t\t\twriter.setStyle( 'width', value + '%', progressBar );\n\t\t} );\n\t} );\n}\n\n// Hides upload progress bar.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\nfunction _hideProgressBar( viewFigure, writer ) {\n\t_removeUIElement( viewFigure, writer, 'progressBar' );\n}\n\n// Shows complete icon and hides after a certain amount of time.\n//\n// @param {module:engine/view/containerelement~ContainerElement} viewFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:engine/view/view~View} view\nfunction _showCompleteIcon( viewFigure, writer, view ) {\n\tconst completeIcon = writer.createUIElement( 'div', { class: 'ck-image-upload-complete-icon' } );\n\n\twriter.insert( writer.createPositionAt( viewFigure, 'end' ), completeIcon );\n\n\tsetTimeout( () => {\n\t\tview.change( writer => writer.remove( writer.createRangeOn( completeIcon ) ) );\n\t}, 3000 );\n}\n\n// Create progress bar element using {@link module:engine/view/uielement~UIElement}.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/uielement~UIElement}\nfunction _createProgressBar( writer ) {\n\tconst progressBar = writer.createUIElement( 'div', { class: 'ck-progress-bar' } );\n\n\twriter.setCustomProperty( 'progressBar', true, progressBar );\n\n\treturn progressBar;\n}\n\n// Create placeholder element using {@link module:engine/view/uielement~UIElement}.\n//\n// @private\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @returns {module:engine/view/uielement~UIElement}\nfunction _createPlaceholder( writer ) {\n\tconst placeholder = writer.createUIElement( 'div', { class: 'ck-upload-placeholder-loader' } );\n\n\twriter.setCustomProperty( 'placeholder', true, placeholder );\n\n\treturn placeholder;\n}\n\n// Returns {@link module:engine/view/uielement~UIElement} of given unique property from image figure element.\n// Returns `undefined` if element is not found.\n//\n// @private\n// @param {module:engine/view/element~Element} imageFigure\n// @param {String} uniqueProperty\n// @returns {module:engine/view/uielement~UIElement|undefined}\nfunction _getUIElement( imageFigure, uniqueProperty ) {\n\tfor ( const child of imageFigure.getChildren() ) {\n\t\tif ( child.getCustomProperty( uniqueProperty ) ) {\n\t\t\treturn child;\n\t\t}\n\t}\n}\n\n// Removes {@link module:engine/view/uielement~UIElement} of given unique property from image figure element.\n//\n// @private\n// @param {module:engine/view/element~Element} imageFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {String} uniqueProperty\nfunction _removeUIElement( viewFigure, writer, uniqueProperty ) {\n\tconst element = _getUIElement( viewFigure, uniqueProperty );\n\n\tif ( element ) {\n\t\twriter.remove( writer.createRangeOn( element ) );\n\t}\n}\n\n// Displays local data from file loader.\n//\n// @param {module:engine/view/element~Element} imageFigure\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n// @param {module:upload/filerepository~FileLoader} loader\nfunction _displayLocalImage( viewFigure, writer, loader ) {\n\tif ( loader.data ) {\n\t\tconst viewImg = getViewImgFromWidget( viewFigure );\n\n\t\twriter.setAttribute( 'src', loader.data, viewImg );\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 700 250\\\"><rect rx=\\\"4\\\"/></svg>\";","/**\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 clipboard/datatransfer\n */\n\n/**\n * A facade over the native [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object.\n */\nexport default class DataTransfer {\n\tconstructor( nativeDataTransfer ) {\n\t\t/**\n\t\t * The array of files created from the native `DataTransfer#files` or `DataTransfer#items`.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Array.<File>} #files\n\t\t */\n\t\tthis.files = getFiles( nativeDataTransfer );\n\n\t\t/**\n\t\t * The native DataTransfer object.\n\t\t *\n\t\t * @private\n\t\t * @member {DataTransfer} #_native\n\t\t */\n\t\tthis._native = nativeDataTransfer;\n\t}\n\n\t/**\n\t * Returns an array of available native content types.\n\t *\n\t * @returns {Array.<String>}\n\t */\n\tget types() {\n\t\treturn this._native.types;\n\t}\n\n\t/**\n\t * Gets the data from the data transfer by its MIME type.\n\t *\n\t *\t\tdataTransfer.getData( 'text/plain' );\n\t *\n\t * @param {String} type The MIME type. E.g. `text/html` or `text/plain`.\n\t * @returns {String}\n\t */\n\tgetData( type ) {\n\t\treturn this._native.getData( type );\n\t}\n\n\t/**\n\t * Sets the data in the data transfer.\n\t *\n\t * @param {String} type The MIME type. E.g. `text/html` or `text/plain`.\n\t * @param {String} data\n\t */\n\tsetData( type, data ) {\n\t\tthis._native.setData( type, data );\n\t}\n\n\t/**\n\t * The effect that is allowed for a drag operation.\n\t *\n\t * @param {String} value\n\t */\n\tset effectAllowed( value ) {\n\t\tthis._native.effectAllowed = value;\n\t}\n\n\tget effectAllowed() {\n\t\treturn this._native.effectAllowed;\n\t}\n\n\t/**\n\t * The actual drop effect.\n\t *\n\t * @param {String} value\n\t */\n\tset dropEffect( value ) {\n\t\tthis._native.dropEffect = value;\n\t}\n\n\tget dropEffect() {\n\t\treturn this._native.dropEffect;\n\t}\n\n\t/**\n\t * Whether the dragging operation was canceled.\n\t *\n\t * @returns {Boolean}\n\t */\n\tget isCanceled() {\n\t\treturn this._native.dropEffect == 'none' || !!this._native.mozUserCancelled;\n\t}\n}\n\nfunction getFiles( nativeDataTransfer ) {\n\t// DataTransfer.files and items are array-like and might not have an iterable interface.\n\tconst files = nativeDataTransfer.files ? Array.from( nativeDataTransfer.files ) : [];\n\tconst items = nativeDataTransfer.items ? Array.from( nativeDataTransfer.items ) : [];\n\n\tif ( files.length ) {\n\t\treturn files;\n\t}\n\t// Chrome has empty DataTransfer.files, but allows getting files through the items interface.\n\treturn items\n\t\t.filter( item => item.kind === 'file' )\n\t\t.map( item => item.getAsFile() );\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 clipboard/clipboardobserver\n */\n\nimport DomEventObserver from '@ckeditor/ckeditor5-engine/src/view/observer/domeventobserver';\nimport EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';\nimport DataTransfer from './datatransfer';\n\n/**\n * Clipboard events observer.\n *\n * Fires the following events:\n *\n * * {@link module:engine/view/document~Document#event:clipboardInput},\n * * {@link module:engine/view/document~Document#event:paste},\n * * {@link module:engine/view/document~Document#event:copy},\n * * {@link module:engine/view/document~Document#event:cut},\n * * {@link module:engine/view/document~Document#event:drop},\n * * {@link module:engine/view/document~Document#event:dragover},\n * * {@link module:engine/view/document~Document#event:dragging},\n * * {@link module:engine/view/document~Document#event:dragstart},\n * * {@link module:engine/view/document~Document#event:dragend},\n * * {@link module:engine/view/document~Document#event:dragenter},\n * * {@link module:engine/view/document~Document#event:dragleave}.\n *\n * **Note**: This observer is not available by default (ckeditor5-engine does not add it on its own).\n * To make it available, it needs to be added to {@link module:engine/view/document~Document} by using\n * the {@link module:engine/view/view~View#addObserver `View#addObserver()`} method. Alternatively, you can load the\n * {@link module:clipboard/clipboard~Clipboard} plugin which adds this observer automatically (because it uses it).\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class ClipboardObserver extends DomEventObserver {\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tconst viewDocument = this.document;\n\n\t\tthis.domEventType = [ 'paste', 'copy', 'cut', 'drop', 'dragover', 'dragstart', 'dragend', 'dragenter', 'dragleave' ];\n\n\t\tthis.listenTo( viewDocument, 'paste', handleInput( 'clipboardInput' ), { priority: 'low' } );\n\t\tthis.listenTo( viewDocument, 'drop', handleInput( 'clipboardInput' ), { priority: 'low' } );\n\t\tthis.listenTo( viewDocument, 'dragover', handleInput( 'dragging' ), { priority: 'low' } );\n\n\t\tfunction handleInput( type ) {\n\t\t\treturn ( evt, data ) => {\n\t\t\t\tdata.preventDefault();\n\n\t\t\t\tconst targetRanges = data.dropRange ? [ data.dropRange ] : null;\n\t\t\t\tconst eventInfo = new EventInfo( viewDocument, type );\n\n\t\t\t\tviewDocument.fire( eventInfo, {\n\t\t\t\t\tdataTransfer: data.dataTransfer,\n\t\t\t\t\tmethod: evt.name,\n\t\t\t\t\ttargetRanges,\n\t\t\t\t\ttarget: data.target\n\t\t\t\t} );\n\n\t\t\t\t// If CKEditor handled the input, do not bubble the original event any further.\n\t\t\t\t// This helps external integrations recognize that fact and act accordingly.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-upload/issues/92\n\t\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\t\tdata.stopPropagation();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n\n\tonDomEvent( domEvent ) {\n\t\tconst evtData = {\n\t\t\tdataTransfer: new DataTransfer( domEvent.clipboardData ? domEvent.clipboardData : domEvent.dataTransfer )\n\t\t};\n\n\t\tif ( domEvent.type == 'drop' || domEvent.type == 'dragover' ) {\n\t\t\tevtData.dropRange = getDropViewRange( this.view, domEvent );\n\t\t}\n\n\t\tthis.fire( domEvent.type, domEvent, evtData );\n\t}\n}\n\nfunction getDropViewRange( view, domEvent ) {\n\tconst domDoc = domEvent.target.ownerDocument;\n\tconst x = domEvent.clientX;\n\tconst y = domEvent.clientY;\n\tlet domRange;\n\n\t// Webkit & Blink.\n\tif ( domDoc.caretRangeFromPoint && domDoc.caretRangeFromPoint( x, y ) ) {\n\t\tdomRange = domDoc.caretRangeFromPoint( x, y );\n\t}\n\t// FF.\n\telse if ( domEvent.rangeParent ) {\n\t\tdomRange = domDoc.createRange();\n\t\tdomRange.setStart( domEvent.rangeParent, domEvent.rangeOffset );\n\t\tdomRange.collapse( true );\n\t}\n\n\tif ( domRange ) {\n\t\treturn view.domConverter.domRangeToView( domRange );\n\t}\n\n\treturn null;\n}\n\n/**\n * Fired as a continuation of the {@link #event:paste} and {@link #event:drop} events.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline clipboard input pipeline}.\n *\n * This event carries a `dataTransfer` object which comes from the clipboard and whose content should be processed\n * and inserted into the editor.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:engine/view/document~Document#event:clipboardInput\n * @param {Object} data The event data.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance.\n * @param {'paste'|'drop'} method Whether the event was triggered by a paste or drop operation.\n * @param {module:engine/view/element~Element} target The tree view element representing the target.\n * @param {Array.<module:engine/view/range~Range>} data.targetRanges Ranges which are the target of the operation\n * (usually into which the content should be inserted).\n * If the clipboard input was triggered by a paste operation, this property is not set. If by a drop operation,\n * then it is the drop position (which can be different than the selection at the moment of drop).\n */\n\n/**\n * Fired when the user drags the content over one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:dragover\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user dropped the content into one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:drop\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n * @param {module:engine/view/range~Range} dropRange The position into which the content is dropped.\n */\n\n/**\n * Fired when the user pasted the content into one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:paste\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user copied the content from one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @event module:engine/view/document~Document#event:copy\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user cut the content from one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @event module:engine/view/document~Document#event:cut\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * The value of the {@link module:engine/view/document~Document#event:paste},\n * {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut} events.\n *\n * In order to access the clipboard data, use the `dataTransfer` property.\n *\n * @class module:clipboard/clipboardobserver~ClipboardEventData\n * @extends module:engine/view/observer/domeventdata~DomEventData\n */\n\n/**\n * The data transfer instance.\n *\n * @readonly\n * @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboardobserver~ClipboardEventData#dataTransfer\n */\n\n/**\n * Fired as a continuation of the {@link #event:dragover} event.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline clipboard input pipeline}.\n *\n * This event carries a `dataTransfer` object which comes from the clipboard and whose content should be processed\n * and inserted into the editor.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboard~Clipboard\n * @event module:engine/view/document~Document#event:dragging\n * @param {Object} data The event data.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance.\n * @param {module:engine/view/element~Element} target The tree view element representing the target.\n * @param {Array.<module:engine/view/range~Range>} data.targetRanges Ranges which are the target of the operation\n * (usually into which the content should be inserted).\n * It is the drop position (which can be different than the selection at the moment of drop).\n */\n\n/**\n * Fired when the user starts dragging the content in one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:dragstart\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user ended dragging the content.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:dragend\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user drags the content into one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:dragenter\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\n */\n\n/**\n * Fired when the user drags the content out of one of the editing roots of the editor.\n *\n * Introduced by {@link module:clipboard/clipboardobserver~ClipboardObserver}.\n *\n * **Note**: This event is not available by default. To make it available, {@link module:clipboard/clipboardobserver~ClipboardObserver}\n * needs to be added to the {@link module:engine/view/document~Document} by using the {@link module:engine/view/view~View#addObserver}\n * method. This is usually done by the {@link module:clipboard/clipboard~Clipboard} plugin, but if for some reason it is not loaded,\n * the observer must be added manually.\n *\n * @see module:engine/view/document~Document#event:clipboardInput\n * @event module:engine/view/document~Document#event:dragleave\n * @param {module:clipboard/clipboardobserver~ClipboardEventData} data The event data.\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 clipboard/utils/viewtoplaintext\n */\n\n// Elements which should not have empty-line padding.\n// Most `view.ContainerElement` want to be separate by new-line, but some are creating one structure\n// together (like `<li>`) so it is better to separate them by only one \"\\n\".\nconst smallPaddingElements = [ 'figcaption', 'li' ];\n\n/**\n * Converts {@link module:engine/view/item~Item view item} and all of its children to plain text.\n *\n * @param {module:engine/view/item~Item} viewItem View item to convert.\n * @returns {String} Plain text representation of `viewItem`.\n */\nexport default function viewToPlainText( viewItem ) {\n\tlet text = '';\n\n\tif ( viewItem.is( '$text' ) || viewItem.is( '$textProxy' ) ) {\n\t\t// If item is `Text` or `TextProxy` simple take its text data.\n\t\ttext = viewItem.data;\n\t} else if ( viewItem.is( 'element', 'img' ) && viewItem.hasAttribute( 'alt' ) ) {\n\t\t// Special case for images - use alt attribute if it is provided.\n\t\ttext = viewItem.getAttribute( 'alt' );\n\t} else if ( viewItem.is( 'element', 'br' ) ) {\n\t\t// A soft break should be converted into a single line break (#8045).\n\t\ttext = '\\n';\n\t} else {\n\t\t// Other elements are document fragments, attribute elements or container elements.\n\t\t// They don't have their own text value, so convert their children.\n\t\tlet prev = null;\n\n\t\tfor ( const child of viewItem.getChildren() ) {\n\t\t\tconst childText = viewToPlainText( child );\n\n\t\t\t// Separate container element children with one or more new-line characters.\n\t\t\tif ( prev && ( prev.is( 'containerElement' ) || child.is( 'containerElement' ) ) ) {\n\t\t\t\tif ( smallPaddingElements.includes( prev.name ) || smallPaddingElements.includes( child.name ) ) {\n\t\t\t\t\ttext += '\\n';\n\t\t\t\t} else {\n\t\t\t\t\ttext += '\\n\\n';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttext += childText;\n\t\t\tprev = child;\n\t\t}\n\t}\n\n\treturn text;\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 clipboard/clipboardpipeline\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport EventInfo from '@ckeditor/ckeditor5-utils/src/eventinfo';\n\nimport ClipboardObserver from './clipboardobserver';\n\nimport plainTextToHtml from './utils/plaintexttohtml';\nimport normalizeClipboardHtml from './utils/normalizeclipboarddata';\nimport viewToPlainText from './utils/viewtoplaintext.js';\n\n// Input pipeline events overview:\n//\n// ┌──────────────────────┐ ┌──────────────────────┐\n// │ view.Document │ │ view.Document │\n// │ paste │ │ drop │\n// └───────────┬──────────┘ └───────────┬──────────┘\n// │ │\n// └────────────────┌────────────────┘\n// │\n// ┌─────────V────────┐\n// │ view.Document │ Retrieves text/html or text/plain from data.dataTransfer\n// │ clipboardInput │ and processes it to view.DocumentFragment.\n// └─────────┬────────┘\n// │\n// ┌───────────V───────────┐\n// │ ClipboardPipeline │ Converts view.DocumentFragment to model.DocumentFragment.\n// │ inputTransformation │\n// └───────────┬───────────┘\n// │\n// ┌──────────V──────────┐\n// │ ClipboardPipeline │ Calls model.insertContent().\n// │ contentInsertion │\n// └─────────────────────┘\n//\n//\n// Output pipeline events overview:\n//\n// ┌──────────────────────┐ ┌──────────────────────┐\n// │ view.Document │ │ view.Document │ Retrieves the selected model.DocumentFragment\n// │ copy │ │ cut │ and converts it to view.DocumentFragment.\n// └───────────┬──────────┘ └───────────┬──────────┘\n// │ │\n// └────────────────┌────────────────┘\n// │\n// ┌─────────V────────┐\n// │ view.Document │ Processes view.DocumentFragment to text/html and text/plain\n// │ clipboardOutput │ and stores the results in data.dataTransfer.\n// └──────────────────┘\n//\n\n/**\n * The clipboard pipeline feature. It is responsible for intercepting the `paste` and `drop` events and\n * passing the pasted content through a series of events in order to insert it into the editor's content.\n * It also handles the `cut` and `copy` events to fill the native clipboard with the serialized editor's data.\n *\n * # Input pipeline\n *\n * The behavior of the default handlers (all at a `low` priority):\n *\n * ## Event: `paste` or `drop`\n *\n * 1. Translates the event data.\n * 2. Fires the {@link module:engine/view/document~Document#event:clipboardInput `view.Document#clipboardInput`} event.\n *\n * ## Event: `view.Document#clipboardInput`\n *\n * 1. If the `data.content` event field is already set (by some listener on a higher priority), it takes this content and fires the event\n * from the last point.\n * 2. Otherwise, it retrieves `text/html` or `text/plain` from `data.dataTransfer`.\n * 3. Normalizes the raw data by applying simple filters on string data.\n * 4. Processes the raw data to {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`} with the\n * {@link module:engine/controller/datacontroller~DataController#htmlProcessor `DataController#htmlProcessor`}.\n * 5. Fires the {@link module:clipboard/clipboardpipeline~ClipboardPipeline#event:inputTransformation\n * `ClipboardPipeline#inputTransformation`} event with the view document fragment in the `data.content` event field.\n *\n * ## Event: `ClipboardPipeline#inputTransformation`\n *\n * 1. Converts {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`} from the `data.content` field to\n * {@link module:engine/model/documentfragment~DocumentFragment `model.DocumentFragment`}.\n * 2. Fires the {@link module:clipboard/clipboardpipeline~ClipboardPipeline#event:contentInsertion `ClipboardPipeline#contentInsertion`}\n * event with the model document fragment in the `data.content` event field.\n * **Note**: The `ClipboardPipeline#contentInsertion` event is fired within a model change block to allow other handlers\n * to run in the same block without post-fixers called in between (i.e., the selection post-fixer).\n *\n * ## Event: `ClipboardPipeline#contentInsertion`\n *\n * 1. Calls {@link module:engine/model/model~Model#insertContent `model.insertContent()`} to insert `data.content`\n * at the current selection position.\n *\n * # Output pipeline\n *\n * The behavior of the default handlers (all at a `low` priority):\n *\n * ## Event: `copy`, `cut` or `dragstart`\n *\n * 1. Retrieves the selected {@link module:engine/model/documentfragment~DocumentFragment `model.DocumentFragment`} by calling\n * {@link module:engine/model/model~Model#getSelectedContent `model#getSelectedContent()`}.\n * 2. Converts the model document fragment to {@link module:engine/view/documentfragment~DocumentFragment `view.DocumentFragment`}.\n * 3. Fires the {@link module:engine/view/document~Document#event:clipboardOutput `view.Document#clipboardOutput`} event\n * with the view document fragment in the `data.content` event field.\n *\n * ## Event: `view.Document#clipboardOutput`\n *\n * 1. Processes `data.content` to HTML and plain text with the\n * {@link module:engine/controller/datacontroller~DataController#htmlProcessor `DataController#htmlProcessor`}.\n * 2. Updates the `data.dataTransfer` data for `text/html` and `text/plain` with the processed data.\n * 3. For the `cut` method, calls {@link module:engine/model/model~Model#deleteContent `model.deleteContent()`}\n * on the current selection.\n *\n * Read more about the clipboard integration in the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ClipboardPipeline extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ClipboardPipeline';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\n\t\tview.addObserver( ClipboardObserver );\n\n\t\tthis._setupPasteDrop();\n\t\tthis._setupCopyCut();\n\t}\n\n\t/**\n\t * The clipboard paste pipeline.\n\t *\n\t * @private\n\t */\n\t_setupPasteDrop() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Pasting and dropping is disabled when editor is in the read-only mode.\n\t\t// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.\n\t\tthis.listenTo( viewDocument, 'clipboardInput', evt => {\n\t\t\tif ( editor.isReadOnly ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => {\n\t\t\tconst dataTransfer = data.dataTransfer;\n\t\t\tlet content = data.content || '';\n\n\t\t\t// Some feature could already inject content in the higher priority event handler (i.e., codeBlock).\n\t\t\tif ( !content ) {\n\t\t\t\tif ( dataTransfer.getData( 'text/html' ) ) {\n\t\t\t\t\tcontent = normalizeClipboardHtml( dataTransfer.getData( 'text/html' ) );\n\t\t\t\t} else if ( dataTransfer.getData( 'text/plain' ) ) {\n\t\t\t\t\tcontent = plainTextToHtml( dataTransfer.getData( 'text/plain' ) );\n\t\t\t\t}\n\n\t\t\t\tcontent = this.editor.data.htmlProcessor.toView( content );\n\t\t\t}\n\n\t\t\tconst eventInfo = new EventInfo( this, 'inputTransformation' );\n\n\t\t\tthis.fire( eventInfo, {\n\t\t\t\tcontent,\n\t\t\t\tdataTransfer,\n\t\t\t\ttargetRanges: data.targetRanges,\n\t\t\t\tmethod: data.method\n\t\t\t} );\n\n\t\t\t// If CKEditor handled the input, do not bubble the original event any further.\n\t\t\t// This helps external integrations recognize this fact and act accordingly.\n\t\t\t// https://github.com/ckeditor/ckeditor5-upload/issues/92\n\t\t\tif ( eventInfo.stop.called ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\n\t\t\tview.scrollToTheSelection();\n\t\t}, { priority: 'low' } );\n\n\t\tthis.listenTo( this, 'inputTransformation', ( evt, data ) => {\n\t\t\tif ( data.content.isEmpty ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst dataController = this.editor.data;\n\n\t\t\t// Convert the pasted content into a model document fragment.\n\t\t\t// The conversion is contextual, but in this case an \"all allowed\" context is needed\n\t\t\t// and for that we use the $clipboardHolder item.\n\t\t\tconst modelFragment = dataController.toModel( data.content, '$clipboardHolder' );\n\n\t\t\tif ( modelFragment.childCount == 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevt.stop();\n\n\t\t\t// Fire content insertion event in a single change block to allow other handlers to run in the same block\n\t\t\t// without post-fixers called in between (i.e., the selection post-fixer).\n\t\t\tmodel.change( () => {\n\t\t\t\tthis.fire( 'contentInsertion', {\n\t\t\t\t\tcontent: modelFragment,\n\t\t\t\t\tmethod: data.method,\n\t\t\t\t\tdataTransfer: data.dataTransfer,\n\t\t\t\t\ttargetRanges: data.targetRanges\n\t\t\t\t} );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\n\t\tthis.listenTo( this, 'contentInsertion', ( evt, data ) => {\n\t\t\tdata.resultRange = model.insertContent( data.content );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * The clipboard copy/cut pipeline.\n\t *\n\t * @private\n\t */\n\t_setupCopyCut() {\n\t\tconst editor = this.editor;\n\t\tconst modelDocument = editor.model.document;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\tfunction onCopyCut( evt, data ) {\n\t\t\tconst dataTransfer = data.dataTransfer;\n\n\t\t\tdata.preventDefault();\n\n\t\t\tconst content = editor.data.toView( editor.model.getSelectedContent( modelDocument.selection ) );\n\n\t\t\tviewDocument.fire( 'clipboardOutput', { dataTransfer, content, method: evt.name } );\n\t\t}\n\n\t\tthis.listenTo( viewDocument, 'copy', onCopyCut, { priority: 'low' } );\n\t\tthis.listenTo( viewDocument, 'cut', ( evt, data ) => {\n\t\t\t// Cutting is disabled when editor is in the read-only mode.\n\t\t\t// See: https://github.com/ckeditor/ckeditor5-clipboard/issues/26.\n\t\t\tif ( editor.isReadOnly ) {\n\t\t\t\tdata.preventDefault();\n\t\t\t} else {\n\t\t\t\tonCopyCut( evt, data );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\tthis.listenTo( viewDocument, 'clipboardOutput', ( evt, data ) => {\n\t\t\tif ( !data.content.isEmpty ) {\n\t\t\t\tdata.dataTransfer.setData( 'text/html', this.editor.data.htmlProcessor.toData( data.content ) );\n\t\t\t\tdata.dataTransfer.setData( 'text/plain', viewToPlainText( data.content ) );\n\t\t\t}\n\n\t\t\tif ( data.method == 'cut' ) {\n\t\t\t\teditor.model.deleteContent( modelDocument.selection );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t}\n}\n\n/**\n * Fired with the `content`, `dataTransfer`, `method`, and `targetRanges` properties:\n *\n * * The `content` which comes from the clipboard (it was pasted or dropped) should be processed in order to be inserted into the editor.\n * * The `dataTransfer` object is available in case the transformation functions need access to the raw clipboard data.\n * * The `method` indicates the original DOM event (for example `'drop'` or `'paste'`).\n * * The `targetRanges` property is an array of view ranges (it is available only for `'drop'`).\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline clipboard input pipeline}.\n *\n * **Note**: You should not stop this event if you want to change the input data. You should modify the `content` property instead.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboardpipeline~ClipboardPipeline\n * @event module:clipboard/clipboardpipeline~ClipboardPipeline#event:inputTransformation\n * @param {Object} data The event data.\n * @param {module:engine/view/documentfragment~DocumentFragment} data.content The event data. The content to be inserted into the editor.\n * It can be modified by event listeners. Read more about the clipboard pipelines in\n * the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance.\n * @param {'paste'|'drop'} data.method Whether the event was triggered by a paste or drop operation.\n * @param {Array.<module:engine/view/range~Range>} data.targetRanges The target drop ranges.\n */\n\n/**\n * Fired with the `content`, `dataTransfer`, `method`, and `targetRanges` properties:\n *\n * * The `content` which comes from the clipboard (was pasted or dropped) should be processed in order to be inserted into the editor.\n * * The `dataTransfer` object is available in case the transformation functions need access to the raw clipboard data.\n * * The `method` indicates the original DOM event (for example `'drop'` or `'paste'`).\n * * The `targetRanges` property is an array of view ranges (it is available only for `'drop'`).\n *\n * Event handlers can modify the content according to the final insertion position.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#input-pipeline clipboard input pipeline}.\n *\n * **Note**: You should not stop this event if you want to change the input data. You should modify the `content` property instead.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboardpipeline~ClipboardPipeline\n * @see module:clipboard/clipboardpipeline~ClipboardPipeline#event:inputTransformation\n * @event module:clipboard/clipboardpipeline~ClipboardPipeline#event:contentInsertion\n * @param {Object} data The event data.\n * @param {module:engine/model/documentfragment~DocumentFragment} data.content The event data. The content to be inserted into the editor.\n * Read more about the clipboard pipelines in the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.\n * @param {module:clipboard/datatransfer~DataTransfer} data.dataTransfer The data transfer instance.\n * @param {'paste'|'drop'} data.method Whether the event was triggered by a paste or drop operation.\n * @param {Array.<module:engine/view/range~Range>} data.targetRanges The target drop ranges.\n * @param {module:engine/model/range~Range} data.resultRange The result of the `model.insertContent()` call\n * (inserted by the event handler at a low priority).\n */\n\n/**\n * Fired on {@link module:engine/view/document~Document#event:copy} and {@link module:engine/view/document~Document#event:cut}\n * with a copy of the selected content. The content can be processed before it ends up in the clipboard.\n *\n * It is a part of the {@glink framework/guides/deep-dive/clipboard#output-pipeline clipboard output pipeline}.\n *\n * @see module:clipboard/clipboardobserver~ClipboardObserver\n * @see module:clipboard/clipboardpipeline~ClipboardPipeline\n * @event module:engine/view/document~Document#event:clipboardOutput\n * @param {module:clipboard/clipboardpipeline~ClipboardOutputEventData} data The event data.\n */\n\n/**\n * The value of the {@link module:engine/view/document~Document#event:clipboardOutput} event.\n *\n * @class module:clipboard/clipboardpipeline~ClipboardOutputEventData\n */\n\n/**\n * The data transfer instance.\n *\n * @readonly\n * @member {module:clipboard/datatransfer~DataTransfer} module:clipboard/clipboardpipeline~ClipboardOutputEventData#dataTransfer\n */\n\n/**\n * Content to be put into the clipboard. It can be modified by the event listeners.\n * Read more about the clipboard pipelines in the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.\n *\n * @member {module:engine/view/documentfragment~DocumentFragment} module:clipboard/clipboardpipeline~ClipboardOutputEventData#content\n */\n\n/**\n * Whether the event was triggered by a copy or cut operation.\n *\n * @member {'copy'|'cut'} module:clipboard/clipboardpipeline~ClipboardOutputEventData#method\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 clipboard/utils/plaintexttohtml\n */\n\n/**\n * Converts plain text to its HTML-ized version.\n *\n * @param {String} text The plain text to convert.\n * @returns {String} HTML generated from the plain text.\n */\nexport default function plainTextToHtml( text ) {\n\ttext = text\n\t\t// Encode <>.\n\t\t.replace( /</g, '&lt;' )\n\t\t.replace( />/g, '&gt;' )\n\t\t// Creates a paragraph for each double line break.\n\t\t.replace( /\\r?\\n\\r?\\n/g, '</p><p>' )\n\t\t// Creates a line break for each single line break.\n\t\t.replace( /\\r?\\n/g, '<br>' )\n\t\t// Preserve trailing spaces (only the first and last one the rest is handled below).\n\t\t.replace( /^\\s/, '&nbsp;' )\n\t\t.replace( /\\s$/, '&nbsp;' )\n\t\t// Preserve other subsequent spaces now.\n\t\t.replace( /\\s\\s/g, ' &nbsp;' );\n\n\tif ( text.includes( '</p><p>' ) || text.includes( '<br>' ) ) {\n\t\t// If we created paragraphs above, add the trailing ones.\n\t\ttext = `<p>${ text }</p>`;\n\t}\n\n\t// TODO:\n\t// * What about '\\nfoo' vs ' foo'?\n\n\treturn text;\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 clipboard/utils/normalizeclipboarddata\n */\n\n/**\n * Removes some popular browser quirks out of the clipboard data (HTML).\n *\n * @param {String} data The HTML data to normalize.\n * @returns {String} Normalized HTML.\n */\nexport default function normalizeClipboardData( data ) {\n\treturn data\n\t\t.replace( /<span(?: class=\"Apple-converted-space\"|)>(\\s+)<\\/span>/g, ( fullMatch, spaces ) => {\n\t\t\t// Handle the most popular and problematic case when even a single space becomes an nbsp;.\n\t\t\t// Decode those to normal spaces. Read more in https://github.com/ckeditor/ckeditor5-clipboard/issues/2.\n\t\t\tif ( spaces.length == 1 ) {\n\t\t\t\treturn ' ';\n\t\t\t}\n\n\t\t\treturn spaces;\n\t\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module clipboard/dragdrop\n */\n\n/* globals setTimeout, clearTimeout */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';\nimport MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport env from '@ckeditor/ckeditor5-utils/src/env';\nimport { isWidget } from '@ckeditor/ckeditor5-widget/src/utils';\n\nimport ClipboardPipeline from './clipboardpipeline';\nimport ClipboardObserver from './clipboardobserver';\n\nimport { throttle } from 'lodash-es';\n\nimport '../theme/clipboard.css';\n\n// Drag and drop events overview:\n//\n// ┌──────────────────┐\n// │ mousedown │ Sets the draggable attribute.\n// └─────────┬────────┘\n// │\n// └─────────────────────┐\n// │ │\n// │ ┌─────────V────────┐\n// │ │ mouseup │ Dragging did not start, removes the draggable attribute.\n// │ └──────────────────┘\n// │\n// ┌─────────V────────┐ Retrieves the selected model.DocumentFragment\n// │ dragstart │ and converts it to view.DocumentFragment.\n// └─────────┬────────┘\n// │\n// ┌─────────V────────┐ Processes view.DocumentFragment to text/html and text/plain\n// │ clipboardOutput │ and stores the results in data.dataTransfer.\n// └─────────┬────────┘\n// │\n// │ DOM dragover\n// ┌────────────┐\n// │ │\n// ┌─────────V────────┐ │\n// │ dragging │ │ Updates the drop target marker.\n// └─────────┬────────┘ │\n// │ │\n// ┌─────────────└────────────┘\n// │ │ │\n// │ ┌─────────V────────┐ │\n// │ │ dragleave │ │ Removes the drop target marker.\n// │ └─────────┬────────┘ │\n// │ │ │\n// ┌───│─────────────┘ │\n// │ │ │ │\n// │ │ ┌─────────V────────┐ │\n// │ │ │ dragenter │ │ Focuses the editor view.\n// │ │ └─────────┬────────┘ │\n// │ │ │ │\n// │ │ └────────────┘\n// │ │\n// │ └─────────────┐\n// │ │ │\n// │ │ ┌─────────V────────┐\n// └───┐ │ drop │ (The default handler of the clipboard pipeline).\n// │ └─────────┬────────┘\n// │ │\n// │ ┌─────────V────────┐ Resolves the final data.targetRanges.\n// │ │ clipboardInput │ Aborts if dropping on dragged content.\n// │ └─────────┬────────┘\n// │ │\n// │ ┌─────────V────────┐\n// │ │ clipboardInput │ (The default handler of the clipboard pipeline).\n// │ └─────────┬────────┘\n// │ │\n// │ ┌───────────V───────────┐\n// │ │ inputTransformation │ (The default handler of the clipboard pipeline).\n// │ └───────────┬───────────┘\n// │ │\n// │ ┌──────────V──────────┐\n// │ │ contentInsertion │ Updates the document selection to drop range.\n// │ └──────────┬──────────┘\n// │ │\n// │ ┌──────────V──────────┐\n// │ │ contentInsertion │ (The default handler of the clipboard pipeline).\n// │ └──────────┬──────────┘\n// │ │\n// │ ┌──────────V──────────┐\n// │ │ contentInsertion │ Removes the content from the original range if the insertion was successful.\n// │ └──────────┬──────────┘\n// │ │\n// └─────────────┐\n// │\n// ┌─────────V────────┐\n// │ dragend │ Removes the drop marker and cleans the state.\n// └──────────────────┘\n//\n\n/**\n * The drag and drop feature. It works on top of the {@link module:clipboard/clipboardpipeline~ClipboardPipeline}.\n *\n * Read more about the clipboard integration in the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class DragDrop extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'DragDrop';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ClipboardPipeline, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\n\t\t/**\n\t\t * The live range over the original content that is being dragged.\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/liverange~LiveRange}\n\t\t */\n\t\tthis._draggedRange = null;\n\n\t\t/**\n\t\t * The UID of current dragging that is used to verify if the drop started in the same editor as the drag start.\n\t\t *\n\t\t * **Note**: This is a workaround for broken 'dragend' events (they are not fired if the source text node got removed).\n\t\t *\n\t\t * @private\n\t\t * @type {String}\n\t\t */\n\t\tthis._draggingUid = '';\n\n\t\t/**\n\t\t * The reference to the model element that currently has a `draggable` attribute set (it is set while dragging).\n\t\t *\n\t\t * @private\n\t\t * @type {module:engine/model/element~Element}\n\t\t */\n\t\tthis._draggableElement = null;\n\n\t\t/**\n\t\t * A throttled callback updating the drop marker.\n\t\t *\n\t\t * @private\n\t\t * @type {Function}\n\t\t */\n\t\tthis._updateDropMarkerThrottled = throttle( targetRange => this._updateDropMarker( targetRange ), 40 );\n\n\t\t/**\n\t\t * A delayed callback removing the drop marker.\n\t\t *\n\t\t * @private\n\t\t * @type {Function}\n\t\t */\n\t\tthis._removeDropMarkerDelayed = delay( () => this._removeDropMarker(), 40 );\n\n\t\t/**\n\t\t * A delayed callback removing draggable attributes.\n\t\t *\n\t\t * @private\n\t\t * @type {Function}\n\t\t */\n\t\tthis._clearDraggableAttributesDelayed = delay( () => this._clearDraggableAttributes(), 40 );\n\n\t\tview.addObserver( ClipboardObserver );\n\t\tview.addObserver( MouseObserver );\n\n\t\tthis._setupDragging();\n\t\tthis._setupContentInsertionIntegration();\n\t\tthis._setupClipboardInputIntegration();\n\t\tthis._setupDropMarker();\n\t\tthis._setupDraggableAttributeHandling();\n\n\t\tthis.listenTo( editor, 'change:isReadOnly', ( evt, name, isReadOnly ) => {\n\t\t\tif ( isReadOnly ) {\n\t\t\t\tthis.forceDisabled( 'readOnlyMode' );\n\t\t\t} else {\n\t\t\t\tthis.clearForceDisabled( 'readOnlyMode' );\n\t\t\t}\n\t\t} );\n\n\t\tthis.on( 'change:isEnabled', ( evt, name, isEnabled ) => {\n\t\t\tif ( !isEnabled ) {\n\t\t\t\tthis._finalizeDragging( false );\n\t\t\t}\n\t\t} );\n\n\t\tif ( env.isAndroid ) {\n\t\t\tthis.forceDisabled( 'noAndroidSupport' );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tif ( this._draggedRange ) {\n\t\t\tthis._draggedRange.detach();\n\t\t\tthis._draggedRange = null;\n\t\t}\n\n\t\tthis._updateDropMarkerThrottled.cancel();\n\t\tthis._removeDropMarkerDelayed.cancel();\n\t\tthis._clearDraggableAttributesDelayed.cancel();\n\n\t\treturn super.destroy();\n\t}\n\n\t/**\n\t * Drag and drop events handling.\n\t *\n\t * @private\n\t */\n\t_setupDragging() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst modelDocument = model.document;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// The handler for the drag start; it is responsible for setting data transfer object.\n\t\tthis.listenTo( viewDocument, 'dragstart', ( evt, data ) => {\n\t\t\tconst selection = modelDocument.selection;\n\n\t\t\t// Don't drag the editable element itself.\n\t\t\tif ( data.target && data.target.is( 'editableElement' ) ) {\n\t\t\t\tdata.preventDefault();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// TODO we could clone this node somewhere and style it to match editing view but without handles,\n\t\t\t// selection outline, WTA buttons, etc.\n\t\t\t// data.dataTransfer._native.setDragImage( data.domTarget, 0, 0 );\n\n\t\t\t// Check if this is dragstart over the widget (but not a nested editable).\n\t\t\tconst draggableWidget = data.target ? findDraggableWidget( data.target ) : null;\n\n\t\t\tif ( draggableWidget ) {\n\t\t\t\tconst modelElement = editor.editing.mapper.toModelElement( draggableWidget );\n\n\t\t\t\tthis._draggedRange = LiveRange.fromRange( model.createRangeOn( modelElement ) );\n\t\t\t}\n\n\t\t\t// If this was not a widget we should check if we need to drag some text content.\n\t\t\telse if ( !viewDocument.selection.isCollapsed ) {\n\t\t\t\tconst selectedElement = viewDocument.selection.getSelectedElement();\n\n\t\t\t\tif ( !selectedElement || !isWidget( selectedElement ) ) {\n\t\t\t\t\tthis._draggedRange = LiveRange.fromRange( selection.getFirstRange() );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( !this._draggedRange ) {\n\t\t\t\tdata.preventDefault();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._draggingUid = uid();\n\n\t\t\tdata.dataTransfer.effectAllowed = this.isEnabled ? 'copyMove' : 'copy';\n\t\t\tdata.dataTransfer.setData( 'application/ckeditor5-dragging-uid', this._draggingUid );\n\n\t\t\tconst draggedSelection = model.createSelection( this._draggedRange.toRange() );\n\t\t\tconst content = editor.data.toView( model.getSelectedContent( draggedSelection ) );\n\n\t\t\tviewDocument.fire( 'clipboardOutput', { dataTransfer: data.dataTransfer, content, method: evt.name } );\n\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tthis._draggedRange.detach();\n\t\t\t\tthis._draggedRange = null;\n\t\t\t\tthis._draggingUid = '';\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\n\t\t// The handler for finalizing drag and drop. It should always be triggered after dragging completes\n\t\t// even if it was completed in a different application.\n\t\t// Note: This is not fired if source text node got removed while downcasting a marker.\n\t\tthis.listenTo( viewDocument, 'dragend', ( evt, data ) => {\n\t\t\tthis._finalizeDragging( !data.dataTransfer.isCanceled && data.dataTransfer.dropEffect == 'move' );\n\t\t}, { priority: 'low' } );\n\n\t\t// Dragging over the editable.\n\t\tthis.listenTo( viewDocument, 'dragenter', () => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tview.focus();\n\t\t} );\n\n\t\t// Dragging out of the editable.\n\t\tthis.listenTo( viewDocument, 'dragleave', () => {\n\t\t\t// We do not know if the mouse left the editor or just some element in it, so let us wait a few milliseconds\n\t\t\t// to check if 'dragover' is not fired.\n\t\t\tthis._removeDropMarkerDelayed();\n\t\t} );\n\n\t\t// Handler for moving dragged content over the target area.\n\t\tthis.listenTo( viewDocument, 'dragging', ( evt, data ) => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tdata.dataTransfer.dropEffect = 'none';\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._removeDropMarkerDelayed.cancel();\n\n\t\t\tconst targetRange = findDropTargetRange( editor, data.targetRanges, data.target );\n\n\t\t\t// If this is content being dragged from another editor, moving out of current editor instance\n\t\t\t// is not possible until 'dragend' event case will be fixed.\n\t\t\tif ( !this._draggedRange ) {\n\t\t\t\tdata.dataTransfer.dropEffect = 'copy';\n\t\t\t}\n\n\t\t\t// In Firefox it is already set and effect allowed remains the same as originally set.\n\t\t\tif ( !env.isGecko ) {\n\t\t\t\tif ( data.dataTransfer.effectAllowed == 'copy' ) {\n\t\t\t\t\tdata.dataTransfer.dropEffect = 'copy';\n\t\t\t\t} else if ( [ 'all', 'copyMove' ].includes( data.dataTransfer.effectAllowed ) ) {\n\t\t\t\t\tdata.dataTransfer.dropEffect = 'move';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* istanbul ignore else */\n\t\t\tif ( targetRange ) {\n\t\t\t\tthis._updateDropMarkerThrottled( targetRange );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Integration with the `clipboardInput` event.\n\t *\n\t * @private\n\t */\n\t_setupClipboardInputIntegration() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Update the event target ranges and abort dropping if dropping over itself.\n\t\tthis.listenTo( viewDocument, 'clipboardInput', ( evt, data ) => {\n\t\t\tif ( data.method != 'drop' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst targetRange = findDropTargetRange( editor, data.targetRanges, data.target );\n\n\t\t\t// The dragging markers must be removed after searching for the target range because sometimes\n\t\t\t// the target lands on the marker itself.\n\t\t\tthis._removeDropMarker();\n\n\t\t\t/* istanbul ignore if */\n\t\t\tif ( !targetRange ) {\n\t\t\t\tthis._finalizeDragging( false );\n\t\t\t\tevt.stop();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Since we cannot rely on the drag end event, we must check if the local drag range is from the current drag and drop\n\t\t\t// or it is from some previous not cleared one.\n\t\t\tif ( this._draggedRange && this._draggingUid != data.dataTransfer.getData( 'application/ckeditor5-dragging-uid' ) ) {\n\t\t\t\tthis._draggedRange.detach();\n\t\t\t\tthis._draggedRange = null;\n\t\t\t\tthis._draggingUid = '';\n\t\t\t}\n\n\t\t\t// Do not do anything if some content was dragged within the same document to the same position.\n\t\t\tconst isMove = getFinalDropEffect( data.dataTransfer ) == 'move';\n\n\t\t\tif ( isMove && this._draggedRange && this._draggedRange.containsRange( targetRange, true ) ) {\n\t\t\t\tthis._finalizeDragging( false );\n\t\t\t\tevt.stop();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Override the target ranges with the one adjusted to the best one for a drop.\n\t\t\tdata.targetRanges = [ editor.editing.mapper.toViewRange( targetRange ) ];\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Integration with the `contentInsertion` event of the clipboard pipeline.\n\t *\n\t * @private\n\t */\n\t_setupContentInsertionIntegration() {\n\t\tconst clipboardPipeline = this.editor.plugins.get( ClipboardPipeline );\n\n\t\tclipboardPipeline.on( 'contentInsertion', ( evt, data ) => {\n\t\t\tif ( !this.isEnabled || data.method !== 'drop' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Update the selection to the target range in the same change block to avoid selection post-fixing\n\t\t\t// and to be able to clone text attributes for plain text dropping.\n\t\t\tconst ranges = data.targetRanges.map( viewRange => this.editor.editing.mapper.toModelRange( viewRange ) );\n\n\t\t\tthis.editor.model.change( writer => writer.setSelection( ranges ) );\n\t\t}, { priority: 'high' } );\n\n\t\tclipboardPipeline.on( 'contentInsertion', ( evt, data ) => {\n\t\t\tif ( !this.isEnabled || data.method !== 'drop' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Remove dragged range content, remove markers, clean after dragging.\n\t\t\tconst isMove = getFinalDropEffect( data.dataTransfer ) == 'move';\n\n\t\t\t// Whether any content was inserted (insertion might fail if the schema is disallowing some elements\n\t\t\t// (for example an image caption allows only the content of a block but not blocks themselves.\n\t\t\t// Some integrations might not return valid range (i.e., table pasting).\n\t\t\tconst isSuccess = !data.resultRange || !data.resultRange.isCollapsed;\n\n\t\t\tthis._finalizeDragging( isSuccess && isMove );\n\t\t}, { priority: 'lowest' } );\n\t}\n\n\t/**\n\t * Adds listeners that add the `draggable` attribute to the elements while the mouse button is down so the dragging could start.\n\t *\n\t * @private\n\t */\n\t_setupDraggableAttributeHandling() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Add the 'draggable' attribute to the widget while pressing the selection handle.\n\t\t// This is required for widgets to be draggable. In Chrome it will enable dragging text nodes.\n\t\tthis.listenTo( viewDocument, 'mousedown', ( evt, data ) => {\n\t\t\t// The lack of data can be caused by editor tests firing fake mouse events. This should not occur\n\t\t\t// in real-life scenarios but this greatly simplifies editor tests that would otherwise fail a lot.\n\t\t\tif ( env.isAndroid || !data ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._clearDraggableAttributesDelayed.cancel();\n\n\t\t\t// Check if this is a mousedown over the widget (but not a nested editable).\n\t\t\tlet draggableElement = findDraggableWidget( data.target );\n\n\t\t\t// Note: There is a limitation that if more than a widget is selected (a widget and some text)\n\t\t\t// and dragging starts on the widget, then only the widget is dragged.\n\n\t\t\t// If this was not a widget then we should check if we need to drag some text content.\n\t\t\t// In Chrome set a 'draggable' attribute on closest editable to allow immediate dragging of the selected text range.\n\t\t\t// In Firefox this is not needed. In Safari it makes the whole editable draggable (not just textual content).\n\t\t\t// Disabled in read-only mode because draggable=\"true\" + contenteditable=\"false\" results\n\t\t\t// in not firing selectionchange event ever, which makes the selection stuck in read-only mode.\n\t\t\tif ( env.isBlink && !editor.isReadOnly && !draggableElement && !viewDocument.selection.isCollapsed ) {\n\t\t\t\tconst selectedElement = viewDocument.selection.getSelectedElement();\n\n\t\t\t\tif ( !selectedElement || !isWidget( selectedElement ) ) {\n\t\t\t\t\tdraggableElement = viewDocument.selection.editableElement;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( draggableElement ) {\n\t\t\t\tview.change( writer => {\n\t\t\t\t\twriter.setAttribute( 'draggable', 'true', draggableElement );\n\t\t\t\t} );\n\n\t\t\t\t// Keep the reference to the model element in case the view element gets removed while dragging.\n\t\t\t\tthis._draggableElement = editor.editing.mapper.toModelElement( draggableElement );\n\t\t\t}\n\t\t} );\n\n\t\t// Remove the draggable attribute in case no dragging started (only mousedown + mouseup).\n\t\tthis.listenTo( viewDocument, 'mouseup', () => {\n\t\t\tif ( !env.isAndroid ) {\n\t\t\t\tthis._clearDraggableAttributesDelayed();\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes the `draggable` attribute from the element that was used for dragging.\n\t *\n\t * @private\n\t */\n\t_clearDraggableAttributes() {\n\t\tconst editing = this.editor.editing;\n\n\t\tediting.view.change( writer => {\n\t\t\t// Remove 'draggable' attribute.\n\t\t\tif ( this._draggableElement && this._draggableElement.root.rootName != '$graveyard' ) {\n\t\t\t\twriter.removeAttribute( 'draggable', editing.mapper.toViewElement( this._draggableElement ) );\n\t\t\t}\n\n\t\t\tthis._draggableElement = null;\n\t\t} );\n\t}\n\n\t/**\n\t * Creates downcast conversion for the drop target marker.\n\t *\n\t * @private\n\t */\n\t_setupDropMarker() {\n\t\tconst editor = this.editor;\n\n\t\t// Drop marker conversion for hovering over widgets.\n\t\teditor.conversion.for( 'editingDowncast' ).markerToHighlight( {\n\t\t\tmodel: 'drop-target',\n\t\t\tview: {\n\t\t\t\tclasses: [ 'ck-clipboard-drop-target-range' ]\n\t\t\t}\n\t\t} );\n\n\t\t// Drop marker conversion for in text drop target.\n\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t\t\tmodel: 'drop-target',\n\t\t\tview: ( data, { writer } ) => {\n\t\t\t\tconst inText = editor.model.schema.checkChild( data.markerRange.start, '$text' );\n\n\t\t\t\tif ( !inText ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treturn writer.createUIElement( 'span', { class: 'ck ck-clipboard-drop-target-position' }, function( domDocument ) {\n\t\t\t\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t\t\t\t// Using word joiner to make this marker as high as text and also making text not break on marker.\n\t\t\t\t\tdomElement.innerHTML = '&NoBreak;<span></span>&NoBreak;';\n\n\t\t\t\t\treturn domElement;\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Updates the drop target marker to the provided range.\n\t *\n\t * @private\n\t * @param {module:engine/model/range~Range} targetRange The range to set the marker to.\n\t */\n\t_updateDropMarker( targetRange ) {\n\t\tconst editor = this.editor;\n\t\tconst markers = editor.model.markers;\n\n\t\teditor.model.change( writer => {\n\t\t\tif ( markers.has( 'drop-target' ) ) {\n\t\t\t\tif ( !markers.get( 'drop-target' ).getRange().isEqual( targetRange ) ) {\n\t\t\t\t\twriter.updateMarker( 'drop-target', { range: targetRange } );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twriter.addMarker( 'drop-target', {\n\t\t\t\t\trange: targetRange,\n\t\t\t\t\tusingOperation: false,\n\t\t\t\t\taffectsData: false\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes the drop target marker.\n\t *\n\t * @private\n\t */\n\t_removeDropMarker() {\n\t\tconst model = this.editor.model;\n\n\t\tthis._removeDropMarkerDelayed.cancel();\n\t\tthis._updateDropMarkerThrottled.cancel();\n\n\t\tif ( model.markers.has( 'drop-target' ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.removeMarker( 'drop-target' );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Deletes the dragged content from its original range and clears the dragging state.\n\t *\n\t * @private\n\t * @param {Boolean} moved Whether the move succeeded.\n\t */\n\t_finalizeDragging( moved ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tthis._removeDropMarker();\n\t\tthis._clearDraggableAttributes();\n\n\t\tthis._draggingUid = '';\n\n\t\tif ( !this._draggedRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Delete moved content.\n\t\tif ( moved && this.isEnabled ) {\n\t\t\tmodel.deleteContent( model.createSelection( this._draggedRange ), { doNotAutoparagraph: true } );\n\t\t}\n\n\t\tthis._draggedRange.detach();\n\t\tthis._draggedRange = null;\n\t}\n}\n\n// Returns fixed selection range for given position and target element.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {Array.<module:engine/view/range~Range>} targetViewRanges\n// @param {module:engine/view/element~Element} targetViewElement\n// @returns {module:engine/model/range~Range|null}\nfunction findDropTargetRange( editor, targetViewRanges, targetViewElement ) {\n\tconst model = editor.model;\n\tconst mapper = editor.editing.mapper;\n\n\tlet range = null;\n\n\tconst targetViewPosition = targetViewRanges ? targetViewRanges[ 0 ].start : null;\n\n\t// A UIElement is not a valid drop element, use parent (this could be a drop marker or any other UIElement).\n\tif ( targetViewElement.is( 'uiElement' ) ) {\n\t\ttargetViewElement = targetViewElement.parent;\n\t}\n\n\t// Quick win if the target is a widget (but not a nested editable).\n\trange = findDropTargetRangeOnWidget( editor, targetViewElement );\n\n\tif ( range ) {\n\t\treturn range;\n\t}\n\n\t// The easiest part is over, now we need to move to the model space.\n\n\t// Find target model element and position.\n\tconst targetModelElement = getClosestMappedModelElement( editor, targetViewElement );\n\tconst targetModelPosition = targetViewPosition ? mapper.toModelPosition( targetViewPosition ) : null;\n\n\t// There is no target position while hovering over an empty table cell.\n\t// In Safari, target position can be empty while hovering over a widget (e.g., a page-break).\n\t// Find the drop position inside the element.\n\tif ( !targetModelPosition ) {\n\t\treturn findDropTargetRangeInElement( editor, targetModelElement );\n\t}\n\n\t// Check if target position is between blocks and adjust drop position to the next object.\n\t// This is because while hovering over a root element next to a widget the target position can jump in crazy places.\n\trange = findDropTargetRangeBetweenBlocks( editor, targetModelPosition, targetModelElement );\n\n\tif ( range ) {\n\t\treturn range;\n\t}\n\n\t// Try fixing selection position.\n\t// In Firefox, the target position lands before widgets but in other browsers it tends to land after a widget.\n\trange = model.schema.getNearestSelectionRange( targetModelPosition, env.isGecko ? 'forward' : 'backward' );\n\n\tif ( range ) {\n\t\treturn range;\n\t}\n\n\t// There is no valid selection position inside the current limit element so find a closest object ancestor.\n\t// This happens if the model position lands directly in the <table> element itself (view target element was a `<td>`\n\t// so a nested editable, but view target position was directly in the `<figure>` element).\n\treturn findDropTargetRangeOnAncestorObject( editor, targetModelPosition.parent );\n}\n\n// Returns fixed selection range for a given position and a target element if it is over the widget but not over its nested editable.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {module:engine/view/element~Element} targetViewElement\n// @returns {module:engine/model/range~Range|null}\nfunction findDropTargetRangeOnWidget( editor, targetViewElement ) {\n\tconst model = editor.model;\n\tconst mapper = editor.editing.mapper;\n\n\t// Quick win if the target is a widget.\n\tif ( isWidget( targetViewElement ) ) {\n\t\treturn model.createRangeOn( mapper.toModelElement( targetViewElement ) );\n\t}\n\n\t// Check if we are deeper over a widget (but not over a nested editable).\n\tif ( !targetViewElement.is( 'editableElement' ) ) {\n\t\t// Find a closest ancestor that is either a widget or an editable element...\n\t\tconst ancestor = targetViewElement.findAncestor( node => isWidget( node ) || node.is( 'editableElement' ) );\n\n\t\t// ...and if the widget was closer then it is a drop target.\n\t\tif ( isWidget( ancestor ) ) {\n\t\t\treturn model.createRangeOn( mapper.toModelElement( ancestor ) );\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Returns fixed selection range inside a model element.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {module:engine/model/element~Element} targetModelElement\n// @returns {module:engine/model/range~Range}\nfunction findDropTargetRangeInElement( editor, targetModelElement ) {\n\tconst model = editor.model;\n\tconst schema = model.schema;\n\n\tconst positionAtElementStart = model.createPositionAt( targetModelElement, 0 );\n\n\treturn schema.getNearestSelectionRange( positionAtElementStart, 'forward' );\n}\n\n// Returns fixed selection range for a given position and a target element if the drop is between blocks.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {module:engine/model/position~Position} targetModelPosition\n// @param {module:engine/model/element~Element} targetModelElement\n// @returns {module:engine/model/range~Range|null}\nfunction findDropTargetRangeBetweenBlocks( editor, targetModelPosition, targetModelElement ) {\n\tconst model = editor.model;\n\n\t// Check if target is between blocks.\n\tif ( !model.schema.checkChild( targetModelElement, '$block' ) ) {\n\t\treturn null;\n\t}\n\n\t// Find position between blocks.\n\tconst positionAtElementStart = model.createPositionAt( targetModelElement, 0 );\n\n\t// Get the common part of the path (inside the target element and the target position).\n\tconst commonPath = targetModelPosition.path.slice( 0, positionAtElementStart.path.length );\n\n\t// Position between the blocks.\n\tconst betweenBlocksPosition = model.createPositionFromPath( targetModelPosition.root, commonPath );\n\tconst nodeAfter = betweenBlocksPosition.nodeAfter;\n\n\t// Adjust drop position to the next object.\n\t// This is because while hovering over a root element next to a widget the target position can jump in crazy places.\n\tif ( nodeAfter && model.schema.isObject( nodeAfter ) ) {\n\t\treturn model.createRangeOn( nodeAfter );\n\t}\n\n\treturn null;\n}\n\n// Returns a selection range on the ancestor object.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {module:engine/model/element~Element} element\n// @returns {module:engine/model/range~Range}\nfunction findDropTargetRangeOnAncestorObject( editor, element ) {\n\tconst model = editor.model;\n\n\twhile ( element ) {\n\t\tif ( model.schema.isObject( element ) ) {\n\t\t\treturn model.createRangeOn( element );\n\t\t}\n\n\t\telement = element.parent;\n\t}\n}\n\n// Returns the closest model element for the specified view element.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {module:engine/view/element~Element} element\n// @returns {module:engine/model/element~Element}\nfunction getClosestMappedModelElement( editor, element ) {\n\tconst mapper = editor.editing.mapper;\n\tconst view = editor.editing.view;\n\n\tconst targetModelElement = mapper.toModelElement( element );\n\n\tif ( targetModelElement ) {\n\t\treturn targetModelElement;\n\t}\n\n\t// Find mapped ancestor if the target is inside not mapped element (for example inline code element).\n\tconst viewPosition = view.createPositionBefore( element );\n\tconst viewElement = mapper.findMappedViewAncestor( viewPosition );\n\n\treturn mapper.toModelElement( viewElement );\n}\n\n// Returns the drop effect that should be a result of dragging the content.\n// This function is handling a quirk when checking the effect in the 'drop' DOM event.\nfunction getFinalDropEffect( dataTransfer ) {\n\tif ( env.isGecko ) {\n\t\treturn dataTransfer.dropEffect;\n\t}\n\n\treturn [ 'all', 'copyMove' ].includes( dataTransfer.effectAllowed ) ? 'move' : 'copy';\n}\n\n// Returns a function wrapper that will trigger a function after a specified wait time.\n// The timeout can be canceled by calling the cancel function on the returned wrapped function.\n//\n// @param {Function} func The function to wrap.\n// @param {Number} wait The timeout in ms.\n// @returns {Function}\nfunction delay( func, wait ) {\n\tlet timer;\n\n\tfunction delayed( ...args ) {\n\t\tdelayed.cancel();\n\t\ttimer = setTimeout( () => func( ...args ), wait );\n\t}\n\n\tdelayed.cancel = () => {\n\t\tclearTimeout( timer );\n\t};\n\n\treturn delayed;\n}\n\n// Returns a widget element that should be dragged.\n//\n// @param {module:engine/view/element~Element} target\n// @returns {module:engine/view/element~Element}\nfunction findDraggableWidget( target ) {\n\t// This is directly an editable so not a widget for sure.\n\tif ( target.is( 'editableElement' ) ) {\n\t\treturn null;\n\t}\n\n\t// TODO: Let's have a isWidgetSelectionHandleDomElement() helper in ckeditor5-widget utils.\n\tif ( target.hasClass( 'ck-widget__selection-handle' ) ) {\n\t\treturn target.findAncestor( isWidget );\n\t}\n\n\t// Direct hit on a widget.\n\tif ( isWidget( target ) ) {\n\t\treturn target;\n\t}\n\n\t// Find closest ancestor that is either a widget or an editable element...\n\tconst ancestor = target.findAncestor( node => isWidget( node ) || node.is( 'editableElement' ) );\n\n\t// ...and if closer was the widget then enable dragging it.\n\tif ( isWidget( ancestor ) ) {\n\t\treturn ancestor;\n\t}\n\n\treturn null;\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 clipboard/pasteplaintext\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport ClipboardObserver from './clipboardobserver';\nimport ClipboardPipeline from './clipboardpipeline';\n\n/**\n * The plugin detects the user's intention to paste plain text.\n *\n * For example, it detects the <kbd>Ctrl/Cmd</kbd> + <kbd>Shift</kbd> + <kbd>V</kbd> keystroke.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class PastePlainText extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PastePlainText';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ClipboardPipeline ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\t\tconst selection = model.document.selection;\n\n\t\tlet shiftPressed = false;\n\n\t\tview.addObserver( ClipboardObserver );\n\n\t\tthis.listenTo( viewDocument, 'keydown', ( evt, data ) => {\n\t\t\tshiftPressed = data.shiftKey;\n\t\t} );\n\n\t\teditor.plugins.get( ClipboardPipeline ).on( 'contentInsertion', ( evt, data ) => {\n\t\t\t// Plain text can be determined based on the event flag (#7799) or auto-detection (#1006). If detected,\n\t\t\t// preserve selection attributes on pasted items.\n\t\t\tif ( !shiftPressed && !isPlainTextFragment( data.content, model.schema ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmodel.change( writer => {\n\t\t\t\t// Formatting attributes should be preserved.\n\t\t\t\tconst textAttributes = Array.from( selection.getAttributes() )\n\t\t\t\t\t.filter( ( [ key ] ) => model.schema.getAttributeProperties( key ).isFormatting );\n\n\t\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\t\tmodel.deleteContent( selection, { doNotAutoparagraph: true } );\n\t\t\t\t}\n\n\t\t\t\t// Also preserve other attributes if they survived the content deletion (because they were not fully selected).\n\t\t\t\t// For example linkHref is not a formatting attribute but it should be preserved if pasted text was in the middle\n\t\t\t\t// of a link.\n\t\t\t\ttextAttributes.push( ...selection.getAttributes() );\n\n\t\t\t\tconst range = writer.createRangeIn( data.content );\n\n\t\t\t\tfor ( const item of range.getItems() ) {\n\t\t\t\t\tif ( item.is( '$textProxy' ) ) {\n\t\t\t\t\t\twriter.setAttributes( textAttributes, item );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n}\n\n// Returns true if specified `documentFragment` represents a plain text.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isPlainTextFragment( documentFragment, schema ) {\n\tif ( documentFragment.childCount > 1 ) {\n\t\treturn false;\n\t}\n\n\tconst child = documentFragment.getChild( 0 );\n\n\tif ( schema.isObject( child ) ) {\n\t\treturn false;\n\t}\n\n\treturn [ ...child.getAttributeKeys() ].length == 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 clipboard/clipboard\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\n\nimport ClipboardPipeline from './clipboardpipeline';\nimport DragDrop from './dragdrop';\nimport PastePlainText from './pasteplaintext';\n\n/**\n * The clipboard feature.\n *\n * Read more about the clipboard integration in the {@glink framework/guides/deep-dive/clipboard clipboard deep dive guide}.\n *\n * This is a \"glue\" plugin which loads the following plugins:\n * * {@link module:clipboard/clipboardpipeline~ClipboardPipeline}\n * * {@link module:clipboard/dragdrop~DragDrop}\n * * {@link module:clipboard/pasteplaintext~PastePlainText}\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Clipboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Clipboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ClipboardPipeline, DragDrop, PastePlainText ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\nimport { FileRepository } from 'ckeditor5/src/upload';\nimport { Command } from 'ckeditor5/src/core';\nimport { toArray } from 'ckeditor5/src/utils';\n\nimport { insertImage, isImageAllowed } from '../image/utils';\n\n/**\n * @module image/imageupload/uploadimagecommand\n */\n\n/**\n * The upload image command.\n *\n * The command is registered by the {@link module:image/imageupload/imageuploadediting~ImageUploadEditing} plugin as `uploadImage`\n * and it is also available via aliased `imageUpload` name.\n *\n * In order to upload an image at the current selection position\n * (according to the {@link module:widget/utils~findOptimalInsertionPosition} algorithm),\n * execute the command and pass the native image file instance:\n *\n *\t\tthis.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {\n *\t\t\t// Assuming that only images were pasted:\n *\t\t\tconst images = Array.from( data.dataTransfer.files );\n *\n *\t\t\t// Upload the first image:\n *\t\t\teditor.execute( 'uploadImage', { file: images[ 0 ] } );\n *\t\t} );\n *\n * It is also possible to insert multiple images at once:\n *\n *\t\teditor.execute( 'uploadImage', {\n *\t\t\tfile: [\n *\t\t\t\tfile1,\n *\t\t\t\tfile2\n *\t\t\t]\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class UploadImageCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst imageElement = this.editor.model.document.selection.getSelectedElement();\n\t\tconst isImage = imageElement && imageElement.name === 'image' || false;\n\n\t\tthis.isEnabled = isImageAllowed( this.editor.model ) || isImage;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} options Options for the executed command.\n\t * @param {File|Array.<File>} options.file The image file or an array of image files to upload.\n\t */\n\texecute( options ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\n\t\tfor ( const file of toArray( options.file ) ) {\n\t\t\tuploadImage( model, fileRepository, file );\n\t\t}\n\t}\n}\n\n// Handles uploading single file.\n//\n// @param {module:engine/model/model~Model} model\n// @param {File} file\nfunction uploadImage( model, fileRepository, file ) {\n\tconst loader = fileRepository.createLoader( file );\n\n\t// Do not throw when upload adapter is not set. FileRepository will log an error anyway.\n\tif ( !loader ) {\n\t\treturn;\n\t}\n\n\tinsertImage( model, { uploadId: loader.id } );\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 image/imageupload/imageuploadediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport { UpcastWriter } from 'ckeditor5/src/engine';\n\nimport { Notification } from 'ckeditor5/src/ui';\nimport { ClipboardPipeline } from 'ckeditor5/src/clipboard';\nimport { FileRepository } from 'ckeditor5/src/upload';\nimport { env } from 'ckeditor5/src/utils';\n\nimport UploadImageCommand from './uploadimagecommand';\nimport { fetchLocalImage, isLocalImage } from '../../src/imageupload/utils';\nimport { createImageTypeRegExp } from './utils';\nimport { getViewImgFromWidget } from '../image/utils';\n\n/**\n * The editing part of the image upload feature. It registers the `'uploadImage'` command\n * and `imageUpload` command as an aliased name.\n *\n * When an image is uploaded it fires the {@link ~ImageUploadEditing#event:uploadComplete `uploadComplete` event}\n * that allows adding custom attributes to the {@link module:engine/model/element~Element image element}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUploadEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository, Notification, ClipboardPipeline ];\n\t}\n\n\tstatic get pluginName() {\n\t\treturn 'ImageUploadEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'image', {\n\t\t\tupload: {\n\t\t\t\ttypes: [ 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff' ]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst doc = editor.model.document;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\n\t\tconst imageTypes = createImageTypeRegExp( editor.config.get( 'image.upload.types' ) );\n\n\t\t// Setup schema to allow uploadId and uploadStatus for images.\n\t\tschema.extend( 'image', {\n\t\t\tallowAttributes: [ 'uploadId', 'uploadStatus' ]\n\t\t} );\n\n\t\tconst uploadImageCommand = new UploadImageCommand( editor );\n\n\t\t// Register `uploadImage` command and add `imageUpload` command as an alias for backward compatibility.\n\t\teditor.commands.add( 'uploadImage', uploadImageCommand );\n\t\teditor.commands.add( 'imageUpload', uploadImageCommand );\n\n\t\t// Register upcast converter for uploadId.\n\t\tconversion.for( 'upcast' )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'img',\n\t\t\t\t\tkey: 'uploadId'\n\t\t\t\t},\n\t\t\t\tmodel: 'uploadId'\n\t\t\t} );\n\n\t\t// Handle pasted images.\n\t\t// For every image file, a new file loader is created and a placeholder image is\n\t\t// inserted into the content. Then, those images are uploaded once they appear in the model\n\t\t// (see Document#change listener below).\n\t\tthis.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {\n\t\t\t// Skip if non empty HTML data is included.\n\t\t\t// https://github.com/ckeditor/ckeditor5-upload/issues/68\n\t\t\tif ( isHtmlIncluded( data.dataTransfer ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst images = Array.from( data.dataTransfer.files ).filter( file => {\n\t\t\t\t// See https://github.com/ckeditor/ckeditor5-image/pull/254.\n\t\t\t\tif ( !file ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\treturn imageTypes.test( file.type );\n\t\t\t} );\n\n\t\t\tif ( !images.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tevt.stop();\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\t// Set selection to paste target.\n\t\t\t\tif ( data.targetRanges ) {\n\t\t\t\t\twriter.setSelection( data.targetRanges.map( viewRange => editor.editing.mapper.toModelRange( viewRange ) ) );\n\t\t\t\t}\n\n\t\t\t\t// Upload images after the selection has changed in order to ensure the command's state is refreshed.\n\t\t\t\teditor.model.enqueueChange( 'default', () => {\n\t\t\t\t\teditor.execute( 'uploadImage', { file: images } );\n\t\t\t\t} );\n\t\t\t} );\n\t\t} );\n\n\t\t// Handle HTML pasted with images with base64 or blob sources.\n\t\t// For every image file, a new file loader is created and a placeholder image is\n\t\t// inserted into the content. Then, those images are uploaded once they appear in the model\n\t\t// (see Document#change listener below).\n\t\tthis.listenTo( editor.plugins.get( 'ClipboardPipeline' ), 'inputTransformation', ( evt, data ) => {\n\t\t\tconst fetchableImages = Array.from( editor.editing.view.createRangeIn( data.content ) )\n\t\t\t\t.filter( value => isLocalImage( value.item ) && !value.item.getAttribute( 'uploadProcessed' ) )\n\t\t\t\t.map( value => { return { promise: fetchLocalImage( value.item ), imageElement: value.item }; } );\n\n\t\t\tif ( !fetchableImages.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst writer = new UpcastWriter( editor.editing.view.document );\n\n\t\t\tfor ( const fetchableImage of fetchableImages ) {\n\t\t\t\t// Set attribute marking that the image was processed already.\n\t\t\t\twriter.setAttribute( 'uploadProcessed', true, fetchableImage.imageElement );\n\n\t\t\t\tconst loader = fileRepository.createLoader( fetchableImage.promise );\n\n\t\t\t\tif ( loader ) {\n\t\t\t\t\twriter.setAttribute( 'src', '', fetchableImage.imageElement );\n\t\t\t\t\twriter.setAttribute( 'uploadId', loader.id, fetchableImage.imageElement );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Prevents from the browser redirecting to the dropped image.\n\t\teditor.editing.view.document.on( 'dragover', ( evt, data ) => {\n\t\t\tdata.preventDefault();\n\t\t} );\n\n\t\t// Upload placeholder images that appeared in the model.\n\t\tdoc.on( 'change', () => {\n\t\t\tconst changes = doc.differ.getChanges( { includeChangesInGraveyard: true } );\n\n\t\t\tfor ( const entry of changes ) {\n\t\t\t\tif ( entry.type == 'insert' && entry.name != '$text' ) {\n\t\t\t\t\tconst item = entry.position.nodeAfter;\n\t\t\t\t\tconst isInGraveyard = entry.position.root.rootName == '$graveyard';\n\n\t\t\t\t\tfor ( const image of getImagesFromChangeItem( editor, item ) ) {\n\t\t\t\t\t\t// Check if the image element still has upload id.\n\t\t\t\t\t\tconst uploadId = image.getAttribute( 'uploadId' );\n\n\t\t\t\t\t\tif ( !uploadId ) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Check if the image is loaded on this client.\n\t\t\t\t\t\tconst loader = fileRepository.loaders.get( uploadId );\n\n\t\t\t\t\t\tif ( !loader ) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( isInGraveyard ) {\n\t\t\t\t\t\t\t// If the image was inserted to the graveyard - abort the loading process.\n\t\t\t\t\t\t\tloader.abort();\n\t\t\t\t\t\t} else if ( loader.status == 'idle' ) {\n\t\t\t\t\t\t\t// If the image was inserted into content and has not been loaded yet, start loading it.\n\t\t\t\t\t\t\tthis._readAndUpload( loader, image );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Set the default handler for feeding the image element with `src` and `srcset` attributes.\n\t\tthis.on( 'uploadComplete', ( evt, { imageElement, data } ) => {\n\t\t\tconst urls = data.urls ? data.urls : data;\n\n\t\t\tthis.editor.model.change( writer => {\n\t\t\t\twriter.setAttribute( 'src', urls.default, imageElement );\n\t\t\t\tthis._parseAndSetSrcsetAttributeOnImage( urls, imageElement, writer );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Reads and uploads an image.\n\t *\n\t * The image is read from the disk and as a Base64-encoded string it is set temporarily to\n\t * `image[src]`. When the image is successfully uploaded, the temporary data is replaced with the target\n\t * image's URL (the URL to the uploaded image on the server).\n\t *\n\t * @protected\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t * @param {module:engine/model/element~Element} imageElement\n\t * @returns {Promise}\n\t */\n\t_readAndUpload( loader, imageElement ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst t = editor.locale.t;\n\t\tconst fileRepository = editor.plugins.get( FileRepository );\n\t\tconst notification = editor.plugins.get( Notification );\n\n\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\twriter.setAttribute( 'uploadStatus', 'reading', imageElement );\n\t\t} );\n\n\t\treturn loader.read()\n\t\t\t.then( () => {\n\t\t\t\tconst promise = loader.upload();\n\n\t\t\t\t// Force repaint in Safari. Without it, the image will display with a wrong size.\n\t\t\t\t// https://github.com/ckeditor/ckeditor5/issues/1975\n\t\t\t\t/* istanbul ignore next */\n\t\t\t\tif ( env.isSafari ) {\n\t\t\t\t\tconst viewFigure = editor.editing.mapper.toViewElement( imageElement );\n\t\t\t\t\tconst viewImg = getViewImgFromWidget( viewFigure );\n\n\t\t\t\t\teditor.editing.view.once( 'render', () => {\n\t\t\t\t\t\t// Early returns just to be safe. There might be some code ran\n\t\t\t\t\t\t// in between the outer scope and this callback.\n\t\t\t\t\t\tif ( !viewImg.parent ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst domFigure = editor.editing.view.domConverter.mapViewToDom( viewImg.parent );\n\n\t\t\t\t\t\tif ( !domFigure ) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst originalDisplay = domFigure.style.display;\n\n\t\t\t\t\t\tdomFigure.style.display = 'none';\n\n\t\t\t\t\t\t// Make sure this line will never be removed during minification for having \"no effect\".\n\t\t\t\t\t\tdomFigure._ckHack = domFigure.offsetHeight;\n\n\t\t\t\t\t\tdomFigure.style.display = originalDisplay;\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\t\twriter.setAttribute( 'uploadStatus', 'uploading', imageElement );\n\t\t\t\t} );\n\n\t\t\t\treturn promise;\n\t\t\t} )\n\t\t\t.then( data => {\n\t\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\t\twriter.setAttribute( 'uploadStatus', 'complete', imageElement );\n\n\t\t\t\t\t/**\n\t\t\t\t\t * An event fired when an image is uploaded. You can hook into this event to provide\n\t\t\t\t\t * custom attributes to the {@link module:engine/model/element~Element image element} based on the data from\n\t\t\t\t\t * the server.\n\t\t\t\t\t *\n\t\t\t\t\t * \t\tconst imageUploadEditing = editor.plugins.get( 'ImageUploadEditing' );\n\t\t\t\t\t *\n\t\t\t\t\t * \t\timageUploadEditing.on( 'uploadComplete', ( evt, { data, imageElement } ) => {\n\t\t\t\t\t * \t\t\teditor.model.change( writer => {\n\t\t\t\t\t * \t\t\t\twriter.setAttribute( 'someAttribute', 'foo', imageElement );\n\t\t\t\t\t * \t\t\t} );\n\t\t\t\t\t * \t\t} );\n\t\t\t\t\t *\n\t\t\t\t\t * You can also stop the default handler that sets the `src` and `srcset` attributes\n\t\t\t\t\t * if you want to provide custom values for these attributes.\n\t\t\t\t\t *\n\t\t\t\t\t * \t\timageUploadEditing.on( 'uploadComplete', ( evt, { data, imageElement } ) => {\n\t\t\t\t\t * \t\t\tevt.stop();\n\t\t\t\t\t * \t\t} );\n\t\t\t\t\t *\n\t\t\t\t\t * **Note**: This event is fired by the {@link module:image/imageupload/imageuploadediting~ImageUploadEditing} plugin.\n\t\t\t\t\t *\n\t\t\t\t\t * @event uploadComplete\n\t\t\t\t\t * @param {Object} data The `uploadComplete` event data.\n\t\t\t\t\t * @param {Object} data.data The data coming from the upload adapter.\n\t\t\t\t\t * @param {module:engine/model/element~Element} data.imageElement The\n\t\t\t\t\t * model {@link module:engine/model/element~Element image element} that can be customized.\n\t\t\t\t\t */\n\t\t\t\t\tthis.fire( 'uploadComplete', { data, imageElement } );\n\t\t\t\t} );\n\n\t\t\t\tclean();\n\t\t\t} )\n\t\t\t.catch( error => {\n\t\t\t\t// If status is not 'error' nor 'aborted' - throw error because it means that something else went wrong,\n\t\t\t\t// it might be generic error and it would be real pain to find what is going on.\n\t\t\t\tif ( loader.status !== 'error' && loader.status !== 'aborted' ) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\n\t\t\t\t// Might be 'aborted'.\n\t\t\t\tif ( loader.status == 'error' && error ) {\n\t\t\t\t\tnotification.showWarning( error, {\n\t\t\t\t\t\ttitle: t( 'Upload failed' ),\n\t\t\t\t\t\tnamespace: 'upload'\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tclean();\n\n\t\t\t\t// Permanently remove image from insertion batch.\n\t\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\t\twriter.remove( imageElement );\n\t\t\t\t} );\n\t\t\t} );\n\n\t\tfunction clean() {\n\t\t\tmodel.enqueueChange( 'transparent', writer => {\n\t\t\t\twriter.removeAttribute( 'uploadId', imageElement );\n\t\t\t\twriter.removeAttribute( 'uploadStatus', imageElement );\n\t\t\t} );\n\n\t\t\tfileRepository.destroyLoader( loader );\n\t\t}\n\t}\n\n\t/**\n\t * Creates the `srcset` attribute based on a given file upload response and sets it as an attribute to a specific image element.\n\t *\n\t * @protected\n\t * @param {Object} data Data object from which `srcset` will be created.\n\t * @param {module:engine/model/element~Element} image The image element on which the `srcset` attribute will be set.\n\t * @param {module:engine/model/writer~Writer} writer\n\t */\n\t_parseAndSetSrcsetAttributeOnImage( data, image, writer ) {\n\t\t// Srcset attribute for responsive images support.\n\t\tlet maxWidth = 0;\n\n\t\tconst srcsetAttribute = Object.keys( data )\n\t\t\t// Filter out keys that are not integers.\n\t\t\t.filter( key => {\n\t\t\t\tconst width = parseInt( key, 10 );\n\n\t\t\t\tif ( !isNaN( width ) ) {\n\t\t\t\t\tmaxWidth = Math.max( maxWidth, width );\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} )\n\n\t\t\t// Convert each key to srcset entry.\n\t\t\t.map( key => `${ data[ key ] } ${ key }w` )\n\n\t\t\t// Join all entries.\n\t\t\t.join( ', ' );\n\n\t\tif ( srcsetAttribute != '' ) {\n\t\t\twriter.setAttribute( 'srcset', {\n\t\t\t\tdata: srcsetAttribute,\n\t\t\t\twidth: maxWidth\n\t\t\t}, image );\n\t\t}\n\t}\n}\n\n// Returns `true` if non-empty `text/html` is included in the data transfer.\n//\n// @param {module:clipboard/datatransfer~DataTransfer} dataTransfer\n// @returns {Boolean}\nexport function isHtmlIncluded( dataTransfer ) {\n\treturn Array.from( dataTransfer.types ).includes( 'text/html' ) && dataTransfer.getData( 'text/html' ) !== '';\n}\n\nfunction getImagesFromChangeItem( editor, item ) {\n\treturn Array.from( editor.model.createRangeOn( item ) )\n\t\t.filter( value => value.item.is( 'element', 'image' ) )\n\t\t.map( value => value.item );\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 image/imageresize/resizeimagecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { isImage } from '../image/utils';\n\n/**\n * The resize image command. Currently, it only supports the width attribute.\n *\n * @extends module:core/command~Command\n */\nexport default class ResizeImageCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst element = this.editor.model.document.selection.getSelectedElement();\n\n\t\tthis.isEnabled = isImage( element );\n\n\t\tif ( !element || !element.hasAttribute( 'width' ) ) {\n\t\t\tthis.value = null;\n\t\t} else {\n\t\t\tthis.value = {\n\t\t\t\twidth: element.getAttribute( 'width' ),\n\t\t\t\theight: null\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t *\t\t// Sets the width to 50%:\n\t *\t\teditor.execute( 'resizeImage', { width: '50%' } );\n\t *\n\t *\t\t// Removes the width attribute:\n\t *\t\teditor.execute( 'resizeImage', { width: null } );\n\t *\n\t * @param {Object} options\n\t * @param {String|null} options.width The new width of the image.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst imageElement = model.document.selection.getSelectedElement();\n\n\t\tthis.value = {\n\t\t\twidth: options.width,\n\t\t\theight: null\n\t\t};\n\n\t\tif ( imageElement ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setAttribute( 'width', options.width, imageElement );\n\t\t\t} );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageresize/imageresizeediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ResizeImageCommand from './resizeimagecommand';\n\n/**\n * The image resize editing feature.\n *\n * It adds the ability to resize each image using handles or manually by\n * {@link module:image/imageresize/imageresizebuttons~ImageResizeButtons} buttons.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageResizeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageResizeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'image', {\n\t\t\tresizeUnit: '%',\n\t\t\tresizeOptions: [ {\n\t\t\t\tname: 'resizeImage:original',\n\t\t\t\tvalue: null,\n\t\t\t\ticon: 'original'\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'resizeImage:25',\n\t\t\t\tvalue: '25',\n\t\t\t\ticon: 'small'\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'resizeImage:50',\n\t\t\t\tvalue: '50',\n\t\t\t\ticon: 'medium'\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'resizeImage:75',\n\t\t\t\tvalue: '75',\n\t\t\t\ticon: 'large'\n\t\t\t} ]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst resizeImageCommand = new ResizeImageCommand( editor );\n\n\t\tthis._registerSchema();\n\t\tthis._registerConverters();\n\n\t\t// Register `resizeImage` command and add `imageResize` command as an alias for backward compatibility.\n\t\teditor.commands.add( 'resizeImage', resizeImageCommand );\n\t\teditor.commands.add( 'imageResize', resizeImageCommand );\n\t}\n\n\t/**\n\t * @private\n\t */\n\t_registerSchema() {\n\t\tthis.editor.model.schema.extend( 'image', { allowAttributes: 'width' } );\n\t\tthis.editor.model.schema.setAttributeProperties( 'width', {\n\t\t\tisFormatting: true\n\t\t} );\n\t}\n\n\t/**\n\t * Registers image resize converters.\n\t *\n\t * @private\n\t */\n\t_registerConverters() {\n\t\tconst editor = this.editor;\n\n\t\t// Dedicated converter to propagate image's attribute to the img tag.\n\t\teditor.conversion.for( 'downcast' ).add( dispatcher =>\n\t\t\tdispatcher.on( 'attribute:width:image', ( evt, data, conversionApi ) => {\n\t\t\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\t\tconst figure = conversionApi.mapper.toViewElement( data.item );\n\n\t\t\t\tif ( data.attributeNewValue !== null ) {\n\t\t\t\t\tviewWriter.setStyle( 'width', data.attributeNewValue, figure );\n\t\t\t\t\tviewWriter.addClass( 'image_resized', figure );\n\t\t\t\t} else {\n\t\t\t\t\tviewWriter.removeStyle( 'width', figure );\n\t\t\t\t\tviewWriter.removeClass( 'image_resized', figure );\n\t\t\t\t}\n\t\t\t} )\n\t\t);\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.attributeToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'figure',\n\t\t\t\t\tstyles: {\n\t\t\t\t\t\twidth: /.+/\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: 'width',\n\t\t\t\t\tvalue: viewElement => viewElement.getStyle( 'width' )\n\t\t\t\t}\n\t\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imageresize/imageresizebuttons\n */\n\nimport { Plugin, icons } from 'ckeditor5/src/core';\nimport { ButtonView, DropdownButtonView, Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui';\nimport { CKEditorError, Collection } from 'ckeditor5/src/utils';\n\nimport ImageResizeEditing from './imageresizeediting';\n\nconst RESIZE_ICONS = {\n\tsmall: icons.objectSizeSmall,\n\tmedium: icons.objectSizeMedium,\n\tlarge: icons.objectSizeLarge,\n\toriginal: icons.objectSizeFull\n};\n\n/**\n * The image resize buttons plugin.\n *\n * It adds a possibility to resize images using the toolbar dropdown or individual buttons, depending on the plugin configuration.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageResizeButtons extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageResizeEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageResizeButtons';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The resize unit.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @type {module:image/image~ImageConfig#resizeUnit}\n\t\t * @default '%'\n\t\t */\n\t\tthis._resizeUnit = editor.config.get( 'image.resizeUnit' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst options = editor.config.get( 'image.resizeOptions' );\n\t\tconst command = editor.commands.get( 'resizeImage' );\n\n\t\tthis.bind( 'isEnabled' ).to( command );\n\n\t\tfor ( const option of options ) {\n\t\t\tthis._registerImageResizeButton( option );\n\t\t}\n\n\t\tthis._registerImageResizeDropdown( options );\n\t}\n\n\t/**\n\t * A helper function that creates a standalone button component for the plugin.\n\t *\n\t * @private\n\t * @param {module:image/imageresize/imageresizebuttons~ImageResizeOption} resizeOption A model of the resize option.\n\t */\n\t_registerImageResizeButton( option ) {\n\t\tconst editor = this.editor;\n\t\tconst { name, value, icon } = option;\n\t\tconst optionValueWithUnit = value ? value + this._resizeUnit : null;\n\n\t\teditor.ui.componentFactory.add( name, locale => {\n\t\t\tconst button = new ButtonView( locale );\n\t\t\tconst command = editor.commands.get( 'resizeImage' );\n\t\t\tconst labelText = this._getOptionLabelValue( option, true );\n\n\t\t\tif ( !RESIZE_ICONS[ icon ] ) {\n\t\t\t\t/**\n\t\t\t\t * When configuring {@link module:image/image~ImageConfig#resizeOptions `config.image.resizeOptions`} for standalone\n\t\t\t\t * buttons, a valid `icon` token must be set for each option.\n\t\t\t\t *\n\t\t\t\t * See all valid options described in the\n\t\t\t\t * {@link module:image/imageresize/imageresizebuttons~ImageResizeOption plugin configuration}.\n\t\t\t\t *\n\t\t\t\t * @error imageresizebuttons-missing-icon\n\t\t\t\t * @param {module:image/imageresize/imageresizebuttons~ImageResizeOption} option Invalid image resize option.\n\t\t\t\t*/\n\t\t\t\tthrow new CKEditorError(\n\t\t\t\t\t'imageresizebuttons-missing-icon',\n\t\t\t\t\teditor,\n\t\t\t\t\toption\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tbutton.set( {\n\t\t\t\t// Use the `label` property for a verbose description (because of ARIA).\n\t\t\t\tlabel: labelText,\n\t\t\t\ticon: RESIZE_ICONS[ icon ],\n\t\t\t\ttooltip: labelText,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\t// Bind button to the command.\n\t\t\tbutton.bind( 'isEnabled' ).to( this );\n\t\t\tbutton.bind( 'isOn' ).to( command, 'value', getIsOnButtonCallback( optionValueWithUnit ) );\n\n\t\t\tthis.listenTo( button, 'execute', () => {\n\t\t\t\teditor.execute( 'resizeImage', { width: optionValueWithUnit } );\n\t\t\t} );\n\n\t\t\treturn button;\n\t\t} );\n\t}\n\n\t/**\n\t * A helper function that creates a dropdown component for the plugin containing all the resize options defined in\n\t * the editor configuration.\n\t *\n\t * @private\n\t * @param {Array.<module:image/imageresize/imageresizebuttons~ImageResizeOption>} options An array of configured options.\n\t */\n\t_registerImageResizeDropdown( options ) {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst originalSizeOption = options.find( option => !option.value );\n\n\t\tconst componentCreator = locale => {\n\t\t\tconst command = editor.commands.get( 'resizeImage' );\n\t\t\tconst dropdownView = createDropdown( locale, DropdownButtonView );\n\t\t\tconst dropdownButton = dropdownView.buttonView;\n\n\t\t\tdropdownButton.set( {\n\t\t\t\ttooltip: t( 'Resize image' ),\n\t\t\t\tcommandValue: originalSizeOption.value,\n\t\t\t\ticon: RESIZE_ICONS.medium,\n\t\t\t\tisToggleable: true,\n\t\t\t\tlabel: this._getOptionLabelValue( originalSizeOption ),\n\t\t\t\twithText: true,\n\t\t\t\tclass: 'ck-resize-image-button'\n\t\t\t} );\n\n\t\t\tdropdownButton.bind( 'label' ).to( command, 'value', commandValue => {\n\t\t\t\tif ( commandValue && commandValue.width ) {\n\t\t\t\t\treturn commandValue.width;\n\t\t\t\t} else {\n\t\t\t\t\treturn this._getOptionLabelValue( originalSizeOption );\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdropdownView.bind( 'isOn' ).to( command );\n\t\t\tdropdownView.bind( 'isEnabled' ).to( this );\n\n\t\t\taddListToDropdown( dropdownView, this._getResizeDropdownListItemDefinitions( options, command ) );\n\n\t\t\tdropdownView.listView.ariaLabel = t( 'Image resize list' );\n\n\t\t\t// Execute command when an item from the dropdown is selected.\n\t\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\t\teditor.execute( evt.source.commandName, { width: evt.source.commandValue } );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t};\n\n\t\t// Register `resizeImage` dropdown and add `imageResize` dropdown as an alias for backward compatibility.\n\t\teditor.ui.componentFactory.add( 'resizeImage', componentCreator );\n\t\teditor.ui.componentFactory.add( 'imageResize', componentCreator );\n\t}\n\n\t/**\n\t * A helper function for creating an option label value string.\n\t *\n\t * @private\n\t * @param {module:image/imageresize/imageresizebuttons~ImageResizeOption} option A resize option object.\n\t * @param {Boolean} [forTooltip] An optional flag for creating a tooltip label.\n\t * @returns {String} A user-defined label combined from the numeric value and the resize unit or the default label\n\t * for reset options (`Original`).\n\t */\n\t_getOptionLabelValue( option, forTooltip ) {\n\t\tconst t = this.editor.t;\n\n\t\tif ( option.label ) {\n\t\t\treturn option.label;\n\t\t} else if ( forTooltip ) {\n\t\t\tif ( option.value ) {\n\t\t\t\treturn t( 'Resize image to %0', option.value + this._resizeUnit );\n\t\t\t} else {\n\t\t\t\treturn t( 'Resize image to the original size' );\n\t\t\t}\n\t\t} else {\n\t\t\tif ( option.value ) {\n\t\t\t\treturn option.value + this._resizeUnit;\n\t\t\t} else {\n\t\t\t\treturn t( 'Original' );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * A helper function that parses the resize options and returns list item definitions ready for use in the dropdown.\n\t *\n\t * @private\n\t * @param {Array.<module:image/imageresize/imageresizebuttons~ImageResizeOption>} options The resize options.\n\t * @param {module:image/imageresize/resizeimagecommand~ResizeImageCommand} command The resize image command.\n\t * @returns {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} Dropdown item definitions.\n\t */\n\t_getResizeDropdownListItemDefinitions( options, command ) {\n\t\tconst itemDefinitions = new Collection();\n\n\t\toptions.map( option => {\n\t\t\tconst optionValueWithUnit = option.value ? option.value + this._resizeUnit : null;\n\t\t\tconst definition = {\n\t\t\t\ttype: 'button',\n\t\t\t\tmodel: new Model( {\n\t\t\t\t\tcommandName: 'resizeImage',\n\t\t\t\t\tcommandValue: optionValueWithUnit,\n\t\t\t\t\tlabel: this._getOptionLabelValue( option ),\n\t\t\t\t\twithText: true,\n\t\t\t\t\ticon: null\n\t\t\t\t} )\n\t\t\t};\n\n\t\t\tdefinition.model.bind( 'isOn' ).to( command, 'value', getIsOnButtonCallback( optionValueWithUnit ) );\n\n\t\t\titemDefinitions.add( definition );\n\t\t} );\n\n\t\treturn itemDefinitions;\n\t}\n}\n\n// A helper function for setting the `isOn` state of buttons in value bindings.\nfunction getIsOnButtonCallback( value ) {\n\treturn commandValue => {\n\t\tif ( value === null && commandValue === value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn commandValue && commandValue.width === value;\n\t};\n}\n\n/**\n * The image resize option used in the {@link module:image/image~ImageConfig#resizeOptions image resize configuration}.\n *\n * @typedef {Object} module:image/imageresize/imageresizebuttons~ImageResizeOption\n * @property {String} name The name of the UI component that changes the image size.\n * * If you configure the feature using individual resize buttons, you can refer to this name in the\n * {@link module:image/image~ImageConfig#toolbar image toolbar configuration}.\n * * If you configure the feature using the resize dropdown, this name will be used for a list item in the dropdown.\n * @property {String} value The value of the resize option without the unit\n * ({@link module:image/image~ImageConfig#resizeUnit configured separately}). `null` resets an image to its original size.\n * @property {String} [resizeOptions.icon] An icon used by an individual resize button (see the `name` property to learn more).\n * Available icons are: `'small'`, `'medium'`, `'large'`, `'original'`.\n * @property {String} [label] An option label displayed in the dropdown or, if the feature is configured using\n * individual buttons, a {@link module:ui/button/buttonview~ButtonView#tooltip} and an ARIA attribute of a button.\n * If not specified, the label is generated automatically based on the `value` option and the\n * {@link module:image/image~ImageConfig#resizeUnit `config.image.resizeUnit`}.\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 image/imageresize/imageresizehandles\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { WidgetResize } from 'ckeditor5/src/widget';\n\nimport ImageLoadObserver from '../image/imageloadobserver';\n\n/**\n * The image resize by handles feature.\n *\n * It adds the ability to resize each image using handles or manually by\n * {@link module:image/imageresize/imageresizebuttons~ImageResizeButtons} buttons.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageResizeHandles extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetResize ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageResizeHandles';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst command = this.editor.commands.get( 'resizeImage' );\n\t\tthis.bind( 'isEnabled' ).to( command );\n\n\t\tthis._setupResizerCreator();\n\t}\n\n\t/**\n\t * Attaches the listeners responsible for creating a resizer for each image, except for images inside the HTML embed preview.\n\t *\n\t * @private\n\t */\n\t_setupResizerCreator() {\n\t\tconst editor = this.editor;\n\t\tconst editingView = editor.editing.view;\n\n\t\teditingView.addObserver( ImageLoadObserver );\n\n\t\tthis.listenTo( editingView.document, 'imageLoaded', ( evt, domEvent ) => {\n\t\t\t// The resizer must be attached only to images loaded by the `ImageInsert`, `ImageUpload` or `LinkImage` plugins.\n\t\t\tif ( !domEvent.target.matches( 'figure.image.ck-widget > img, figure.image.ck-widget > a > img' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst imageView = editor.editing.view.domConverter.domToView( domEvent.target );\n\t\t\tconst widgetView = imageView.findAncestor( 'figure' );\n\t\t\tlet resizer = this.editor.plugins.get( WidgetResize ).getResizerByViewElement( widgetView );\n\n\t\t\tif ( resizer ) {\n\t\t\t\t// There are rare cases when the image will be triggered multiple times for the same widget, e.g. when\n\t\t\t\t// the image's source was changed after upload (https://github.com/ckeditor/ckeditor5/pull/8108#issuecomment-708302992).\n\t\t\t\tresizer.redraw();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst mapper = editor.editing.mapper;\n\t\t\tconst imageModel = mapper.toModelElement( widgetView );\n\n\t\t\tresizer = editor.plugins\n\t\t\t\t.get( WidgetResize )\n\t\t\t\t.attachTo( {\n\t\t\t\t\tunit: editor.config.get( 'image.resizeUnit' ),\n\n\t\t\t\t\tmodelElement: imageModel,\n\t\t\t\t\tviewElement: widgetView,\n\t\t\t\t\teditor,\n\n\t\t\t\t\tgetHandleHost( domWidgetElement ) {\n\t\t\t\t\t\treturn domWidgetElement.querySelector( 'img' );\n\t\t\t\t\t},\n\t\t\t\t\tgetResizeHost( domWidgetElement ) {\n\t\t\t\t\t\treturn domWidgetElement;\n\t\t\t\t\t},\n\t\t\t\t\t// TODO consider other positions.\n\t\t\t\t\tisCentered() {\n\t\t\t\t\t\tconst imageStyle = imageModel.getAttribute( 'imageStyle' );\n\n\t\t\t\t\t\treturn !imageStyle || imageStyle == 'full' || imageStyle == 'alignCenter';\n\t\t\t\t\t},\n\n\t\t\t\t\tonCommit( newValue ) {\n\t\t\t\t\t\teditor.execute( 'resizeImage', { width: newValue } );\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\tresizer.on( 'updateSize', () => {\n\t\t\t\tif ( !widgetView.hasClass( 'image_resized' ) ) {\n\t\t\t\t\teditingView.change( writer => {\n\t\t\t\t\t\twriter.addClass( 'image_resized', widgetView );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tresizer.bind( 'isEnabled' ).to( this );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/**\n * @module link/utils\n */\n\nimport { toMap } from 'ckeditor5/src/utils';\n\n/**\n * Helper class that ties together all {@link module:link/link~LinkDecoratorAutomaticDefinition} and provides\n * the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement downcast dispatchers} for them.\n */\nexport default class AutomaticDecorators {\n\tconstructor() {\n\t\t/**\n\t\t * Stores the definition of {@link module:link/link~LinkDecoratorAutomaticDefinition automatic decorators}.\n\t\t * This data is used as a source for a downcast dispatcher to create a proper conversion to output data.\n\t\t *\n\t\t * @private\n\t\t * @type {Set}\n\t\t */\n\t\tthis._definitions = new Set();\n\t}\n\n\t/**\n\t * Gives information about the number of decorators stored in the {@link module:link/utils~AutomaticDecorators} instance.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Number}\n\t */\n\tget length() {\n\t\treturn this._definitions.size;\n\t}\n\n\t/**\n\t * Adds automatic decorator objects or an array with them to be used during downcasting.\n\t *\n\t * @param {module:link/link~LinkDecoratorAutomaticDefinition|Array.<module:link/link~LinkDecoratorAutomaticDefinition>} item\n\t * A configuration object of automatic rules for decorating links. It might also be an array of such objects.\n\t */\n\tadd( item ) {\n\t\tif ( Array.isArray( item ) ) {\n\t\t\titem.forEach( item => this._definitions.add( item ) );\n\t\t} else {\n\t\t\tthis._definitions.add( item );\n\t\t}\n\t}\n\n\t/**\n\t * Provides the conversion helper used in the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add} method.\n\t *\n\t * @returns {Function} A dispatcher function used as conversion helper\n\t * in {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add}.\n\t */\n\tgetDispatcher() {\n\t\treturn dispatcher => {\n\t\t\tdispatcher.on( 'attribute:linkHref', ( evt, data, conversionApi ) => {\n\t\t\t\t// There is only test as this behavior decorates links and\n\t\t\t\t// it is run before dispatcher which actually consumes this node.\n\t\t\t\t// This allows on writing own dispatcher with highest priority,\n\t\t\t\t// which blocks both native converter and this additional decoration.\n\t\t\t\tif ( !conversionApi.consumable.test( data.item, 'attribute:linkHref' ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\t\tconst viewSelection = viewWriter.document.selection;\n\n\t\t\t\tfor ( const item of this._definitions ) {\n\t\t\t\t\tconst viewElement = viewWriter.createAttributeElement( 'a', item.attributes, {\n\t\t\t\t\t\tpriority: 5\n\t\t\t\t\t} );\n\t\t\t\t\tviewWriter.setCustomProperty( 'link', true, viewElement );\n\t\t\t\t\tif ( item.callback( data.attributeNewValue ) ) {\n\t\t\t\t\t\tif ( data.item.is( 'selection' ) ) {\n\t\t\t\t\t\t\tviewWriter.wrap( viewSelection.getFirstRange(), viewElement );\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tviewWriter.wrap( conversionApi.mapper.toViewRange( data.range ), viewElement );\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tviewWriter.unwrap( conversionApi.mapper.toViewRange( data.range ), viewElement );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, { priority: 'high' } );\n\t\t};\n\t}\n\n\t/**\n\t * Provides the conversion helper used in the {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add} method\n\t * when linking images.\n\t *\n\t * @returns {Function} A dispatcher function used as conversion helper\n\t * in {@link module:engine/conversion/downcasthelpers~DowncastHelpers#add}.\n\t */\n\tgetDispatcherForLinkedImage() {\n\t\treturn dispatcher => {\n\t\t\tdispatcher.on( 'attribute:linkHref:image', ( evt, data, conversionApi ) => {\n\t\t\t\tconst viewFigure = conversionApi.mapper.toViewElement( data.item );\n\t\t\t\tconst linkInImage = Array.from( viewFigure.getChildren() ).find( child => child.name === 'a' );\n\n\t\t\t\tfor ( const item of this._definitions ) {\n\t\t\t\t\tconst attributes = toMap( item.attributes );\n\n\t\t\t\t\tif ( item.callback( data.attributeNewValue ) ) {\n\t\t\t\t\t\tfor ( const [ key, val ] of attributes ) {\n\t\t\t\t\t\t\tif ( key === 'class' ) {\n\t\t\t\t\t\t\t\tconversionApi.writer.addClass( val, linkInImage );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconversionApi.writer.setAttribute( key, val, linkInImage );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfor ( const [ key, val ] of attributes ) {\n\t\t\t\t\t\t\tif ( key === 'class' ) {\n\t\t\t\t\t\t\t\tconversionApi.writer.removeClass( val, linkInImage );\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconversionApi.writer.removeAttribute( key, linkInImage );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t};\n\t}\n}\n","import baseSlice from './_baseSlice.js';\n\n/**\n * Casts `array` to a slice if it's needed.\n *\n * @private\n * @param {Array} array The array to inspect.\n * @param {number} start The start position.\n * @param {number} [end=array.length] The end position.\n * @returns {Array} Returns the cast slice.\n */\nfunction castSlice(array, start, end) {\n var length = array.length;\n end = end === undefined ? length : end;\n return (!start && end >= length) ? array : baseSlice(array, start, end);\n}\n\nexport default castSlice;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsZWJ = '\\\\u200d';\n\n/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */\nvar reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']');\n\n/**\n * Checks if `string` contains Unicode symbols.\n *\n * @private\n * @param {string} string The string to inspect.\n * @returns {boolean} Returns `true` if a symbol is found, else `false`.\n */\nfunction hasUnicode(string) {\n return reHasUnicode.test(string);\n}\n\nexport default hasUnicode;\n","/**\n * Converts an ASCII `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction asciiToArray(string) {\n return string.split('');\n}\n\nexport default asciiToArray;\n","/** Used to compose unicode character classes. */\nvar rsAstralRange = '\\\\ud800-\\\\udfff',\n rsComboMarksRange = '\\\\u0300-\\\\u036f',\n reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',\n rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',\n rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,\n rsVarRange = '\\\\ufe0e\\\\ufe0f';\n\n/** Used to compose unicode capture groups. */\nvar rsAstral = '[' + rsAstralRange + ']',\n rsCombo = '[' + rsComboRange + ']',\n rsFitz = '\\\\ud83c[\\\\udffb-\\\\udfff]',\n rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',\n rsNonAstral = '[^' + rsAstralRange + ']',\n rsRegional = '(?:\\\\ud83c[\\\\udde6-\\\\uddff]){2}',\n rsSurrPair = '[\\\\ud800-\\\\udbff][\\\\udc00-\\\\udfff]',\n rsZWJ = '\\\\u200d';\n\n/** Used to compose unicode regexes. */\nvar reOptMod = rsModifier + '?',\n rsOptVar = '[' + rsVarRange + ']?',\n rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',\n rsSeq = rsOptVar + reOptMod + rsOptJoin,\n rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';\n\n/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */\nvar reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');\n\n/**\n * Converts a Unicode `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction unicodeToArray(string) {\n return string.match(reUnicode) || [];\n}\n\nexport default unicodeToArray;\n","import asciiToArray from './_asciiToArray.js';\nimport hasUnicode from './_hasUnicode.js';\nimport unicodeToArray from './_unicodeToArray.js';\n\n/**\n * Converts `string` to an array.\n *\n * @private\n * @param {string} string The string to convert.\n * @returns {Array} Returns the converted array.\n */\nfunction stringToArray(string) {\n return hasUnicode(string)\n ? unicodeToArray(string)\n : asciiToArray(string);\n}\n\nexport default stringToArray;\n","import castSlice from './_castSlice.js';\nimport hasUnicode from './_hasUnicode.js';\nimport stringToArray from './_stringToArray.js';\nimport toString from './toString.js';\n\n/**\n * Creates a function like `_.lowerFirst`.\n *\n * @private\n * @param {string} methodName The name of the `String` case method to use.\n * @returns {Function} Returns the new case function.\n */\nfunction createCaseFirst(methodName) {\n return function(string) {\n string = toString(string);\n\n var strSymbols = hasUnicode(string)\n ? stringToArray(string)\n : undefined;\n\n var chr = strSymbols\n ? strSymbols[0]\n : string.charAt(0);\n\n var trailing = strSymbols\n ? castSlice(strSymbols, 1).join('')\n : string.slice(1);\n\n return chr[methodName]() + trailing;\n };\n}\n\nexport default createCaseFirst;\n","import createCaseFirst from './_createCaseFirst.js';\n\n/**\n * Converts the first character of `string` to upper case.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.upperFirst('fred');\n * // => 'Fred'\n *\n * _.upperFirst('FRED');\n * // => 'FRED'\n */\nvar upperFirst = createCaseFirst('toUpperCase');\n\nexport default upperFirst;\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 link/utils\n */\n\nimport { upperFirst } from 'lodash-es';\n\nconst ATTRIBUTE_WHITESPACES = /[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205f\\u3000]/g; // eslint-disable-line no-control-regex\nconst SAFE_URL = /^(?:(?:https?|ftps?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i;\n\n// Simplified email test - should be run over previously found URL.\nconst EMAIL_REG_EXP = /^[\\S]+@((?![-_])(?:[-\\w\\u00a1-\\uffff]{0,63}[^-_]\\.))+(?:[a-z\\u00a1-\\uffff]{2,})$/i;\n\n// The regex checks for the protocol syntax ('xxxx://' or 'xxxx:')\n// or non-word characters at the beginning of the link ('/', '#' etc.).\nconst PROTOCOL_REG_EXP = /^((\\w+:(\\/{2,})?)|(\\W))/i;\n\n/**\n * A keystroke used by the {@link module:link/linkui~LinkUI link UI feature}.\n */\nexport const LINK_KEYSTROKE = 'Ctrl+K';\n\n/**\n * Returns `true` if a given view node is the link element.\n *\n * @param {module:engine/view/node~Node} node\n * @returns {Boolean}\n */\nexport function isLinkElement( node ) {\n\treturn node.is( 'attributeElement' ) && !!node.getCustomProperty( 'link' );\n}\n\n/**\n * Creates a link {@link module:engine/view/attributeelement~AttributeElement} with the provided `href` attribute.\n *\n * @param {String} href\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n * @returns {module:engine/view/attributeelement~AttributeElement}\n */\nexport function createLinkElement( href, { writer } ) {\n\t// Priority 5 - https://github.com/ckeditor/ckeditor5-link/issues/121.\n\tconst linkElement = writer.createAttributeElement( 'a', { href }, { priority: 5 } );\n\twriter.setCustomProperty( 'link', true, linkElement );\n\n\treturn linkElement;\n}\n\n/**\n * Returns a safe URL based on a given value.\n *\n * A URL is considered safe if it is safe for the user (does not contain any malicious code).\n *\n * If a URL is considered unsafe, a simple `\"#\"` is returned.\n *\n * @protected\n * @param {*} url\n * @returns {String} Safe URL.\n */\nexport function ensureSafeUrl( url ) {\n\turl = String( url );\n\n\treturn isSafeUrl( url ) ? url : '#';\n}\n\n// Checks whether the given URL is safe for the user (does not contain any malicious code).\n//\n// @param {String} url URL to check.\nfunction isSafeUrl( url ) {\n\tconst normalizedUrl = url.replace( ATTRIBUTE_WHITESPACES, '' );\n\n\treturn normalizedUrl.match( SAFE_URL );\n}\n\n/**\n * Returns the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration processed\n * to respect the locale of the editor, i.e. to display the {@link module:link/link~LinkDecoratorManualDefinition label}\n * in the correct language.\n *\n * **Note**: Only the few most commonly used labels are translated automatically. Other labels should be manually\n * translated in the {@link module:link/link~LinkConfig#decorators `config.link.decorators`} configuration.\n *\n * @param {module:utils/locale~Locale#t} t shorthand for {@link module:utils/locale~Locale#t Locale#t}\n * @param {Array.<module:link/link~LinkDecoratorDefinition>} The decorator reference\n * where the label values should be localized.\n * @returns {Array.<module:link/link~LinkDecoratorDefinition>}\n */\nexport function getLocalizedDecorators( t, decorators ) {\n\tconst localizedDecoratorsLabels = {\n\t\t'Open in a new tab': t( 'Open in a new tab' ),\n\t\t'Downloadable': t( 'Downloadable' )\n\t};\n\n\tdecorators.forEach( decorator => {\n\t\tif ( decorator.label && localizedDecoratorsLabels[ decorator.label ] ) {\n\t\t\tdecorator.label = localizedDecoratorsLabels[ decorator.label ];\n\t\t}\n\t\treturn decorator;\n\t} );\n\n\treturn decorators;\n}\n\n/**\n * Converts an object with defined decorators to a normalized array of decorators. The `id` key is added for each decorator and\n * is used as the attribute's name in the model.\n *\n * @param {Object.<String, module:link/link~LinkDecoratorDefinition>} decorators\n * @returns {Array.<module:link/link~LinkDecoratorDefinition>}\n */\nexport function normalizeDecorators( decorators ) {\n\tconst retArray = [];\n\n\tif ( decorators ) {\n\t\tfor ( const [ key, value ] of Object.entries( decorators ) ) {\n\t\t\tconst decorator = Object.assign(\n\t\t\t\t{},\n\t\t\t\tvalue,\n\t\t\t\t{ id: `link${ upperFirst( key ) }` }\n\t\t\t);\n\t\t\tretArray.push( decorator );\n\t\t}\n\t}\n\n\treturn retArray;\n}\n\n/**\n * Returns `true` if the specified `element` is an image and it can be linked (the element allows having the `linkHref` attribute).\n *\n * @params {module:engine/model/element~Element|null} element\n * @params {module:engine/model/schema~Schema} schema\n * @returns {Boolean}\n */\nexport function isImageAllowed( element, schema ) {\n\tif ( !element ) {\n\t\treturn false;\n\t}\n\n\treturn element.is( 'element', 'image' ) && schema.checkAttribute( 'image', 'linkHref' );\n}\n\n/**\n * Returns `true` if the specified `value` is an email.\n *\n * @params {String} value\n * @returns {Boolean}\n */\nexport function isEmail( value ) {\n\treturn EMAIL_REG_EXP.test( value );\n}\n\n/**\n * Adds the protocol prefix to the specified `link` when:\n *\n * * it does not contain it already, and there is a {@link module:link/link~LinkConfig#defaultProtocol `defaultProtocol` }\n * configuration value provided,\n * * or the link is an email address.\n *\n *\n * @params {String} link\n * @params {String} defaultProtocol\n * @returns {Boolean}\n */\nexport function addLinkProtocolIfApplicable( link, defaultProtocol ) {\n\tconst protocol = isEmail( link ) ? 'mailto:' : defaultProtocol;\n\tconst isProtocolNeeded = !!protocol && !PROTOCOL_REG_EXP.test( link );\n\n\treturn link && isProtocolNeeded ? protocol + link : link;\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 link/linkcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { findAttributeRange } from 'ckeditor5/src/typing';\nimport { Collection, toMap, first } from 'ckeditor5/src/utils';\n\nimport AutomaticDecorators from './utils/automaticdecorators';\nimport { isImageAllowed } from './utils';\n\n/**\n * The link command. It is used by the {@link module:link/link~Link link feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class LinkCommand extends Command {\n\t/**\n\t * The value of the `'linkHref'` attribute if the start of the selection is located in a node with this attribute.\n\t *\n\t * @observable\n\t * @readonly\n\t * @member {Object|undefined} #value\n\t */\n\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A collection of {@link module:link/utils~ManualDecorator manual decorators}\n\t\t * corresponding to the {@link module:link/link~LinkConfig#decorators decorator configuration}.\n\t\t *\n\t\t * You can consider it a model with states of manual decorators added to the currently selected link.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:utils/collection~Collection}\n\t\t */\n\t\tthis.manualDecorators = new Collection();\n\n\t\t/**\n\t\t * An instance of the helper that ties together all {@link module:link/link~LinkDecoratorAutomaticDefinition}\n\t\t * that are used by the {@glink features/link link} and the {@glink features/image#linking-images linking images} features.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:link/utils~AutomaticDecorators}\n\t\t */\n\t\tthis.automaticDecorators = new AutomaticDecorators();\n\t}\n\n\t/**\n\t * Synchronizes the state of {@link #manualDecorators} with the currently present elements in the model.\n\t */\n\trestoreManualDecoratorStates() {\n\t\tfor ( const manualDecorator of this.manualDecorators ) {\n\t\t\tmanualDecorator.value = this._getDecoratorStateFromModel( manualDecorator.id );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst selectedElement = first( doc.selection.getSelectedBlocks() );\n\n\t\t// A check for the `LinkImage` plugin. If the selection contains an element, get values from the element.\n\t\t// Currently the selection reads attributes from text nodes only. See #7429 and #7465.\n\t\tif ( isImageAllowed( selectedElement, model.schema ) ) {\n\t\t\tthis.value = selectedElement.getAttribute( 'linkHref' );\n\t\t\tthis.isEnabled = model.schema.checkAttribute( selectedElement, 'linkHref' );\n\t\t} else {\n\t\t\tthis.value = doc.selection.getAttribute( 'linkHref' );\n\t\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );\n\t\t}\n\n\t\tfor ( const manualDecorator of this.manualDecorators ) {\n\t\t\tmanualDecorator.value = this._getDecoratorStateFromModel( manualDecorator.id );\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is non-collapsed, the `linkHref` attribute will be applied to nodes inside the selection, but only to\n\t * those nodes where the `linkHref` attribute is allowed (disallowed nodes will be omitted).\n\t *\n\t * When the selection is collapsed and is not inside the text with the `linkHref` attribute, a\n\t * new {@link module:engine/model/text~Text text node} with the `linkHref` attribute will be inserted in place of the caret, but\n\t * only if such element is allowed in this place. The `_data` of the inserted text will equal the `href` parameter.\n\t * The selection will be updated to wrap the just inserted text node.\n\t *\n\t * When the selection is collapsed and inside the text with the `linkHref` attribute, the attribute value will be updated.\n\t *\n\t * # Decorators and model attribute management\n\t *\n\t * There is an optional argument to this command that applies or removes model\n\t * {@glink framework/guides/architecture/editing-engine#text-attributes text attributes} brought by\n\t * {@link module:link/utils~ManualDecorator manual link decorators}.\n\t *\n\t * Text attribute names in the model correspond to the entries in the {@link module:link/link~LinkConfig#decorators configuration}.\n\t * For every decorator configured, a model text attribute exists with the \"link\" prefix. For example, a `'linkMyDecorator'` attribute\n\t * corresponds to `'myDecorator'` in the configuration.\n\t *\n\t * To learn more about link decorators, check out the {@link module:link/link~LinkConfig#decorators `config.link.decorators`}\n\t * documentation.\n\t *\n\t * Here is how to manage decorator attributes with the link command:\n\t *\n\t *\t\tconst linkCommand = editor.commands.get( 'link' );\n\t *\n\t *\t\t// Adding a new decorator attribute.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: true\n\t *\t\t} );\n\t *\n\t *\t\t// Removing a decorator attribute from the selection.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: false\n\t *\t\t} );\n\t *\n\t *\t\t// Adding multiple decorator attributes at the same time.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: true,\n\t *\t\t\tlinkIsDownloadable: true,\n\t *\t\t} );\n\t *\n\t *\t\t// Removing and adding decorator attributes at the same time.\n\t *\t\tlinkCommand.execute( 'http://example.com', {\n\t *\t\t\tlinkIsExternal: false,\n\t *\t\t\tlinkFoo: true,\n\t *\t\t\tlinkIsDownloadable: false,\n\t *\t\t} );\n\t *\n\t * **Note**: If the decorator attribute name is not specified, its state remains untouched.\n\t *\n\t * **Note**: {@link module:link/unlinkcommand~UnlinkCommand#execute `UnlinkCommand#execute()`} removes all\n\t * decorator attributes.\n\t *\n\t * @fires execute\n\t * @param {String} href Link destination.\n\t * @param {Object} [manualDecoratorIds={}] The information about manual decorator attributes to be applied or removed upon execution.\n\t */\n\texecute( href, manualDecoratorIds = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\t// Stores information about manual decorators to turn them on/off when command is applied.\n\t\tconst truthyManualDecorators = [];\n\t\tconst falsyManualDecorators = [];\n\n\t\tfor ( const name in manualDecoratorIds ) {\n\t\t\tif ( manualDecoratorIds[ name ] ) {\n\t\t\t\ttruthyManualDecorators.push( name );\n\t\t\t} else {\n\t\t\t\tfalsyManualDecorators.push( name );\n\t\t\t}\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\t// If selection is collapsed then update selected link or insert new one at the place of caret.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tconst position = selection.getFirstPosition();\n\n\t\t\t\t// When selection is inside text with `linkHref` attribute.\n\t\t\t\tif ( selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\t\t// Then update `linkHref` value.\n\t\t\t\t\tconst linkRange = findAttributeRange( position, 'linkHref', selection.getAttribute( 'linkHref' ), model );\n\n\t\t\t\t\twriter.setAttribute( 'linkHref', href, linkRange );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.setAttribute( item, true, linkRange );\n\t\t\t\t\t} );\n\n\t\t\t\t\tfalsyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.removeAttribute( item, linkRange );\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Put the selection at the end of the updated link.\n\t\t\t\t\twriter.setSelection( writer.createPositionAfter( linkRange.end.nodeBefore ) );\n\t\t\t\t}\n\t\t\t\t// If not then insert text node with `linkHref` attribute in place of caret.\n\t\t\t\t// However, since selection is collapsed, attribute value will be used as data for text node.\n\t\t\t\t// So, if `href` is empty, do not create text node.\n\t\t\t\telse if ( href !== '' ) {\n\t\t\t\t\tconst attributes = toMap( selection.getAttributes() );\n\n\t\t\t\t\tattributes.set( 'linkHref', href );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\tattributes.set( item, true );\n\t\t\t\t\t} );\n\n\t\t\t\t\tconst { end: positionAfter } = model.insertContent( writer.createText( href, attributes ), position );\n\n\t\t\t\t\t// Put the selection at the end of the inserted link.\n\t\t\t\t\t// Using end of range returned from insertContent in case nodes with the same attributes got merged.\n\t\t\t\t\twriter.setSelection( positionAfter );\n\t\t\t\t}\n\n\t\t\t\t// Remove the `linkHref` attribute and all link decorators from the selection.\n\t\t\t\t// It stops adding a new content into the link element.\n\t\t\t\t[ 'linkHref', ...truthyManualDecorators, ...falsyManualDecorators ].forEach( item => {\n\t\t\t\t\twriter.removeSelectionAttribute( item );\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t// If selection has non-collapsed ranges, we change attribute on nodes inside those ranges\n\t\t\t\t// omitting nodes where the `linkHref` attribute is disallowed.\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), 'linkHref' );\n\n\t\t\t\t// But for the first, check whether the `linkHref` attribute is allowed on selected blocks (e.g. the \"image\" element).\n\t\t\t\tconst allowedRanges = [];\n\n\t\t\t\tfor ( const element of selection.getSelectedBlocks() ) {\n\t\t\t\t\tif ( model.schema.checkAttribute( element, 'linkHref' ) ) {\n\t\t\t\t\t\tallowedRanges.push( writer.createRangeOn( element ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Ranges that accept the `linkHref` attribute. Since we will iterate over `allowedRanges`, let's clone it.\n\t\t\t\tconst rangesToUpdate = allowedRanges.slice();\n\n\t\t\t\t// For all selection ranges we want to check whether given range is inside an element that accepts the `linkHref` attribute.\n\t\t\t\t// If so, we don't want to propagate applying the attribute to its children.\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\tif ( this._isRangeToUpdate( range, allowedRanges ) ) {\n\t\t\t\t\t\trangesToUpdate.push( range );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor ( const range of rangesToUpdate ) {\n\t\t\t\t\twriter.setAttribute( 'linkHref', href, range );\n\n\t\t\t\t\ttruthyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.setAttribute( item, true, range );\n\t\t\t\t\t} );\n\n\t\t\t\t\tfalsyManualDecorators.forEach( item => {\n\t\t\t\t\t\twriter.removeAttribute( item, range );\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Provides information whether a decorator with a given name is present in the currently processed selection.\n\t *\n\t * @private\n\t * @param {String} decoratorName The name of the manual decorator used in the model\n\t * @returns {Boolean} The information whether a given decorator is currently present in the selection.\n\t */\n\t_getDecoratorStateFromModel( decoratorName ) {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst selectedElement = first( doc.selection.getSelectedBlocks() );\n\n\t\t// A check for the `LinkImage` plugin. If the selection contains an element, get values from the element.\n\t\t// Currently the selection reads attributes from text nodes only. See #7429 and #7465.\n\t\tif ( isImageAllowed( selectedElement, model.schema ) ) {\n\t\t\treturn selectedElement.getAttribute( decoratorName );\n\t\t}\n\n\t\treturn doc.selection.getAttribute( decoratorName );\n\t}\n\n\t/**\n\t * Checks whether specified `range` is inside an element that accepts the `linkHref` attribute.\n\t *\n\t * @private\n\t * @param {module:engine/view/range~Range} range A range to check.\n\t * @param {Array.<module:engine/view/range~Range>} allowedRanges An array of ranges created on elements where the attribute is accepted.\n\t * @returns {Boolean}\n\t */\n\t_isRangeToUpdate( range, allowedRanges ) {\n\t\tfor ( const allowedRange of allowedRanges ) {\n\t\t\t// A range is inside an element that will have the `linkHref` attribute. Do not modify its nodes.\n\t\t\tif ( allowedRange.containsRange( range ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/unlinkcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { findAttributeRange } from 'ckeditor5/src/typing';\nimport { first } from 'ckeditor5/src/utils';\n\nimport { isImageAllowed } from './utils';\n\n/**\n * The unlink command. It is used by the {@link module:link/link~Link link plugin}.\n *\n * @extends module:core/command~Command\n */\nexport default class UnlinkCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tconst selectedElement = first( doc.selection.getSelectedBlocks() );\n\n\t\t// A check for the `LinkImage` plugin. If the selection contains an image element, get values from the element.\n\t\t// Currently the selection reads attributes from text nodes only. See #7429 and #7465.\n\t\tif ( isImageAllowed( selectedElement, model.schema ) ) {\n\t\t\tthis.isEnabled = model.schema.checkAttribute( selectedElement, 'linkHref' );\n\t\t} else {\n\t\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'linkHref' );\n\t\t}\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is collapsed, it removes the `linkHref` attribute from each node with the same `linkHref` attribute value.\n\t * When the selection is non-collapsed, it removes the `linkHref` attribute from each node in selected ranges.\n\t *\n\t * # Decorators\n\t *\n\t * If {@link module:link/link~LinkConfig#decorators `config.link.decorators`} is specified,\n\t * all configured decorators are removed together with the `linkHref` attribute.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\tmodel.change( writer => {\n\t\t\t// Get ranges to unlink.\n\t\t\tconst rangesToUnlink = selection.isCollapsed ?\n\t\t\t\t[ findAttributeRange(\n\t\t\t\t\tselection.getFirstPosition(),\n\t\t\t\t\t'linkHref',\n\t\t\t\t\tselection.getAttribute( 'linkHref' ),\n\t\t\t\t\tmodel\n\t\t\t\t) ] :\n\t\t\t\tmodel.schema.getValidRanges( selection.getRanges(), 'linkHref' );\n\n\t\t\t// Remove `linkHref` attribute from specified ranges.\n\t\t\tfor ( const range of rangesToUnlink ) {\n\t\t\t\twriter.removeAttribute( 'linkHref', range );\n\t\t\t\t// If there are registered custom attributes, then remove them during unlink.\n\t\t\t\tif ( linkCommand ) {\n\t\t\t\t\tfor ( const manualDecorator of linkCommand.manualDecorators ) {\n\t\t\t\t\t\twriter.removeAttribute( manualDecorator.id, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module link/utils\n */\n\nimport { ObservableMixin, mix } from 'ckeditor5/src/utils';\n\n/**\n * Helper class that stores manual decorators with observable {@link module:link/utils~ManualDecorator#value}\n * to support integration with the UI state. An instance of this class is a model with the state of individual manual decorators.\n * These decorators are kept as collections in {@link module:link/linkcommand~LinkCommand#manualDecorators}.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n */\nexport default class ManualDecorator {\n\t/**\n\t * Creates a new instance of {@link module:link/utils~ManualDecorator}.\n\t *\n\t * @param {Object} config\n\t * @param {String} config.id The name of the attribute used in the model that represents a given manual decorator.\n\t * For example: `'linkIsExternal'`.\n\t * @param {String} config.label The label used in the user interface to toggle the manual decorator.\n\t * @param {Object} config.attributes A set of attributes added to output data when the decorator is active for a specific link.\n\t * Attributes should keep the format of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.\n\t * @param {Boolean} [config.defaultValue] Controls whether the decorator is \"on\" by default.\n\t */\n\tconstructor( { id, label, attributes, defaultValue } ) {\n\t\t/**\n\t\t * An ID of a manual decorator which is the name of the attribute in the model, for example: 'linkManualDecorator0'.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.id = id;\n\n\t\t/**\n\t\t * The value of the current manual decorator. It reflects its state from the UI.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} module:link/utils~ManualDecorator#value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * The default value of manual decorator.\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis.defaultValue = defaultValue;\n\n\t\t/**\n\t\t * The label used in the user interface to toggle the manual decorator.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.label = label;\n\n\t\t/**\n\t\t * A set of attributes added to downcasted data when the decorator is activated for a specific link.\n\t\t * Attributes should be added in a form of attributes defined in {@link module:engine/view/elementdefinition~ElementDefinition}.\n\t\t *\n\t\t * @type {Object}\n\t\t */\n\t\tthis.attributes = attributes;\n\t}\n}\n\nmix( ManualDecorator, ObservableMixin );\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 link/linkediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { MouseObserver } from 'ckeditor5/src/engine';\nimport { Input, TwoStepCaretMovement, inlineHighlight, findAttributeRange } from 'ckeditor5/src/typing';\nimport { ClipboardPipeline } from 'ckeditor5/src/clipboard';\nimport { keyCodes } from 'ckeditor5/src/utils';\n\nimport LinkCommand from './linkcommand';\nimport UnlinkCommand from './unlinkcommand';\nimport ManualDecorator from './utils/manualdecorator';\nimport { createLinkElement, ensureSafeUrl, getLocalizedDecorators, normalizeDecorators } from './utils';\n\nimport '../theme/link.css';\n\nconst HIGHLIGHT_CLASS = 'ck-link_selected';\nconst DECORATOR_AUTOMATIC = 'automatic';\nconst DECORATOR_MANUAL = 'manual';\nconst EXTERNAL_LINKS_REGEXP = /^(https?:)?\\/\\//;\n\n/**\n * The link engine feature.\n *\n * It introduces the `linkHref=\"url\"` attribute in the model which renders to the view as a `<a href=\"url\">` element\n * as well as `'link'` and `'unlink'` commands.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class LinkEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'LinkEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\t// Clipboard is required for handling cut and paste events while typing over the link.\n\t\treturn [ TwoStepCaretMovement, Input, ClipboardPipeline ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'link', {\n\t\t\taddTargetToExternalLinks: false\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow link attribute on all inline nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: 'linkHref' } );\n\n\t\teditor.conversion.for( 'dataDowncast' )\n\t\t\t.attributeToElement( { model: 'linkHref', view: createLinkElement } );\n\n\t\teditor.conversion.for( 'editingDowncast' )\n\t\t\t.attributeToElement( { model: 'linkHref', view: ( href, conversionApi ) => {\n\t\t\t\treturn createLinkElement( ensureSafeUrl( href ), conversionApi );\n\t\t\t} } );\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.elementToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'a',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\thref: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: 'linkHref',\n\t\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'href' )\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Create linking commands.\n\t\teditor.commands.add( 'link', new LinkCommand( editor ) );\n\t\teditor.commands.add( 'unlink', new UnlinkCommand( editor ) );\n\n\t\tconst linkDecorators = getLocalizedDecorators( editor.t, normalizeDecorators( editor.config.get( 'link.decorators' ) ) );\n\n\t\tthis._enableAutomaticDecorators( linkDecorators.filter( item => item.mode === DECORATOR_AUTOMATIC ) );\n\t\tthis._enableManualDecorators( linkDecorators.filter( item => item.mode === DECORATOR_MANUAL ) );\n\n\t\t// Enable two-step caret movement for `linkHref` attribute.\n\t\tconst twoStepCaretMovementPlugin = editor.plugins.get( TwoStepCaretMovement );\n\t\ttwoStepCaretMovementPlugin.registerAttribute( 'linkHref' );\n\n\t\t// Setup highlight over selected link.\n\t\tinlineHighlight( editor, 'linkHref', 'a', HIGHLIGHT_CLASS );\n\n\t\t// Change the attributes of the selection in certain situations after the link was inserted into the document.\n\t\tthis._enableInsertContentSelectionAttributesFixer();\n\n\t\t// Handle a click at the beginning/end of a link element.\n\t\tthis._enableClickingAfterLink();\n\n\t\t// Handle typing over the link.\n\t\tthis._enableTypingOverLink();\n\n\t\t// Handle removing the content after the link element.\n\t\tthis._handleDeleteContentAfterLink();\n\t}\n\n\t/**\n\t * Processes an array of configured {@link module:link/link~LinkDecoratorAutomaticDefinition automatic decorators}\n\t * and registers a {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher downcast dispatcher}\n\t * for each one of them. Downcast dispatchers are obtained using the\n\t * {@link module:link/utils~AutomaticDecorators#getDispatcher} method.\n\t *\n\t * **Note**: This method also activates the automatic external link decorator if enabled with\n\t * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}.\n\t *\n\t * @private\n\t * @param {Array.<module:link/link~LinkDecoratorAutomaticDefinition>} automaticDecoratorDefinitions\n\t */\n\t_enableAutomaticDecorators( automaticDecoratorDefinitions ) {\n\t\tconst editor = this.editor;\n\t\t// Store automatic decorators in the command instance as we do the same with manual decorators.\n\t\t// Thanks to that, `LinkImageEditing` plugin can re-use the same definitions.\n\t\tconst command = editor.commands.get( 'link' );\n\t\tconst automaticDecorators = command.automaticDecorators;\n\n\t\t// Adds a default decorator for external links.\n\t\tif ( editor.config.get( 'link.addTargetToExternalLinks' ) ) {\n\t\t\tautomaticDecorators.add( {\n\t\t\t\tid: 'linkIsExternal',\n\t\t\t\tmode: DECORATOR_AUTOMATIC,\n\t\t\t\tcallback: url => EXTERNAL_LINKS_REGEXP.test( url ),\n\t\t\t\tattributes: {\n\t\t\t\t\ttarget: '_blank',\n\t\t\t\t\trel: 'noopener noreferrer'\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tautomaticDecorators.add( automaticDecoratorDefinitions );\n\n\t\tif ( automaticDecorators.length ) {\n\t\t\teditor.conversion.for( 'downcast' ).add( automaticDecorators.getDispatcher() );\n\t\t}\n\t}\n\n\t/**\n\t * Processes an array of configured {@link module:link/link~LinkDecoratorManualDefinition manual decorators},\n\t * transforms them into {@link module:link/utils~ManualDecorator} instances and stores them in the\n\t * {@link module:link/linkcommand~LinkCommand#manualDecorators} collection (a model for manual decorators state).\n\t *\n\t * Also registers an {@link module:engine/conversion/downcasthelpers~DowncastHelpers#attributeToElement attribute-to-element}\n\t * converter for each manual decorator and extends the {@link module:engine/model/schema~Schema model's schema}\n\t * with adequate model attributes.\n\t *\n\t * @private\n\t * @param {Array.<module:link/link~LinkDecoratorManualDefinition>} manualDecoratorDefinitions\n\t */\n\t_enableManualDecorators( manualDecoratorDefinitions ) {\n\t\tif ( !manualDecoratorDefinitions.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'link' );\n\t\tconst manualDecorators = command.manualDecorators;\n\n\t\tmanualDecoratorDefinitions.forEach( decorator => {\n\t\t\teditor.model.schema.extend( '$text', { allowAttributes: decorator.id } );\n\n\t\t\t// Keeps reference to manual decorator to decode its name to attributes during downcast.\n\t\t\tmanualDecorators.add( new ManualDecorator( decorator ) );\n\n\t\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\t\tmodel: decorator.id,\n\t\t\t\tview: ( manualDecoratorName, { writer } ) => {\n\t\t\t\t\tif ( manualDecoratorName ) {\n\t\t\t\t\t\tconst attributes = manualDecorators.get( decorator.id ).attributes;\n\t\t\t\t\t\tconst element = writer.createAttributeElement( 'a', attributes, { priority: 5 } );\n\t\t\t\t\t\twriter.setCustomProperty( 'link', true, element );\n\n\t\t\t\t\t\treturn element;\n\t\t\t\t\t}\n\t\t\t\t} } );\n\n\t\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'a',\n\t\t\t\t\tattributes: manualDecorators.get( decorator.id ).attributes\n\t\t\t\t},\n\t\t\t\tmodel: {\n\t\t\t\t\tkey: decorator.id\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/model/model~Model#event:insertContent} and corrects the model\n\t * selection attributes if the selection is at the end of a link after inserting the content.\n\t *\n\t * The purpose of this action is to improve the overall UX because the user is no longer \"trapped\" by the\n\t * `linkHref` attribute of the selection and they can type a \"clean\" (`linkHref`less) text right away.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/6053.\n\t *\n\t * @private\n\t */\n\t_enableInsertContentSelectionAttributesFixer() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\tthis.listenTo( model, 'insertContent', () => {\n\t\t\tconst nodeBefore = selection.anchor.nodeBefore;\n\t\t\tconst nodeAfter = selection.anchor.nodeAfter;\n\n\t\t\t// NOTE: ↰ and ↱ represent the gravity of the selection.\n\n\t\t\t// The only truly valid case is:\n\t\t\t//\n\t\t\t//\t\t ↰\n\t\t\t//\t\t...<$text linkHref=\"foo\">INSERTED[]</$text>\n\t\t\t//\n\t\t\t// If the selection is not \"trapped\" by the `linkHref` attribute after inserting, there's nothing\n\t\t\t// to fix there.\n\t\t\tif ( !selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Filter out the following case where a link with the same href (e.g. <a href=\"foo\">INSERTED</a>) is inserted\n\t\t\t// in the middle of an existing link:\n\t\t\t//\n\t\t\t// Before insertion:\n\t\t\t//\t\t ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">l[]ink</$text>\n\t\t\t//\n\t\t\t// Expected after insertion:\n\t\t\t//\t\t ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">lINSERTED[]ink</$text>\n\t\t\t//\n\t\t\tif ( !nodeBefore ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Filter out the following case where the selection has the \"linkHref\" attribute because the\n\t\t\t// gravity is overridden and some text with another attribute (e.g. <b>INSERTED</b>) is inserted:\n\t\t\t//\n\t\t\t// Before insertion:\n\t\t\t//\n\t\t\t//\t\t ↱\n\t\t\t//\t\t<$text linkHref=\"foo\">[]link</$text>\n\t\t\t//\n\t\t\t// Expected after insertion:\n\t\t\t//\n\t\t\t//\t\t ↱\n\t\t\t//\t\t<$text bold=\"true\">INSERTED</$text><$text linkHref=\"foo\">[]link</$text>\n\t\t\t//\n\t\t\tif ( !nodeBefore.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Filter out the following case where a link is a inserted in the middle (or before) another link\n\t\t\t// (different URLs, so they will not merge). In this (let's say weird) case, we can leave the selection\n\t\t\t// attributes as they are because the user will end up writing in one link or another anyway.\n\t\t\t//\n\t\t\t// Before insertion:\n\t\t\t//\n\t\t\t//\t\t ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">l[]ink</$text>\n\t\t\t//\n\t\t\t// Expected after insertion:\n\t\t\t//\n\t\t\t//\t\t ↰\n\t\t\t//\t\t<$text linkHref=\"foo\">l</$text><$text linkHref=\"bar\">INSERTED[]</$text><$text linkHref=\"foo\">ink</$text>\n\t\t\t//\n\t\t\tif ( nodeAfter && nodeAfter.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmodel.change( writer => {\n\t\t\t\tremoveLinkAttributesFromSelection( writer, linkCommand.manualDecorators );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/view/document~Document#event:mousedown} and\n\t * {@link module:engine/view/document~Document#event:selectionChange} and puts the selection before/after a link node\n\t * if clicked at the beginning/ending of the link.\n\t *\n\t * The purpose of this action is to allow typing around the link node directly after a click.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/1016.\n\t *\n\t * @private\n\t */\n\t_enableClickingAfterLink() {\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\teditor.editing.view.addObserver( MouseObserver );\n\n\t\tlet clicked = false;\n\n\t\t// Detect the click.\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', () => {\n\t\t\tclicked = true;\n\t\t} );\n\n\t\t// When the selection has changed...\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', () => {\n\t\t\tif ( !clicked ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ...and it was caused by the click...\n\t\t\tclicked = false;\n\n\t\t\tconst selection = editor.model.document.selection;\n\n\t\t\t// ...and no text is selected...\n\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// ...and clicked text is the link...\n\t\t\tif ( !selection.hasAttribute( 'linkHref' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst position = selection.getFirstPosition();\n\t\t\tconst linkRange = findAttributeRange( position, 'linkHref', selection.getAttribute( 'linkHref' ), editor.model );\n\n\t\t\t// ...check whether clicked start/end boundary of the link.\n\t\t\t// If so, remove the `linkHref` attribute.\n\t\t\tif ( position.isTouching( linkRange.start ) || position.isTouching( linkRange.end ) ) {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\tremoveLinkAttributesFromSelection( writer, linkCommand.manualDecorators );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/model/model~Model#deleteContent} and {@link module:engine/model/model~Model#insertContent}\n\t * and checks whether typing over the link. If so, attributes of removed text are preserved and applied to the inserted text.\n\t *\n\t * The purpose of this action is to allow modifying a text without loosing the `linkHref` attribute (and other).\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/4762.\n\t *\n\t * @private\n\t */\n\t_enableTypingOverLink() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\n\t\t// Selection attributes when started typing over the link.\n\t\tlet selectionAttributes;\n\n\t\t// Whether pressed `Backspace` or `Delete`. If so, attributes should not be preserved.\n\t\tlet deletedContent;\n\n\t\t// Detect pressing `Backspace` / `Delete`.\n\t\tthis.listenTo( view.document, 'delete', () => {\n\t\t\tdeletedContent = true;\n\t\t}, { priority: 'high' } );\n\n\t\t// Listening to `model#deleteContent` allows detecting whether selected content was a link.\n\t\t// If so, before removing the element, we will copy its attributes.\n\t\tthis.listenTo( editor.model, 'deleteContent', () => {\n\t\t\tconst selection = editor.model.document.selection;\n\n\t\t\t// Copy attributes only if anything is selected.\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// When the content was deleted, do not preserve attributes.\n\t\t\tif ( deletedContent ) {\n\t\t\t\tdeletedContent = false;\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Enabled only when typing.\n\t\t\tif ( !isTyping( editor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( shouldCopyAttributes( editor.model ) ) {\n\t\t\t\tselectionAttributes = selection.getAttributes();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// Listening to `model#insertContent` allows detecting the content insertion.\n\t\t// We want to apply attributes that were removed while typing over the link.\n\t\tthis.listenTo( editor.model, 'insertContent', ( evt, [ element ] ) => {\n\t\t\tdeletedContent = false;\n\n\t\t\t// Enabled only when typing.\n\t\t\tif ( !isTyping( editor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !selectionAttributes ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\tfor ( const [ attribute, value ] of selectionAttributes ) {\n\t\t\t\t\twriter.setAttribute( attribute, value, element );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tselectionAttributes = null;\n\t\t}, { priority: 'high' } );\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/model/model~Model#deleteContent} and checks whether\n\t * removing a content right after the \"linkHref\" attribute.\n\t *\n\t * If so, the selection should not preserve the `linkHref` attribute. However, if\n\t * the {@link module:typing/twostepcaretmovement~TwoStepCaretMovement} plugin is active and\n\t * the selection has the \"linkHref\" attribute due to overriden gravity (at the end), the `linkHref` attribute should stay untouched.\n\t *\n\t * The purpose of this action is to allow removing the link text and keep the selection outside the link.\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/7521.\n\t *\n\t * @private\n\t */\n\t_handleDeleteContentAfterLink() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst view = editor.editing.view;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\t// A flag whether attributes `linkHref` attribute should be preserved.\n\t\tlet shouldPreserveAttributes = false;\n\n\t\t// A flag whether the `Backspace` key was pressed.\n\t\tlet hasBackspacePressed = false;\n\n\t\t// Detect pressing `Backspace`.\n\t\tthis.listenTo( view.document, 'delete', ( evt, data ) => {\n\t\t\thasBackspacePressed = data.domEvent.keyCode === keyCodes.backspace;\n\t\t}, { priority: 'high' } );\n\n\t\t// Before removing the content, check whether the selection is inside a link or at the end of link but with 2-SCM enabled.\n\t\t// If so, we want to preserve link attributes.\n\t\tthis.listenTo( model, 'deleteContent', () => {\n\t\t\t// Reset the state.\n\t\t\tshouldPreserveAttributes = false;\n\n\t\t\tconst position = selection.getFirstPosition();\n\t\t\tconst linkHref = selection.getAttribute( 'linkHref' );\n\n\t\t\tif ( !linkHref ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst linkRange = findAttributeRange( position, 'linkHref', linkHref, model );\n\n\t\t\t// Preserve `linkHref` attribute if the selection is in the middle of the link or\n\t\t\t// the selection is at the end of the link and 2-SCM is activated.\n\t\t\tshouldPreserveAttributes = linkRange.containsPosition( position ) || linkRange.end.isEqual( position );\n\t\t}, { priority: 'high' } );\n\n\t\t// After removing the content, check whether the current selection should preserve the `linkHref` attribute.\n\t\tthis.listenTo( model, 'deleteContent', () => {\n\t\t\t// If didn't press `Backspace`.\n\t\t\tif ( !hasBackspacePressed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\thasBackspacePressed = false;\n\n\t\t\t// Disable the mechanism if inside a link (`<$text url=\"foo\">F[]oo</$text>` or <$text url=\"foo\">Foo[]</$text>`).\n\t\t\tif ( shouldPreserveAttributes ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Use `model.enqueueChange()` in order to execute the callback at the end of the changes process.\n\t\t\teditor.model.enqueueChange( writer => {\n\t\t\t\tremoveLinkAttributesFromSelection( writer, linkCommand.manualDecorators );\n\t\t\t} );\n\t\t}, { priority: 'low' } );\n\t}\n}\n\n// Make the selection free of link-related model attributes.\n// All link-related model attributes start with \"link\". That includes not only \"linkHref\"\n// but also all decorator attributes (they have dynamic names).\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:utils/collection~Collection} manualDecorators\nfunction removeLinkAttributesFromSelection( writer, manualDecorators ) {\n\twriter.removeSelectionAttribute( 'linkHref' );\n\n\tfor ( const decorator of manualDecorators ) {\n\t\twriter.removeSelectionAttribute( decorator.id );\n\t}\n}\n\n// Checks whether selection's attributes should be copied to the new inserted text.\n//\n// @param {module:engine/model/model~Model} model\n// @returns {Boolean}\nfunction shouldCopyAttributes( model ) {\n\tconst selection = model.document.selection;\n\tconst firstPosition = selection.getFirstPosition();\n\tconst lastPosition = selection.getLastPosition();\n\tconst nodeAtFirstPosition = firstPosition.nodeAfter;\n\n\t// The text link node does not exist...\n\tif ( !nodeAtFirstPosition ) {\n\t\treturn false;\n\t}\n\n\t// ...or it isn't the text node...\n\tif ( !nodeAtFirstPosition.is( '$text' ) ) {\n\t\treturn false;\n\t}\n\n\t// ...or isn't the link.\n\tif ( !nodeAtFirstPosition.hasAttribute( 'linkHref' ) ) {\n\t\treturn false;\n\t}\n\n\t// `textNode` = the position is inside the link element.\n\t// `nodeBefore` = the position is at the end of the link element.\n\tconst nodeAtLastPosition = lastPosition.textNode || lastPosition.nodeBefore;\n\n\t// If both references the same node selection contains a single text node.\n\tif ( nodeAtFirstPosition === nodeAtLastPosition ) {\n\t\treturn true;\n\t}\n\n\t// If nodes are not equal, maybe the link nodes has defined additional attributes inside.\n\t// First, we need to find the entire link range.\n\tconst linkRange = findAttributeRange( firstPosition, 'linkHref', nodeAtFirstPosition.getAttribute( 'linkHref' ), model );\n\n\t// Then we can check whether selected range is inside the found link range. If so, attributes should be preserved.\n\treturn linkRange.containsRange( model.createRange( firstPosition, lastPosition ), true );\n}\n\n// Checks whether provided changes were caused by typing.\n//\n// @params {module:core/editor/editor~Editor} editor\n// @returns {Boolean}\nfunction isTyping( editor ) {\n\tconst input = editor.plugins.get( 'Input' );\n\n\treturn input.isInput( editor.model.change( writer => writer.batch ) );\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 link/ui/linkformview\n */\n\nimport {\n\tButtonView,\n\tFocusCycler,\n\tLabeledFieldView,\n\tSwitchButtonView,\n\tView,\n\tViewCollection,\n\tcreateLabeledInputText,\n\tinjectCssTransitionDisabler,\n\tsubmitHandler\n} from 'ckeditor5/src/ui';\nimport { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\n// See: #8833.\n// eslint-disable-next-line ckeditor5-rules/ckeditor-imports\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\nimport '../../theme/linkform.css';\n\n/**\n * The link form view controller class.\n *\n * See {@link module:link/ui/linkformview~LinkFormView}.\n *\n * @extends module:ui/view~View\n */\nexport default class LinkFormView extends View {\n\t/**\n\t * Creates an instance of the {@link module:link/ui/linkformview~LinkFormView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {module:link/linkcommand~LinkCommand} linkCommand Reference to {@link module:link/linkcommand~LinkCommand}.\n\t * @param {String} [protocol] A value of a protocol to be displayed in the input's placeholder.\n\t */\n\tconstructor( locale, linkCommand ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * The URL input view.\n\t\t *\n\t\t * @member {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t\t */\n\t\tthis.urlInputView = this._createUrlInput();\n\n\t\t/**\n\t\t * The Save button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.saveButtonView = this._createButton( t( 'Save' ), icons.check, 'ck-button-save' );\n\t\tthis.saveButtonView.type = 'submit';\n\n\t\t/**\n\t\t * The Cancel button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.cancelButtonView = this._createButton( t( 'Cancel' ), icons.cancel, 'ck-button-cancel', 'cancel' );\n\n\t\t/**\n\t\t * A collection of {@link module:ui/button/switchbuttonview~SwitchButtonView},\n\t\t * which corresponds to {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators}\n\t\t * configured in the editor.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._manualDecoratorSwitches = this._createManualDecoratorSwitches( linkCommand );\n\n\t\t/**\n\t\t * A collection of child views in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this._createFormChildren( linkCommand.manualDecorators );\n\n\t\t/**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\tconst classList = [ 'ck', 'ck-link-form', 'ck-responsive-form' ];\n\n\t\tif ( linkCommand.manualDecorators.length ) {\n\t\t\tclassList.push( 'ck-link-form_layout-vertical', 'ck-vertical-form' );\n\t\t}\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\n\t\t\tattributes: {\n\t\t\t\tclass: classList,\n\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/90\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: this.children\n\t\t} );\n\n\t\tinjectCssTransitionDisabler( this );\n\t}\n\n\t/**\n\t * Obtains the state of the {@link module:ui/button/switchbuttonview~SwitchButtonView switch buttons} representing\n\t * {@link module:link/linkcommand~LinkCommand#manualDecorators manual link decorators}\n\t * in the {@link module:link/ui/linkformview~LinkFormView}.\n\t *\n\t * @returns {Object.<String,Boolean>} Key-value pairs, where the key is the name of the decorator and the value is\n\t * its state.\n\t */\n\tgetDecoratorSwitchesState() {\n\t\treturn Array.from( this._manualDecoratorSwitches ).reduce( ( accumulator, switchButton ) => {\n\t\t\taccumulator[ switchButton.name ] = switchButton.isOn;\n\t\t\treturn accumulator;\n\t\t}, {} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\tconst childViews = [\n\t\t\tthis.urlInputView,\n\t\t\t...this._manualDecoratorSwitches,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t];\n\n\t\tchildViews.forEach( v => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( v );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( v.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the fist {@link #_focusables} in the form.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Creates a labeled input view.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView} Labeled field view instance.\n\t */\n\t_createUrlInput() {\n\t\tconst t = this.locale.t;\n\t\tconst labeledInput = new LabeledFieldView( this.locale, createLabeledInputText );\n\n\t\tlabeledInput.label = t( 'Link URL' );\n\n\t\treturn labeledInput;\n\t}\n\n\t/**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} className The additional button CSS class name.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, className, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: className\n\t\t\t}\n\t\t} );\n\n\t\tif ( eventName ) {\n\t\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\t\t}\n\n\t\treturn button;\n\t}\n\n\t/**\n\t * Populates {@link module:ui/viewcollection~ViewCollection} of {@link module:ui/button/switchbuttonview~SwitchButtonView}\n\t * made based on {@link module:link/linkcommand~LinkCommand#manualDecorators}.\n\t *\n\t * @private\n\t * @param {module:link/linkcommand~LinkCommand} linkCommand A reference to the link command.\n\t * @returns {module:ui/viewcollection~ViewCollection} of switch buttons.\n\t */\n\t_createManualDecoratorSwitches( linkCommand ) {\n\t\tconst switches = this.createCollection();\n\n\t\tfor ( const manualDecorator of linkCommand.manualDecorators ) {\n\t\t\tconst switchButton = new SwitchButtonView( this.locale );\n\n\t\t\tswitchButton.set( {\n\t\t\t\tname: manualDecorator.id,\n\t\t\t\tlabel: manualDecorator.label,\n\t\t\t\twithText: true\n\t\t\t} );\n\n\t\t\tswitchButton.bind( 'isOn' ).toMany( [ manualDecorator, linkCommand ], 'value', ( decoratorValue, commandValue ) => {\n\t\t\t\treturn commandValue === undefined && decoratorValue === undefined ? manualDecorator.defaultValue : decoratorValue;\n\t\t\t} );\n\n\t\t\tswitchButton.on( 'execute', () => {\n\t\t\t\tmanualDecorator.set( 'value', !switchButton.isOn );\n\t\t\t} );\n\n\t\t\tswitches.add( switchButton );\n\t\t}\n\n\t\treturn switches;\n\t}\n\n\t/**\n\t * Populates the {@link #children} collection of the form.\n\t *\n\t * If {@link module:link/linkcommand~LinkCommand#manualDecorators manual decorators} are configured in the editor, it creates an\n\t * additional `View` wrapping all {@link #_manualDecoratorSwitches} switch buttons corresponding\n\t * to these decorators.\n\t *\n\t * @private\n\t * @param {module:utils/collection~Collection} manualDecorators A reference to\n\t * the collection of manual decorators stored in the link command.\n\t * @returns {module:ui/viewcollection~ViewCollection} The children of link form view.\n\t */\n\t_createFormChildren( manualDecorators ) {\n\t\tconst children = this.createCollection();\n\n\t\tchildren.add( this.urlInputView );\n\n\t\tif ( manualDecorators.length ) {\n\t\t\tconst additionalButtonsView = new View();\n\n\t\t\tadditionalButtonsView.setTemplate( {\n\t\t\t\ttag: 'ul',\n\t\t\t\tchildren: this._manualDecoratorSwitches.map( switchButton => ( {\n\t\t\t\t\ttag: 'li',\n\t\t\t\t\tchildren: [ switchButton ],\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t\t'ck-list__item'\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t} ) ),\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t'ck-reset',\n\t\t\t\t\t\t'ck-list'\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\t\t\tchildren.add( additionalButtonsView );\n\t\t}\n\n\t\tchildren.add( this.saveButtonView );\n\t\tchildren.add( this.cancelButtonView );\n\n\t\treturn children;\n\t}\n}\n\n/**\n * Fired when the form view is submitted (when one of the children triggered the submit event),\n * for example with a click on {@link #saveButtonView}.\n *\n * @event submit\n */\n\n/**\n * Fired when the form view is canceled, for example with a click on {@link #cancelButtonView}.\n *\n * @event cancel\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 link/ui/linkactionsview\n */\n\nimport { ButtonView, View, ViewCollection, FocusCycler } from 'ckeditor5/src/ui';\nimport { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\nimport { ensureSafeUrl } from '../utils';\n\n// See: #8833.\n// eslint-disable-next-line ckeditor5-rules/ckeditor-imports\nimport '@ckeditor/ckeditor5-ui/theme/components/responsive-form/responsiveform.css';\nimport '../../theme/linkactions.css';\n\nimport unlinkIcon from '../../theme/icons/unlink.svg';\n\n/**\n * The link actions view class. This view displays the link preview, allows\n * unlinking or editing the link.\n *\n * @extends module:ui/view~View\n */\nexport default class LinkActionsView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\n\t\t/**\n\t\t * Tracks information about DOM focus in the actions.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * The href preview view.\n\t\t *\n\t\t * @member {module:ui/view~View}\n\t\t */\n\t\tthis.previewButtonView = this._createPreviewButton();\n\n\t\t/**\n\t\t * The unlink button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.unlinkButtonView = this._createButton( t( 'Unlink' ), unlinkIcon, 'unlink' );\n\n\t\t/**\n\t\t * The edit link button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.editButtonView = this._createButton( t( 'Edit link' ), icons.pencil, 'edit' );\n\n\t\t/**\n\t\t * The value of the \"href\" attribute of the link to use in the {@link #previewButtonView}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String}\n\t\t */\n\t\tthis.set( 'href' );\n\n\t\t/**\n\t\t * A collection of views that can be focused in the view.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the view.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-link-actions',\n\t\t\t\t\t'ck-responsive-form'\n\t\t\t\t],\n\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/90\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\tthis.previewButtonView,\n\t\t\t\tthis.editButtonView,\n\t\t\t\tthis.unlinkButtonView\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tconst childViews = [\n\t\t\tthis.previewButtonView,\n\t\t\tthis.editButtonView,\n\t\t\tthis.unlinkButtonView\n\t\t];\n\n\t\tchildViews.forEach( v => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( v );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( v.element );\n\t\t} );\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the fist {@link #_focusables} in the actions.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Creates a button view.\n\t *\n\t * @private\n\t * @param {String} label The button label.\n\t * @param {String} icon The button icon.\n\t * @param {String} [eventName] An event name that the `ButtonView#execute` event will be delegated to.\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createButton( label, icon, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\n\t\treturn button;\n\t}\n\n\t/**\n\t * Creates a link href preview button.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView} The button view instance.\n\t */\n\t_createPreviewButton() {\n\t\tconst button = new ButtonView( this.locale );\n\t\tconst bind = this.bindTemplate;\n\t\tconst t = this.t;\n\n\t\tbutton.set( {\n\t\t\twithText: true,\n\t\t\ttooltip: t( 'Open link in new tab' )\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-link-actions__preview'\n\t\t\t\t],\n\t\t\t\thref: bind.to( 'href', href => href && ensureSafeUrl( href ) ),\n\t\t\t\ttarget: '_blank',\n\t\t\t\trel: 'noopener noreferrer'\n\t\t\t}\n\t\t} );\n\n\t\tbutton.bind( 'label' ).to( this, 'href', href => {\n\t\t\treturn href || t( 'This link has no URL' );\n\t\t} );\n\n\t\tbutton.bind( 'isEnabled' ).to( this, 'href', href => !!href );\n\n\t\tbutton.template.tag = 'a';\n\t\tbutton.template.eventListeners = {};\n\n\t\treturn button;\n\t}\n}\n\n/**\n * Fired when the {@link #editButtonView} is clicked.\n *\n * @event edit\n */\n\n/**\n * Fired when the {@link #unlinkButtonView} is clicked.\n *\n * @event unlink\n */\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184zm4.919 10.562-1.414 1.414a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.061-1.06l1.414 1.414 1.414-1.415a.75.75 0 0 1 1.061 1.061l-1.414 1.414 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414z\\\"/></svg>\";","/**\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 link/linkui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ClickObserver } from 'ckeditor5/src/engine';\nimport { ButtonView, ContextualBalloon, clickOutsideHandler } from 'ckeditor5/src/ui';\n\nimport LinkFormView from './ui/linkformview';\nimport LinkActionsView from './ui/linkactionsview';\nimport { addLinkProtocolIfApplicable, isLinkElement, LINK_KEYSTROKE } from './utils';\n\nimport linkIcon from '../theme/icons/link.svg';\n\nconst VISUAL_SELECTION_MARKER_NAME = 'link-ui';\n\n/**\n * The link UI plugin. It introduces the `'link'` and `'unlink'` buttons and support for the <kbd>Ctrl+K</kbd> keystroke.\n *\n * It uses the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class LinkUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'LinkUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.editing.view.addObserver( ClickObserver );\n\n\t\t/**\n\t\t * The actions view displayed inside of the balloon.\n\t\t *\n\t\t * @member {module:link/ui/linkactionsview~LinkActionsView}\n\t\t */\n\t\tthis.actionsView = this._createActionsView();\n\n\t\t/**\n\t\t * The form view displayed inside the balloon.\n\t\t *\n\t\t * @member {module:link/ui/linkformview~LinkFormView}\n\t\t */\n\t\tthis.formView = this._createFormView();\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t// Create toolbar buttons.\n\t\tthis._createToolbarLinkButton();\n\n\t\t// Attach lifecycle actions to the the balloon.\n\t\tthis._enableUserBalloonInteractions();\n\n\t\t// Renders a fake visual selection marker on an expanded selection.\n\t\teditor.conversion.for( 'editingDowncast' ).markerToHighlight( {\n\t\t\tmodel: VISUAL_SELECTION_MARKER_NAME,\n\t\t\tview: {\n\t\t\t\tclasses: [ 'ck-fake-link-selection' ]\n\t\t\t}\n\t\t} );\n\n\t\t// Renders a fake visual selection marker on a collapsed selection.\n\t\teditor.conversion.for( 'editingDowncast' ).markerToElement( {\n\t\t\tmodel: VISUAL_SELECTION_MARKER_NAME,\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tclasses: [ 'ck-fake-link-selection', 'ck-fake-link-selection_collapsed' ]\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis.formView.destroy();\n\t}\n\n\t/**\n\t * Creates the {@link module:link/ui/linkactionsview~LinkActionsView} instance.\n\t *\n\t * @private\n\t * @returns {module:link/ui/linkactionsview~LinkActionsView} The link actions view instance.\n\t */\n\t_createActionsView() {\n\t\tconst editor = this.editor;\n\t\tconst actionsView = new LinkActionsView( editor.locale );\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\t\tconst unlinkCommand = editor.commands.get( 'unlink' );\n\n\t\tactionsView.bind( 'href' ).to( linkCommand, 'value' );\n\t\tactionsView.editButtonView.bind( 'isEnabled' ).to( linkCommand );\n\t\tactionsView.unlinkButtonView.bind( 'isEnabled' ).to( unlinkCommand );\n\n\t\t// Execute unlink command after clicking on the \"Edit\" button.\n\t\tthis.listenTo( actionsView, 'edit', () => {\n\t\t\tthis._addFormView();\n\t\t} );\n\n\t\t// Execute unlink command after clicking on the \"Unlink\" button.\n\t\tthis.listenTo( actionsView, 'unlink', () => {\n\t\t\teditor.execute( 'unlink' );\n\t\t\tthis._hideUI();\n\t\t} );\n\n\t\t// Close the panel on esc key press when the **actions have focus**.\n\t\tactionsView.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._hideUI();\n\t\t\tcancel();\n\t\t} );\n\n\t\t// Open the form view on Ctrl+K when the **actions have focus**..\n\t\tactionsView.keystrokes.set( LINK_KEYSTROKE, ( data, cancel ) => {\n\t\t\tthis._addFormView();\n\t\t\tcancel();\n\t\t} );\n\n\t\treturn actionsView;\n\t}\n\n\t/**\n\t * Creates the {@link module:link/ui/linkformview~LinkFormView} instance.\n\t *\n\t * @private\n\t * @returns {module:link/ui/linkformview~LinkFormView} The link form view instance.\n\t */\n\t_createFormView() {\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\t\tconst defaultProtocol = editor.config.get( 'link.defaultProtocol' );\n\n\t\tconst formView = new LinkFormView( editor.locale, linkCommand );\n\n\t\tformView.urlInputView.fieldView.bind( 'value' ).to( linkCommand, 'value' );\n\n\t\t// Form elements should be read-only when corresponding commands are disabled.\n\t\tformView.urlInputView.bind( 'isReadOnly' ).to( linkCommand, 'isEnabled', value => !value );\n\t\tformView.saveButtonView.bind( 'isEnabled' ).to( linkCommand );\n\n\t\t// Execute link command after clicking the \"Save\" button.\n\t\tthis.listenTo( formView, 'submit', () => {\n\t\t\tconst { value } = formView.urlInputView.fieldView.element;\n\t\t\tconst parsedUrl = addLinkProtocolIfApplicable( value, defaultProtocol );\n\t\t\teditor.execute( 'link', parsedUrl, formView.getDecoratorSwitchesState() );\n\t\t\tthis._closeFormView();\n\t\t} );\n\n\t\t// Hide the panel after clicking the \"Cancel\" button.\n\t\tthis.listenTo( formView, 'cancel', () => {\n\t\t\tthis._closeFormView();\n\t\t} );\n\n\t\t// Close the panel on esc key press when the **form has focus**.\n\t\tformView.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._closeFormView();\n\t\t\tcancel();\n\t\t} );\n\n\t\treturn formView;\n\t}\n\n\t/**\n\t * Creates a toolbar Link button. Clicking this button will show\n\t * a {@link #_balloon} attached to the selection.\n\t *\n\t * @private\n\t */\n\t_createToolbarLinkButton() {\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\t\tconst t = editor.t;\n\n\t\t// Handle the `Ctrl+K` keystroke and show the panel.\n\t\teditor.keystrokes.set( LINK_KEYSTROKE, ( keyEvtData, cancel ) => {\n\t\t\t// Prevent focusing the search bar in FF, Chrome and Edge. See https://github.com/ckeditor/ckeditor5/issues/4811.\n\t\t\tcancel();\n\n\t\t\tif ( linkCommand.isEnabled ) {\n\t\t\t\tthis._showUI( true );\n\t\t\t}\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'link', locale => {\n\t\t\tconst button = new ButtonView( locale );\n\n\t\t\tbutton.isEnabled = true;\n\t\t\tbutton.label = t( 'Link' );\n\t\t\tbutton.icon = linkIcon;\n\t\t\tbutton.keystroke = LINK_KEYSTROKE;\n\t\t\tbutton.tooltip = true;\n\t\t\tbutton.isToggleable = true;\n\n\t\t\t// Bind button to the command.\n\t\t\tbutton.bind( 'isEnabled' ).to( linkCommand, 'isEnabled' );\n\t\t\tbutton.bind( 'isOn' ).to( linkCommand, 'value', value => !!value );\n\n\t\t\t// Show the panel on button click.\n\t\t\tthis.listenTo( button, 'execute', () => this._showUI( true ) );\n\n\t\t\treturn button;\n\t\t} );\n\t}\n\n\t/**\n\t * Attaches actions that control whether the balloon panel containing the\n\t * {@link #formView} is visible or not.\n\t *\n\t * @private\n\t */\n\t_enableUserBalloonInteractions() {\n\t\tconst viewDocument = this.editor.editing.view.document;\n\n\t\t// Handle click on view document and show panel when selection is placed inside the link element.\n\t\t// Keep panel open until selection will be inside the same link element.\n\t\tthis.listenTo( viewDocument, 'click', () => {\n\t\t\tconst parentLink = this._getSelectedLinkElement();\n\n\t\t\tif ( parentLink ) {\n\t\t\t\t// Then show panel but keep focus inside editor editable.\n\t\t\t\tthis._showUI();\n\t\t\t}\n\t\t} );\n\n\t\t// Focus the form if the balloon is visible and the Tab key has been pressed.\n\t\tthis.editor.keystrokes.set( 'Tab', ( data, cancel ) => {\n\t\t\tif ( this._areActionsVisible && !this.actionsView.focusTracker.isFocused ) {\n\t\t\t\tthis.actionsView.focus();\n\t\t\t\tcancel();\n\t\t\t}\n\t\t}, {\n\t\t\t// Use the high priority because the link UI navigation is more important\n\t\t\t// than other feature's actions, e.g. list indentation.\n\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/146\n\t\t\tpriority: 'high'\n\t\t} );\n\n\t\t// Close the panel on the Esc key press when the editable has focus and the balloon is visible.\n\t\tthis.editor.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tif ( this._isUIVisible ) {\n\t\t\t\tthis._hideUI();\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this.formView,\n\t\t\tactivator: () => this._isUIInPanel,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideUI()\n\t\t} );\n\t}\n\n\t/**\n\t * Adds the {@link #actionsView} to the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_addActionsView() {\n\t\tif ( this._areActionsInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.actionsView,\n\t\t\tposition: this._getBalloonPositionData()\n\t\t} );\n\t}\n\n\t/**\n\t * Adds the {@link #formView} to the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_addFormView() {\n\t\tif ( this._isFormInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst linkCommand = editor.commands.get( 'link' );\n\n\t\tthis.formView.disableCssTransitions();\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.formView,\n\t\t\tposition: this._getBalloonPositionData()\n\t\t} );\n\n\t\t// Select input when form view is currently visible.\n\t\tif ( this._balloon.visibleView === this.formView ) {\n\t\t\tthis.formView.urlInputView.fieldView.select();\n\t\t}\n\n\t\tthis.formView.enableCssTransitions();\n\n\t\t// Make sure that each time the panel shows up, the URL field remains in sync with the value of\n\t\t// the command. If the user typed in the input, then canceled the balloon (`urlInputView.fieldView#value` stays\n\t\t// unaltered) and re-opened it without changing the value of the link command (e.g. because they\n\t\t// clicked the same link), they would see the old value instead of the actual value of the command.\n\t\t// https://github.com/ckeditor/ckeditor5-link/issues/78\n\t\t// https://github.com/ckeditor/ckeditor5-link/issues/123\n\t\tthis.formView.urlInputView.fieldView.element.value = linkCommand.value || '';\n\t}\n\n\t/**\n\t * Closes the form view. Decides whether the balloon should be hidden completely or if the action view should be shown. This is\n\t * decided upon the link command value (which has a value if the document selection is in the link).\n\t *\n\t * Additionally, if any {@link module:link/link~LinkConfig#decorators} are defined in the editor configuration, the state of\n\t * switch buttons responsible for manual decorator handling is restored.\n\t *\n\t * @private\n\t */\n\t_closeFormView() {\n\t\tconst linkCommand = this.editor.commands.get( 'link' );\n\n\t\t// Restore manual decorator states to represent the current model state. This case is important to reset the switch buttons\n\t\t// when the user cancels the editing form.\n\t\tlinkCommand.restoreManualDecoratorStates();\n\n\t\tif ( linkCommand.value !== undefined ) {\n\t\t\tthis._removeFormView();\n\t\t} else {\n\t\t\tthis._hideUI();\n\t\t}\n\t}\n\n\t/**\n\t * Removes the {@link #formView} from the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_removeFormView() {\n\t\tif ( this._isFormInPanel ) {\n\t\t\t// Blur the input element before removing it from DOM to prevent issues in some browsers.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/1501.\n\t\t\tthis.formView.saveButtonView.focus();\n\n\t\t\tthis._balloon.remove( this.formView );\n\n\t\t\t// Because the form has an input which has focus, the focus must be brought back\n\t\t\t// to the editor. Otherwise, it would be lost.\n\t\t\tthis.editor.editing.view.focus();\n\n\t\t\tthis._hideFakeVisualSelection();\n\t\t}\n\t}\n\n\t/**\n\t * Shows the correct UI type. It is either {@link #formView} or {@link #actionsView}.\n\t *\n\t * @param {Boolean} forceVisible\n\t * @private\n\t */\n\t_showUI( forceVisible = false ) {\n\t\t// When there's no link under the selection, go straight to the editing UI.\n\t\tif ( !this._getSelectedLinkElement() ) {\n\t\t\t// Show visual selection on a text without a link when the contextual balloon is displayed.\n\t\t\t// See https://github.com/ckeditor/ckeditor5/issues/4721.\n\t\t\tthis._showFakeVisualSelection();\n\n\t\t\tthis._addActionsView();\n\n\t\t\t// Be sure panel with link is visible.\n\t\t\tif ( forceVisible ) {\n\t\t\t\tthis._balloon.showStack( 'main' );\n\t\t\t}\n\n\t\t\tthis._addFormView();\n\t\t}\n\t\t// If there's a link under the selection...\n\t\telse {\n\t\t\t// Go to the editing UI if actions are already visible.\n\t\t\tif ( this._areActionsVisible ) {\n\t\t\t\tthis._addFormView();\n\t\t\t}\n\t\t\t// Otherwise display just the actions UI.\n\t\t\telse {\n\t\t\t\tthis._addActionsView();\n\t\t\t}\n\n\t\t\t// Be sure panel with link is visible.\n\t\t\tif ( forceVisible ) {\n\t\t\t\tthis._balloon.showStack( 'main' );\n\t\t\t}\n\t\t}\n\n\t\t// Begin responding to ui#update once the UI is added.\n\t\tthis._startUpdatingUI();\n\t}\n\n\t/**\n\t * Removes the {@link #formView} from the {@link #_balloon}.\n\t *\n\t * See {@link #_addFormView}, {@link #_addActionsView}.\n\t *\n\t * @protected\n\t */\n\t_hideUI() {\n\t\tif ( !this._isUIInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\n\t\tthis.stopListening( editor.ui, 'update' );\n\t\tthis.stopListening( this._balloon, 'change:visibleView' );\n\n\t\t// Make sure the focus always gets back to the editable _before_ removing the focused form view.\n\t\t// Doing otherwise causes issues in some browsers. See https://github.com/ckeditor/ckeditor5-link/issues/193.\n\t\teditor.editing.view.focus();\n\n\t\t// Remove form first because it's on top of the stack.\n\t\tthis._removeFormView();\n\n\t\t// Then remove the actions view because it's beneath the form.\n\t\tthis._balloon.remove( this.actionsView );\n\n\t\tthis._hideFakeVisualSelection();\n\t}\n\n\t/**\n\t * Makes the UI react to the {@link module:core/editor/editorui~EditorUI#event:update} event to\n\t * reposition itself when the editor UI should be refreshed.\n\t *\n\t * See: {@link #_hideUI} to learn when the UI stops reacting to the `update` event.\n\t *\n\t * @protected\n\t */\n\t_startUpdatingUI() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\n\t\tlet prevSelectedLink = this._getSelectedLinkElement();\n\t\tlet prevSelectionParent = getSelectionParent();\n\n\t\tconst update = () => {\n\t\t\tconst selectedLink = this._getSelectedLinkElement();\n\t\t\tconst selectionParent = getSelectionParent();\n\n\t\t\t// Hide the panel if:\n\t\t\t//\n\t\t\t// * the selection went out of the EXISTING link element. E.g. user moved the caret out\n\t\t\t// of the link,\n\t\t\t// * the selection went to a different parent when creating a NEW link. E.g. someone\n\t\t\t// else modified the document.\n\t\t\t// * the selection has expanded (e.g. displaying link actions then pressing SHIFT+Right arrow).\n\t\t\t//\n\t\t\t// Note: #_getSelectedLinkElement will return a link for a non-collapsed selection only\n\t\t\t// when fully selected.\n\t\t\tif ( ( prevSelectedLink && !selectedLink ) ||\n\t\t\t\t( !prevSelectedLink && selectionParent !== prevSelectionParent ) ) {\n\t\t\t\tthis._hideUI();\n\t\t\t}\n\t\t\t// Update the position of the panel when:\n\t\t\t// * link panel is in the visible stack\n\t\t\t// * the selection remains in the original link element,\n\t\t\t// * there was no link element in the first place, i.e. creating a new link\n\t\t\telse if ( this._isUIVisible ) {\n\t\t\t\t// If still in a link element, simply update the position of the balloon.\n\t\t\t\t// If there was no link (e.g. inserting one), the balloon must be moved\n\t\t\t\t// to the new position in the editing view (a new native DOM range).\n\t\t\t\tthis._balloon.updatePosition( this._getBalloonPositionData() );\n\t\t\t}\n\n\t\t\tprevSelectedLink = selectedLink;\n\t\t\tprevSelectionParent = selectionParent;\n\t\t};\n\n\t\tfunction getSelectionParent() {\n\t\t\treturn viewDocument.selection.focus.getAncestors()\n\t\t\t\t.reverse()\n\t\t\t\t.find( node => node.is( 'element' ) );\n\t\t}\n\n\t\tthis.listenTo( editor.ui, 'update', update );\n\t\tthis.listenTo( this._balloon, 'change:visibleView', update );\n\t}\n\n\t/**\n\t * Returns `true` when {@link #formView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isFormInPanel() {\n\t\treturn this._balloon.hasView( this.formView );\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _areActionsInPanel() {\n\t\treturn this._balloon.hasView( this.actionsView );\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} is in the {@link #_balloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _areActionsVisible() {\n\t\treturn this._balloon.visibleView === this.actionsView;\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon}.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isUIInPanel() {\n\t\treturn this._isFormInPanel || this._areActionsInPanel;\n\t}\n\n\t/**\n\t * Returns `true` when {@link #actionsView} or {@link #formView} is in the {@link #_balloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isUIVisible() {\n\t\tconst visibleView = this._balloon.visibleView;\n\n\t\treturn visibleView == this.formView || this._areActionsVisible;\n\t}\n\n\t/**\n\t * Returns positioning options for the {@link #_balloon}. They control the way the balloon is attached\n\t * to the target element or selection.\n\t *\n\t * If the selection is collapsed and inside a link element, the panel will be attached to the\n\t * entire link element. Otherwise, it will be attached to the selection.\n\t *\n\t * @private\n\t * @returns {module:utils/dom/position~Options}\n\t */\n\t_getBalloonPositionData() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst model = this.editor.model;\n\t\tconst viewDocument = view.document;\n\t\tlet target = null;\n\n\t\tif ( model.markers.has( VISUAL_SELECTION_MARKER_NAME ) ) {\n\t\t\t// There are cases when we highlight selection using a marker (#7705, #4721).\n\t\t\tconst markerViewElements = Array.from( this.editor.editing.mapper.markerNameToElements( VISUAL_SELECTION_MARKER_NAME ) );\n\t\t\tconst newRange = view.createRange(\n\t\t\t\tview.createPositionBefore( markerViewElements[ 0 ] ),\n\t\t\t\tview.createPositionAfter( markerViewElements[ markerViewElements.length - 1 ] )\n\t\t\t);\n\n\t\t\ttarget = view.domConverter.viewRangeToDom( newRange );\n\t\t} else {\n\t\t\tconst targetLink = this._getSelectedLinkElement();\n\t\t\tconst range = viewDocument.selection.getFirstRange();\n\n\t\t\ttarget = targetLink ?\n\t\t\t\t// When selection is inside link element, then attach panel to this element.\n\t\t\t\tview.domConverter.mapViewToDom( targetLink ) :\n\t\t\t\t// Otherwise attach panel to the selection.\n\t\t\t\tview.domConverter.viewRangeToDom( range );\n\t\t}\n\n\t\treturn { target };\n\t}\n\n\t/**\n\t * Returns the link {@link module:engine/view/attributeelement~AttributeElement} under\n\t * the {@link module:engine/view/document~Document editing view's} selection or `null`\n\t * if there is none.\n\t *\n\t * **Note**: For a noncollapsed selection, the link element is only returned when **fully**\n\t * selected and the **only** element within the selection boundaries.\n\t *\n\t * @private\n\t * @returns {module:engine/view/attributeelement~AttributeElement|null}\n\t */\n\t_getSelectedLinkElement() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst selection = view.document.selection;\n\n\t\tif ( selection.isCollapsed ) {\n\t\t\treturn findLinkElementAncestor( selection.getFirstPosition() );\n\t\t} else {\n\t\t\t// The range for fully selected link is usually anchored in adjacent text nodes.\n\t\t\t// Trim it to get closer to the actual link element.\n\t\t\tconst range = selection.getFirstRange().getTrimmed();\n\t\t\tconst startLink = findLinkElementAncestor( range.start );\n\t\t\tconst endLink = findLinkElementAncestor( range.end );\n\n\t\t\tif ( !startLink || startLink != endLink ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Check if the link element is fully selected.\n\t\t\tif ( view.createRangeIn( startLink ).getTrimmed().isEqual( range ) ) {\n\t\t\t\treturn startLink;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Displays a fake visual selection when the contextual balloon is displayed.\n\t *\n\t * This adds a 'link-ui' marker into the document that is rendered as a highlight on selected text fragment.\n\t *\n\t * @private\n\t */\n\t_showFakeVisualSelection() {\n\t\tconst model = this.editor.model;\n\n\t\tmodel.change( writer => {\n\t\t\tconst range = model.document.selection.getFirstRange();\n\n\t\t\tif ( model.markers.has( VISUAL_SELECTION_MARKER_NAME ) ) {\n\t\t\t\twriter.updateMarker( VISUAL_SELECTION_MARKER_NAME, { range } );\n\t\t\t} else {\n\t\t\t\tif ( range.start.isAtEnd ) {\n\t\t\t\t\tconst startPosition = range.start.getLastMatchingPosition(\n\t\t\t\t\t\t( { item } ) => !model.schema.isContent( item ),\n\t\t\t\t\t\t{ boundaries: range }\n\t\t\t\t\t);\n\n\t\t\t\t\twriter.addMarker( VISUAL_SELECTION_MARKER_NAME, {\n\t\t\t\t\t\tusingOperation: false,\n\t\t\t\t\t\taffectsData: false,\n\t\t\t\t\t\trange: writer.createRange( startPosition, range.end )\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\twriter.addMarker( VISUAL_SELECTION_MARKER_NAME, {\n\t\t\t\t\t\tusingOperation: false,\n\t\t\t\t\t\taffectsData: false,\n\t\t\t\t\t\trange\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Hides the fake visual selection created in {@link #_showFakeVisualSelection}.\n\t *\n\t * @private\n\t */\n\t_hideFakeVisualSelection() {\n\t\tconst model = this.editor.model;\n\n\t\tif ( model.markers.has( VISUAL_SELECTION_MARKER_NAME ) ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.removeMarker( VISUAL_SELECTION_MARKER_NAME );\n\t\t\t} );\n\t\t}\n\t}\n}\n\n// Returns a link element if there's one among the ancestors of the provided `Position`.\n//\n// @private\n// @param {module:engine/view/position~Position} View position to analyze.\n// @returns {module:engine/view/attributeelement~AttributeElement|null} Link element at the position or null.\nfunction findLinkElementAncestor( position ) {\n\treturn position.getAncestors().find( ancestor => isLinkElement( ancestor ) );\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m11.077 15 .991-1.416a.75.75 0 1 1 1.229.86l-1.148 1.64a.748.748 0 0 1-.217.206 5.251 5.251 0 0 1-8.503-5.955.741.741 0 0 1 .12-.274l1.147-1.639a.75.75 0 1 1 1.228.86L4.933 10.7l.006.003a3.75 3.75 0 0 0 6.132 4.294l.006.004zm5.494-5.335a.748.748 0 0 1-.12.274l-1.147 1.639a.75.75 0 1 1-1.228-.86l.86-1.23a3.75 3.75 0 0 0-6.144-4.301l-.86 1.229a.75.75 0 0 1-1.229-.86l1.148-1.64a.748.748 0 0 1 .217-.206 5.251 5.251 0 0 1 8.503 5.955zm-4.563-2.532a.75.75 0 0 1 .184 1.045l-3.155 4.505a.75.75 0 1 1-1.229-.86l3.155-4.506a.75.75 0 0 1 1.045-.184z\\\"/></svg>\";","/**\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 link/autolink\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { TextWatcher, getLastTextLine } from 'ckeditor5/src/typing';\n\nimport { addLinkProtocolIfApplicable } from './utils';\n\nconst MIN_LINK_LENGTH_WITH_SPACE_AT_END = 4; // Ie: \"t.co \" (length 5).\n\n// This was a tweak from https://gist.github.com/dperini/729294.\nconst URL_REG_EXP = new RegExp(\n\t// Group 1: Line start or after a space.\n\t'(^|\\\\s)' +\n\t// Group 2: Detected URL (or e-mail).\n\t'(' +\n\t\t// Protocol identifier or short syntax \"//\"\n\t\t// a. Full form http://user@foo.bar.baz:8080/foo/bar.html#baz?foo=bar\n\t\t'(' +\n\t\t\t'(?:(?:(?:https?|ftp):)?\\\\/\\\\/)' +\n\t\t\t// BasicAuth using user:pass (optional)\n\t\t\t'(?:\\\\S+(?::\\\\S*)?@)?' +\n\t\t\t'(?:' +\n\t\t\t\t// IP address dotted notation octets\n\t\t\t\t// excludes loopback network 0.0.0.0\n\t\t\t\t// excludes reserved space >= 224.0.0.0\n\t\t\t\t// excludes network & broadcast addresses\n\t\t\t\t// (first & last IP address of each class)\n\t\t\t\t'(?:[1-9]\\\\d?|1\\\\d\\\\d|2[01]\\\\d|22[0-3])' +\n\t\t\t\t'(?:\\\\.(?:1?\\\\d{1,2}|2[0-4]\\\\d|25[0-5])){2}' +\n\t\t\t\t'(?:\\\\.(?:[1-9]\\\\d?|1\\\\d\\\\d|2[0-4]\\\\d|25[0-4]))' +\n\t\t\t\t'|' +\n\t\t\t\t'(' +\n\t\t\t\t\t// Do not allow `www.foo` - see https://github.com/ckeditor/ckeditor5/issues/8050.\n\t\t\t\t\t'((?!www\\\\.)|(www\\\\.))' +\n\t\t\t\t\t// Host & domain names.\n\t\t\t\t\t'(?![-_])(?:[-_a-z0-9\\\\u00a1-\\\\uffff]{1,63}\\\\.)+' +\n\t\t\t\t\t// TLD identifier name.\n\t\t\t\t\t'(?:[a-z\\\\u00a1-\\\\uffff]{2,63})' +\n\t\t\t\t')' +\n\t\t\t')' +\n\t\t\t// port number (optional)\n\t\t\t'(?::\\\\d{2,5})?' +\n\t\t\t// resource path (optional)\n\t\t\t'(?:[/?#]\\\\S*)?' +\n\t\t')' +\n\t\t'|' +\n\t\t// b. Short form (either www.example.com or example@example.com)\n\t\t'(' +\n\t\t\t'(www.|(\\\\S+@))' +\n\t\t\t// Host & domain names.\n\t\t\t'((?![-_])(?:[-_a-z0-9\\\\u00a1-\\\\uffff]{1,63}\\\\.))+' +\n\t\t\t// TLD identifier name.\n\t\t\t'(?:[a-z\\\\u00a1-\\\\uffff]{2,63})' +\n\t\t')' +\n\t')$', 'i' );\n\nconst URL_GROUP_IN_MATCH = 2;\n\n/**\n * The autolink plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class AutoLink extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'AutoLink';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\n\t\tselection.on( 'change:range', () => {\n\t\t\t// Disable plugin when selection is inside a code block.\n\t\t\tthis.isEnabled = !selection.anchor.parent.is( 'element', 'codeBlock' );\n\t\t} );\n\n\t\tthis._enableTypingHandling();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tthis._enableEnterHandling();\n\t\tthis._enableShiftEnterHandling();\n\t}\n\n\t/**\n\t * Enables autolinking on typing.\n\t *\n\t * @private\n\t */\n\t_enableTypingHandling() {\n\t\tconst editor = this.editor;\n\n\t\tconst watcher = new TextWatcher( editor.model, text => {\n\t\t\t// 1. Detect <kbd>Space</kbd> after a text with a potential link.\n\t\t\tif ( !isSingleSpaceAtTheEnd( text ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// 2. Check text before last typed <kbd>Space</kbd>.\n\t\t\tconst url = getUrlAtTextEnd( text.substr( 0, text.length - 1 ) );\n\n\t\t\tif ( url ) {\n\t\t\t\treturn { url };\n\t\t\t}\n\t\t} );\n\n\t\tconst input = editor.plugins.get( 'Input' );\n\n\t\twatcher.on( 'matched:data', ( evt, data ) => {\n\t\t\tconst { batch, range, url } = data;\n\n\t\t\tif ( !input.isInput( batch ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst linkEnd = range.end.getShiftedBy( -1 ); // Executed after a space character.\n\t\t\tconst linkStart = linkEnd.getShiftedBy( -url.length );\n\n\t\t\tconst linkRange = editor.model.createRange( linkStart, linkEnd );\n\n\t\t\tthis._applyAutoLink( url, linkRange );\n\t\t} );\n\n\t\twatcher.bind( 'isEnabled' ).to( this );\n\t}\n\n\t/**\n\t * Enables autolinking on the <kbd>Enter</kbd> key.\n\t *\n\t * @private\n\t */\n\t_enableEnterHandling() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst enterCommand = editor.commands.get( 'enter' );\n\n\t\tif ( !enterCommand ) {\n\t\t\treturn;\n\t\t}\n\n\t\tenterCommand.on( 'execute', () => {\n\t\t\tconst position = model.document.selection.getFirstPosition();\n\n\t\t\tif ( !position.parent.previousSibling ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst rangeToCheck = model.createRangeIn( position.parent.previousSibling );\n\n\t\t\tthis._checkAndApplyAutoLinkOnRange( rangeToCheck );\n\t\t} );\n\t}\n\n\t/**\n\t * Enables autolinking on the <kbd>Shift</kbd>+<kbd>Enter</kbd> keyboard shortcut.\n\t *\n\t * @private\n\t */\n\t_enableShiftEnterHandling() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tconst shiftEnterCommand = editor.commands.get( 'shiftEnter' );\n\n\t\tif ( !shiftEnterCommand ) {\n\t\t\treturn;\n\t\t}\n\n\t\tshiftEnterCommand.on( 'execute', () => {\n\t\t\tconst position = model.document.selection.getFirstPosition();\n\n\t\t\tconst rangeToCheck = model.createRange(\n\t\t\t\tmodel.createPositionAt( position.parent, 0 ),\n\t\t\t\tposition.getShiftedBy( -1 )\n\t\t\t);\n\n\t\t\tthis._checkAndApplyAutoLinkOnRange( rangeToCheck );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if the passed range contains a linkable text.\n\t *\n\t * @param {module:engine/model/range~Range} rangeToCheck\n\t * @private\n\t */\n\t_checkAndApplyAutoLinkOnRange( rangeToCheck ) {\n\t\tconst model = this.editor.model;\n\t\tconst { text, range } = getLastTextLine( rangeToCheck, model );\n\n\t\tconst url = getUrlAtTextEnd( text );\n\n\t\tif ( url ) {\n\t\t\tconst linkRange = model.createRange(\n\t\t\t\trange.end.getShiftedBy( -url.length ),\n\t\t\t\trange.end\n\t\t\t);\n\n\t\t\tthis._applyAutoLink( url, linkRange );\n\t\t}\n\t}\n\n\t/**\n\t * Applies a link on a given range.\n\t *\n\t * @param {String} url The URL to link.\n\t * @param {module:engine/model/range~Range} range The text range to apply the link attribute to.\n\t * @private\n\t */\n\t_applyAutoLink( link, range ) {\n\t\tconst model = this.editor.model;\n\n\t\tif ( !this.isEnabled || !isLinkAllowedOnRange( range, model ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Enqueue change to make undo step.\n\t\tmodel.enqueueChange( writer => {\n\t\t\tconst defaultProtocol = this.editor.config.get( 'link.defaultProtocol' );\n\t\t\tconst parsedUrl = addLinkProtocolIfApplicable( link, defaultProtocol );\n\t\t\twriter.setAttribute( 'linkHref', parsedUrl, range );\n\t\t} );\n\t}\n}\n\n// Check if text should be evaluated by the plugin in order to reduce number of RegExp checks on whole text.\nfunction isSingleSpaceAtTheEnd( text ) {\n\treturn text.length > MIN_LINK_LENGTH_WITH_SPACE_AT_END && text[ text.length - 1 ] === ' ' && text[ text.length - 2 ] !== ' ';\n}\n\nfunction getUrlAtTextEnd( text ) {\n\tconst match = URL_REG_EXP.exec( text );\n\n\treturn match ? match[ URL_GROUP_IN_MATCH ] : null;\n}\n\nfunction isLinkAllowedOnRange( range, model ) {\n\treturn model.schema.checkAttributeInSelection( model.createSelection( range ), 'linkHref' );\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 list/listcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * The list command. It is used by the {@link module:list/list~List list feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class ListCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {'numbered'|'bulleted'} type List type that will be handled by this command.\n\t */\n\tconstructor( editor, type ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The type of the list created by the command.\n\t\t *\n\t\t * @readonly\n\t\t * @member {'numbered'|'bulleted'|'todo'}\n\t\t */\n\t\tthis.type = type;\n\n\t\t/**\n\t\t * A flag indicating whether the command is active, which means that the selection starts in a list of the same type.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the list command.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will try to convert the\n\t * selected items and potentially the neighbor elements to the proper list items. If set to `false` it will convert selected elements\n\t * to paragraphs. If not set, the command will toggle selected elements to list items or paragraphs, depending on the selection.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst blocks = Array.from( document.selection.getSelectedBlocks() )\n\t\t\t.filter( block => checkCanBecomeListItem( block, model.schema ) );\n\n\t\t// Whether we are turning off some items.\n\t\tconst turnOff = options.forceValue !== undefined ? !options.forceValue : this.value;\n\n\t\t// If we are turning off items, we are going to rename them to paragraphs.\n\n\t\tmodel.change( writer => {\n\t\t\t// If part of a list got turned off, we need to handle (outdent) all of sub-items of the last turned-off item.\n\t\t\t// To be sure that model is all the time in a good state, we first fix items below turned-off item.\n\t\t\tif ( turnOff ) {\n\t\t\t\t// Start from the model item that is just after the last turned-off item.\n\t\t\t\tlet next = blocks[ blocks.length - 1 ].nextSibling;\n\t\t\t\tlet currentIndent = Number.POSITIVE_INFINITY;\n\t\t\t\tlet changes = [];\n\n\t\t\t\t// Correct indent of all items after the last turned off item.\n\t\t\t\t// Rules that should be followed:\n\t\t\t\t// 1. All direct sub-items of turned-off item should become indent 0, because the first item after it\n\t\t\t\t// will be the first item of a new list. Other items are at the same level, so should have same 0 index.\n\t\t\t\t// 2. All items with indent lower than indent of turned-off item should become indent 0, because they\n\t\t\t\t// should not end up as a child of any of list items that they were not children of before.\n\t\t\t\t// 3. All other items should have their indent changed relatively to it's parent.\n\t\t\t\t//\n\t\t\t\t// For example:\n\t\t\t\t// 1 * --------\n\t\t\t\t// 2 * --------\n\t\t\t\t// 3 * --------\t\t\t<-- this is turned off.\n\t\t\t\t// 4 * --------\t\t<-- this has to become indent = 0, because it will be first item on a new list.\n\t\t\t\t// 5 * --------\t<-- this should be still be a child of item above, so indent = 1.\n\t\t\t\t// 6 * --------\t\t\t<-- this has to become indent = 0, because it should not be a child of any of items above.\n\t\t\t\t// 7 * --------\t\t<-- this should be still be a child of item above, so indent = 1.\n\t\t\t\t// 8 * --------\t\t\t\t<-- this has to become indent = 0.\n\t\t\t\t// 9 * --------\t\t\t<-- this should still be a child of item above, so indent = 1.\n\t\t\t\t// 10 * --------\t\t<-- this should still be a child of item above, so indent = 2.\n\t\t\t\t// 11 * --------\t\t<-- this should still be at the same level as item above, so indent = 2.\n\t\t\t\t// 12 * --------\t\t\t\t<-- this and all below are left unchanged.\n\t\t\t\t// 13 * --------\n\t\t\t\t// 14 * --------\n\t\t\t\t//\n\t\t\t\t// After turning off 3 the list becomes:\n\t\t\t\t//\n\t\t\t\t// 1 * --------\n\t\t\t\t// 2 * --------\n\t\t\t\t//\n\t\t\t\t// 3 --------\n\t\t\t\t//\n\t\t\t\t// 4 * --------\n\t\t\t\t// 5 * --------\n\t\t\t\t// 6 * --------\n\t\t\t\t// 7 * --------\n\t\t\t\t// 8 * --------\n\t\t\t\t// 9 * --------\n\t\t\t\t// 10 * --------\n\t\t\t\t// 11 * --------\n\t\t\t\t// 12 * --------\n\t\t\t\t// 13 * --------\n\t\t\t\t// 14 * --------\n\t\t\t\t//\n\t\t\t\t// Thanks to this algorithm no lists are mismatched and no items get unexpected children/parent, while\n\t\t\t\t// those parent-child connection which are possible to maintain are still maintained. It's worth noting\n\t\t\t\t// that this is the same effect that we would be get by multiple use of outdent command. However doing\n\t\t\t\t// it like this is much more efficient because it's less operation (less memory usage, easier OT) and\n\t\t\t\t// less conversion (faster).\n\t\t\t\twhile ( next && next.name == 'listItem' && next.getAttribute( 'listIndent' ) !== 0 ) {\n\t\t\t\t\t// Check each next list item, as long as its indent is bigger than 0.\n\t\t\t\t\t// If the indent is 0 we are not going to change anything anyway.\n\t\t\t\t\tconst indent = next.getAttribute( 'listIndent' );\n\n\t\t\t\t\t// We check if that's item indent is lower as current relative indent.\n\t\t\t\t\tif ( indent < currentIndent ) {\n\t\t\t\t\t\t// If it is, current relative indent becomes that indent.\n\t\t\t\t\t\tcurrentIndent = indent;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Fix indent relatively to current relative indent.\n\t\t\t\t\t// Note, that if we just changed the current relative indent, the newIndent will be equal to 0.\n\t\t\t\t\tconst newIndent = indent - currentIndent;\n\n\t\t\t\t\t// Save the entry in changes array. We do not apply it at the moment, because we will need to\n\t\t\t\t\t// reverse the changes so the last item is changed first.\n\t\t\t\t\t// This is to keep model in correct state all the time.\n\t\t\t\t\tchanges.push( { element: next, listIndent: newIndent } );\n\n\t\t\t\t\t// Find next item.\n\t\t\t\t\tnext = next.nextSibling;\n\t\t\t\t}\n\n\t\t\t\tchanges = changes.reverse();\n\n\t\t\t\tfor ( const item of changes ) {\n\t\t\t\t\twriter.setAttribute( 'listIndent', item.listIndent, item.element );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we are turning on, we might change some items that are already `listItem`s but with different type.\n\t\t\t// Changing one nested list item to other type should also trigger changing all its siblings so the\n\t\t\t// whole nested list is of the same type.\n\t\t\t// Example (assume changing to numbered list):\n\t\t\t// * ------\t\t\t\t<-- do not fix, top level item\n\t\t\t// * ------\t\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t// * ------\t\t<-- do not fix, item is not affected (different list)\n\t\t\t// * ------\t\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t// * ------\t\t<-- fix, because latter list item of this item's list is changed\n\t\t\t// * ---[--\t\t<-- already in selection\n\t\t\t// * ------\t\t\t<-- already in selection\n\t\t\t// * ------\t\t\t<-- already in selection\n\t\t\t// * ------\t\t\t\t<-- already in selection, but does not cause other list items to change because is top-level\n\t\t\t// * ---]--\t\t\t<-- already in selection\n\t\t\t// * ------\t\t\t<-- fix, because preceding list item of this item's list is changed\n\t\t\t// * ------\t\t<-- do not fix, item is not affected (different list)\n\t\t\t// * ------\t\t\t\t<-- do not fix, top level item\n\t\t\tif ( !turnOff ) {\n\t\t\t\t// Find lowest indent among selected items. This will be indicator what is the indent of\n\t\t\t\t// top-most list affected by the command.\n\t\t\t\tlet lowestIndent = Number.POSITIVE_INFINITY;\n\n\t\t\t\tfor ( const item of blocks ) {\n\t\t\t\t\tif ( item.is( 'element', 'listItem' ) && item.getAttribute( 'listIndent' ) < lowestIndent ) {\n\t\t\t\t\t\tlowestIndent = item.getAttribute( 'listIndent' );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Do not execute the fix for top-level lists.\n\t\t\t\tlowestIndent = lowestIndent === 0 ? 1 : lowestIndent;\n\n\t\t\t\t// Fix types of list items that are \"before\" the selected blocks.\n\t\t\t\t_fixType( blocks, true, lowestIndent );\n\n\t\t\t\t// Fix types of list items that are \"after\" the selected blocks.\n\t\t\t\t_fixType( blocks, false, lowestIndent );\n\t\t\t}\n\n\t\t\t// Phew! Now it will be easier :).\n\t\t\t// For each block element that was in the selection, we will either: turn it to list item,\n\t\t\t// turn it to paragraph, or change it's type. Or leave it as it is.\n\t\t\t// Do it in reverse as there might be multiple blocks (same as with changing indents).\n\t\t\tfor ( const element of blocks.reverse() ) {\n\t\t\t\tif ( turnOff && element.name == 'listItem' ) {\n\t\t\t\t\t// We are turning off and the element is a `listItem` - it should be converted to `paragraph`.\n\t\t\t\t\t// List item specific attributes are removed by post fixer.\n\t\t\t\t\twriter.rename( element, 'paragraph' );\n\t\t\t\t} else if ( !turnOff && element.name != 'listItem' ) {\n\t\t\t\t\t// We are turning on and the element is not a `listItem` - it should be converted to `listItem`.\n\t\t\t\t\t// The order of operations is important to keep model in correct state.\n\t\t\t\t\twriter.setAttributes( { listType: this.type, listIndent: 0 }, element );\n\t\t\t\t\twriter.rename( element, 'listItem' );\n\t\t\t\t} else if ( !turnOff && element.name == 'listItem' && element.getAttribute( 'listType' ) != this.type ) {\n\t\t\t\t\t// We are turning on and the element is a `listItem` but has different type - change it's type and\n\t\t\t\t\t// type of it's all siblings that have same indent.\n\t\t\t\t\twriter.setAttribute( 'listType', this.type, element );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Event fired by the {@link #execute} method.\n\t\t\t *\n\t\t\t * It allows to execute an action after executing the {@link ~ListCommand#execute} method, for example adjusting\n\t\t\t * attributes of changed blocks.\n\t\t\t *\n\t\t\t * @protected\n\t\t\t * @event _executeCleanup\n\t\t\t */\n\t\t\tthis.fire( '_executeCleanup', blocks );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {Boolean} The current value.\n\t */\n\t_getValue() {\n\t\t// Check whether closest `listItem` ancestor of the position has a correct type.\n\t\tconst listItem = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\treturn !!listItem && listItem.is( 'element', 'listItem' ) && listItem.getAttribute( 'listType' ) == this.type;\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\t// If command value is true it means that we are in list item, so the command should be enabled.\n\t\tif ( this.value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\tif ( !firstBlock ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Otherwise, check if list item can be inserted at the position start.\n\t\treturn checkCanBecomeListItem( firstBlock, schema );\n\t}\n}\n\n// Helper function used when one or more list item have their type changed. Fixes type of other list items\n// that are affected by the change (are in same lists) but are not directly in selection. The function got extracted\n// not to duplicated code, as same fix has to be performed before and after selection.\n//\n// @param {Array.<module:engine/model/node~Node>} blocks Blocks that are in selection.\n// @param {Boolean} isBackward Specified whether fix will be applied for blocks before first selected block (`true`)\n// or blocks after last selected block (`false`).\n// @param {Number} lowestIndent Lowest indent among selected blocks.\nfunction _fixType( blocks, isBackward, lowestIndent ) {\n\t// We need to check previous sibling of first changed item and next siblings of last changed item.\n\tconst startingItem = isBackward ? blocks[ 0 ] : blocks[ blocks.length - 1 ];\n\n\tif ( startingItem.is( 'element', 'listItem' ) ) {\n\t\tlet item = startingItem[ isBackward ? 'previousSibling' : 'nextSibling' ];\n\t\t// During processing items, keeps the lowest indent of already processed items.\n\t\t// This saves us from changing too many items.\n\t\t// Following example is for going forward as it is easier to read, however same applies to going backward.\n\t\t// * ------\n\t\t// * ------\n\t\t// * --[---\n\t\t// * ------\t\t<-- `lowestIndent` should be 1\n\t\t// * --]---\t\t<-- `startingItem`, `currentIndent` = 2, `lowestIndent` == 1\n\t\t// * ------\t\t<-- should be fixed, `indent` == 2 == `currentIndent`\n\t\t// * ------\t\t<-- should be fixed, set `currentIndent` to 1, `indent` == 1 == `currentIndent`\n\t\t// * ------\t\t<-- should not be fixed, item is in different list, `indent` = 2, `indent` != `currentIndent`\n\t\t// * ------\t\t<-- should be fixed, `indent` == 1 == `currentIndent`\n\t\t// * ------\t\t\t<-- break loop (`indent` < `lowestIndent`)\n\t\tlet currentIndent = startingItem.getAttribute( 'listIndent' );\n\n\t\t// Look back until a list item with indent lower than reference `lowestIndent`.\n\t\t// That would be the parent of nested sublist which contains item having `lowestIndent`.\n\t\twhile ( item && item.is( 'element', 'listItem' ) && item.getAttribute( 'listIndent' ) >= lowestIndent ) {\n\t\t\tif ( currentIndent > item.getAttribute( 'listIndent' ) ) {\n\t\t\t\tcurrentIndent = item.getAttribute( 'listIndent' );\n\t\t\t}\n\n\t\t\t// Found an item that is in the same nested sublist.\n\t\t\tif ( item.getAttribute( 'listIndent' ) == currentIndent ) {\n\t\t\t\t// Just add the item to selected blocks like it was selected by the user.\n\t\t\t\tblocks[ isBackward ? 'unshift' : 'push' ]( item );\n\t\t\t}\n\n\t\t\titem = item[ isBackward ? 'previousSibling' : 'nextSibling' ];\n\t\t}\n\t}\n}\n\n// Checks whether the given block can be replaced by a listItem.\n//\n// @private\n// @param {module:engine/model/element~Element} block A block to be tested.\n// @param {module:engine/model/schema~Schema} schema The schema of the document.\n// @returns {Boolean}\nfunction checkCanBecomeListItem( block, schema ) {\n\treturn schema.checkChild( block.parent, 'listItem' ) && !schema.isObject( block );\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 list/indentcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * The list indent command. It is used by the {@link module:list/list~List list feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class IndentCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {'forward'|'backward'} indentDirection The direction of indent. If it is equal to `backward`, the command\n\t * will outdent a list item.\n\t */\n\tconstructor( editor, indentDirection ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Determines by how much the command will change the list item's indent attribute.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {Number}\n\t\t */\n\t\tthis._indentBy = indentDirection == 'forward' ? 1 : -1;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Indents or outdents (depending on the {@link #constructor}'s `indentDirection` parameter) selected list items.\n\t *\n\t * @fires execute\n\t * @fires _executeCleanup\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tlet itemsToChange = Array.from( doc.selection.getSelectedBlocks() );\n\n\t\tmodel.change( writer => {\n\t\t\tconst lastItem = itemsToChange[ itemsToChange.length - 1 ];\n\n\t\t\t// Indenting a list item should also indent all the items that are already sub-items of indented item.\n\t\t\tlet next = lastItem.nextSibling;\n\n\t\t\t// Check all items after last indented item, as long as their indent is bigger than indent of that item.\n\t\t\twhile ( next && next.name == 'listItem' && next.getAttribute( 'listIndent' ) > lastItem.getAttribute( 'listIndent' ) ) {\n\t\t\t\titemsToChange.push( next );\n\n\t\t\t\tnext = next.nextSibling;\n\t\t\t}\n\n\t\t\t// We need to be sure to keep model in correct state after each small change, because converters\n\t\t\t// bases on that state and assumes that model is correct.\n\t\t\t// Because of that, if the command outdents items, we will outdent them starting from the last item, as\n\t\t\t// it is safer.\n\t\t\tif ( this._indentBy < 0 ) {\n\t\t\t\titemsToChange = itemsToChange.reverse();\n\t\t\t}\n\n\t\t\tfor ( const item of itemsToChange ) {\n\t\t\t\tconst indent = item.getAttribute( 'listIndent' ) + this._indentBy;\n\n\t\t\t\t// If indent is lower than 0, it means that the item got outdented when it was not indented.\n\t\t\t\t// This means that we need to convert that list item to paragraph.\n\t\t\t\tif ( indent < 0 ) {\n\t\t\t\t\t// To keep the model as correct as possible, first rename listItem, then remove attributes,\n\t\t\t\t\t// as listItem without attributes is very incorrect and will cause problems in converters.\n\t\t\t\t\t// No need to remove attributes, will be removed by post fixer.\n\t\t\t\t\twriter.rename( item, 'paragraph' );\n\t\t\t\t}\n\t\t\t\t// If indent is >= 0, change the attribute value.\n\t\t\t\telse {\n\t\t\t\t\twriter.setAttribute( 'listIndent', indent, item );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Event fired by the {@link #execute} method.\n\t\t\t *\n\t\t\t * It allows to execute an action after executing the {@link ~IndentCommand#execute} method, for example adjusting\n\t\t\t * attributes of changed list items.\n\t\t\t *\n\t\t\t * @protected\n\t\t\t * @event _executeCleanup\n\t\t\t */\n\t\t\tthis.fire( '_executeCleanup', itemsToChange );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\t// Check whether any of position's ancestor is a list item.\n\t\tconst listItem = first( this.editor.model.document.selection.getSelectedBlocks() );\n\n\t\t// If selection is not in a list item, the command is disabled.\n\t\tif ( !listItem || !listItem.is( 'element', 'listItem' ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( this._indentBy > 0 ) {\n\t\t\t// Cannot indent first item in it's list. Check if before `listItem` is a list item that is in same list.\n\t\t\t// To be in the same list, the item has to have same attributes and cannot be \"split\" by an item with lower indent.\n\t\t\tconst indent = listItem.getAttribute( 'listIndent' );\n\t\t\tconst type = listItem.getAttribute( 'listType' );\n\n\t\t\tlet prev = listItem.previousSibling;\n\n\t\t\twhile ( prev && prev.is( 'element', 'listItem' ) && prev.getAttribute( 'listIndent' ) >= indent ) {\n\t\t\t\tif ( prev.getAttribute( 'listIndent' ) == indent ) {\n\t\t\t\t\t// The item is on the same level.\n\t\t\t\t\t// If it has same type, it means that we found a preceding sibling from the same list.\n\t\t\t\t\t// If it does not have same type, it means that `listItem` is on different list (this can happen only\n\t\t\t\t\t// on top level lists, though).\n\t\t\t\t\treturn prev.getAttribute( 'listType' ) == type;\n\t\t\t\t}\n\n\t\t\t\tprev = prev.previousSibling;\n\t\t\t}\n\n\t\t\t// Could not find similar list item, this means that `listItem` is first in its list.\n\t\t\treturn false;\n\t\t}\n\n\t\t// If we are outdenting it is enough to be in list item. Every list item can always be outdented.\n\t\treturn true;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/utils\n */\n\nimport { TreeWalker, getFillerOffset } from 'ckeditor5/src/engine';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\n/**\n * Creates a list item {@link module:engine/view/containerelement~ContainerElement}.\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} writer The writer instance.\n * @returns {module:engine/view/containerelement~ContainerElement}\n */\nexport function createViewListItemElement( writer ) {\n\tconst viewItem = writer.createContainerElement( 'li' );\n\n\tviewItem.getFillerOffset = getListItemFillerOffset;\n\n\treturn viewItem;\n}\n\n/**\n * Helper function that creates a `<ul><li></li></ul>` or (`<ol>`) structure out of the given `modelItem` model `listItem` element.\n * Then, it binds the created view list item (`<li>`) with the model `listItem` element.\n * The function then returns the created view list item (`<li>`).\n *\n * @param {module:engine/model/item~Item} modelItem Model list item.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface.\n * @returns {module:engine/view/containerelement~ContainerElement} View list element.\n */\nexport function generateLiInUl( modelItem, conversionApi ) {\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\tconst listType = modelItem.getAttribute( 'listType' ) == 'numbered' ? 'ol' : 'ul';\n\tconst viewItem = createViewListItemElement( viewWriter );\n\n\tconst viewList = viewWriter.createContainerElement( listType, null );\n\n\tviewWriter.insert( viewWriter.createPositionAt( viewList, 0 ), viewItem );\n\n\tmapper.bindElements( modelItem, viewItem );\n\n\treturn viewItem;\n}\n\n/**\n * Helper function that inserts a view list at a correct place and merges it with its siblings.\n * It takes a model list item element (`modelItem`) and a corresponding view list item element (`injectedItem`). The view list item\n * should be in a view list element (`<ul>` or `<ol>`) and should be its only child.\n * See comments below to better understand the algorithm.\n *\n * @param {module:engine/view/item~Item} modelItem Model list item.\n * @param {module:engine/view/containerelement~ContainerElement} injectedItem\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface.\n * @param {module:engine/model/model~Model} model The model instance.\n */\nexport function injectViewList( modelItem, injectedItem, conversionApi, model ) {\n\tconst injectedList = injectedItem.parent;\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\n\t// The position where the view list will be inserted.\n\tlet insertPosition = mapper.toViewPosition( model.createPositionBefore( modelItem ) );\n\n\t// 1. Find the previous list item that has the same or smaller indent. Basically we are looking for the first model item\n\t// that is a \"parent\" or \"sibling\" of the injected model item.\n\t// If there is no such list item, it means that the injected list item is the first item in \"its list\".\n\tconst refItem = getSiblingListItem( modelItem.previousSibling, {\n\t\tsameIndent: true,\n\t\tsmallerIndent: true,\n\t\tlistIndent: modelItem.getAttribute( 'listIndent' )\n\t} );\n\tconst prevItem = modelItem.previousSibling;\n\n\tif ( refItem && refItem.getAttribute( 'listIndent' ) == modelItem.getAttribute( 'listIndent' ) ) {\n\t\t// There is a list item with the same indent - we found the same-level sibling.\n\t\t// Break the list after it. The inserted view item will be added in the broken space.\n\t\tconst viewItem = mapper.toViewElement( refItem );\n\t\tinsertPosition = viewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\t} else {\n\t\t// There is no list item with the same indent. Check the previous model item.\n\t\tif ( prevItem && prevItem.name == 'listItem' ) {\n\t\t\t// If it is a list item, it has to have a lower indent.\n\t\t\t// It means that the inserted item should be added to it as its nested item.\n\t\t\tinsertPosition = mapper.toViewPosition( model.createPositionAt( prevItem, 'end' ) );\n\n\t\t\t// There could be some not mapped elements (eg. span in to-do list) but we need to insert\n\t\t\t// a nested list directly inside the li element.\n\t\t\tconst mappedViewAncestor = mapper.findMappedViewAncestor( insertPosition );\n\t\t\tconst nestedList = findNestedList( mappedViewAncestor );\n\n\t\t\t// If there already is some nested list, then use it's position.\n\t\t\tif ( nestedList ) {\n\t\t\t\tinsertPosition = viewWriter.createPositionBefore( nestedList );\n\t\t\t} else {\n\t\t\t\t// Else just put new list on the end of list item content.\n\t\t\t\tinsertPosition = viewWriter.createPositionAt( mappedViewAncestor, 'end' );\n\t\t\t}\n\t\t} else {\n\t\t\t// The previous item is not a list item (or does not exist at all).\n\t\t\t// Just map the position and insert the view item at the mapped position.\n\t\t\tinsertPosition = mapper.toViewPosition( model.createPositionBefore( modelItem ) );\n\t\t}\n\t}\n\n\tinsertPosition = positionAfterUiElements( insertPosition );\n\n\t// Insert the view item.\n\tviewWriter.insert( insertPosition, injectedList );\n\n\t// 2. Handle possible children of the injected model item.\n\tif ( prevItem && prevItem.name == 'listItem' ) {\n\t\tconst prevView = mapper.toViewElement( prevItem );\n\n\t\tconst walkerBoundaries = viewWriter.createRange( viewWriter.createPositionAt( prevView, 0 ), insertPosition );\n\t\tconst walker = walkerBoundaries.getWalker( { ignoreElementEnd: true } );\n\n\t\tfor ( const value of walker ) {\n\t\t\tif ( value.item.is( 'element', 'li' ) ) {\n\t\t\t\tconst breakPosition = viewWriter.breakContainer( viewWriter.createPositionBefore( value.item ) );\n\t\t\t\tconst viewList = value.item.parent;\n\n\t\t\t\tconst targetPosition = viewWriter.createPositionAt( injectedItem, 'end' );\n\t\t\t\tmergeViewLists( viewWriter, targetPosition.nodeBefore, targetPosition.nodeAfter );\n\t\t\t\tviewWriter.move( viewWriter.createRangeOn( viewList ), targetPosition );\n\n\t\t\t\twalker.position = breakPosition;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst nextViewList = injectedList.nextSibling;\n\n\t\tif ( nextViewList && ( nextViewList.is( 'element', 'ul' ) || nextViewList.is( 'element', 'ol' ) ) ) {\n\t\t\tlet lastSubChild = null;\n\n\t\t\tfor ( const child of nextViewList.getChildren() ) {\n\t\t\t\tconst modelChild = mapper.toModelElement( child );\n\n\t\t\t\tif ( modelChild && modelChild.getAttribute( 'listIndent' ) > modelItem.getAttribute( 'listIndent' ) ) {\n\t\t\t\t\tlastSubChild = child;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( lastSubChild ) {\n\t\t\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( lastSubChild ) );\n\t\t\t\tviewWriter.move( viewWriter.createRangeOn( lastSubChild.parent ), viewWriter.createPositionAt( injectedItem, 'end' ) );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Merge the inserted view list with its possible neighbor lists.\n\tmergeViewLists( viewWriter, injectedList, injectedList.nextSibling );\n\tmergeViewLists( viewWriter, injectedList.previousSibling, injectedList );\n}\n\n/**\n * Helper function that takes two parameters that are expected to be view list elements, and merges them.\n * The merge happens only if both parameters are list elements of the same type (the same element name and the same class attributes).\n *\n * @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter The writer instance.\n * @param {module:engine/view/item~Item} firstList The first element to compare.\n * @param {module:engine/view/item~Item} secondList The second element to compare.\n * @returns {module:engine/view/position~Position|null} The position after merge or `null` when there was no merge.\n */\nexport function mergeViewLists( viewWriter, firstList, secondList ) {\n\t// Check if two lists are going to be merged.\n\tif ( !firstList || !secondList || ( firstList.name != 'ul' && firstList.name != 'ol' ) ) {\n\t\treturn null;\n\t}\n\n\t// Both parameters are list elements, so compare types now.\n\tif ( firstList.name != secondList.name || firstList.getAttribute( 'class' ) !== secondList.getAttribute( 'class' ) ) {\n\t\treturn null;\n\t}\n\n\treturn viewWriter.mergeContainers( viewWriter.createPositionAfter( firstList ) );\n}\n\n/**\n * Helper function that for a given `view.Position`, returns a `view.Position` that is after all `view.UIElement`s that\n * are after the given position.\n *\n * For example:\n * `<container:p>foo^<ui:span></ui:span><ui:span></ui:span>bar</container:p>`\n * For position ^, the position before \"bar\" will be returned.\n *\n * @param {module:engine/view/position~Position} viewPosition\n * @returns {module:engine/view/position~Position}\n */\nexport function positionAfterUiElements( viewPosition ) {\n\treturn viewPosition.getLastMatchingPosition( value => value.item.is( 'uiElement' ) );\n}\n\n/**\n * Helper function that searches for a previous list item sibling of a given model item that meets the given criteria\n * passed by the options object.\n *\n * @param {module:engine/model/item~Item} modelItem\n * @param {Object} options Search criteria.\n * @param {Boolean} [options.sameIndent=false] Whether the sought sibling should have the same indentation.\n * @param {Boolean} [options.smallerIndent=false] Whether the sought sibling should have a smaller indentation.\n * @param {Number} [options.listIndent] The reference indentation.\n * @param {'forward'|'backward'} [options.direction='backward'] Walking direction.\n * @returns {module:engine/model/item~Item|null}\n */\nexport function getSiblingListItem( modelItem, options ) {\n\tconst sameIndent = !!options.sameIndent;\n\tconst smallerIndent = !!options.smallerIndent;\n\tconst indent = options.listIndent;\n\n\tlet item = modelItem;\n\n\twhile ( item && item.name == 'listItem' ) {\n\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\tif ( ( sameIndent && indent == itemIndent ) || ( smallerIndent && indent > itemIndent ) ) {\n\t\t\treturn item;\n\t\t}\n\n\t\tif ( options.direction === 'forward' ) {\n\t\t\titem = item.nextSibling;\n\t\t} else {\n\t\t\titem = item.previousSibling;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Helper method for creating a UI button and linking it with an appropriate command.\n *\n * @private\n * @param {module:core/editor/editor~Editor} editor The editor instance to which the UI component will be added.\n * @param {String} commandName The name of the command.\n * @param {Object} label The button label.\n * @param {String} icon The source of the icon.\n */\nexport function createUIComponent( editor, commandName, label, icon ) {\n\teditor.ui.componentFactory.add( commandName, locale => {\n\t\tconst command = editor.commands.get( commandName );\n\t\tconst buttonView = new ButtonView( locale );\n\n\t\tbuttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true,\n\t\t\tisToggleable: true\n\t\t} );\n\n\t\t// Bind button model to command.\n\t\tbuttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t// Execute command.\n\t\tbuttonView.on( 'execute', () => {\n\t\t\teditor.execute( commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn buttonView;\n\t} );\n}\n\n/**\n * Returns a first list view element that is direct child of the given view element.\n *\n * @param {module:engine/view/element~Element} viewElement\n * @return {module:engine/view/element~Element|null}\n */\nexport function findNestedList( viewElement ) {\n\tfor ( const node of viewElement.getChildren() ) {\n\t\tif ( node.name == 'ul' || node.name == 'ol' ) {\n\t\t\treturn node;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n/**\n * Returns an array with all `listItem` elements that represents the same list.\n *\n * It means that values for `listIndent`, `listType`, and `listStyle` for all items are equal.\n *\n * @param {module:engine/model/position~Position} position Starting position.\n * @param {'forward'|'backward'} direction Walking direction.\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getSiblingNodes( position, direction ) {\n\tconst items = [];\n\tconst listItem = position.parent;\n\tconst walkerOptions = {\n\t\tignoreElementEnd: true,\n\t\tstartPosition: position,\n\t\tshallow: true,\n\t\tdirection\n\t};\n\tconst limitIndent = listItem.getAttribute( 'listIndent' );\n\tconst nodes = [ ...new TreeWalker( walkerOptions ) ]\n\t\t.filter( value => value.item.is( 'element' ) )\n\t\t.map( value => value.item );\n\n\tfor ( const element of nodes ) {\n\t\t// If found something else than `listItem`, we're out of the list scope.\n\t\tif ( !element.is( 'element', 'listItem' ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// If current parsed item has lower indent that element that the element that was a starting point,\n\t\t// it means we left a nested list. Abort searching items.\n\t\t//\n\t\t// ■ List item 1. [listIndent=0]\n\t\t// ○ List item 2.[] [listIndent=1], limitIndent = 1,\n\t\t// ○ List item 3. [listIndent=1]\n\t\t// ■ List item 4. [listIndent=0]\n\t\t//\n\t\t// Abort searching when leave nested list.\n\t\tif ( element.getAttribute( 'listIndent' ) < limitIndent ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// ■ List item 1.[] [listIndent=0] limitIndent = 0,\n\t\t// ○ List item 2. [listIndent=1]\n\t\t// ○ List item 3. [listIndent=1]\n\t\t// ■ List item 4. [listIndent=0]\n\t\t//\n\t\t// Ignore nested lists.\n\t\tif ( element.getAttribute( 'listIndent' ) > limitIndent ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ■ List item 1.[] [listType=bulleted]\n\t\t// 1. List item 2. [listType=numbered]\n\t\t// 2.List item 3. [listType=numbered]\n\t\t//\n\t\t// Abort searching when found a different kind of a list.\n\t\tif ( element.getAttribute( 'listType' ) !== listItem.getAttribute( 'listType' ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// ■ List item 1.[] [listType=bulleted]\n\t\t// ■ List item 2. [listType=bulleted]\n\t\t// ○ List item 3. [listType=bulleted]\n\t\t// ○ List item 4. [listType=bulleted]\n\t\t//\n\t\t// Abort searching when found a different list style.\n\t\tif ( element.getAttribute( 'listStyle' ) !== listItem.getAttribute( 'listStyle' ) ) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif ( direction === 'backward' ) {\n\t\t\titems.unshift( element );\n\t\t} else {\n\t\t\titems.push( element );\n\t\t}\n\t}\n\n\treturn items;\n}\n\n// Implementation of getFillerOffset for view list item element.\n//\n// @returns {Number|null} Block filler offset or `null` if block filler is not needed.\nfunction getListItemFillerOffset() {\n\tconst hasOnlyLists = !this.isEmpty && ( this.getChild( 0 ).name == 'ul' || this.getChild( 0 ).name == 'ol' );\n\n\tif ( this.isEmpty || hasOnlyLists ) {\n\t\treturn 0;\n\t}\n\n\treturn getFillerOffset.call( this );\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 list/converters\n */\n\nimport { TreeWalker } from 'ckeditor5/src/engine';\n\nimport {\n\tgenerateLiInUl,\n\tinjectViewList,\n\tmergeViewLists,\n\tgetSiblingListItem,\n\tpositionAfterUiElements\n} from './utils';\n\n/**\n * A model-to-view converter for the `listItem` model element insertion.\n *\n * It creates a `<ul><li></li><ul>` (or `<ol>`) view structure out of a `listItem` model element, inserts it at the correct\n * position, and merges the list with surrounding lists (if available).\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewInsertion( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst consumable = conversionApi.consumable;\n\n\t\tif ( !consumable.test( data.item, 'insert' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listType' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listIndent' )\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconsumable.consume( data.item, 'insert' );\n\t\tconsumable.consume( data.item, 'attribute:listType' );\n\t\tconsumable.consume( data.item, 'attribute:listIndent' );\n\n\t\tconst modelItem = data.item;\n\t\tconst viewItem = generateLiInUl( modelItem, conversionApi );\n\n\t\tinjectViewList( modelItem, viewItem, conversionApi, model );\n\t};\n}\n\n/**\n * A model-to-view converter for the `listItem` model element removal.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewRemove( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.position );\n\t\tconst viewStart = viewPosition.getLastMatchingPosition( value => !value.item.is( 'element', 'li' ) );\n\t\tconst viewItem = viewStart.nodeAfter;\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// 1. Break the container after and before the list item.\n\t\t// This will create a view list with one view list item - the one to remove.\n\t\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t\t// 2. Remove the list with the item to remove.\n\t\tconst viewList = viewItem.parent;\n\t\tconst viewListPrev = viewList.previousSibling;\n\t\tconst removeRange = viewWriter.createRangeOn( viewList );\n\t\tconst removed = viewWriter.remove( removeRange );\n\n\t\t// 3. Merge the whole created by breaking and removing the list.\n\t\tif ( viewListPrev && viewListPrev.nextSibling ) {\n\t\t\tmergeViewLists( viewWriter, viewListPrev, viewListPrev.nextSibling );\n\t\t}\n\n\t\t// 4. Bring back nested list that was in the removed <li>.\n\t\tconst modelItem = conversionApi.mapper.toModelElement( viewItem );\n\n\t\thoistNestedLists( modelItem.getAttribute( 'listIndent' ) + 1, data.position, removeRange.start, viewItem, conversionApi, model );\n\n\t\t// 5. Unbind removed view item and all children.\n\t\tfor ( const child of viewWriter.createRangeIn( removed ).getItems() ) {\n\t\t\tconversionApi.mapper.unbindViewElement( child );\n\t\t}\n\n\t\tevt.stop();\n\t};\n}\n\n/**\n * A model-to-view converter for the `type` attribute change on the `listItem` model element.\n *\n * This change means that the `<li>` element parent changes from `<ul>` to `<ol>` (or vice versa). This is accomplished\n * by breaking view elements and changing their name. The next {@link module:list/converters~modelViewMergeAfterChangeType}\n * converter will attempt to merge split nodes.\n *\n * Splitting this conversion into 2 steps makes it possible to add an additional conversion in the middle.\n * Check {@link module:list/todolistconverters~modelViewChangeType} to see an example of it.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewChangeType( evt, data, conversionApi ) {\n\tif ( !conversionApi.consumable.consume( data.item, 'attribute:listType' ) ) {\n\t\treturn;\n\t}\n\n\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\tconst viewWriter = conversionApi.writer;\n\n\t// Break the container after and before the list item.\n\t// This will create a view list with one view list item -- the one that changed type.\n\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t// Change name of the view list that holds the changed view item.\n\t// We cannot just change name property, because that would not render properly.\n\tconst viewList = viewItem.parent;\n\tconst listName = data.attributeNewValue == 'numbered' ? 'ol' : 'ul';\n\n\tviewWriter.rename( listName, viewList );\n}\n\n/**\n * A model-to-view converter that attempts to merge nodes split by {@link module:list/converters~modelViewChangeType}.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewMergeAfterChangeType( evt, data, conversionApi ) {\n\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\tconst viewList = viewItem.parent;\n\tconst viewWriter = conversionApi.writer;\n\n\t// Merge the changed view list with other lists, if possible.\n\tmergeViewLists( viewWriter, viewList, viewList.nextSibling );\n\tmergeViewLists( viewWriter, viewList.previousSibling, viewList );\n\n\t// Consumable insertion of children inside the item. They are already handled by re-building the item in view.\n\tfor ( const child of data.item.getChildren() ) {\n\t\tconversionApi.consumable.consume( child, 'insert' );\n\t}\n}\n\n/**\n * A model-to-view converter for the `listIndent` attribute change on the `listItem` model element.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewChangeIndent( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( !conversionApi.consumable.consume( data.item, 'attribute:listIndent' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\t// 1. Break the container after and before the list item.\n\t\t// This will create a view list with one view list item -- the one that changed type.\n\t\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\t\tviewWriter.breakContainer( viewWriter.createPositionAfter( viewItem ) );\n\n\t\t// 2. Extract view list with changed view list item and merge \"hole\" possibly created by breaking and removing elements.\n\t\tconst viewList = viewItem.parent;\n\t\tconst viewListPrev = viewList.previousSibling;\n\t\tconst removeRange = viewWriter.createRangeOn( viewList );\n\t\tviewWriter.remove( removeRange );\n\n\t\tif ( viewListPrev && viewListPrev.nextSibling ) {\n\t\t\tmergeViewLists( viewWriter, viewListPrev, viewListPrev.nextSibling );\n\t\t}\n\n\t\t// 3. Bring back nested list that was in the removed <li>.\n\t\thoistNestedLists( data.attributeOldValue + 1, data.range.start, removeRange.start, viewItem, conversionApi, model );\n\n\t\t// 4. Inject view list like it is newly inserted.\n\t\tinjectViewList( data.item, viewItem, conversionApi, model );\n\n\t\t// 5. Consume insertion of children inside the item. They are already handled by re-building the item in view.\n\t\tfor ( const child of data.item.getChildren() ) {\n\t\t\tconversionApi.consumable.consume( child, 'insert' );\n\t\t}\n\t};\n}\n\n/**\n * A special model-to-view converter introduced by the {@link module:list/list~List list feature}. This converter is fired for\n * insert change of every model item, and should be fired before the actual converter. The converter checks whether the inserted\n * model item is a non-`listItem` element. If it is, and it is inserted inside a view list, the converter breaks the\n * list so the model element is inserted to the view parent element corresponding to its model parent element.\n *\n * The converter prevents such situations:\n *\n *\t\t// Model: // View:\n *\t\t<listItem>foo</listItem> <ul>\n *\t\t<listItem>bar</listItem> <li>foo</li>\n *\t\t <li>bar</li>\n *\t\t </ul>\n *\n *\t\t// After change: // Correct view guaranteed by this converter:\n *\t\t<listItem>foo</listItem> <ul><li>foo</li></ul><p>xxx</p><ul><li>bar</li></ul>\n *\t\t<paragraph>xxx</paragraph> // Instead of this wrong view state:\n *\t\t<listItem>bar</listItem> <ul><li>foo</li><p>xxx</p><li>bar</li></ul>\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewSplitOnInsert( evt, data, conversionApi ) {\n\tif ( data.item.name != 'listItem' ) {\n\t\tlet viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst lists = [];\n\n\t\t// Break multiple ULs/OLs if there are.\n\t\t//\n\t\t// Imagine following list:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.1.3 --------\n\t\t// 1.1.3.1 --------\n\t\t// 1.2 --------\n\t\t// 1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\t// Insert paragraph after item 1.1.1:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t//\n\t\t// Lorem ipsum.\n\t\t//\n\t\t// 1.1.2 --------\n\t\t// 1.1.3 --------\n\t\t// 1.1.3.1 --------\n\t\t// 1.2 --------\n\t\t// 1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\t// In this case 1.1.2 has to become beginning of a new list.\n\t\t// We need to break list before 1.1.2 (obvious), then we need to break list also before 1.2.\n\t\t// Then we need to move those broken pieces one after another and merge:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t//\n\t\t// Lorem ipsum.\n\t\t//\n\t\t// 1.1.2 --------\n\t\t// 1.1.3 --------\n\t\t// 1.1.3.1 --------\n\t\t// 1.2 --------\n\t\t// 1.2.1 --------\n\t\t// 2 --------\n\t\t//\n\t\twhile ( viewPosition.parent.name == 'ul' || viewPosition.parent.name == 'ol' ) {\n\t\t\tviewPosition = viewWriter.breakContainer( viewPosition );\n\n\t\t\tif ( viewPosition.parent.name != 'li' ) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Remove lists that are after inserted element.\n\t\t\t// They will be brought back later, below the inserted element.\n\t\t\tconst removeStart = viewPosition;\n\t\t\tconst removeEnd = viewWriter.createPositionAt( viewPosition.parent, 'end' );\n\n\t\t\t// Don't remove if there is nothing to remove.\n\t\t\tif ( !removeStart.isEqual( removeEnd ) ) {\n\t\t\t\tconst removed = viewWriter.remove( viewWriter.createRange( removeStart, removeEnd ) );\n\t\t\t\tlists.push( removed );\n\t\t\t}\n\n\t\t\tviewPosition = viewWriter.createPositionAfter( viewPosition.parent );\n\t\t}\n\n\t\t// Bring back removed lists.\n\t\tif ( lists.length > 0 ) {\n\t\t\tfor ( let i = 0; i < lists.length; i++ ) {\n\t\t\t\tconst previousList = viewPosition.nodeBefore;\n\t\t\t\tconst insertedRange = viewWriter.insert( viewPosition, lists[ i ] );\n\t\t\t\tviewPosition = insertedRange.end;\n\n\t\t\t\t// Don't merge first list! We want a split in that place (this is why this converter is introduced).\n\t\t\t\tif ( i > 0 ) {\n\t\t\t\t\tconst mergePos = mergeViewLists( viewWriter, previousList, previousList.nextSibling );\n\n\t\t\t\t\t// If `mergePos` is in `previousList` it means that the lists got merged.\n\t\t\t\t\t// In this case, we need to fix insert position.\n\t\t\t\t\tif ( mergePos && mergePos.parent == previousList ) {\n\t\t\t\t\t\tviewPosition.offset--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Merge last inserted list with element after it.\n\t\t\tmergeViewLists( viewWriter, viewPosition.nodeBefore, viewPosition.nodeAfter );\n\t\t}\n\t}\n}\n\n/**\n * A special model-to-view converter introduced by the {@link module:list/list~List list feature}. This converter takes care of\n * merging view lists after something is removed or moved from near them.\n *\n * Example:\n *\n *\t\t// Model: // View:\n *\t\t<listItem>foo</listItem> <ul><li>foo</li></ul>\n *\t\t<paragraph>xxx</paragraph> <p>xxx</p>\n *\t\t<listItem>bar</listItem> <ul><li>bar</li></ul>\n *\n *\t\t// After change: // Correct view guaranteed by this converter:\n *\t\t<listItem>foo</listItem> <ul>\n *\t\t<listItem>bar</listItem> <li>foo</li>\n *\t\t <li>bar</li>\n *\t\t </ul>\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:remove\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data Additional information about the change.\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi Conversion interface.\n */\nexport function modelViewMergeAfter( evt, data, conversionApi ) {\n\tconst viewPosition = conversionApi.mapper.toViewPosition( data.position );\n\tconst viewItemPrev = viewPosition.nodeBefore;\n\tconst viewItemNext = viewPosition.nodeAfter;\n\n\t// Merge lists if something (remove, move) was done from inside of list.\n\t// Merging will be done only if both items are view lists of the same type.\n\t// The check is done inside the helper function.\n\tmergeViewLists( conversionApi.writer, viewItemPrev, viewItemNext );\n}\n\n/**\n * A view-to-model converter that converts the `<li>` view elements into the `listItem` model elements.\n *\n * To set correct values of the `listType` and `listIndent` attributes the converter:\n * * checks `<li>`'s parent,\n * * stores and increases the `conversionApi.store.indent` value when `<li>`'s sub-items are converted.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function viewModelConverter( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.consume( data.viewItem, { name: true } ) ) {\n\t\tconst writer = conversionApi.writer;\n\n\t\t// 1. Create `listItem` model element.\n\t\tconst listItem = writer.createElement( 'listItem' );\n\n\t\t// 2. Handle `listItem` model element attributes.\n\t\tconst indent = getIndent( data.viewItem );\n\n\t\twriter.setAttribute( 'listIndent', indent, listItem );\n\n\t\t// Set 'bulleted' as default. If this item is pasted into a context,\n\t\tconst type = data.viewItem.parent && data.viewItem.parent.name == 'ol' ? 'numbered' : 'bulleted';\n\t\twriter.setAttribute( 'listType', type, listItem );\n\n\t\tif ( !conversionApi.safeInsert( listItem, data.modelCursor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst nextPosition = viewToModelListItemChildrenConverter( listItem, data.viewItem.getChildren(), conversionApi );\n\n\t\t// Result range starts before the first item and ends after the last.\n\t\tdata.modelRange = writer.createRange( data.modelCursor, nextPosition );\n\n\t\tconversionApi.updateConversionResult( listItem, data );\n\t}\n}\n\n/**\n * A view-to-model converter for the `<ul>` and `<ol>` view elements that cleans the input view of garbage.\n * This is mostly to clean whitespaces from between the `<li>` view elements inside the view list element, however, also\n * incorrect data can be cleared if the view was incorrect.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function cleanList( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.test( data.viewItem, { name: true } ) ) {\n\t\t// Caching children because when we start removing them iterating fails.\n\t\tconst children = Array.from( data.viewItem.getChildren() );\n\n\t\tfor ( const child of children ) {\n\t\t\tconst isWrongElement = !( child.is( 'element', 'li' ) || isList( child ) );\n\n\t\t\tif ( isWrongElement ) {\n\t\t\t\tchild._remove();\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * A view-to-model converter for the `<li>` elements that cleans whitespace formatting from the input view.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input and a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function cleanListItem( evt, data, conversionApi ) {\n\tif ( conversionApi.consumable.test( data.viewItem, { name: true } ) ) {\n\t\tif ( data.viewItem.childCount === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst children = [ ...data.viewItem.getChildren() ];\n\n\t\tlet foundList = false;\n\t\tlet firstNode = true;\n\n\t\tfor ( const child of children ) {\n\t\t\tif ( foundList && !isList( child ) ) {\n\t\t\t\tchild._remove();\n\t\t\t}\n\n\t\t\tif ( child.is( '$text' ) ) {\n\t\t\t\t// If this is the first node and it's a text node, left-trim it.\n\t\t\t\tif ( firstNode ) {\n\t\t\t\t\tchild._data = child.data.trimStart();\n\t\t\t\t}\n\n\t\t\t\t// If this is the last text node before <ul> or <ol>, right-trim it.\n\t\t\t\tif ( !child.nextSibling || isList( child.nextSibling ) ) {\n\t\t\t\t\tchild._data = child.data.trimEnd();\n\t\t\t\t}\n\t\t\t} else if ( isList( child ) ) {\n\t\t\t\t// If this is a <ul> or <ol>, do not process it, just mark that we already visited list element.\n\t\t\t\tfoundList = true;\n\t\t\t}\n\n\t\t\tfirstNode = false;\n\t\t}\n\t}\n}\n\n/**\n * Returns a callback for model position to view position mapping for {@link module:engine/conversion/mapper~Mapper}. The callback fixes\n * positions between the `listItem` elements that would be incorrectly mapped because of how list items are represented in the model\n * and in the view.\n *\n * @see module:engine/conversion/mapper~Mapper#event:modelToViewPosition\n * @param {module:engine/view/view~View} view A view instance.\n * @returns {Function}\n */\nexport function modelToViewPosition( view ) {\n\treturn ( evt, data ) => {\n\t\tif ( data.isPhantom ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelItem = data.modelPosition.nodeBefore;\n\n\t\tif ( modelItem && modelItem.is( 'element', 'listItem' ) ) {\n\t\t\tconst viewItem = data.mapper.toViewElement( modelItem );\n\t\t\tconst topmostViewList = viewItem.getAncestors().find( isList );\n\t\t\tconst walker = view.createPositionAt( viewItem, 0 ).getWalker();\n\n\t\t\tfor ( const value of walker ) {\n\t\t\t\tif ( value.type == 'elementStart' && value.item.is( 'element', 'li' ) ) {\n\t\t\t\t\tdata.viewPosition = value.previousPosition;\n\n\t\t\t\t\tbreak;\n\t\t\t\t} else if ( value.type == 'elementEnd' && value.item == topmostViewList ) {\n\t\t\t\t\tdata.viewPosition = value.nextPosition;\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * The callback for view position to model position mapping for {@link module:engine/conversion/mapper~Mapper}. The callback fixes\n * positions between the `<li>` elements that would be incorrectly mapped because of how list items are represented in the model\n * and in the view.\n *\n * @see module:engine/conversion/mapper~Mapper#event:viewToModelPosition\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function viewToModelPosition( model ) {\n\treturn ( evt, data ) => {\n\t\tconst viewPos = data.viewPosition;\n\t\tconst viewParent = viewPos.parent;\n\t\tconst mapper = data.mapper;\n\n\t\tif ( viewParent.name == 'ul' || viewParent.name == 'ol' ) {\n\t\t\t// Position is directly in <ul> or <ol>.\n\t\t\tif ( !viewPos.isAtEnd ) {\n\t\t\t\t// If position is not at the end, it must be before <li>.\n\t\t\t\t// Get that <li>, map it to `listItem` and set model position before that `listItem`.\n\t\t\t\tconst modelNode = mapper.toModelElement( viewPos.nodeAfter );\n\n\t\t\t\tdata.modelPosition = model.createPositionBefore( modelNode );\n\t\t\t} else {\n\t\t\t\t// Position is at the end of <ul> or <ol>, so there is no <li> after it to be mapped.\n\t\t\t\t// There is <li> before the position, but we cannot just map it to `listItem` and set model position after it,\n\t\t\t\t// because that <li> may contain nested items.\n\t\t\t\t// We will check \"model length\" of that <li>, in other words - how many `listItem`s are in that <li>.\n\t\t\t\tconst modelNode = mapper.toModelElement( viewPos.nodeBefore );\n\t\t\t\tconst modelLength = mapper.getModelLength( viewPos.nodeBefore );\n\n\t\t\t\t// Then we get model position before mapped `listItem` and shift it accordingly.\n\t\t\t\tdata.modelPosition = model.createPositionBefore( modelNode ).getShiftedBy( modelLength );\n\t\t\t}\n\n\t\t\tevt.stop();\n\t\t} else if (\n\t\t\tviewParent.name == 'li' &&\n\t\t\tviewPos.nodeBefore &&\n\t\t\t( viewPos.nodeBefore.name == 'ul' || viewPos.nodeBefore.name == 'ol' )\n\t\t) {\n\t\t\t// In most cases when view position is in <li> it is in text and this is a correct position.\n\t\t\t// However, if position is after <ul> or <ol> we have to fix it -- because in model <ul>/<ol> are not in the `listItem`.\n\t\t\tconst modelNode = mapper.toModelElement( viewParent );\n\n\t\t\t// Check all <ul>s and <ol>s that are in the <li> but before mapped position.\n\t\t\t// Get model length of those elements and then add it to the offset of `listItem` mapped to the original <li>.\n\t\t\tlet modelLength = 1; // Starts from 1 because the original <li> has to be counted in too.\n\t\t\tlet viewList = viewPos.nodeBefore;\n\n\t\t\twhile ( viewList && isList( viewList ) ) {\n\t\t\t\tmodelLength += mapper.getModelLength( viewList );\n\n\t\t\t\tviewList = viewList.previousSibling;\n\t\t\t}\n\n\t\t\tdata.modelPosition = model.createPositionBefore( modelNode ).getShiftedBy( modelLength );\n\n\t\t\tevt.stop();\n\t\t}\n\t};\n}\n\n/**\n * Post-fixer that reacts to changes on document and fixes incorrect model states.\n *\n * In the example below, there is a correct list structure.\n * Then the middle element is removed so the list structure will become incorrect:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>Item 2</listItem> <--- this is removed.\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Item 3</listItem>\n *\n * The list structure after the middle element is removed:\n *\n * \t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Item 3</listItem>\n *\n * Should become:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>Item 1</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>Item 3</listItem> <--- note that indent got post-fixed.\n *\n * @param {module:engine/model/model~Model} model The data model.\n * @param {module:engine/model/writer~Writer} writer The writer to do changes with.\n * @returns {Boolean} `true` if any change has been applied, `false` otherwise.\n */\nexport function modelChangePostFixer( model, writer ) {\n\tconst changes = model.document.differ.getChanges();\n\tconst itemToListHead = new Map();\n\n\tlet applied = false;\n\n\tfor ( const entry of changes ) {\n\t\tif ( entry.type == 'insert' && entry.name == 'listItem' ) {\n\t\t\t_addListToFix( entry.position );\n\t\t} else if ( entry.type == 'insert' && entry.name != 'listItem' ) {\n\t\t\tif ( entry.name != '$text' ) {\n\t\t\t\t// In case of renamed element.\n\t\t\t\tconst item = entry.position.nodeAfter;\n\n\t\t\t\tif ( item.hasAttribute( 'listIndent' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listIndent', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tif ( item.hasAttribute( 'listType' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listType', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tif ( item.hasAttribute( 'listStyle' ) ) {\n\t\t\t\t\twriter.removeAttribute( 'listStyle', item );\n\n\t\t\t\t\tapplied = true;\n\t\t\t\t}\n\n\t\t\t\tfor ( const innerItem of Array.from( model.createRangeIn( item ) ).filter( e => e.item.is( 'element', 'listItem' ) ) ) {\n\t\t\t\t\t_addListToFix( innerItem.previousPosition );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst posAfter = entry.position.getShiftedBy( entry.length );\n\n\t\t\t_addListToFix( posAfter );\n\t\t} else if ( entry.type == 'remove' && entry.name == 'listItem' ) {\n\t\t\t_addListToFix( entry.position );\n\t\t} else if ( entry.type == 'attribute' && entry.attributeKey == 'listIndent' ) {\n\t\t\t_addListToFix( entry.range.start );\n\t\t} else if ( entry.type == 'attribute' && entry.attributeKey == 'listType' ) {\n\t\t\t_addListToFix( entry.range.start );\n\t\t}\n\t}\n\n\tfor ( const listHead of itemToListHead.values() ) {\n\t\t_fixListIndents( listHead );\n\t\t_fixListTypes( listHead );\n\t}\n\n\treturn applied;\n\n\tfunction _addListToFix( position ) {\n\t\tconst previousNode = position.nodeBefore;\n\n\t\tif ( !previousNode || !previousNode.is( 'element', 'listItem' ) ) {\n\t\t\tconst item = position.nodeAfter;\n\n\t\t\tif ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\t\titemToListHead.set( item, item );\n\t\t\t}\n\t\t} else {\n\t\t\tlet listHead = previousNode;\n\n\t\t\tif ( itemToListHead.has( listHead ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (\n\t\t\t\t// Cache previousSibling and reuse for performance reasons. See #6581.\n\t\t\t\tlet previousSibling = listHead.previousSibling;\n\t\t\t\tpreviousSibling && previousSibling.is( 'element', 'listItem' );\n\t\t\t\tpreviousSibling = listHead.previousSibling\n\t\t\t) {\n\t\t\t\tlistHead = previousSibling;\n\n\t\t\t\tif ( itemToListHead.has( listHead ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\titemToListHead.set( previousNode, listHead );\n\t\t}\n\t}\n\n\tfunction _fixListIndents( item ) {\n\t\tlet maxIndent = 0;\n\t\tlet fixBy = null;\n\n\t\twhile ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\t\tif ( itemIndent > maxIndent ) {\n\t\t\t\tlet newIndent;\n\n\t\t\t\tif ( fixBy === null ) {\n\t\t\t\t\tfixBy = itemIndent - maxIndent;\n\t\t\t\t\tnewIndent = maxIndent;\n\t\t\t\t} else {\n\t\t\t\t\tif ( fixBy > itemIndent ) {\n\t\t\t\t\t\tfixBy = itemIndent;\n\t\t\t\t\t}\n\n\t\t\t\t\tnewIndent = itemIndent - fixBy;\n\t\t\t\t}\n\n\t\t\t\twriter.setAttribute( 'listIndent', newIndent, item );\n\n\t\t\t\tapplied = true;\n\t\t\t} else {\n\t\t\t\tfixBy = null;\n\t\t\t\tmaxIndent = item.getAttribute( 'listIndent' ) + 1;\n\t\t\t}\n\n\t\t\titem = item.nextSibling;\n\t\t}\n\t}\n\n\tfunction _fixListTypes( item ) {\n\t\tlet typesStack = [];\n\t\tlet prev = null;\n\n\t\twhile ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\tconst itemIndent = item.getAttribute( 'listIndent' );\n\n\t\t\tif ( prev && prev.getAttribute( 'listIndent' ) > itemIndent ) {\n\t\t\t\ttypesStack = typesStack.slice( 0, itemIndent + 1 );\n\t\t\t}\n\n\t\t\tif ( itemIndent != 0 ) {\n\t\t\t\tif ( typesStack[ itemIndent ] ) {\n\t\t\t\t\tconst type = typesStack[ itemIndent ];\n\n\t\t\t\t\tif ( item.getAttribute( 'listType' ) != type ) {\n\t\t\t\t\t\twriter.setAttribute( 'listType', type, item );\n\n\t\t\t\t\t\tapplied = true;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttypesStack[ itemIndent ] = item.getAttribute( 'listType' );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprev = item;\n\t\t\titem = item.nextSibling;\n\t\t}\n\t}\n}\n\n/**\n * A fixer for pasted content that includes list items.\n *\n * It fixes indentation of pasted list items so the pasted items match correctly to the context they are pasted into.\n *\n * Example:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>A</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>B^</listItem>\n *\t\t// At ^ paste: <listItem listType=\"bulleted\" listIndent=4>X</listItem>\n *\t\t// <listItem listType=\"bulleted\" listIndent=5>Y</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>C</listItem>\n *\n * Should become:\n *\n *\t\t<listItem listType=\"bulleted\" listIndent=0>A</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=1>BX</listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>Y/listItem>\n *\t\t<listItem listType=\"bulleted\" listIndent=2>C</listItem>\n *\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Array} args Arguments of {@link module:engine/model/model~Model#insertContent}.\n */\nexport function modelIndentPasteFixer( evt, [ content, selectable ] ) {\n\t// Check whether inserted content starts from a `listItem`. If it does not, it means that there are some other\n\t// elements before it and there is no need to fix indents, because even if we insert that content into a list,\n\t// that list will be broken.\n\t// Note: we also need to handle singular elements because inserting item with indent 0 into 0,1,[],2\n\t// would create incorrect model.\n\tlet item = content.is( 'documentFragment' ) ? content.getChild( 0 ) : content;\n\n\tlet selection;\n\n\tif ( !selectable ) {\n\t\tselection = this.document.selection;\n\t} else {\n\t\tselection = this.createSelection( selectable );\n\t}\n\n\tif ( item && item.is( 'element', 'listItem' ) ) {\n\t\t// Get a reference list item. Inserted list items will be fixed according to that item.\n\t\tconst pos = selection.getFirstPosition();\n\t\tlet refItem = null;\n\n\t\tif ( pos.parent.is( 'element', 'listItem' ) ) {\n\t\t\trefItem = pos.parent;\n\t\t} else if ( pos.nodeBefore && pos.nodeBefore.is( 'element', 'listItem' ) ) {\n\t\t\trefItem = pos.nodeBefore;\n\t\t}\n\n\t\t// If there is `refItem` it means that we do insert list items into an existing list.\n\t\tif ( refItem ) {\n\t\t\t// First list item in `data` has indent equal to 0 (it is a first list item). It should have indent equal\n\t\t\t// to the indent of reference item. We have to fix the first item and all of it's children and following siblings.\n\t\t\t// Indent of all those items has to be adjusted to reference item.\n\t\t\tconst indentChange = refItem.getAttribute( 'listIndent' );\n\n\t\t\t// Fix only if there is anything to fix.\n\t\t\tif ( indentChange > 0 ) {\n\t\t\t\t// Adjust indent of all \"first\" list items in inserted data.\n\t\t\t\twhile ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\t\t\titem._setAttribute( 'listIndent', item.getAttribute( 'listIndent' ) + indentChange );\n\n\t\t\t\t\titem = item.nextSibling;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Helper function that converts children of a given `<li>` view element into corresponding model elements.\n// The function maintains proper order of elements if model `listItem` is split during the conversion\n// due to block children conversion.\n//\n// @param {module:engine/model/element~Element} listItemModel List item model element to which converted children will be inserted.\n// @param {Iterable.<module:engine/view/node~Node>} viewChildren View elements which will be converted.\n// @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n// @returns {module:engine/model/position~Position} Position on which next elements should be inserted after children conversion.\nfunction viewToModelListItemChildrenConverter( listItemModel, viewChildren, conversionApi ) {\n\tconst { writer, schema } = conversionApi;\n\n\t// A position after the last inserted `listItem`.\n\tlet nextPosition = writer.createPositionAfter( listItemModel );\n\n\t// Check all children of the converted `<li>`. At this point we assume there are no \"whitespace\" view text nodes\n\t// in view list, between view list items. This should be handled by `<ul>` and `<ol>` converters.\n\tfor ( const child of viewChildren ) {\n\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t\t\t// If the children is a list, we will insert its conversion result after currently handled `listItem`.\n\t\t\t// Then, next insertion position will be set after all the new list items (and maybe other elements if\n\t\t\t// something split list item).\n\t\t\t//\n\t\t\t// If this is a list, we expect that some `listItem`s and possibly other blocks will be inserted, however `.modelCursor`\n\t\t\t// should be set after last `listItem` (or block). This is why it feels safe to use it as `nextPosition`\n\t\t\tnextPosition = conversionApi.convertItem( child, nextPosition ).modelCursor;\n\t\t} else {\n\t\t\t// If this is not a list, try inserting content at the end of the currently handled `listItem`.\n\t\t\tconst result = conversionApi.convertItem( child, writer.createPositionAt( listItemModel, 'end' ) );\n\n\t\t\t// It may end up that the current `listItem` becomes split (if that content cannot be inside `listItem`). For example:\n\t\t\t//\n\t\t\t// <li><p>Foo</p></li>\n\t\t\t//\n\t\t\t// will be converted to:\n\t\t\t//\n\t\t\t// <listItem></listItem><paragraph>Foo</paragraph><listItem></listItem>\n\t\t\t//\n\t\t\tconst convertedChild = result.modelRange.start.nodeAfter;\n\t\t\tconst wasSplit = convertedChild && convertedChild.is( 'element' ) && !schema.checkChild( listItemModel, convertedChild.name );\n\n\t\t\tif ( wasSplit ) {\n\t\t\t\t// As `lastListItem` got split, we need to update it to the second part of the split `listItem` element.\n\t\t\t\t//\n\t\t\t\t// `modelCursor` should be set to a position where the conversion should continue. There are multiple possible scenarios\n\t\t\t\t// that may happen. Usually, `modelCursor` (marked as `#` below) would point to the second list item after conversion:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><p>Foo</p></li>` -> `<listItem></listItem><paragraph>Foo</paragraph><listItem>#</listItem>`\n\t\t\t\t//\n\t\t\t\t// However, in some cases, like auto-paragraphing, the position is placed at the end of the block element:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><div>Foo</div></li>` -> `<listItem></listItem><paragraph>Foo#</paragraph><listItem></listItem>`\n\t\t\t\t//\n\t\t\t\t// or after an element if another element broken auto-paragraphed element:\n\t\t\t\t//\n\t\t\t\t//\t\t`<li><div><h2>Foo</h2></div></li>` -> `<listItem></listItem><heading1>Foo</heading1>#<listItem></listItem>`\n\t\t\t\t//\n\t\t\t\t// We need to check for such cases and use proper list item and position based on it.\n\t\t\t\t//\n\t\t\t\tif ( result.modelCursor.parent.is( 'element', 'listItem' ) ) {\n\t\t\t\t\t// (1).\n\t\t\t\t\tlistItemModel = result.modelCursor.parent;\n\t\t\t\t} else {\n\t\t\t\t\t// (2), (3).\n\t\t\t\t\tlistItemModel = findNextListItem( result.modelCursor );\n\t\t\t\t}\n\n\t\t\t\tnextPosition = writer.createPositionAfter( listItemModel );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nextPosition;\n}\n\n// Helper function that seeks for a next list item starting from given `startPosition`.\nfunction findNextListItem( startPosition ) {\n\tconst treeWalker = new TreeWalker( { startPosition } );\n\n\tlet value;\n\n\tdo {\n\t\tvalue = treeWalker.next();\n\t} while ( !value.value.item.is( 'element', 'listItem' ) );\n\n\treturn value.value.item;\n}\n\n// Helper function that takes all children of given `viewRemovedItem` and moves them in a correct place, according\n// to other given parameters.\nfunction hoistNestedLists( nextIndent, modelRemoveStartPosition, viewRemoveStartPosition, viewRemovedItem, conversionApi, model ) {\n\t// Find correct previous model list item element.\n\t// The element has to have either same or smaller indent than given reference indent.\n\t// This will be the model element which will get nested items (if it has smaller indent) or sibling items (if it has same indent).\n\t// Keep in mind that such element might not be found, if removed item was the first item.\n\tconst prevModelItem = getSiblingListItem( modelRemoveStartPosition.nodeBefore, {\n\t\tsameIndent: true,\n\t\tsmallerIndent: true,\n\t\tlistIndent: nextIndent,\n\t\tfoo: 'b'\n\t} );\n\n\tconst mapper = conversionApi.mapper;\n\tconst viewWriter = conversionApi.writer;\n\n\t// Indent of found element or `null` if the element has not been found.\n\tconst prevIndent = prevModelItem ? prevModelItem.getAttribute( 'listIndent' ) : null;\n\n\tlet insertPosition;\n\n\tif ( !prevModelItem ) {\n\t\t// If element has not been found, simply insert lists at the position where the removed item was:\n\t\t//\n\t\t// Lorem ipsum.\n\t\t// 1 -------- <--- this is removed, no previous list item, put nested items in place of removed item.\n\t\t// 1.1 -------- <--- this is reference indent.\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// Lorem ipsum.\n\t\t// 1.1 --------\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\tinsertPosition = viewRemoveStartPosition;\n\t} else if ( prevIndent == nextIndent ) {\n\t\t// If element has been found and has same indent as reference indent it means that nested items should\n\t\t// become siblings of found element:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.2 -------- <--- this is `prevModelItem`.\n\t\t// 2 -------- <--- this is removed, previous list item has indent same as reference indent.\n\t\t// 2.1 -------- <--- this is reference indent, this and 2.2 should become siblings of 1.2.\n\t\t// 2.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1 --------\n\t\t// 1.2 --------\n\t\t// 2.1 --------\n\t\t// 2.2 --------\n\t\tconst prevViewList = mapper.toViewElement( prevModelItem ).parent;\n\t\tinsertPosition = viewWriter.createPositionAfter( prevViewList );\n\t} else {\n\t\t// If element has been found and has smaller indent as reference indent it means that nested items\n\t\t// should become nested items of found item:\n\t\t//\n\t\t// 1 -------- <--- this is `prevModelItem`.\n\t\t// 1.1 -------- <--- this is removed, previous list item has indent smaller than reference indent.\n\t\t// 1.1.1 -------- <--- this is reference indent, this and 1.1.1 should become nested items of 1.\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\t//\n\t\t// Becomes:\n\t\t//\n\t\t// 1 --------\n\t\t// 1.1.1 --------\n\t\t// 1.1.2 --------\n\t\t// 1.2 --------\n\t\t//\n\t\t// Note: in this case 1.1.1 have indent 2 while 1 have indent 0. In model that should not be possible,\n\t\t// because following item may have indent bigger only by one. But this is fixed by postfixer.\n\t\tconst modelPosition = model.createPositionAt( prevModelItem, 'end' );\n\t\tinsertPosition = mapper.toViewPosition( modelPosition );\n\t}\n\n\tinsertPosition = positionAfterUiElements( insertPosition );\n\n\t// Handle multiple lists. This happens if list item has nested numbered and bulleted lists. Following lists\n\t// are inserted after the first list (no need to recalculate insertion position for them).\n\tfor ( const child of [ ...viewRemovedItem.getChildren() ] ) {\n\t\tif ( isList( child ) ) {\n\t\t\tinsertPosition = viewWriter.move( viewWriter.createRangeOn( child ), insertPosition ).end;\n\n\t\t\tmergeViewLists( viewWriter, child, child.nextSibling );\n\t\t\tmergeViewLists( viewWriter, child.previousSibling, child );\n\t\t}\n\t}\n}\n\n// Checks if view element is a list type (ul or ol).\n//\n// @param {module:engine/view/element~Element} viewElement\n// @returns {Boolean}\nfunction isList( viewElement ) {\n\treturn viewElement.is( 'element', 'ol' ) || viewElement.is( 'element', 'ul' );\n}\n\n// Calculates the indent value for a list item. Handles HTML compliant and non-compliant lists.\n//\n// Also, fixes non HTML compliant lists indents:\n//\n//\t\tbefore: fixed list:\n//\t\tOL OL\n//\t\t|-> LI (parent LIs: 0) |-> LI (indent: 0)\n//\t\t |-> OL |-> OL\n//\t\t |-> OL |\n//\t\t | |-> OL |\n//\t\t | |-> OL |\n//\t\t | |-> LI (parent LIs: 1) |-> LI (indent: 1)\n//\t\t |-> LI (parent LIs: 1) |-> LI (indent: 1)\n//\n//\t\tbefore: fixed list:\n//\t\tOL OL\n//\t\t|-> OL |\n//\t\t |-> OL |\n//\t\t |-> OL |\n//\t\t |-> LI (parent LIs: 0) |-> LI (indent: 0)\n//\n//\t\tbefore: fixed list:\n//\t\tOL OL\n//\t\t|-> LI (parent LIs: 0) |-> LI (indent: 0)\n//\t\t|-> OL |-> OL\n//\t\t |-> LI (parent LIs: 0) |-> LI (indent: 1)\n//\n// @param {module:engine/view/element~Element} listItem\n// @param {Object} conversionStore\n// @returns {Number}\nfunction getIndent( listItem ) {\n\tlet indent = 0;\n\n\tlet parent = listItem.parent;\n\n\twhile ( parent ) {\n\t\t// Each LI in the tree will result in an increased indent for HTML compliant lists.\n\t\tif ( parent.is( 'element', 'li' ) ) {\n\t\t\tindent++;\n\t\t} else {\n\t\t\t// If however the list is nested in other list we should check previous sibling of any of the list elements...\n\t\t\tconst previousSibling = parent.previousSibling;\n\n\t\t\t// ...because the we might need increase its indent:\n\t\t\t//\t\tbefore: fixed list:\n\t\t\t//\t\tOL OL\n\t\t\t//\t\t|-> LI (parent LIs: 0) |-> LI (indent: 0)\n\t\t\t//\t\t|-> OL |-> OL\n\t\t\t//\t\t |-> LI (parent LIs: 0) |-> LI (indent: 1)\n\t\t\tif ( previousSibling && previousSibling.is( 'element', 'li' ) ) {\n\t\t\t\tindent++;\n\t\t\t}\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n\n\treturn indent;\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 list/listediting\n */\n\nimport ListCommand from './listcommand';\nimport IndentCommand from './indentcommand';\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Enter } from 'ckeditor5/src/enter';\nimport { Delete } from 'ckeditor5/src/typing';\n\nimport {\n\tcleanList,\n\tcleanListItem,\n\tmodelViewInsertion,\n\tmodelViewChangeType,\n\tmodelViewMergeAfterChangeType,\n\tmodelViewMergeAfter,\n\tmodelViewRemove,\n\tmodelViewSplitOnInsert,\n\tmodelViewChangeIndent,\n\tmodelChangePostFixer,\n\tmodelIndentPasteFixer,\n\tviewModelConverter,\n\tmodelToViewPosition,\n\tviewToModelPosition\n} from './converters';\n\n/**\n * The engine of the list feature. It handles creating, editing and removing lists and list items.\n *\n * It registers the `'numberedList'`, `'bulletedList'`, `'indentList'` and `'outdentList'` commands.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ListEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ Enter, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Schema.\n\t\t// Note: in case `$block` will ever be allowed in `listItem`, keep in mind that this feature\n\t\t// uses `Selection#getSelectedBlocks()` without any additional processing to obtain all selected list items.\n\t\t// If there are blocks allowed inside list item, algorithms using `getSelectedBlocks()` will have to be modified.\n\t\teditor.model.schema.register( 'listItem', {\n\t\t\tinheritAllFrom: '$block',\n\t\t\tallowAttributes: [ 'listType', 'listIndent' ]\n\t\t} );\n\n\t\t// Converters.\n\t\tconst data = editor.data;\n\t\tconst editing = editor.editing;\n\n\t\teditor.model.document.registerPostFixer( writer => modelChangePostFixer( editor.model, writer ) );\n\n\t\tediting.mapper.registerViewToModelLength( 'li', getViewListItemLength );\n\t\tdata.mapper.registerViewToModelLength( 'li', getViewListItemLength );\n\n\t\tediting.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );\n\t\tediting.mapper.on( 'viewToModelPosition', viewToModelPosition( editor.model ) );\n\t\tdata.mapper.on( 'modelToViewPosition', modelToViewPosition( editing.view ) );\n\n\t\teditor.conversion.for( 'editingDowncast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );\n\t\t\t\tdispatcher.on( 'attribute:listType:listItem', modelViewChangeType, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'attribute:listType:listItem', modelViewMergeAfterChangeType, { priority: 'low' } );\n\t\t\t\tdispatcher.on( 'attribute:listIndent:listItem', modelViewChangeIndent( editor.model ) );\n\t\t\t\tdispatcher.on( 'remove:listItem', modelViewRemove( editor.model ) );\n\t\t\t\tdispatcher.on( 'remove', modelViewMergeAfter, { priority: 'low' } );\n\t\t\t} );\n\n\t\teditor.conversion.for( 'dataDowncast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'insert', modelViewSplitOnInsert, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'insert:listItem', modelViewInsertion( editor.model ) );\n\t\t\t} );\n\n\t\teditor.conversion.for( 'upcast' )\n\t\t\t.add( dispatcher => {\n\t\t\t\tdispatcher.on( 'element:ul', cleanList, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:ol', cleanList, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:li', cleanListItem, { priority: 'high' } );\n\t\t\t\tdispatcher.on( 'element:li', viewModelConverter );\n\t\t\t} );\n\n\t\t// Fix indentation of pasted items.\n\t\teditor.model.on( 'insertContent', modelIndentPasteFixer, { priority: 'high' } );\n\n\t\t// Register commands for numbered and bulleted list.\n\t\teditor.commands.add( 'numberedList', new ListCommand( editor, 'numbered' ) );\n\t\teditor.commands.add( 'bulletedList', new ListCommand( editor, 'bulleted' ) );\n\n\t\t// Register commands for indenting.\n\t\teditor.commands.add( 'indentList', new IndentCommand( editor, 'forward' ) );\n\t\teditor.commands.add( 'outdentList', new IndentCommand( editor, 'backward' ) );\n\n\t\tconst viewDocument = editing.view.document;\n\n\t\t// Overwrite default Enter key behavior.\n\t\t// If Enter key is pressed with selection collapsed in empty list item, outdent it instead of breaking it.\n\t\tthis.listenTo( viewDocument, 'enter', ( evt, data ) => {\n\t\t\tconst doc = this.editor.model.document;\n\t\t\tconst positionParent = doc.selection.getLastPosition().parent;\n\n\t\t\tif ( doc.selection.isCollapsed && positionParent.name == 'listItem' && positionParent.isEmpty ) {\n\t\t\t\tthis.editor.execute( 'outdentList' );\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { context: 'li' } );\n\n\t\t// Overwrite default Backspace key behavior.\n\t\t// If Backspace key is pressed with selection collapsed on first position in first list item, outdent it. #83\n\t\tthis.listenTo( viewDocument, 'delete', ( evt, data ) => {\n\t\t\t// Check conditions from those that require less computations like those immediately available.\n\t\t\tif ( data.direction !== 'backward' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selection = this.editor.model.document.selection;\n\n\t\t\tif ( !selection.isCollapsed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\n\t\t\tif ( !firstPosition.isAtStart ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst positionParent = firstPosition.parent;\n\n\t\t\tif ( positionParent.name !== 'listItem' ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst previousIsAListItem = positionParent.previousSibling && positionParent.previousSibling.name === 'listItem';\n\n\t\t\tif ( previousIsAListItem ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.editor.execute( 'outdentList' );\n\n\t\t\tdata.preventDefault();\n\t\t\tevt.stop();\n\t\t}, { context: 'li' } );\n\n\t\tconst getCommandExecuter = commandName => {\n\t\t\treturn ( data, cancel ) => {\n\t\t\t\tconst command = this.editor.commands.get( commandName );\n\n\t\t\t\tif ( command.isEnabled ) {\n\t\t\t\t\tthis.editor.execute( commandName );\n\t\t\t\t\tcancel();\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\n\t\teditor.keystrokes.set( 'Tab', getCommandExecuter( 'indentList' ) );\n\t\teditor.keystrokes.set( 'Shift+Tab', getCommandExecuter( 'outdentList' ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst commands = this.editor.commands;\n\n\t\tconst indent = commands.get( 'indent' );\n\t\tconst outdent = commands.get( 'outdent' );\n\n\t\tif ( indent ) {\n\t\t\tindent.registerChildCommand( commands.get( 'indentList' ) );\n\t\t}\n\n\t\tif ( outdent ) {\n\t\t\toutdent.registerChildCommand( commands.get( 'outdentList' ) );\n\t\t}\n\t}\n}\n\nfunction getViewListItemLength( element ) {\n\tlet length = 1;\n\n\tfor ( const child of element.getChildren() ) {\n\t\tif ( child.name == 'ul' || child.name == 'ol' ) {\n\t\t\tfor ( const item of child.getChildren() ) {\n\t\t\t\tlength += getViewListItemLength( item );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn length;\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM3.5 3v5H2V3.7H1v-1h2.5V3zM.343 17.857l2.59-3.257H2.92a.6.6 0 1 0-1.04 0H.302a2 2 0 1 1 3.995 0h-.001c-.048.405-.16.734-.333.988-.175.254-.59.692-1.244 1.312H4.3v1h-4l.043-.043zM7 14.75a.75.75 0 0 1 .75-.75h9.5a.75.75 0 1 1 0 1.5h-9.5a.75.75 0 0 1-.75-.75z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M7 5.75c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zm-6 0C1 4.784 1.777 4 2.75 4c.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75C1.784 7.5 1 6.723 1 5.75zm6 9c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zm-6 0c0-.966.777-1.75 1.75-1.75.966 0 1.75.777 1.75 1.75 0 .966-.777 1.75-1.75 1.75-.966 0-1.75-.777-1.75-1.75z\\\"/></svg>\";","/**\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 list/listui\n */\n\nimport { createUIComponent } from './utils';\n\nimport numberedListIcon from '../theme/icons/numberedlist.svg';\nimport bulletedListIcon from '../theme/icons/bulletedlist.svg';\n\nimport { Plugin } from 'ckeditor5/src/core';\n\n/**\n * The list UI feature. It introduces the `'numberedList'` and `'bulletedList'` buttons that\n * allow to convert paragraphs to and from list items and indent or outdent them.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ListUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst t = this.editor.t;\n\n\t\t// Create two buttons and link them with numberedList and bulletedList commands.\n\t\tcreateUIComponent( this.editor, 'numberedList', t( 'Numbered List' ), numberedListIcon );\n\t\tcreateUIComponent( this.editor, 'bulletedList', t( 'Bulleted List' ), bulletedListIcon );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/liststylecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { getSiblingNodes } from './utils';\n\n/**\n * The list style command. It is used by the {@link module:list/liststyle~ListStyle list style feature}.\n *\n * @extends module:core/command~Command\n */\nexport default class ListStyleCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {String} defaultType The list type that will be used by default if the value was not specified during\n\t * the command execution.\n\t */\n\tconstructor( editor, defaultType ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The default type of the list style.\n\t\t *\n\t\t * @protected\n\t\t * @member {String}\n\t\t */\n\t\tthis._defaultType = defaultType;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @param {Object} options\n\t * @param {String|null} options.type The type of the list style, e.g. `'disc'` or `'square'`. If `null` is specified, the default\n\t * style will be applied.\n\t * @protected\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\t// For all selected blocks find all list items that are being selected\n\t\t// and update the `listStyle` attribute in those lists.\n\t\tlet listItems = [ ...document.selection.getSelectedBlocks() ]\n\t\t\t.filter( element => element.is( 'element', 'listItem' ) )\n\t\t\t.map( element => {\n\t\t\t\tconst position = model.change( writer => writer.createPositionAt( element, 0 ) );\n\n\t\t\t\treturn [\n\t\t\t\t\t...getSiblingNodes( position, 'backward' ),\n\t\t\t\t\t...getSiblingNodes( position, 'forward' )\n\t\t\t\t];\n\t\t\t} )\n\t\t\t.flat();\n\n\t\t// Since `getSelectedBlocks()` can return items that belong to the same list, and\n\t\t// `getSiblingNodes()` returns the entire list, we need to remove duplicated items.\n\t\tlistItems = [ ...new Set( listItems ) ];\n\n\t\tif ( !listItems.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\tfor ( const item of listItems ) {\n\t\t\t\twriter.setAttribute( 'listStyle', options.type || this._defaultType, item );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {String|null} The current value.\n\t */\n\t_getValue() {\n\t\tconst listItem = this.editor.model.document.selection.getFirstPosition().parent;\n\n\t\tif ( listItem && listItem.is( 'element', 'listItem' ) ) {\n\t\t\treturn listItem.getAttribute( 'listStyle' );\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\tconst editor = this.editor;\n\n\t\tconst numberedList = editor.commands.get( 'numberedList' );\n\t\tconst bulletedList = editor.commands.get( 'bulletedList' );\n\n\t\treturn numberedList.isEnabled || bulletedList.isEnabled;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/liststyleediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ListEditing from './listediting';\nimport ListStyleCommand from './liststylecommand';\nimport { getSiblingListItem, getSiblingNodes } from './utils';\n\nconst DEFAULT_LIST_TYPE = 'default';\n\n/**\n * The list style engine feature.\n *\n * It sets the value for the `listItem` attribute of the {@link module:list/list~List `<listItem>`} element that\n * allows modifying the list style type.\n *\n * It registers the `'listStyle'` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListStyleEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ListEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ListStyleEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\t// Extend schema.\n\t\tmodel.schema.extend( 'listItem', {\n\t\t\tallowAttributes: [ 'listStyle' ]\n\t\t} );\n\n\t\teditor.commands.add( 'listStyle', new ListStyleCommand( editor, DEFAULT_LIST_TYPE ) );\n\n\t\t// Fix list attributes when modifying their nesting levels (the `listIndent` attribute).\n\t\tthis.listenTo( editor.commands.get( 'indentList' ), '_executeCleanup', fixListAfterIndentListCommand( editor ) );\n\t\tthis.listenTo( editor.commands.get( 'outdentList' ), '_executeCleanup', fixListAfterOutdentListCommand( editor ) );\n\n\t\tthis.listenTo( editor.commands.get( 'bulletedList' ), '_executeCleanup', restoreDefaultListStyle( editor ) );\n\t\tthis.listenTo( editor.commands.get( 'numberedList' ), '_executeCleanup', restoreDefaultListStyle( editor ) );\n\n\t\t// Register a post-fixer that ensures that the `listStyle` attribute is specified in each `listItem` element.\n\t\tmodel.document.registerPostFixer( fixListStyleAttributeOnListItemElements( editor ) );\n\n\t\t// Set up conversion.\n\t\teditor.conversion.for( 'upcast' ).add( upcastListItemStyle() );\n\t\teditor.conversion.for( 'downcast' ).add( downcastListStyleAttribute() );\n\n\t\t// Handle merging two separated lists into the single one.\n\t\tthis._mergeListStyleAttributeWhileMergingLists();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\n\t\t// Enable post-fixer that removes the `listStyle` attribute from to-do list items only if the \"TodoList\" plugin is on.\n\t\t// We need to registry the hook here since the `TodoList` plugin can be added after the `ListStyleEditing`.\n\t\tif ( editor.commands.get( 'todoList' ) ) {\n\t\t\teditor.model.document.registerPostFixer( removeListStyleAttributeFromTodoList( editor ) );\n\t\t}\n\t}\n\n\t/**\n\t * Starts listening to {@link module:engine/model/model~Model#deleteContent} checks whether two lists will be merged into a single one\n\t * after deleting the content.\n\t *\n\t * The purpose of this action is to adjust the `listStyle` value for the list that was merged.\n\t *\n\t * Consider the following model's content:\n\t *\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 1</listItem>\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 2</listItem>\n\t * <paragraph>[A paragraph.]</paragraph>\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"circle\">UL List item 1</listItem>\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"circle\">UL List item 2</listItem>\n\t *\n\t * After removing the paragraph element, the second list will be merged into the first one.\n\t * We want to inherit the `listStyle` attribute for the second list from the first one.\n\t *\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 1</listItem>\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 2</listItem>\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 1</listItem>\n\t * <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 2</listItem>\n\t *\n\t * See https://github.com/ckeditor/ckeditor5/issues/7879.\n\t *\n\t * @private\n\t */\n\t_mergeListStyleAttributeWhileMergingLists() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\t// First the outer-most`listItem` in the first list reference.\n\t\t// If found, the lists should be merged and this `listItem` provides the `listStyle` attribute\n\t\t// and it is also a starting point when searching for items in the second list.\n\t\tlet firstMostOuterItem;\n\n\t\t// Check whether the removed content is between two lists.\n\t\tthis.listenTo( model, 'deleteContent', ( evt, [ selection ] ) => {\n\t\t\tconst firstPosition = selection.getFirstPosition();\n\t\t\tconst lastPosition = selection.getLastPosition();\n\n\t\t\t// Typing or removing content in a single item. Aborting.\n\t\t\tif ( firstPosition.parent === lastPosition.parent ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// An element before the content that will be removed is not a list.\n\t\t\tif ( !firstPosition.parent.is( 'element', 'listItem' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst nextSibling = lastPosition.parent.nextSibling;\n\n\t\t\t// An element after the content that will be removed is not a list.\n\t\t\tif ( !nextSibling || !nextSibling.is( 'element', 'listItem' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Find the outermost list item based on the `listIndent` attribute. We can't assume that `listIndent=0`\n\t\t\t// because the selection can be hooked in nested lists.\n\t\t\t//\n\t\t\t// <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 1</listItem>\n\t\t\t// <listItem listIndent=\"1\" listType=\"bulleted\" listStyle=\"square\">UL List [item 1.1</listItem>\n\t\t\t// <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"circle\">[]UL List item 1.</listItem>\n\t\t\t// <listItem listIndent=\"1\" listType=\"bulleted\" listStyle=\"circle\">UL List ]item 1.1</listItem>\n\t\t\t//\n\t\t\t// After deleting the content, we would like to inherit the \"square\" attribute for the last element:\n\t\t\t//\n\t\t\t// <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 1</listItem>\n\t\t\t// <listItem listIndent=\"1\" listType=\"bulleted\" listStyle=\"square\">UL List []item 1.1</listItem>\n\t\t\tconst mostOuterItemList = getSiblingListItem( firstPosition.parent, {\n\t\t\t\tsameIndent: true,\n\t\t\t\tlistIndent: nextSibling.getAttribute( 'listIndent' )\n\t\t\t} );\n\n\t\t\t// The outermost list item may not exist while removing elements between lists with different value\n\t\t\t// of the `listIndent` attribute. In such a case we don't want to update anything. See: #8073.\n\t\t\tif ( !mostOuterItemList ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( mostOuterItemList.getAttribute( 'listType' ) === nextSibling.getAttribute( 'listType' ) ) {\n\t\t\t\tfirstMostOuterItem = mostOuterItemList;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// If so, update the `listStyle` attribute for the second list.\n\t\tthis.listenTo( model, 'deleteContent', () => {\n\t\t\tif ( !firstMostOuterItem ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmodel.change( writer => {\n\t\t\t\t// Find the first most-outer item list in the merged list.\n\t\t\t\t// A case when the first list item in the second list was merged into the last item in the first list.\n\t\t\t\t//\n\t\t\t\t// <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 1</listItem>\n\t\t\t\t// <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"square\">UL List item 2</listItem>\n\t\t\t\t// <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"circle\">[]UL List item 1</listItem>\n\t\t\t\t// <listItem listIndent=\"0\" listType=\"bulleted\" listStyle=\"circle\">UL List item 2</listItem>\n\t\t\t\tconst secondListMostOuterItem = getSiblingListItem( firstMostOuterItem.nextSibling, {\n\t\t\t\t\tsameIndent: true,\n\t\t\t\t\tlistIndent: firstMostOuterItem.getAttribute( 'listIndent' ),\n\t\t\t\t\tdirection: 'forward'\n\t\t\t\t} );\n\n\t\t\t\tconst items = [\n\t\t\t\t\tsecondListMostOuterItem,\n\t\t\t\t\t...getSiblingNodes( writer.createPositionAt( secondListMostOuterItem, 0 ), 'forward' )\n\t\t\t\t];\n\n\t\t\t\tfor ( const listItem of items ) {\n\t\t\t\t\twriter.setAttribute( 'listStyle', firstMostOuterItem.getAttribute( 'listStyle' ), listItem );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tfirstMostOuterItem = null;\n\t\t}, { priority: 'low' } );\n\t}\n}\n\n// Returns a converter that consumes the `style` attribute and searches for the `list-style-type` definition.\n// If not found, the `\"default\"` value will be used.\n//\n// @returns {Function}\nfunction upcastListItemStyle() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:li', ( evt, data, conversionApi ) => {\n\t\t\tconst listParent = data.viewItem.parent;\n\t\t\tconst listStyle = listParent.getStyle( 'list-style-type' ) || DEFAULT_LIST_TYPE;\n\t\t\tconst listItem = data.modelRange.start.nodeAfter || data.modelRange.end.nodeBefore;\n\n\t\t\tconversionApi.writer.setAttribute( 'listStyle', listStyle, listItem );\n\t\t}, { priority: 'low' } );\n\t};\n}\n\n// Returns a converter that adds the `list-style-type` definition as a value for the `style` attribute.\n// The `\"default\"` value is removed and not present in the view/data.\n//\n// @returns {Function}\nfunction downcastListStyleAttribute() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'attribute:listStyle:listItem', ( evt, data, conversionApi ) => {\n\t\t\tconst viewWriter = conversionApi.writer;\n\t\t\tconst currentElement = data.item;\n\n\t\t\tconst previousElement = getSiblingListItem( currentElement.previousSibling, {\n\t\t\t\tsameIndent: true,\n\t\t\t\tlistIndent: currentElement.getAttribute( 'listIndent' ),\n\t\t\t\tdirection: 'backward'\n\t\t\t} );\n\n\t\t\tconst viewItem = conversionApi.mapper.toViewElement( currentElement );\n\n\t\t\t// A case when elements represent different lists. We need to separate their container.\n\t\t\tif ( !areRepresentingSameList( currentElement, previousElement ) ) {\n\t\t\t\tviewWriter.breakContainer( viewWriter.createPositionBefore( viewItem ) );\n\t\t\t}\n\n\t\t\tsetListStyle( viewWriter, data.attributeNewValue, viewItem.parent );\n\t\t}, { priority: 'low' } );\n\t};\n\n\t// Checks whether specified list items belong to the same list.\n\t//\n\t// @param {module:engine/model/element~Element} `listItem1` The first list item to check.\n\t// @param {module:engine/model/element~Element|null} `listItem2` The second list item to check.\n\t// @returns {Boolean}\n\tfunction areRepresentingSameList( listItem1, listItem2 ) {\n\t\treturn listItem2 &&\n\t\t\tlistItem1.getAttribute( 'listType' ) === listItem2.getAttribute( 'listType' ) &&\n\t\t\tlistItem1.getAttribute( 'listIndent' ) === listItem2.getAttribute( 'listIndent' ) &&\n\t\t\tlistItem1.getAttribute( 'listStyle' ) === listItem2.getAttribute( 'listStyle' );\n\t}\n\n\t// Updates or removes the `list-style-type` from the `element`.\n\t//\n\t// @param {module:engine/view/downcastwriter~DowncastWriter} writer\n\t// @param {String} listStyle\n\t// @param {module:engine/view/element~Element} element\n\tfunction setListStyle( writer, listStyle, element ) {\n\t\tif ( listStyle && listStyle !== DEFAULT_LIST_TYPE ) {\n\t\t\twriter.setStyle( 'list-style-type', listStyle, element );\n\t\t} else {\n\t\t\twriter.removeStyle( 'list-style-type', element );\n\t\t}\n\t}\n}\n\n// When indenting list, nested list should clear its value for the `listStyle` attribute or inherit from nested lists.\n//\n// ■ List item 1.\n// ■ List item 2.[]\n// ■ List item 3.\n// editor.execute( 'indentList' );\n//\n// ■ List item 1.\n// ○ List item 2.[]\n// ■ List item 3.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @returns {Function}\nfunction fixListAfterIndentListCommand( editor ) {\n\treturn ( evt, changedItems ) => {\n\t\tlet valueToSet;\n\n\t\tconst root = changedItems[ 0 ];\n\t\tconst rootIndent = root.getAttribute( 'listIndent' );\n\n\t\tconst itemsToUpdate = changedItems.filter( item => item.getAttribute( 'listIndent' ) === rootIndent );\n\n\t\t// A case where a few list items are indented must be checked separately\n\t\t// since `getSiblingListItem()` returns the first changed element.\n\t\t// ■ List item 1.\n\t\t// ○ [List item 2.\n\t\t// ○ List item 3.]\n\t\t// ■ List item 4.\n\t\t//\n\t\t// List items: `2` and `3` should be adjusted.\n\t\tif ( root.previousSibling.getAttribute( 'listIndent' ) + 1 === rootIndent ) {\n\t\t\t// valueToSet = root.previousSibling.getAttribute( 'listStyle' ) || DEFAULT_LIST_TYPE;\n\t\t\tvalueToSet = DEFAULT_LIST_TYPE;\n\t\t} else {\n\t\t\tconst previousSibling = getSiblingListItem( root.previousSibling, {\n\t\t\t\tsameIndent: true, direction: 'backward', listIndent: rootIndent\n\t\t\t} );\n\n\t\t\tvalueToSet = previousSibling.getAttribute( 'listStyle' );\n\t\t}\n\n\t\teditor.model.change( writer => {\n\t\t\tfor ( const item of itemsToUpdate ) {\n\t\t\t\twriter.setAttribute( 'listStyle', valueToSet, item );\n\t\t\t}\n\t\t} );\n\t};\n}\n\n// When outdenting a list, a nested list should copy its value for the `listStyle` attribute\n// from the previous sibling list item including the same value for the `listIndent` value.\n//\n// ■ List item 1.\n// ○ List item 2.[]\n// ■ List item 3.\n//\n// editor.execute( 'outdentList' );\n//\n// ■ List item 1.\n// ■ List item 2.[]\n// ■ List item 3.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @returns {Function}\nfunction fixListAfterOutdentListCommand( editor ) {\n\treturn ( evt, changedItems ) => {\n\t\tchangedItems = changedItems.reverse().filter( item => item.is( 'element', 'listItem' ) );\n\n\t\tif ( !changedItems.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst indent = changedItems[ 0 ].getAttribute( 'listIndent' );\n\t\tconst listType = changedItems[ 0 ].getAttribute( 'listType' );\n\t\tlet listItem = changedItems[ 0 ].previousSibling;\n\n\t\t// ■ List item 1.\n\t\t// ○ List item 2.\n\t\t// ○ List item 3.[]\n\t\t// ■ List item 4.\n\t\t//\n\t\t// After outdenting a list, `List item 3` should inherit the `listStyle` attribute from `List item 1`.\n\t\t//\n\t\t// ■ List item 1.\n\t\t// ○ List item 2.\n\t\t// ■ List item 3.[]\n\t\t// ■ List item 4.\n\t\tif ( listItem.is( 'element', 'listItem' ) ) {\n\t\t\twhile ( listItem.getAttribute( 'listIndent' ) !== indent ) {\n\t\t\t\tlistItem = listItem.previousSibling;\n\t\t\t}\n\t\t} else {\n\t\t\tlistItem = null;\n\t\t}\n\n\t\t// Outdenting such a list should restore values based on `List item 4`.\n\t\t// ■ List item 1.[]\n\t\t// ○ List item 2.\n\t\t// ○ List item 3.\n\t\t// ■ List item 4.\n\t\tif ( !listItem ) {\n\t\t\tlistItem = changedItems[ changedItems.length - 1 ].nextSibling;\n\t\t}\n\n\t\t// And such a list should not modify anything.\n\t\t// However, `listItem` can indicate a node below the list. Be sure that we have the `listItem` element.\n\t\t// ■ List item 1.[]\n\t\t// ○ List item 2.\n\t\t// ○ List item 3.\n\t\t// <paragraph>The later if check.</paragraph>\n\t\tif ( !listItem || !listItem.is( 'element', 'listItem' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Do not modify the list if found `listItem` represents other type of list than outdented list items.\n\t\tif ( listItem.getAttribute( 'listType' ) !== listType ) {\n\t\t\treturn;\n\t\t}\n\n\t\teditor.model.change( writer => {\n\t\t\tconst itemsToUpdate = changedItems.filter( item => item.getAttribute( 'listIndent' ) === indent );\n\n\t\t\tfor ( const item of itemsToUpdate ) {\n\t\t\t\twriter.setAttribute( 'listStyle', listItem.getAttribute( 'listStyle' ), item );\n\t\t\t}\n\t\t} );\n\t};\n}\n\n// Each `listItem` element must have specified the `listStyle` attribute.\n// This post-fixer checks whether inserted elements `listItem` elements should inherit the `listStyle` value from\n// their sibling nodes or should use the default value.\n//\n// Paragraph[]\n// ■ List item 1. // [listStyle=\"square\", listType=\"bulleted\"]\n// ■ List item 2. // ...\n// ■ List item 3. // ...\n//\n// editor.execute( 'bulletedList' )\n//\n// ■ Paragraph[] // [listStyle=\"square\", listType=\"bulleted\"]\n// ■ List item 1. // [listStyle=\"square\", listType=\"bulleted\"]\n// ■ List item 2.\n// ■ List item 3.\n//\n// It also covers a such change:\n//\n// [Paragraph 1\n// Paragraph 2]\n// ■ List item 1. // [listStyle=\"square\", listType=\"bulleted\"]\n// ■ List item 2. // ...\n// ■ List item 3. // ...\n//\n// editor.execute( 'numberedList' )\n//\n// 1. [Paragraph 1 // [listStyle=\"default\", listType=\"numbered\"]\n// 2. Paragraph 2] // [listStyle=\"default\", listType=\"numbered\"]\n// ■ List item 1. // [listStyle=\"square\", listType=\"bulleted\"]\n// ■ List item 2. // ...\n// ■ List item 3. // ...\n//\n// @param {module:core/editor/editor~Editor} editor\n// @returns {Function}\nfunction fixListStyleAttributeOnListItemElements( editor ) {\n\treturn writer => {\n\t\tlet wasFixed = false;\n\n\t\tconst insertedListItems = getChangedListItems( editor.model.document.differ.getChanges() )\n\t\t\t.filter( item => {\n\t\t\t\t// Don't touch todo lists. They are handled in another post-fixer.\n\t\t\t\treturn item.getAttribute( 'listType' ) !== 'todo';\n\t\t\t} );\n\n\t\tif ( !insertedListItems.length ) {\n\t\t\treturn wasFixed;\n\t\t}\n\n\t\t// Check whether the last inserted element is next to the `listItem` element.\n\t\t//\n\t\t// ■ Paragraph[] // <-- The inserted item.\n\t\t// ■ List item 1.\n\t\tlet existingListItem = insertedListItems[ insertedListItems.length - 1 ].nextSibling;\n\n\t\t// If it doesn't, maybe the `listItem` was inserted at the end of the list.\n\t\t//\n\t\t// ■ List item 1.\n\t\t// ■ Paragraph[] // <-- The inserted item.\n\t\tif ( !existingListItem || !existingListItem.is( 'element', 'listItem' ) ) {\n\t\t\texistingListItem = insertedListItems[ insertedListItems.length - 1 ].previousSibling;\n\n\t\t\tif ( existingListItem ) {\n\t\t\t\tconst indent = insertedListItems[ 0 ].getAttribute( 'listIndent' );\n\n\t\t\t\t// But we need to find a `listItem` with the `listIndent=0` attribute.\n\t\t\t\t// If doesn't, maybe the `listItem` was inserted at the end of the list.\n\t\t\t\t//\n\t\t\t\t// ■ List item 1.\n\t\t\t\t// ○ List item 2.\n\t\t\t\t// ■ Paragraph[] // <-- The inserted item.\n\t\t\t\twhile ( existingListItem.is( 'element', 'listItem' ) && existingListItem.getAttribute( 'listIndent' ) !== indent ) {\n\t\t\t\t\texistingListItem = existingListItem.previousSibling;\n\n\t\t\t\t\t// If the item does not exist, most probably there is no other content in the editor. See: #8072.\n\t\t\t\t\tif ( !existingListItem ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor ( const item of insertedListItems ) {\n\t\t\tif ( !item.hasAttribute( 'listStyle' ) ) {\n\t\t\t\tif ( shouldInheritListType( existingListItem, item ) ) {\n\t\t\t\t\twriter.setAttribute( 'listStyle', existingListItem.getAttribute( 'listStyle' ), item );\n\t\t\t\t} else {\n\t\t\t\t\twriter.setAttribute( 'listStyle', DEFAULT_LIST_TYPE, item );\n\t\t\t\t}\n\t\t\t\twasFixed = true;\n\t\t\t} else {\n\t\t\t\t// Adjust the `listStyle` attribute for inserted (pasted) items. See #8160.\n\t\t\t\t//\n\t\t\t\t// ■ List item 1. // [listStyle=\"square\", listType=\"bulleted\"]\n\t\t\t\t// ○ List item 1.1. // [listStyle=\"circle\", listType=\"bulleted\"]\n\t\t\t\t// ○ [] (selection is here)\n\t\t\t\t//\n\t\t\t\t// Then, pasting a list with different attributes (listStyle, listType):\n\t\t\t\t//\n\t\t\t\t// 1. First. // [listStyle=\"decimal\", listType=\"numbered\"]\n\t\t\t\t// 2. Second // [listStyle=\"decimal\", listType=\"numbered\"]\n\t\t\t\t//\n\t\t\t\t// The `listType` attribute will be corrected by the `ListEditing` converters.\n\t\t\t\t// We need to adjust the `listStyle` attribute. Expected structure:\n\t\t\t\t//\n\t\t\t\t// ■ List item 1. // [listStyle=\"square\", listType=\"bulleted\"]\n\t\t\t\t// ○ List item 1.1. // [listStyle=\"circle\", listType=\"bulleted\"]\n\t\t\t\t// ○ First. // [listStyle=\"circle\", listType=\"bulleted\"]\n\t\t\t\t// ○ Second // [listStyle=\"circle\", listType=\"bulleted\"]\n\t\t\t\tconst previousSibling = item.previousSibling;\n\n\t\t\t\tif ( shouldInheritListTypeFromPreviousItem( previousSibling, item ) ) {\n\t\t\t\t\twriter.setAttribute( 'listStyle', previousSibling.getAttribute( 'listStyle' ), item );\n\n\t\t\t\t\twasFixed = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn wasFixed;\n\t};\n}\n\n// Checks whether the `listStyle` attribute should be copied from the `baseItem` element.\n//\n// The attribute should be copied if the inserted element does not have defined it and\n// the value for the element is other than default in the base element.\n//\n// @param {module:engine/model/element~Element|null} baseItem\n// @param {module:engine/model/element~Element} itemToChange\n// @returns {Boolean}\nfunction shouldInheritListType( baseItem, itemToChange ) {\n\tif ( !baseItem ) {\n\t\treturn false;\n\t}\n\n\tconst baseListStyle = baseItem.getAttribute( 'listStyle' );\n\n\tif ( !baseListStyle ) {\n\t\treturn false;\n\t}\n\n\tif ( baseListStyle === DEFAULT_LIST_TYPE ) {\n\t\treturn false;\n\t}\n\n\tif ( baseItem.getAttribute( 'listType' ) !== itemToChange.getAttribute( 'listType' ) ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Checks whether the `listStyle` attribute should be copied from previous list item.\n//\n// The attribute should be copied if there's a mismatch of styles of the pasted list into a nested list.\n// Top-level lists are not normalized as we allow side-by-side list of different types.\n//\n// @param {module:engine/model/element~Element|null} previousItem\n// @param {module:engine/model/element~Element} itemToChange\n// @returns {Boolean}\nfunction shouldInheritListTypeFromPreviousItem( previousItem, itemToChange ) {\n\tif ( !previousItem || !previousItem.is( 'element', 'listItem' ) ) {\n\t\treturn false;\n\t}\n\n\tif ( itemToChange.getAttribute( 'listType' ) !== previousItem.getAttribute( 'listType' ) ) {\n\t\treturn false;\n\t}\n\n\tconst previousItemIndent = previousItem.getAttribute( 'listIndent' );\n\n\tif ( previousItemIndent < 1 || previousItemIndent !== itemToChange.getAttribute( 'listIndent' ) ) {\n\t\treturn false;\n\t}\n\n\tconst previousItemListStyle = previousItem.getAttribute( 'listStyle' );\n\n\tif ( !previousItemListStyle || previousItemListStyle === itemToChange.getAttribute( 'listStyle' ) ) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\n// Removes the `listStyle` attribute from \"todo\" list items.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @returns {Function}\nfunction removeListStyleAttributeFromTodoList( editor ) {\n\treturn writer => {\n\t\tconst todoListItems = getChangedListItems( editor.model.document.differ.getChanges() )\n\t\t\t.filter( item => {\n\t\t\t\t// Handle the todo lists only. The rest is handled in another post-fixer.\n\t\t\t\treturn item.getAttribute( 'listType' ) === 'todo' && item.hasAttribute( 'listStyle' );\n\t\t\t} );\n\n\t\tif ( !todoListItems.length ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor ( const item of todoListItems ) {\n\t\t\twriter.removeAttribute( 'listStyle', item );\n\t\t}\n\n\t\treturn true;\n\t};\n}\n\n// Restores the `listStyle` attribute after changing the list type.\n//\n// @param {module:core/editor/editor~Editor} editor\n// @returns {Function}\nfunction restoreDefaultListStyle( editor ) {\n\treturn ( evt, changedItems ) => {\n\t\tchangedItems = changedItems.filter( item => item.is( 'element', 'listItem' ) );\n\n\t\teditor.model.change( writer => {\n\t\t\tfor ( const item of changedItems ) {\n\t\t\t\t// Remove the attribute. Post-fixer will restore the proper value.\n\t\t\t\twriter.removeAttribute( 'listStyle', item );\n\t\t\t}\n\t\t} );\n\t};\n}\n\n// Returns the `listItem` that was inserted or changed.\n//\n// @param {Array.<Object>} changes The changes list returned by the differ.\n// @returns {Array.<module:engine/model/element~Element>}\nfunction getChangedListItems( changes ) {\n\tconst items = [];\n\n\tfor ( const change of changes ) {\n\t\tconst item = getItemFromChange( change );\n\n\t\tif ( item && item.is( 'element', 'listItem' ) ) {\n\t\t\titems.push( item );\n\t\t}\n\t}\n\n\treturn items;\n}\n\nfunction getItemFromChange( change ) {\n\tif ( change.type === 'attribute' ) {\n\t\treturn change.range.start.nodeAfter;\n\t}\n\n\tif ( change.type === 'insert' ) {\n\t\treturn change.position.nodeAfter;\n\t}\n\n\treturn null;\n}\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 list/liststyleui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView, SplitButtonView, createDropdown, addToolbarToDropdown } from 'ckeditor5/src/ui';\n\nimport bulletedListIcon from '../theme/icons/bulletedlist.svg';\nimport numberedListIcon from '../theme/icons/numberedlist.svg';\n\nimport listStyleDiscIcon from '../theme/icons/liststyledisc.svg';\nimport listStyleCircleIcon from '../theme/icons/liststylecircle.svg';\nimport listStyleSquareIcon from '../theme/icons/liststylesquare.svg';\nimport listStyleDecimalIcon from '../theme/icons/liststyledecimal.svg';\nimport listStyleDecimalWithLeadingZeroIcon from '../theme/icons/liststyledecimalleadingzero.svg';\nimport listStyleLowerRomanIcon from '../theme/icons/liststylelowerroman.svg';\nimport listStyleUpperRomanIcon from '../theme/icons/liststyleupperroman.svg';\nimport listStyleLowerLatinIcon from '../theme/icons/liststylelowerlatin.svg';\nimport listStyleUpperLatinIcon from '../theme/icons/liststyleupperlatin.svg';\n\nimport '../theme/liststyles.css';\n\n/**\n * The list style UI plugin. It introduces the extended `'bulletedList'` and `'numberedList'` toolbar\n * buttons that allow users to change styles of individual lists in the content.\n *\n * **Note**: Buttons introduced by this plugin override implementations from the {@link module:list/listui~ListUI}\n * (because they share the same names).\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListStyleUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ListStyleUI';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.locale.t;\n\n\t\teditor.ui.componentFactory.add( 'bulletedList', getSplitButtonCreator( {\n\t\t\teditor,\n\t\t\tparentCommandName: 'bulletedList',\n\t\t\tbuttonLabel: t( 'Bulleted List' ),\n\t\t\tbuttonIcon: bulletedListIcon,\n\t\t\ttoolbarAriaLabel: t( 'Bulleted list styles toolbar' ),\n\t\t\tstyleDefinitions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the disc list style' ),\n\t\t\t\t\ttooltip: t( 'Disc' ),\n\t\t\t\t\ttype: 'disc',\n\t\t\t\t\ticon: listStyleDiscIcon\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the circle list style' ),\n\t\t\t\t\ttooltip: t( 'Circle' ),\n\t\t\t\t\ttype: 'circle',\n\t\t\t\t\ticon: listStyleCircleIcon\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the square list style' ),\n\t\t\t\t\ttooltip: t( 'Square' ),\n\t\t\t\t\ttype: 'square',\n\t\t\t\t\ticon: listStyleSquareIcon\n\t\t\t\t}\n\t\t\t]\n\t\t} ) );\n\n\t\teditor.ui.componentFactory.add( 'numberedList', getSplitButtonCreator( {\n\t\t\teditor,\n\t\t\tparentCommandName: 'numberedList',\n\t\t\tbuttonLabel: t( 'Numbered List' ),\n\t\t\tbuttonIcon: numberedListIcon,\n\t\t\ttoolbarAriaLabel: t( 'Numbered list styles toolbar' ),\n\t\t\tstyleDefinitions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the decimal list style' ),\n\t\t\t\t\ttooltip: t( 'Decimal' ),\n\t\t\t\t\ttype: 'decimal',\n\t\t\t\t\ticon: listStyleDecimalIcon\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the decimal with leading zero list style' ),\n\t\t\t\t\ttooltip: t( 'Decimal with leading zero' ),\n\t\t\t\t\ttype: 'decimal-leading-zero',\n\t\t\t\t\ticon: listStyleDecimalWithLeadingZeroIcon\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the lowerroman list style' ),\n\t\t\t\t\ttooltip: t( 'Lowerroman' ),\n\t\t\t\t\ttype: 'lower-roman',\n\t\t\t\t\ticon: listStyleLowerRomanIcon\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the upperroman list style' ),\n\t\t\t\t\ttooltip: t( 'Upper-roman' ),\n\t\t\t\t\ttype: 'upper-roman',\n\t\t\t\t\ticon: listStyleUpperRomanIcon\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the lowerlatin list style' ),\n\t\t\t\t\ttooltip: t( 'Lower-latin' ),\n\t\t\t\t\ttype: 'lower-latin',\n\t\t\t\t\ticon: listStyleLowerLatinIcon\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: t( 'Toggle the upperlatin list style' ),\n\t\t\t\t\ttooltip: t( 'Upper-latin' ),\n\t\t\t\t\ttype: 'upper-latin',\n\t\t\t\t\ticon: listStyleUpperLatinIcon\n\t\t\t\t}\n\t\t\t]\n\t\t} ) );\n\t}\n}\n\n// A helper that returns a function that creates a split button with a toolbar in the dropdown,\n// which in turn contains buttons allowing users to change list styles in the context of the current selection.\n//\n// @param {Object} options\n// @param {module:core/editor/editor~Editor} options.editor\n// @param {'bulletedList'|'numberedList'} options.parentCommandName The name of the higher-order editor command associated with\n// the set of particular list styles (e.g. \"bulletedList\" for \"disc\", \"circle\", and \"square\" styles).\n// @param {String} options.buttonLabel Label of the main part of the split button.\n// @param {String} options.buttonIcon The SVG string of an icon for the main part of the split button.\n// @param {String} options.toolbarAriaLabel The ARIA label for the toolbar in the split button dropdown.\n// @param {Object} options.styleDefinitions Definitions of the style buttons.\n// @returns {Function} A function that can be passed straight into {@link module:ui/componentfactory~ComponentFactory#add}.\nfunction getSplitButtonCreator( { editor, parentCommandName, buttonLabel, buttonIcon, toolbarAriaLabel, styleDefinitions } ) {\n\tconst parentCommand = editor.commands.get( parentCommandName );\n\tconst listStyleCommand = editor.commands.get( 'listStyle' );\n\n\t// @param {module:utils/locale~Locale} locale\n\t// @returns {module:ui/dropdown/dropdownview~DropdownView}\n\treturn locale => {\n\t\tconst dropdownView = createDropdown( locale, SplitButtonView );\n\t\tconst splitButtonView = dropdownView.buttonView;\n\t\tconst styleButtonCreator = getStyleButtonCreator( { editor, parentCommandName, listStyleCommand } );\n\n\t\taddToolbarToDropdown( dropdownView, styleDefinitions.map( styleButtonCreator ) );\n\n\t\tdropdownView.bind( 'isEnabled' ).to( parentCommand );\n\t\tdropdownView.toolbarView.ariaLabel = toolbarAriaLabel;\n\t\tdropdownView.class = 'ck-list-styles-dropdown';\n\n\t\tsplitButtonView.on( 'execute', () => {\n\t\t\teditor.execute( parentCommandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\tsplitButtonView.set( {\n\t\t\tlabel: buttonLabel,\n\t\t\ticon: buttonIcon,\n\t\t\ttooltip: true,\n\t\t\tisToggleable: true\n\t\t} );\n\n\t\tsplitButtonView.bind( 'isOn' ).to( parentCommand, 'value', value => !!value );\n\n\t\treturn dropdownView;\n\t};\n}\n\n// A helper that returns a function (factory) that creates individual buttons used by users to change styles\n// of lists.\n//\n// @param {Object} options\n// @param {module:core/editor/editor~Editor} options.editor\n// @param {module:list/liststylecommand~ListStylesCommand} options.listStyleCommand The instance of the `ListStylesCommand` class.\n// @param {'bulletedList'|'numberedList'} options.parentCommandName The name of the higher-order command associated with a\n// particular list style (e.g. \"bulletedList\" is associated with \"square\" and \"numberedList\" is associated with \"roman\").\n// @returns {Function} A function that can be passed straight into {@link module:ui/componentfactory~ComponentFactory#add}.\nfunction getStyleButtonCreator( { editor, listStyleCommand, parentCommandName } ) {\n\tconst locale = editor.locale;\n\tconst parentCommand = editor.commands.get( parentCommandName );\n\n\t// @param {String} label The label of the style button.\n\t// @param {String} type The type of the style button (e.g. \"roman\" or \"circle\").\n\t// @param {String} icon The SVG string of an icon of the style button.\n\t// @param {String} tooltip The tooltip text of the button (shorter than verbose label).\n\t// @returns {module:ui/button/buttonview~ButtonView}\n\treturn ( { label, type, icon, tooltip } ) => {\n\t\tconst button = new ButtonView( locale );\n\n\t\tbutton.set( { label, icon, tooltip } );\n\n\t\tlistStyleCommand.on( 'change:value', () => {\n\t\t\tbutton.isOn = listStyleCommand.value === type;\n\t\t} );\n\n\t\tbutton.on( 'execute', () => {\n\t\t\t// If the content the selection is anchored to is a list, let's change its style.\n\t\t\tif ( parentCommand.value ) {\n\t\t\t\t// If the current list style is not set in the model or the style is different than the\n\t\t\t\t// one to be applied, simply apply the new style.\n\t\t\t\tif ( listStyleCommand.value !== type ) {\n\t\t\t\t\teditor.execute( 'listStyle', { type } );\n\t\t\t\t}\n\t\t\t\t// If the style was the same, remove it (the button works as an off toggle).\n\t\t\t\telse {\n\t\t\t\t\teditor.execute( 'listStyle', { type: listStyleCommand._defaultType } );\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If the content the selection is anchored to is not a list, let's create a list of a desired style.\n\t\t\telse {\n\t\t\t\teditor.model.change( () => {\n\t\t\t\t\teditor.execute( parentCommandName );\n\t\t\t\t\teditor.execute( 'listStyle', { type } );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn button;\n\t};\n}\n","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M11 27a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0-9a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0-9a3 3 0 1 1 0 6 3 3 0 0 1 0-6z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M11 27a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0 1a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm0-10a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0 1a2 2 0 1 0 0 4 2 2 0 0 0 0-4zm0-10a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm0 1a2 2 0 1 0 0 4 2 2 0 0 0 0-4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M14 27v6H8v-6h6zm0-9v6H8v-6h6zm0-9v6H8V9h6z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M10.29 15V8.531H9.286c-.14.393-.4.736-.778 1.03-.378.295-.728.495-1.05.6v1.121a4.257 4.257 0 0 0 1.595-.936V15h1.235zm3.343 0v-1.235h-1.235V15h1.235zM11.3 24v-1.147H8.848c.064-.111.148-.226.252-.343.104-.117.351-.354.74-.712.39-.357.66-.631.81-.821.225-.288.39-.562.494-.824.104-.263.156-.539.156-.829 0-.51-.182-.936-.545-1.279-.363-.342-.863-.514-1.499-.514-.58 0-1.063.148-1.45.444-.387.296-.617.784-.69 1.463l1.23.124c.024-.36.112-.619.264-.774.153-.155.358-.233.616-.233.26 0 .465.074.613.222.148.148.222.36.222.635 0 .25-.085.501-.255.756-.126.185-.468.536-1.024 1.055-.692.641-1.155 1.156-1.389 1.544-.234.389-.375.8-.422 1.233H11.3zm2.333 0v-1.235h-1.235V24h1.235zM9.204 34.11c.615 0 1.129-.2 1.542-.598.413-.398.62-.88.62-1.446 0-.39-.11-.722-.332-.997a1.5 1.5 0 0 0-.886-.532c.619-.337.928-.788.928-1.353 0-.399-.151-.756-.453-1.073-.366-.386-.852-.58-1.459-.58a2.25 2.25 0 0 0-.96.2 1.617 1.617 0 0 0-.668.55c-.16.232-.28.544-.358.933l1.138.194c.032-.282.123-.495.272-.642.15-.146.33-.22.54-.22.215 0 .386.065.515.194s.193.302.193.518c0 .255-.087.46-.263.613-.176.154-.43.227-.765.218l-.136 1.006c.22-.061.409-.092.567-.092.24 0 .444.09.61.272.168.182.251.428.251.739 0 .328-.087.589-.261.782a.833.833 0 0 1-.644.29.841.841 0 0 1-.607-.242c-.167-.16-.27-.394-.307-.698l-1.196.145c.062.542.285.98.668 1.316.384.335.868.503 1.45.503zm4.43-.11v-1.235h-1.236V34h1.235z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M5.714 15.11c.624 0 1.11-.22 1.46-.66.421-.533.632-1.408.632-2.627 0-1.222-.21-2.096-.629-2.624-.351-.445-.839-.668-1.463-.668-.624 0-1.11.22-1.459.66-.422.533-.633 1.406-.633 2.619 0 1.236.192 2.095.576 2.577.384.482.89.723 1.516.723zm0-1.024a.614.614 0 0 1-.398-.14c-.115-.094-.211-.283-.287-.565-.077-.283-.115-.802-.115-1.558s.043-1.294.128-1.613c.064-.246.155-.417.272-.512a.617.617 0 0 1 .4-.143.61.61 0 0 1 .398.143c.116.095.211.284.288.567.076.283.114.802.114 1.558s-.043 1.292-.128 1.608c-.064.246-.155.417-.272.512a.617.617 0 0 1-.4.143zm6.078.914V8.531H10.79c-.14.393-.4.736-.778 1.03-.378.295-.728.495-1.05.6v1.121a4.257 4.257 0 0 0 1.595-.936V15h1.235zm3.344 0v-1.235h-1.235V15h1.235zm-9.422 9.11c.624 0 1.11-.22 1.46-.66.421-.533.632-1.408.632-2.627 0-1.222-.21-2.096-.629-2.624-.351-.445-.839-.668-1.463-.668-.624 0-1.11.22-1.459.66-.422.533-.633 1.406-.633 2.619 0 1.236.192 2.095.576 2.577.384.482.89.723 1.516.723zm0-1.024a.614.614 0 0 1-.398-.14c-.115-.094-.211-.283-.287-.565-.077-.283-.115-.802-.115-1.558s.043-1.294.128-1.613c.064-.246.155-.417.272-.512a.617.617 0 0 1 .4-.143.61.61 0 0 1 .398.143c.116.095.211.284.288.567.076.283.114.802.114 1.558s-.043 1.292-.128 1.608c-.064.246-.155.417-.272.512a.617.617 0 0 1-.4.143zm7.088.914v-1.147H10.35c.065-.111.149-.226.253-.343.104-.117.35-.354.74-.712.39-.357.66-.631.81-.821.225-.288.39-.562.493-.824.104-.263.156-.539.156-.829 0-.51-.181-.936-.544-1.279-.364-.342-.863-.514-1.499-.514-.58 0-1.063.148-1.45.444-.387.296-.617.784-.69 1.463l1.23.124c.024-.36.112-.619.264-.774.152-.155.357-.233.615-.233.261 0 .465.074.613.222.148.148.222.36.222.635 0 .25-.085.501-.255.756-.126.185-.467.536-1.024 1.055-.691.641-1.154 1.156-1.388 1.544-.235.389-.375.8-.422 1.233h4.328zm2.334 0v-1.235h-1.235V24h1.235zM5.714 34.11c.624 0 1.11-.22 1.46-.66.421-.533.632-1.408.632-2.627 0-1.222-.21-2.096-.629-2.624-.351-.445-.839-.668-1.463-.668-.624 0-1.11.22-1.459.66-.422.533-.633 1.406-.633 2.619 0 1.236.192 2.095.576 2.577.384.482.89.723 1.516.723zm0-1.024a.614.614 0 0 1-.398-.14c-.115-.094-.211-.283-.287-.565-.077-.283-.115-.802-.115-1.558s.043-1.294.128-1.613c.064-.246.155-.417.272-.512a.617.617 0 0 1 .4-.143.61.61 0 0 1 .398.143c.116.095.211.284.288.567.076.283.114.802.114 1.558s-.043 1.292-.128 1.608c-.064.246-.155.417-.272.512a.617.617 0 0 1-.4.143zm4.992 1.024c.616 0 1.13-.2 1.543-.598.413-.398.62-.88.62-1.446 0-.39-.111-.722-.332-.997a1.5 1.5 0 0 0-.886-.532c.618-.337.927-.788.927-1.353 0-.399-.15-.756-.452-1.073-.366-.386-.853-.58-1.46-.58a2.25 2.25 0 0 0-.96.2 1.617 1.617 0 0 0-.667.55c-.16.232-.28.544-.359.933l1.139.194c.032-.282.123-.495.272-.642.15-.146.33-.22.54-.22.214 0 .386.065.515.194s.193.302.193.518c0 .255-.088.46-.264.613-.175.154-.43.227-.764.218l-.136 1.006c.22-.061.408-.092.566-.092.24 0 .444.09.611.272.167.182.25.428.25.739 0 .328-.086.589-.26.782a.833.833 0 0 1-.644.29.841.841 0 0 1-.607-.242c-.167-.16-.27-.394-.308-.698l-1.195.145c.062.542.284.98.668 1.316.384.335.867.503 1.45.503zm4.43-.11v-1.235h-1.235V34h1.235z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M11.88 8.7V7.558h-1.234V8.7h1.234zm0 5.3V9.333h-1.234V14h1.234zm2.5 0v-1.235h-1.234V14h1.235zm-4.75 4.7v-1.142H8.395V18.7H9.63zm0 5.3v-4.667H8.395V24H9.63zm2.5-5.3v-1.142h-1.234V18.7h1.235zm0 5.3v-4.667h-1.234V24h1.235zm2.501 0v-1.235h-1.235V24h1.235zM7.38 28.7v-1.142H6.145V28.7H7.38zm0 5.3v-4.667H6.145V34H7.38zm2.5-5.3v-1.142H8.646V28.7H9.88zm0 5.3v-4.667H8.646V34H9.88zm2.5-5.3v-1.142h-1.234V28.7h1.235zm0 5.3v-4.667h-1.234V34h1.235zm2.501 0v-1.235h-1.235V34h1.235z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M11.916 15V8.558h-1.301V15h1.3zm2.465 0v-1.235h-1.235V15h1.235zM9.665 25v-6.442h-1.3V25h1.3zm2.5 0v-6.442h-1.3V25h1.3zm2.466 0v-1.235h-1.235V25h1.235zm-7.216 9v-6.442h-1.3V34h1.3zm2.5 0v-6.442h-1.3V34h1.3zm2.501 0v-6.442h-1.3V34h1.3zm2.465 0v-1.235h-1.235V34h1.235z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"M9.62 14.105c.272 0 .528-.05.768-.153s.466-.257.677-.462c.009.024.023.072.044.145.047.161.086.283.119.365h1.221a2.649 2.649 0 0 1-.222-.626c-.04-.195-.059-.498-.059-.908l.013-1.441c0-.536-.055-.905-.165-1.105-.11-.201-.3-.367-.569-.497-.27-.13-.68-.195-1.23-.195-.607 0-1.064.108-1.371.325-.308.217-.525.55-.65 1.002l1.12.202c.076-.217.176-.369.299-.455.123-.086.294-.13.514-.13.325 0 .546.05.663.152.118.101.176.27.176.508v.123c-.222.093-.622.194-1.2.303-.427.082-.755.178-.982.288-.227.11-.403.268-.53.474a1.327 1.327 0 0 0-.188.706c0 .398.138.728.415.988.277.261.656.391 1.136.391zm.368-.87a.675.675 0 0 1-.492-.189.606.606 0 0 1-.193-.448c0-.176.08-.32.241-.435.106-.07.33-.142.673-.215a7.19 7.19 0 0 0 .751-.19v.247c0 .296-.016.496-.048.602a.773.773 0 0 1-.295.409 1.07 1.07 0 0 1-.637.22zm4.645.765v-1.235h-1.235V14h1.235zM10.2 25.105c.542 0 1.003-.215 1.382-.646.38-.43.57-1.044.57-1.84 0-.771-.187-1.362-.559-1.774a1.82 1.82 0 0 0-1.41-.617c-.522 0-.973.216-1.354.65v-2.32H7.594V25h1.147v-.686a1.9 1.9 0 0 0 .67.592c.26.133.523.2.79.2zm-.299-.975c-.354 0-.638-.164-.852-.492-.153-.232-.229-.59-.229-1.073 0-.468.098-.818.295-1.048a.93.93 0 0 1 .738-.345c.302 0 .55.118.743.354.193.236.29.62.29 1.154 0 .5-.096.868-.288 1.1-.192.233-.424.35-.697.35zm4.478.87v-1.235h-1.234V25h1.234zm-4.017 9.105c.6 0 1.08-.142 1.437-.426.357-.284.599-.704.725-1.261l-1.213-.207c-.061.326-.167.555-.316.688a.832.832 0 0 1-.576.2.916.916 0 0 1-.75-.343c-.185-.228-.278-.62-.278-1.173 0-.498.091-.853.274-1.066.183-.212.429-.318.736-.318.232 0 .42.061.565.184.145.123.238.306.28.55l1.216-.22c-.146-.501-.387-.874-.722-1.119-.336-.244-.788-.366-1.356-.366-.695 0-1.245.214-1.653.643-.407.43-.61 1.03-.61 1.8 0 .762.202 1.358.608 1.788.406.431.95.646 1.633.646zM14.633 34v-1.235h-1.235V34h1.235z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 44 44\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M35 29a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17zm0-9a1 1 0 0 1 1 1v1a1 1 0 0 1-1 1H18a1 1 0 0 1-1-1v-1a1 1 0 0 1 1-1h17z\\\" fill-opacity=\\\".163\\\"/><path d=\\\"m7.88 15 .532-1.463h2.575L11.549 15h1.415l-2.58-6.442H9.01L6.5 15h1.38zm2.69-2.549H8.811l.87-2.39.887 2.39zM14.88 15v-1.235h-1.234V15h1.234zM9.352 25c.83-.006 1.352-.02 1.569-.044.346-.038.636-.14.872-.305.236-.166.422-.387.558-.664.137-.277.205-.562.205-.855 0-.372-.106-.695-.317-.97-.21-.276-.512-.471-.905-.585a1.51 1.51 0 0 0 .661-.567 1.5 1.5 0 0 0 .244-.83c0-.28-.066-.53-.197-.754a1.654 1.654 0 0 0-.495-.539 1.676 1.676 0 0 0-.672-.266c-.25-.042-.63-.063-1.14-.063H7.158V25h2.193zm.142-3.88H8.46v-1.49h.747c.612 0 .983.007 1.112.022.217.026.38.102.49.226.11.125.165.287.165.486a.68.68 0 0 1-.192.503.86.86 0 0 1-.525.23 11.47 11.47 0 0 1-.944.023h.18zm.17 2.795H8.46v-1.723h1.05c.592 0 .977.03 1.154.092.177.062.313.16.406.295a.84.84 0 0 1 .14.492c0 .228-.06.41-.181.547a.806.806 0 0 1-.473.257c-.126.026-.423.04-.892.04zM14.88 25v-1.235h-1.234V25h1.234zm-5.018 9.11c.691 0 1.262-.17 1.711-.512.45-.341.772-.864.965-1.567l-1.261-.4c-.109.472-.287.818-.536 1.037-.25.22-.547.33-.892.33-.47 0-.85-.173-1.143-.519-.293-.345-.44-.925-.44-1.74 0-.767.15-1.322.447-1.665.297-.343.684-.514 1.162-.514.346 0 .64.096.881.29.242.193.4.457.477.79l1.288-.307c-.147-.516-.367-.911-.66-1.187-.492-.465-1.132-.698-1.92-.698-.902 0-1.63.296-2.184.89-.554.593-.83 1.426-.83 2.498 0 1.014.275 1.813.825 2.397.551.585 1.254.877 2.11.877zM14.88 34v-1.235h-1.234V34h1.234z\\\"/></svg>\";","/**\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 list/checktodolistcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nconst attributeKey = 'todoListChecked';\n\n/**\n * The check to-do command.\n *\n * The command is registered by the {@link module:list/todolistediting~TodoListEditing} as\n * the `checkTodoList` editor command and it is also available via aliased `todoListCheck` name.\n *\n * @extends module:core/command~Command\n */\nexport default class CheckTodoListCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A flag indicating whether the command is active. The command is active when at least one of\n\t\t * {@link module:engine/model/selection~Selection selected} elements is a to-do list item.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEnabled\n\t\t */\n\n\t\t/**\n\t\t * A list of to-do list items selected by the {@link module:engine/model/selection~Selection}.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Array.<module:engine/model/element~Element>} #value\n\t\t */\n\n\t\t/**\n\t\t * A list of to-do list items selected by the {@link module:engine/model/selection~Selection}.\n\t\t *\n\t\t * @protected\n\t\t * @type {Array.<module:engine/model/element~Element>}\n\t\t */\n\t\tthis._selectedElements = [];\n\n\t\t// Refresh command before executing to be sure all values are up to date.\n\t\t// It is needed when selection has changed before command execution, in the same change block.\n\t\tthis.on( 'execute', () => {\n\t\t\tthis.refresh();\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Updates the command's {@link #value} and {@link #isEnabled} properties based on the current selection.\n\t */\n\trefresh() {\n\t\tthis._selectedElements = this._getSelectedItems();\n\t\tthis.value = this._selectedElements.every( element => !!element.getAttribute( 'todoListChecked' ) );\n\t\tthis.isEnabled = !!this._selectedElements.length;\n\t}\n\n\t/**\n\t * Gets all to-do list items selected by the {@link module:engine/model/selection~Selection}.\n\t *\n\t * @private\n\t * @returns {Array.<module:engine/model/element~Element>}\n\t */\n\t_getSelectedItems() {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\n\t\tconst selectionRange = model.document.selection.getFirstRange();\n\t\tconst startElement = selectionRange.start.parent;\n\t\tconst elements = [];\n\n\t\tif ( schema.checkAttribute( startElement, attributeKey ) ) {\n\t\t\telements.push( startElement );\n\t\t}\n\n\t\tfor ( const item of selectionRange.getItems() ) {\n\t\t\tif ( schema.checkAttribute( item, attributeKey ) && !elements.includes( item ) ) {\n\t\t\t\telements.push( item );\n\t\t\t}\n\t\t}\n\n\t\treturn elements;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply\n\t * the attribute. Otherwise, the command will remove the attribute. If not set, the command will look for its current\n\t * value to decide what it should do.\n\t */\n\texecute( options = {} ) {\n\t\tthis.editor.model.change( writer => {\n\t\t\tfor ( const element of this._selectedElements ) {\n\t\t\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\n\t\t\t\tif ( value ) {\n\t\t\t\t\twriter.setAttribute( attributeKey, true, element );\n\t\t\t\t} else {\n\t\t\t\t\twriter.removeAttribute( attributeKey, element );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/todolistconverters\n */\n\n/* global document */\n\nimport { createElement } from 'ckeditor5/src/utils';\n\nimport { generateLiInUl, injectViewList, positionAfterUiElements, findNestedList } from './utils';\n\n/**\n * A model-to-view converter for the `listItem` model element insertion.\n *\n * It converts the `listItem` model element to an unordered list with a {@link module:engine/view/uielement~UIElement checkbox element}\n * at the beginning of each list item. It also merges the list with surrounding lists (if available).\n *\n * It is used by {@link module:engine/controller/editingcontroller~EditingController}.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:engine/model/model~Model} model Model instance.\n * @param {Function} onCheckboxChecked Callback function.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewInsertion( model, onCheckboxChecked ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst consumable = conversionApi.consumable;\n\n\t\tif ( !consumable.test( data.item, 'insert' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listType' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listIndent' )\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( data.item.getAttribute( 'listType' ) != 'todo' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelItem = data.item;\n\n\t\tconsumable.consume( modelItem, 'insert' );\n\t\tconsumable.consume( modelItem, 'attribute:listType' );\n\t\tconsumable.consume( modelItem, 'attribute:listIndent' );\n\t\tconsumable.consume( modelItem, 'attribute:todoListChecked' );\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewItem = generateLiInUl( modelItem, conversionApi );\n\n\t\tconst isChecked = !!modelItem.getAttribute( 'todoListChecked' );\n\t\tconst checkmarkElement = createCheckmarkElement( modelItem, viewWriter, isChecked, onCheckboxChecked );\n\n\t\tconst span = viewWriter.createContainerElement( 'span', {\n\t\t\tclass: 'todo-list__label__description'\n\t\t} );\n\n\t\tviewWriter.addClass( 'todo-list', viewItem.parent );\n\t\tviewWriter.insert( viewWriter.createPositionAt( viewItem, 0 ), checkmarkElement );\n\t\tviewWriter.insert( viewWriter.createPositionAfter( checkmarkElement ), span );\n\n\t\tinjectViewList( modelItem, viewItem, conversionApi, model );\n\t};\n}\n\n/**\n * A model-to-view converter for the `listItem` model element insertion.\n *\n * It is used by {@link module:engine/controller/datacontroller~DataController}.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:insert\n * @param {module:engine/model/model~Model} model Model instance.\n * @returns {Function} Returns a conversion callback.\n */\nexport function dataModelViewInsertion( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst consumable = conversionApi.consumable;\n\n\t\tif ( !consumable.test( data.item, 'insert' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listType' ) ||\n\t\t\t!consumable.test( data.item, 'attribute:listIndent' )\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( data.item.getAttribute( 'listType' ) != 'todo' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelItem = data.item;\n\n\t\tconsumable.consume( modelItem, 'insert' );\n\t\tconsumable.consume( modelItem, 'attribute:listType' );\n\t\tconsumable.consume( modelItem, 'attribute:listIndent' );\n\t\tconsumable.consume( modelItem, 'attribute:todoListChecked' );\n\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst viewItem = generateLiInUl( modelItem, conversionApi );\n\n\t\tviewWriter.addClass( 'todo-list', viewItem.parent );\n\n\t\tconst label = viewWriter.createContainerElement( 'label', {\n\t\t\tclass: 'todo-list__label'\n\t\t} );\n\n\t\tconst checkbox = viewWriter.createEmptyElement( 'input', {\n\t\t\ttype: 'checkbox',\n\t\t\tdisabled: 'disabled'\n\t\t} );\n\n\t\tconst span = viewWriter.createContainerElement( 'span', {\n\t\t\tclass: 'todo-list__label__description'\n\t\t} );\n\n\t\tif ( modelItem.getAttribute( 'todoListChecked' ) ) {\n\t\t\tviewWriter.setAttribute( 'checked', 'checked', checkbox );\n\t\t}\n\n\t\tviewWriter.insert( viewWriter.createPositionAt( viewItem, 0 ), label );\n\t\tviewWriter.insert( viewWriter.createPositionAt( label, 0 ), checkbox );\n\t\tviewWriter.insert( viewWriter.createPositionAfter( checkbox ), span );\n\n\t\tinjectViewList( modelItem, viewItem, conversionApi, model );\n\t};\n}\n\n/**\n * A view-to-model converter for the checkbox element inside a view list item.\n *\n * It changes the `listType` of the model `listItem` to a `todo` value.\n * When a view checkbox element is marked as checked, an additional `todoListChecked=\"true\"` attribute is added to the model item.\n *\n * It is used by {@link module:engine/controller/datacontroller~DataController}.\n *\n * @see module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element\n * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the fired event.\n * @param {Object} data An object containing conversion input, a placeholder for conversion output and possibly other values.\n * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion interface to be used by the callback.\n */\nexport function dataViewModelCheckmarkInsertion( evt, data, conversionApi ) {\n\tconst modelCursor = data.modelCursor;\n\tconst modelItem = modelCursor.parent;\n\tconst viewItem = data.viewItem;\n\n\tif ( viewItem.getAttribute( 'type' ) != 'checkbox' || modelItem.name != 'listItem' || !modelCursor.isAtStart ) {\n\t\treturn;\n\t}\n\n\tif ( !conversionApi.consumable.consume( viewItem, { name: true } ) ) {\n\t\treturn;\n\t}\n\n\tconst writer = conversionApi.writer;\n\n\twriter.setAttribute( 'listType', 'todo', modelItem );\n\n\tif ( data.viewItem.hasAttribute( 'checked' ) ) {\n\t\twriter.setAttribute( 'todoListChecked', true, modelItem );\n\t}\n\n\tdata.modelRange = writer.createRange( modelCursor );\n}\n\n/**\n * A model-to-view converter for the `listType` attribute change on the `listItem` model element.\n *\n * This change means that the `<li>` element parent changes to `<ul class=\"todo-list\">` and a\n * {@link module:engine/view/uielement~UIElement checkbox UI element} is added at the beginning\n * of the list item element (or vice versa).\n *\n * This converter is preceded by {@link module:list/converters~modelViewChangeType} and followed by\n * {@link module:list/converters~modelViewMergeAfterChangeType} to handle splitting and merging surrounding lists of the same type.\n *\n * It is used by {@link module:engine/controller/editingcontroller~EditingController}.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {Function} onCheckedChange Callback fired after clicking the checkbox UI element.\n * @param {module:engine/view/view~View} view Editing view controller.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewChangeType( onCheckedChange, view ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewItem = conversionApi.mapper.toViewElement( data.item );\n\t\tconst viewWriter = conversionApi.writer;\n\n\t\tconst labelElement = findLabel( viewItem, view );\n\n\t\tif ( data.attributeNewValue == 'todo' ) {\n\t\t\tconst isChecked = !!data.item.getAttribute( 'todoListChecked' );\n\t\t\tconst checkmarkElement = createCheckmarkElement( data.item, viewWriter, isChecked, onCheckedChange );\n\n\t\t\tconst span = viewWriter.createContainerElement( 'span', {\n\t\t\t\tclass: 'todo-list__label__description'\n\t\t\t} );\n\n\t\t\tconst itemRange = viewWriter.createRangeIn( viewItem );\n\t\t\tconst nestedList = findNestedList( viewItem );\n\n\t\t\tconst descriptionStart = positionAfterUiElements( itemRange.start );\n\t\t\tconst descriptionEnd = nestedList ? viewWriter.createPositionBefore( nestedList ) : itemRange.end;\n\t\t\tconst descriptionRange = viewWriter.createRange( descriptionStart, descriptionEnd );\n\n\t\t\tviewWriter.addClass( 'todo-list', viewItem.parent );\n\t\t\tviewWriter.move( descriptionRange, viewWriter.createPositionAt( span, 0 ) );\n\t\t\tviewWriter.insert( viewWriter.createPositionAt( viewItem, 0 ), checkmarkElement );\n\t\t\tviewWriter.insert( viewWriter.createPositionAfter( checkmarkElement ), span );\n\t\t} else if ( data.attributeOldValue == 'todo' ) {\n\t\t\tconst descriptionSpan = findDescription( viewItem, view );\n\n\t\t\tviewWriter.removeClass( 'todo-list', viewItem.parent );\n\t\t\tviewWriter.remove( labelElement );\n\t\t\tviewWriter.move( viewWriter.createRangeIn( descriptionSpan ), viewWriter.createPositionBefore( descriptionSpan ) );\n\t\t\tviewWriter.remove( descriptionSpan );\n\t\t}\n\t};\n}\n\n/**\n * A model-to-view converter for the `todoListChecked` attribute change on the `listItem` model element.\n *\n * It marks the {@link module:engine/view/uielement~UIElement checkbox UI element} as checked.\n *\n * It is used by {@link module:engine/controller/editingcontroller~EditingController}.\n *\n * @see module:engine/conversion/downcastdispatcher~DowncastDispatcher#event:attribute\n * @param {Function} onCheckedChange Callback fired after clicking the checkbox UI element.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelViewChangeChecked( onCheckedChange ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\t// Do not convert `todoListChecked` attribute when to-do list item has changed to other list item.\n\t\t// This attribute will be removed by the model post fixer.\n\t\tif ( data.item.getAttribute( 'listType' ) != 'todo' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !conversionApi.consumable.consume( data.item, 'attribute:todoListChecked' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { mapper, writer: viewWriter } = conversionApi;\n\t\tconst isChecked = !!data.item.getAttribute( 'todoListChecked' );\n\t\tconst viewItem = mapper.toViewElement( data.item );\n\t\t// Because of m -> v position mapper we can be sure checkbox is always at the beginning.\n\t\tconst oldCheckmarkElement = viewItem.getChild( 0 );\n\t\tconst newCheckmarkElement = createCheckmarkElement( data.item, viewWriter, isChecked, onCheckedChange );\n\n\t\tviewWriter.insert( viewWriter.createPositionAfter( oldCheckmarkElement ), newCheckmarkElement );\n\t\tviewWriter.remove( oldCheckmarkElement );\n\t};\n}\n\n/**\n * A model-to-view position at zero offset mapper.\n *\n * This helper ensures that position inside todo-list in the view is mapped after the checkbox.\n *\n * It only handles the position at the beginning of a list item as other positions are properly mapped be the default mapper.\n *\n * @param {module:engine/view/view~View} view\n * @return {Function}\n */\nexport function mapModelToViewPosition( view ) {\n\treturn ( evt, data ) => {\n\t\tconst modelPosition = data.modelPosition;\n\t\tconst parent = modelPosition.parent;\n\n\t\tif ( !parent.is( 'element', 'listItem' ) || parent.getAttribute( 'listType' ) != 'todo' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst viewLi = data.mapper.toViewElement( parent );\n\t\tconst descSpan = findDescription( viewLi, view );\n\n\t\tif ( descSpan ) {\n\t\t\tdata.viewPosition = data.mapper.findPositionIn( descSpan, modelPosition.offset );\n\t\t}\n\t};\n}\n\n// Creates a checkbox UI element.\n//\n// @private\n// @param {module:engine/model/item~Item} modelItem\n// @param {module:engine/view/downcastwriter~DowncastWriter} viewWriter\n// @param {Boolean} isChecked\n// @param {Function} onChange\n// @returns {module:view/uielement~UIElement}\nfunction createCheckmarkElement( modelItem, viewWriter, isChecked, onChange ) {\n\tconst uiElement = viewWriter.createUIElement(\n\t\t'label',\n\t\t{\n\t\t\tclass: 'todo-list__label',\n\t\t\tcontenteditable: false\n\t\t},\n\t\tfunction( domDocument ) {\n\t\t\tconst checkbox = createElement( document, 'input', { type: 'checkbox' } );\n\n\t\t\tif ( isChecked ) {\n\t\t\t\tcheckbox.setAttribute( 'checked', 'checked' );\n\t\t\t}\n\n\t\t\tcheckbox.addEventListener( 'change', () => onChange( modelItem ) );\n\n\t\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t\tdomElement.appendChild( checkbox );\n\n\t\t\treturn domElement;\n\t\t}\n\t);\n\n\treturn uiElement;\n}\n\n// Helper method to find label element inside li.\nfunction findLabel( viewItem, view ) {\n\tconst range = view.createRangeIn( viewItem );\n\n\tfor ( const value of range ) {\n\t\tif ( value.item.is( 'uiElement', 'label' ) ) {\n\t\t\treturn value.item;\n\t\t}\n\t}\n}\n\nfunction findDescription( viewItem, view ) {\n\tconst range = view.createRangeIn( viewItem );\n\n\tfor ( const value of range ) {\n\t\tif ( value.item.is( 'containerElement', 'span' ) && value.item.hasClass( 'todo-list__label__description' ) ) {\n\t\t\treturn value.item;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/todolistediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport {\n\tgetCode,\n\tparseKeystroke,\n\tgetLocalizedArrowKeyCodeDirection\n} from 'ckeditor5/src/utils';\n\nimport ListCommand from './listcommand';\nimport ListEditing from './listediting';\nimport CheckTodoListCommand from './checktodolistcommand';\nimport {\n\tdataModelViewInsertion,\n\tdataViewModelCheckmarkInsertion,\n\tmapModelToViewPosition,\n\tmodelViewChangeChecked,\n\tmodelViewChangeType,\n\tmodelViewInsertion\n} from './todolistconverters';\n\nconst ITEM_TOGGLE_KEYSTROKE = parseKeystroke( 'Ctrl+Enter' );\n\n/**\n * The engine of the to-do list feature. It handles creating, editing and removing to-do lists and their items.\n *\n * It registers the entire functionality of the {@link module:list/listediting~ListEditing list editing plugin} and extends\n * it with the commands:\n *\n * - `'todoList'`,\n * - `'checkTodoList'`,\n * - `'todoListCheck'` as an alias for `checkTodoList` command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TodoListEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TodoListEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ListEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst { editing, data, model } = editor;\n\n\t\t// Extend schema.\n\t\tmodel.schema.extend( 'listItem', {\n\t\t\tallowAttributes: [ 'todoListChecked' ]\n\t\t} );\n\n\t\t// Disallow todoListChecked attribute on other nodes than listItem with to-do listType.\n\t\tmodel.schema.addAttributeCheck( ( context, attributeName ) => {\n\t\t\tconst item = context.last;\n\n\t\t\tif ( attributeName == 'todoListChecked' && item.name == 'listItem' && item.getAttribute( 'listType' ) != 'todo' ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\t// Register `todoList` command.\n\t\teditor.commands.add( 'todoList', new ListCommand( editor, 'todo' ) );\n\n\t\tconst checkTodoListCommand = new CheckTodoListCommand( editor );\n\n\t\t// Register `checkTodoList` command and add `todoListCheck` command as an alias for backward compatibility.\n\t\teditor.commands.add( 'checkTodoList', checkTodoListCommand );\n\t\teditor.commands.add( 'todoListCheck', checkTodoListCommand );\n\n\t\t// Define converters.\n\t\tdata.downcastDispatcher.on( 'insert:listItem', dataModelViewInsertion( model ), { priority: 'high' } );\n\t\tdata.upcastDispatcher.on( 'element:input', dataViewModelCheckmarkInsertion, { priority: 'high' } );\n\n\t\tediting.downcastDispatcher.on(\n\t\t\t'insert:listItem',\n\t\t\tmodelViewInsertion( model, listItem => this._handleCheckmarkChange( listItem ) ),\n\t\t\t{ priority: 'high' }\n\t\t);\n\t\tediting.downcastDispatcher.on(\n\t\t\t'attribute:listType:listItem',\n\t\t\tmodelViewChangeType( listItem => this._handleCheckmarkChange( listItem ), editing.view )\n\t\t);\n\t\tediting.downcastDispatcher.on(\n\t\t\t'attribute:todoListChecked:listItem',\n\t\t\tmodelViewChangeChecked( listItem => this._handleCheckmarkChange( listItem ) )\n\t\t);\n\n\t\tediting.mapper.on( 'modelToViewPosition', mapModelToViewPosition( editing.view ) );\n\t\tdata.mapper.on( 'modelToViewPosition', mapModelToViewPosition( editing.view ) );\n\n\t\t// Jump at the end of the previous node on left arrow key press, when selection is after the checkbox.\n\t\t//\n\t\t// <blockquote><p>Foo</p></blockquote>\n\t\t// <ul><li><checkbox/>{}Bar</li></ul>\n\t\t//\n\t\t// press: `<-`\n\t\t//\n\t\t// <blockquote><p>Foo{}</p></blockquote>\n\t\t// <ul><li><checkbox/>Bar</li></ul>\n\t\t//\n\t\tthis.listenTo( editing.view.document, 'arrowKey', jumpOverCheckmarkOnSideArrowKeyPress( model, editor.locale ), { context: 'li' } );\n\n\t\t// Toggle check state of selected to-do list items on keystroke.\n\t\tthis.listenTo( editing.view.document, 'keydown', ( evt, data ) => {\n\t\t\tif ( getCode( data ) === ITEM_TOGGLE_KEYSTROKE ) {\n\t\t\t\teditor.execute( 'checkTodoList' );\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\n\t\t// Remove `todoListChecked` attribute when a host element is no longer a to-do list item.\n\t\tconst listItemsToFix = new Set();\n\n\t\tthis.listenTo( model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\tif ( operation.type == 'rename' && operation.oldName == 'listItem' ) {\n\t\t\t\tconst item = operation.position.nodeAfter;\n\n\t\t\t\tif ( item.hasAttribute( 'todoListChecked' ) ) {\n\t\t\t\t\tlistItemsToFix.add( item );\n\t\t\t\t}\n\t\t\t} else if ( operation.type == 'changeAttribute' && operation.key == 'listType' && operation.oldValue === 'todo' ) {\n\t\t\t\tfor ( const item of operation.range.getItems() ) {\n\t\t\t\t\tif ( item.hasAttribute( 'todoListChecked' ) && item.getAttribute( 'listType' ) !== 'todo' ) {\n\t\t\t\t\t\tlistItemsToFix.add( item );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tmodel.document.registerPostFixer( writer => {\n\t\t\tlet hasChanged = false;\n\n\t\t\tfor ( const listItem of listItemsToFix ) {\n\t\t\t\twriter.removeAttribute( 'todoListChecked', listItem );\n\t\t\t\thasChanged = true;\n\t\t\t}\n\n\t\t\tlistItemsToFix.clear();\n\n\t\t\treturn hasChanged;\n\t\t} );\n\t}\n\n\t/**\n\t * Handles the checkbox element change, moves the selection to the corresponding model item to make it possible\n\t * to toggle the `todoListChecked` attribute using the command, and restores the selection position.\n\t *\n\t * Some say it's a hack :) Moving the selection only for executing the command on a certain node and restoring it after,\n\t * is not a clear solution. We need to design an API for using commands beyond the selection range.\n\t * See https://github.com/ckeditor/ckeditor5/issues/1954.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} listItem\n\t */\n\t_handleCheckmarkChange( listItem ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst previousSelectionRanges = Array.from( model.document.selection.getRanges() );\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( listItem, 'end' );\n\t\t\teditor.execute( 'checkTodoList' );\n\t\t\twriter.setSelection( previousSelectionRanges );\n\t\t} );\n\t}\n}\n\n// Handles the left/right (LTR/RTL content) arrow key and moves the selection at the end of the previous block element\n// if the selection is just after the checkbox element. In other words, it jumps over the checkbox element when\n// moving the selection to the left/right (LTR/RTL).\n//\n// @private\n// @param {module:engine/model/model~Model} model\n// @param {module:utils/locale~Locale} locale\n// @returns {Function} Callback for 'keydown' events.\nfunction jumpOverCheckmarkOnSideArrowKeyPress( model, locale ) {\n\treturn ( eventInfo, domEventData ) => {\n\t\tconst direction = getLocalizedArrowKeyCodeDirection( domEventData.keyCode, locale.contentLanguageDirection );\n\n\t\tif ( direction != 'left' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst schema = model.schema;\n\t\tconst selection = model.document.selection;\n\n\t\tif ( !selection.isCollapsed ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = selection.getFirstPosition();\n\t\tconst parent = position.parent;\n\n\t\tif ( parent.name === 'listItem' && parent.getAttribute( 'listType' ) == 'todo' && position.isAtStart ) {\n\t\t\tconst newRange = schema.getNearestSelectionRange( model.createPositionBefore( parent ), 'backward' );\n\n\t\t\tif ( newRange ) {\n\t\t\t\tmodel.change( writer => writer.setSelection( newRange ) );\n\t\t\t}\n\n\t\t\tdomEventData.preventDefault();\n\t\t\tdomEventData.stopPropagation();\n\t\t\teventInfo.stop();\n\t\t}\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/todolistui\n */\n\nimport { createUIComponent } from './utils';\nimport todoListIcon from '../theme/icons/todolist.svg';\nimport { Plugin } from 'ckeditor5/src/core';\n\n/**\n * The to-do list UI feature. It introduces the `'todoList'` button that\n * allows to convert elements to and from to-do list items and to indent or outdent them.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TodoListUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TodoListUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst t = this.editor.t;\n\n\t\tcreateUIComponent( this.editor, 'todoList', t( 'To-do List' ), todoListIcon );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m2.315 14.705 2.224-2.24a.689.689 0 0 1 .963 0 .664.664 0 0 1 0 .949L2.865 16.07a.682.682 0 0 1-.112.089.647.647 0 0 1-.852-.051L.688 14.886a.635.635 0 0 1 0-.903.647.647 0 0 1 .91 0l.717.722zm5.185.045a.75.75 0 0 1 .75-.75h9.5a.75.75 0 1 1 0 1.5h-9.5a.75.75 0 0 1-.75-.75zM2.329 5.745l2.21-2.226a.689.689 0 0 1 .963 0 .664.664 0 0 1 0 .95L2.865 7.125a.685.685 0 0 1-.496.196.644.644 0 0 1-.468-.187L.688 5.912a.635.635 0 0 1 0-.903.647.647 0 0 1 .91 0l.73.736zM7.5 5.75A.75.75 0 0 1 8.25 5h9.5a.75.75 0 1 1 0 1.5h-9.5a.75.75 0 0 1-.75-.75z\\\"/></svg>\";","/**\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 paste-from-office/filters/list\n */\n\nimport { Matcher, UpcastWriter } from 'ckeditor5/src/engine';\n\n/**\n * Transforms Word specific list-like elements to the semantic HTML lists.\n *\n * Lists in Word are represented by block elements with special attributes like:\n *\n *\t\t<p class=MsoListParagraphCxSpFirst style='mso-list:l1 level1 lfo1'>...</p> // Paragraph based list.\n *\t\t<h1 style='mso-list:l0 level1 lfo1'>...</h1> // Heading 1 based list.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment The view structure to be transformed.\n * @param {String} stylesString Styles from which list-like elements styling will be extracted.\n */\nexport function transformListItemLikeElementsIntoLists( documentFragment, stylesString ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst writer = new UpcastWriter( documentFragment.document );\n\tconst itemLikeElements = findAllItemLikeElements( documentFragment, writer );\n\n\tif ( !itemLikeElements.length ) {\n\t\treturn;\n\t}\n\n\tlet currentList = null;\n\tlet currentIndentation = 1;\n\n\titemLikeElements.forEach( ( itemLikeElement, i ) => {\n\t\tconst isDifferentList = isNewListNeeded( itemLikeElements[ i - 1 ], itemLikeElement );\n\t\tconst previousItemLikeElement = isDifferentList ? null : itemLikeElements[ i - 1 ];\n\t\tconst indentationDifference = getIndentationDifference( previousItemLikeElement, itemLikeElement );\n\n\t\tif ( isDifferentList ) {\n\t\t\tcurrentList = null;\n\t\t\tcurrentIndentation = 1;\n\t\t}\n\n\t\tif ( !currentList || indentationDifference !== 0 ) {\n\t\t\tconst listStyle = detectListStyle( itemLikeElement, stylesString );\n\n\t\t\tif ( !currentList ) {\n\t\t\t\tcurrentList = insertNewEmptyList( listStyle, itemLikeElement.element, writer );\n\t\t\t} else if ( itemLikeElement.indent > currentIndentation ) {\n\t\t\t\tconst lastListItem = currentList.getChild( currentList.childCount - 1 );\n\t\t\t\tconst lastListItemChild = lastListItem.getChild( lastListItem.childCount - 1 );\n\n\t\t\t\tcurrentList = insertNewEmptyList( listStyle, lastListItemChild, writer );\n\t\t\t\tcurrentIndentation += 1;\n\t\t\t} else if ( itemLikeElement.indent < currentIndentation ) {\n\t\t\t\tconst differentIndentation = currentIndentation - itemLikeElement.indent;\n\n\t\t\t\tcurrentList = findParentListAtLevel( currentList, differentIndentation );\n\t\t\t\tcurrentIndentation = parseInt( itemLikeElement.indent );\n\t\t\t}\n\n\t\t\tif ( itemLikeElement.indent <= currentIndentation ) {\n\t\t\t\tif ( !currentList.is( 'element', listStyle.type ) ) {\n\t\t\t\t\tcurrentList = writer.rename( listStyle.type, currentList );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst listItem = transformElementIntoListItem( itemLikeElement.element, writer );\n\n\t\twriter.appendChild( listItem, currentList );\n\t} );\n}\n\n/**\n * Removes paragraph wrapping content inside a list item.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport function unwrapParagraphInListItem( documentFragment, writer ) {\n\tfor ( const value of writer.createRangeIn( documentFragment ) ) {\n\t\tconst element = value.item;\n\n\t\tif ( element.is( 'element', 'li' ) ) {\n\t\t\t// Google Docs allows on single paragraph inside LI.\n\t\t\tconst firstChild = element.getChild( 0 );\n\n\t\t\tif ( firstChild && firstChild.is( 'element', 'p' ) ) {\n\t\t\t\twriter.unwrapElement( firstChild );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Finds all list-like elements in a given document fragment.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// in which to look for list-like nodes.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.<Object>} Array of found list-like items. Each item is an object containing:\n//\n//\t\t* {module:engine/src/view/element~Element} element List-like element.\n//\t\t* {Number} id List item id parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} order List item creation order parsed from `mso-list` style (see `getListItemData()` function).\n//\t\t* {Number} indent List item indentation level parsed from `mso-list` style (see `getListItemData()` function).\nfunction findAllItemLikeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\t// Matcher for finding list-like elements.\n\tconst itemLikeElementsMatcher = new Matcher( {\n\t\tname: /^p|h\\d+$/,\n\t\tstyles: {\n\t\t\t'mso-list': /.*/\n\t\t}\n\t} );\n\n\tconst itemLikeElements = [];\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && itemLikeElementsMatcher.match( value.item ) ) {\n\t\t\tconst itemData = getListItemData( value.item );\n\n\t\t\titemLikeElements.push( {\n\t\t\t\telement: value.item,\n\t\t\t\tid: itemData.id,\n\t\t\t\torder: itemData.order,\n\t\t\t\tindent: itemData.indent\n\t\t\t} );\n\t\t}\n\t}\n\n\treturn itemLikeElements;\n}\n\n// Extracts list item style from the provided CSS.\n//\n// List item style is extracted from the CSS stylesheet. Each list with its specific style attribute\n// value (`mso-list:l1 level1 lfo1`) has its dedicated properties in a CSS stylesheet defined with a selector like:\n//\n// \t\t@list l1:level1 { ... }\n//\n// It contains `mso-level-number-format` property which defines list numbering/bullet style. If this property\n// is not defined it means default `decimal` numbering.\n//\n// Here CSS string representation is used as `mso-level-number-format` property is an invalid CSS property\n// and will be removed during CSS parsing.\n//\n// @param {Object} listLikeItem List-like item for which list style will be searched for. Usually\n// a result of `findAllItemLikeElements()` function.\n// @param {String} stylesString CSS stylesheet.\n// @returns {Object} result\n// @returns {String} result.type List type, could be `ul` or `ol`.\n// @returns {String|null} result.style List style, for example: `decimal`, `lower-roman`, etc. It is extracted\n// directly from Word stylesheet and adjusted to represent proper values for the CSS `list-style-type` property.\n// If it cannot be adjusted, the `null` value is returned.\nfunction detectListStyle( listLikeItem, stylesString ) {\n\tconst listStyleRegexp = new RegExp( `@list l${ listLikeItem.id }:level${ listLikeItem.indent }\\\\s*({[^}]*)`, 'gi' );\n\tconst listStyleTypeRegex = /mso-level-number-format:([^;]{0,100});/gi;\n\n\tconst listStyleMatch = listStyleRegexp.exec( stylesString );\n\n\tlet listStyleType = 'decimal'; // Decimal is default one.\n\tlet type = 'ol'; // <ol> is default list.\n\n\tif ( listStyleMatch && listStyleMatch[ 1 ] ) {\n\t\tconst listStyleTypeMatch = listStyleTypeRegex.exec( listStyleMatch[ 1 ] );\n\n\t\tif ( listStyleTypeMatch && listStyleTypeMatch[ 1 ] ) {\n\t\t\tlistStyleType = listStyleTypeMatch[ 1 ].trim();\n\t\t\ttype = listStyleType !== 'bullet' && listStyleType !== 'image' ? 'ol' : 'ul';\n\t\t}\n\n\t\t// Styles for the numbered lists are always defined in the Word CSS stylesheet.\n\t\t// Unordered lists MAY contain a value for the Word CSS definition `mso-level-text` but sometimes\n\t\t// this tag is missing. And because of that, we cannot depend on that. We need to predict the list style value\n\t\t// based on the list style marker element.\n\t\tif ( listStyleType === 'bullet' ) {\n\t\t\tconst bulletedStyle = findBulletedListStyle( listLikeItem.element );\n\n\t\t\tif ( bulletedStyle ) {\n\t\t\t\tlistStyleType = bulletedStyle;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttype,\n\t\tstyle: mapListStyleDefinition( listStyleType )\n\t};\n}\n\n// Tries to extract the `list-style-type` value based on the marker element for bulleted list.\n//\n// @param {module:engine/view/element~Element} element\n// @returns {module:engine/view/element~Element|null}\nfunction findBulletedListStyle( element ) {\n\tconst listMarkerElement = findListMarkerNode( element );\n\n\tif ( !listMarkerElement ) {\n\t\treturn null;\n\t}\n\n\tconst listMarker = listMarkerElement._data;\n\n\tif ( listMarker === 'o' ) {\n\t\treturn 'circle';\n\t} else if ( listMarker === '·' ) {\n\t\treturn 'disc';\n\t}\n\t// Word returns '§' instead of '■' for the square list style.\n\telse if ( listMarker === '§' ) {\n\t\treturn 'square';\n\t}\n\n\treturn null;\n}\n\n// Tries to find a text node that represents the marker element (list-style-type).\n//\n// @param {module:engine/view/element~Element} element\n// @returns {module:engine/view/text~Text|null}\nfunction findListMarkerNode( element ) {\n\t// If the first child is a text node, it is a value for the element.\n\tif ( element.getChild( 0 ).is( '$text' ) ) {\n\t\treturn null;\n\t}\n\n\tconst textNodeOrElement = element.getChild( 0 ).getChild( 0 );\n\n\tif ( textNodeOrElement.is( '$text' ) ) {\n\t\treturn textNodeOrElement;\n\t}\n\n\treturn textNodeOrElement.getChild( 0 );\n}\n\n// Parses the `list-style-type` value extracted directly from the Word CSS stylesheet and returns proper CSS definition.\n//\n// @param {String|null} value\n// @returns {String|null}\nfunction mapListStyleDefinition( value ) {\n\tswitch ( value ) {\n\t\tcase 'arabic-leading-zero':\n\t\t\treturn 'decimal-leading-zero';\n\t\tcase 'alpha-upper':\n\t\t\treturn 'upper-alpha';\n\t\tcase 'alpha-lower':\n\t\t\treturn 'lower-alpha';\n\t\tcase 'roman-upper':\n\t\t\treturn 'upper-roman';\n\t\tcase 'roman-lower':\n\t\t\treturn 'lower-roman';\n\t\tcase 'circle':\n\t\tcase 'disc':\n\t\tcase 'square':\n\t\t\treturn value;\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\n// Creates empty list of a given type and inserts it after a specified element.\n//\n// @param {Object} listStyle List style object which determines the type of newly created list.\n// Usually a result of `detectListStyle()` function.\n// @param {module:engine/view/element~Element} element Element after which list is inserted.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} Newly created list element.\n\nfunction insertNewEmptyList( listStyle, element, writer ) {\n\tconst parent = element.parent;\n\tconst list = writer.createElement( listStyle.type );\n\tconst position = parent.getChildIndex( element ) + 1;\n\n\twriter.insertChild( position, list, parent );\n\n\t// We do not support modifying the marker for a particular list item.\n\t// Set the value for the `list-style-type` property directly to the list container.\n\tif ( listStyle.style ) {\n\t\twriter.setStyle( 'list-style-type', listStyle.style, list );\n\t}\n\n\treturn list;\n}\n\n// Transforms a given element into a semantic list item. As the function operates on a provided\n// {module:engine/src/view/element~Element element} it will modify the view structure to which this element belongs.\n//\n// @param {module:engine/view/element~Element} element Element which will be transformed into a list item.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {module:engine/view/element~Element} New element to which the given one was transformed. It is\n// inserted in place of the old element (the reference to the old element is lost due to renaming).\nfunction transformElementIntoListItem( element, writer ) {\n\tremoveBulletElement( element, writer );\n\n\treturn writer.rename( 'li', element );\n}\n\n// Extracts list item information from Word specific list-like element style:\n//\n//\t\t`style=\"mso-list:l1 level1 lfo1\"`\n//\n// where:\n//\n//\t\t* `l1` is a list id (however it does not mean this is a continuous list - see #43),\n//\t\t* `level1` is a list item indentation level,\n//\t\t* `lfo1` is a list insertion order in a document.\n//\n// @param {module:engine/view/element~Element} element Element from which style data is extracted.\n// @returns {Object} result\n// @returns {Number} result.id Parent list id.\n// @returns {Number} result.order List item creation order.\n// @returns {Number} result.indent List item indentation level.\nfunction getListItemData( element ) {\n\tconst data = {};\n\tconst listStyle = element.getStyle( 'mso-list' );\n\n\tif ( listStyle ) {\n\t\tconst idMatch = listStyle.match( /(^|\\s{1,100})l(\\d+)/i );\n\t\tconst orderMatch = listStyle.match( /\\s{0,100}lfo(\\d+)/i );\n\t\tconst indentMatch = listStyle.match( /\\s{0,100}level(\\d+)/i );\n\n\t\tif ( idMatch && orderMatch && indentMatch ) {\n\t\t\tdata.id = idMatch[ 2 ];\n\t\t\tdata.order = orderMatch[ 1 ];\n\t\t\tdata.indent = indentMatch[ 1 ];\n\t\t}\n\t}\n\n\treturn data;\n}\n\n// Removes span with a numbering/bullet from a given element.\n//\n// @param {module:engine/view/element~Element} element\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeBulletElement( element, writer ) {\n\t// Matcher for finding `span` elements holding lists numbering/bullets.\n\tconst bulletMatcher = new Matcher( {\n\t\tname: 'span',\n\t\tstyles: {\n\t\t\t'mso-list': 'Ignore'\n\t\t}\n\t} );\n\n\tconst range = writer.createRangeIn( element );\n\n\tfor ( const value of range ) {\n\t\tif ( value.type === 'elementStart' && bulletMatcher.match( value.item ) ) {\n\t\t\twriter.remove( value.item );\n\t\t}\n\t}\n}\n\n// Whether the previous and current items belong to the same list. It is determined based on `item.id`\n// (extracted from `mso-list` style, see #getListItemData) and a previous sibling of the current item.\n//\n// However, it's quite easy to change the `id` attribute for nested lists in Word. It will break the list feature while pasting.\n// Let's check also the `indent` attribute. If the difference between those two elements is equal to 1, we can assume that\n// the `currentItem` is a beginning of the nested list because lists in CKEditor 5 always start with the `indent=0` attribute.\n// See: https://github.com/ckeditor/ckeditor5/issues/7805.\n//\n// @param {Object} previousItem\n// @param {Object} currentItem\n// @returns {Boolean}\nfunction isNewListNeeded( previousItem, currentItem ) {\n\tif ( !previousItem ) {\n\t\treturn true;\n\t}\n\n\tif ( previousItem.id !== currentItem.id ) {\n\t\t// See: https://github.com/ckeditor/ckeditor5/issues/7805.\n\t\t//\n\t\t// * List item 1.\n\t\t// - Nested list item 1.\n\t\tif ( currentItem.indent - previousItem.indent === 1 ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tconst previousSibling = currentItem.element.previousSibling;\n\n\tif ( !previousSibling ) {\n\t\treturn true;\n\t}\n\n\t// Even with the same id the list does not have to be continuous (#43).\n\treturn !isList( previousSibling );\n}\n\nfunction isList( element ) {\n\treturn element.is( 'element', 'ol' ) || element.is( 'element', 'ul' );\n}\n\n// Calculates the indentation difference between two given list items (based on the indent attribute\n// extracted from the `mso-list` style, see #getListItemData).\n//\n// @param {Object} previousItem\n// @param {Object} currentItem\n// @returns {Number}\nfunction getIndentationDifference( previousItem, currentItem ) {\n\treturn previousItem ? currentItem.indent - previousItem.indent : currentItem.indent - 1;\n}\n\n// Finds the parent list element (ul/ol) of a given list element with indentation level lower by a given value.\n//\n// @param {module:engine/view/element~Element} listElement List element from which to start looking for a parent list.\n// @param {Number} indentationDifference Indentation difference between lists.\n// @returns {module:engine/view/element~Element} Found list element with indentation level lower by a given value.\nfunction findParentListAtLevel( listElement, indentationDifference ) {\n\tconst ancestors = listElement.getAncestors( { parentFirst: true } );\n\n\tlet parentList = null;\n\tlet levelChange = 0;\n\n\tfor ( const ancestor of ancestors ) {\n\t\tif ( ancestor.name === 'ul' || ancestor.name === 'ol' ) {\n\t\t\tlevelChange++;\n\t\t}\n\n\t\tif ( levelChange === indentationDifference ) {\n\t\t\tparentList = ancestor;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn parentList;\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 paste-from-office/normalizers/googledocsnormalizer\n */\n\nimport { UpcastWriter } from 'ckeditor5/src/engine';\n\nimport removeBoldWrapper from '../filters/removeboldwrapper';\nimport { unwrapParagraphInListItem } from '../filters/list';\n\nconst googleDocsMatch = /id=(\"|')docs-internal-guid-[-0-9a-f]+(\"|')/i;\n\n/**\n * Normalizer for the content pasted from Google Docs.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class GoogleDocsNormalizer {\n\t/**\n\t * Creates a new `GoogleDocsNormalizer` instance.\n\t *\n\t * @param {module:engine/view/document~Document} document View document.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn googleDocsMatch.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst writer = new UpcastWriter( this.document );\n\n\t\tremoveBoldWrapper( data.content, writer );\n\t\tunwrapParagraphInListItem( data.content, writer );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/removeboldwrapper\n */\n\n/**\n * Removes `<b>` tag wrapper added by Google Docs to a copied content.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment element `data.content` obtained from clipboard\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n */\nexport default function removeBoldWrapper( documentFragment, writer ) {\n\tfor ( const child of documentFragment.getChildren() ) {\n\t\tif ( child.is( 'element', 'b' ) && child.getStyle( 'font-weight' ) === 'normal' ) {\n\t\t\tconst childIndex = documentFragment.getChildIndex( child );\n\n\t\t\twriter.remove( child );\n\t\t\twriter.insertChild( childIndex, child.getChildren(), documentFragment );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/space\n */\n\n/**\n * Replaces last space preceding elements closing tag with `&nbsp;`. Such operation prevents spaces from being removed\n * during further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n * This method also takes into account Word specific `<o:p></o:p>` empty tags.\n * Additionally multiline sequences of spaces and new lines between tags are removed (see #39 and #40).\n *\n * @param {String} htmlString HTML string in which spacing should be normalized.\n * @returns {String} Input HTML with spaces normalized.\n */\nexport function normalizeSpacing( htmlString ) {\n\t// Run normalizeSafariSpaceSpans() two times to cover nested spans.\n\treturn normalizeSafariSpaceSpans( normalizeSafariSpaceSpans( htmlString ) )\n\t\t// Remove all \\r\\n from \"spacerun spans\" so the last replace line doesn't strip all whitespaces.\n\t\t.replace( /(<span\\s+style=['\"]mso-spacerun:yes['\"]>[^\\S\\r\\n]*?)[\\r\\n]+([^\\S\\r\\n]*<\\/span>)/g, '$1$2' )\n\t\t.replace( /<span\\s+style=['\"]mso-spacerun:yes['\"]><\\/span>/g, '' )\n\t\t.replace( / <\\//g, '\\u00A0</' )\n\t\t.replace( / <o:p><\\/o:p>/g, '\\u00A0<o:p></o:p>' )\n\t\t// Remove <o:p> block filler from empty paragraph. Safari uses \\u00A0 instead of &nbsp;.\n\t\t.replace( /<o:p>(&nbsp;|\\u00A0)<\\/o:p>/g, '' )\n\t\t// Remove all whitespaces when they contain any \\r or \\n.\n\t\t.replace( />([^\\S\\r\\n]*[\\r\\n]\\s*)</g, '><' );\n}\n\n/**\n * Normalizes spacing in special Word `spacerun spans` (`<span style='mso-spacerun:yes'>\\s+</span>`) by replacing\n * all spaces with `&nbsp; ` pairs. This prevents spaces from being removed during further DOM/View processing\n * (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n *\n * @param {Document} htmlDocument Native `Document` object in which spacing should be normalized.\n */\nexport function normalizeSpacerunSpans( htmlDocument ) {\n\thtmlDocument.querySelectorAll( 'span[style*=spacerun]' ).forEach( el => {\n\t\tconst innerTextLength = el.innerText.length || 0;\n\n\t\tel.innerHTML = Array( innerTextLength + 1 ).join( '\\u00A0 ' ).substr( 0, innerTextLength );\n\t} );\n}\n\n// Normalizes specific spacing generated by Safari when content pasted from Word (`<span class=\"Apple-converted-space\"> </span>`)\n// by replacing all spaces sequences longer than 1 space with `&nbsp; ` pairs. This prevents spaces from being removed during\n// further DOM/View processing (see especially {@link module:engine/view/domconverter~DomConverter#_processDataFromDomText}).\n//\n// This function is similar to {@link module:clipboard/utils/normalizeclipboarddata normalizeClipboardData util} but uses\n// regular spaces / &nbsp; sequence for replacement.\n//\n// @param {String} htmlString HTML string in which spacing should be normalized\n// @returns {String} Input HTML with spaces normalized.\nfunction normalizeSafariSpaceSpans( htmlString ) {\n\treturn htmlString.replace( /<span(?: class=\"Apple-converted-space\"|)>(\\s+)<\\/span>/g, ( fullMatch, spaces ) => {\n\t\treturn spaces.length === 1 ? ' ' : Array( spaces.length + 1 ).join( '\\u00A0 ' ).substr( 0, spaces.length );\n\t} );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/filters/parse\n */\n\n/* globals DOMParser */\n\nimport { DomConverter, ViewDocument } from 'ckeditor5/src/engine';\n\nimport { normalizeSpacing, normalizeSpacerunSpans } from './space';\n\n/**\n * Parses provided HTML extracting contents of `<body>` and `<style>` tags.\n *\n * @param {String} htmlString HTML string to be parsed.\n * @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n * @returns {Object} result\n * @returns {module:engine/view/documentfragment~DocumentFragment} result.body Parsed body\n * content as a traversable structure.\n * @returns {String} result.bodyString Entire body content as a string.\n * @returns {Array.<CSSStyleSheet>} result.styles Array of native `CSSStyleSheet` objects, each representing\n * separate `style` tag from the source HTML.\n * @returns {String} result.stylesString All `style` tags contents combined in the order of occurrence into one string.\n */\nexport function parseHtml( htmlString, stylesProcessor ) {\n\tconst domParser = new DOMParser();\n\n\t// Remove Word specific \"if comments\" so content inside is not omitted by the parser.\n\thtmlString = htmlString.replace( /<!--\\[if gte vml 1]>/g, '' );\n\n\tconst normalizedHtml = normalizeSpacing( cleanContentAfterBody( htmlString ) );\n\n\t// Parse htmlString as native Document object.\n\tconst htmlDocument = domParser.parseFromString( normalizedHtml, 'text/html' );\n\n\tnormalizeSpacerunSpans( htmlDocument );\n\n\t// Get `innerHTML` first as transforming to View modifies the source document.\n\tconst bodyString = htmlDocument.body.innerHTML;\n\n\t// Transform document.body to View.\n\tconst bodyView = documentToView( htmlDocument, stylesProcessor );\n\n\t// Extract stylesheets.\n\tconst stylesObject = extractStyles( htmlDocument );\n\n\treturn {\n\t\tbody: bodyView,\n\t\tbodyString,\n\t\tstyles: stylesObject.styles,\n\t\tstylesString: stylesObject.stylesString\n\t};\n}\n\n// Transforms native `Document` object into {@link module:engine/view/documentfragment~DocumentFragment}.\n//\n// @param {Document} htmlDocument Native `Document` object to be transformed.\n// @param {module:engine/view/stylesmap~StylesProcessor} stylesProcessor\n// @returns {module:engine/view/documentfragment~DocumentFragment}\nfunction documentToView( htmlDocument, stylesProcessor ) {\n\tconst viewDocument = new ViewDocument( stylesProcessor );\n\tconst domConverter = new DomConverter( viewDocument, { blockFillerMode: 'nbsp' } );\n\tconst fragment = htmlDocument.createDocumentFragment();\n\tconst nodes = htmlDocument.body.childNodes;\n\n\twhile ( nodes.length > 0 ) {\n\t\tfragment.appendChild( nodes[ 0 ] );\n\t}\n\n\treturn domConverter.domToView( fragment );\n}\n\n// Extracts both `CSSStyleSheet` and string representation from all `style` elements available in a provided `htmlDocument`.\n//\n// @param {Document} htmlDocument Native `Document` object from which styles will be extracted.\n// @returns {Object} result\n// @returns {Array.<CSSStyleSheet>} result.styles Array of native `CSSStyleSheet` object, each representing\n// separate `style` tag from the source object.\n// @returns {String} result.stylesString All `style` tags contents combined in the order of occurrence as one string.\nfunction extractStyles( htmlDocument ) {\n\tconst styles = [];\n\tconst stylesString = [];\n\tconst styleTags = Array.from( htmlDocument.getElementsByTagName( 'style' ) );\n\n\tfor ( const style of styleTags ) {\n\t\tif ( style.sheet && style.sheet.cssRules && style.sheet.cssRules.length ) {\n\t\t\tstyles.push( style.sheet );\n\t\t\tstylesString.push( style.innerHTML );\n\t\t}\n\t}\n\n\treturn {\n\t\tstyles,\n\t\tstylesString: stylesString.join( ' ' )\n\t};\n}\n\n// Removes leftover content from between closing </body> and closing </html> tag:\n//\n// \t\t<html><body><p>Foo Bar</p></body><span>Fo</span></html> -> <html><body><p>Foo Bar</p></body></html>\n//\n// This function is used as specific browsers (Edge) add some random content after `body` tag when pasting from Word.\n// @param {String} htmlString The HTML string to be cleaned.\n// @returns {String} The HTML string with leftover content removed.\nfunction cleanContentAfterBody( htmlString ) {\n\tconst bodyCloseTag = '</body>';\n\tconst htmlCloseTag = '</html>';\n\n\tconst bodyCloseIndex = htmlString.indexOf( bodyCloseTag );\n\n\tif ( bodyCloseIndex < 0 ) {\n\t\treturn htmlString;\n\t}\n\n\tconst htmlCloseIndex = htmlString.indexOf( htmlCloseTag, bodyCloseIndex + bodyCloseTag.length );\n\n\treturn htmlString.substring( 0, bodyCloseIndex + bodyCloseTag.length ) +\n\t\t( htmlCloseIndex >= 0 ? htmlString.substring( htmlCloseIndex ) : '' );\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 paste-from-office/filters/image\n */\n\n/* globals btoa */\n\nimport { Matcher, UpcastWriter } from 'ckeditor5/src/engine';\n\n/**\n * Replaces source attribute of all `<img>` elements representing regular\n * images (not the Word shapes) with inlined base64 image representation extracted from RTF or Blob data.\n *\n * @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment on which transform images.\n * @param {String} rtfData The RTF data from which images representation will be used.\n */\nexport function replaceImagesSourceWithBase64( documentFragment, rtfData ) {\n\tif ( !documentFragment.childCount ) {\n\t\treturn;\n\t}\n\n\tconst upcastWriter = new UpcastWriter();\n\tconst shapesIds = findAllShapesIds( documentFragment, upcastWriter );\n\n\tremoveAllImgElementsRepresentingShapes( shapesIds, documentFragment, upcastWriter );\n\tremoveAllShapeElements( documentFragment, upcastWriter );\n\n\tconst images = findAllImageElementsWithLocalSource( documentFragment, upcastWriter );\n\n\tif ( images.length ) {\n\t\treplaceImagesFileSourceWithInlineRepresentation( images, extractImageDataFromRtf( rtfData ), upcastWriter );\n\t}\n}\n\n/**\n * Converts given HEX string to base64 representation.\n *\n * @protected\n * @param {String} hexString The HEX string to be converted.\n * @returns {String} Base64 representation of a given HEX string.\n */\nexport function _convertHexToBase64( hexString ) {\n\treturn btoa( hexString.match( /\\w{2}/g ).map( char => {\n\t\treturn String.fromCharCode( parseInt( char, 16 ) );\n\t} ).join( '' ) );\n}\n\n// Finds all shapes (`<v:*>...</v:*>`) ids. Shapes can represent images (canvas)\n// or Word shapes (which does not have RTF or Blob representation).\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment\n// from which to extract shape ids.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Array.<String>} Array of shape ids.\nfunction findAllShapesIds( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new Matcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapesIds = [];\n\n\tfor ( const value of range ) {\n\t\tconst el = value.item;\n\t\tconst prevSiblingName = el.previousSibling && el.previousSibling.name || null;\n\n\t\t// If shape element have 'o:gfxdata' attribute and is not directly before `<v:shapetype>` element it means it represent Word shape.\n\t\tif ( shapeElementsMatcher.match( el ) && el.getAttribute( 'o:gfxdata' ) && prevSiblingName !== 'v:shapetype' ) {\n\t\t\tshapesIds.push( value.item.getAttribute( 'id' ) );\n\t\t}\n\t}\n\n\treturn shapesIds;\n}\n\n// Removes all `<img>` elements which represents Word shapes and not regular images.\n//\n// @param {Array.<String>} shapesIds Shape ids which will be checked against `<img>` elements.\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove `<img>` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllImgElementsRepresentingShapes( shapesIds, documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new Matcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tconst el = value.item;\n\t\t\tconst shapes = el.getAttribute( 'v:shapes' ) ? el.getAttribute( 'v:shapes' ).split( ' ' ) : [];\n\n\t\t\tif ( shapes.length && shapes.every( shape => shapesIds.indexOf( shape ) > -1 ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t// Shapes may also have empty source while content is paste in some browsers (Safari).\n\t\t\t} else if ( !el.getAttribute( 'src' ) ) {\n\t\t\t\timgs.push( el );\n\t\t\t}\n\t\t}\n\t}\n\n\tfor ( const img of imgs ) {\n\t\twriter.remove( img );\n\t}\n}\n\n// Removes all shape elements (`<v:*>...</v:*>`) so they do not pollute the output structure.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment from which to remove shape elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction removeAllShapeElements( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst shapeElementsMatcher = new Matcher( {\n\t\tname: /v:(.+)/\n\t} );\n\n\tconst shapes = [];\n\n\tfor ( const value of range ) {\n\t\tif ( shapeElementsMatcher.match( value.item ) ) {\n\t\t\tshapes.push( value.item );\n\t\t}\n\t}\n\n\tfor ( const shape of shapes ) {\n\t\twriter.remove( shape );\n\t}\n}\n\n// Finds all `<img>` elements in a given document fragment which have source pointing to local `file://` resource.\n//\n// @param {module:engine/view/documentfragment~DocumentFragment} documentFragment Document fragment in which to look for `<img>` elements.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\n// @returns {Object} result All found images grouped by source type.\n// @returns {Array.<module:engine/view/element~Element>} result.file Array of found `<img>` elements with `file://` source.\n// @returns {Array.<module:engine/view/element~Element>} result.blob Array of found `<img>` elements with `blob:` source.\nfunction findAllImageElementsWithLocalSource( documentFragment, writer ) {\n\tconst range = writer.createRangeIn( documentFragment );\n\n\tconst imageElementsMatcher = new Matcher( {\n\t\tname: 'img'\n\t} );\n\n\tconst imgs = [];\n\n\tfor ( const value of range ) {\n\t\tif ( imageElementsMatcher.match( value.item ) ) {\n\t\t\tif ( value.item.getAttribute( 'src' ).startsWith( 'file://' ) ) {\n\t\t\t\timgs.push( value.item );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn imgs;\n}\n\n// Extracts all images HEX representations from a given RTF data.\n//\n// @param {String} rtfData The RTF data from which to extract images HEX representation.\n// @returns {Array.<Object>} Array of found HEX representations. Each array item is an object containing:\n//\n// \t\t* {String} hex Image representation in HEX format.\n// \t\t* {string} type Type of image, `image/png` or `image/jpeg`.\nfunction extractImageDataFromRtf( rtfData ) {\n\tif ( !rtfData ) {\n\t\treturn [];\n\t}\n\n\tconst regexPictureHeader = /{\\\\pict[\\s\\S]+?\\\\bliptag-?\\d+(\\\\blipupi-?\\d+)?({\\\\\\*\\\\blipuid\\s?[\\da-fA-F]+)?[\\s}]*?/;\n\tconst regexPicture = new RegExp( '(?:(' + regexPictureHeader.source + '))([\\\\da-fA-F\\\\s]+)\\\\}', 'g' );\n\tconst images = rtfData.match( regexPicture );\n\tconst result = [];\n\n\tif ( images ) {\n\t\tfor ( const image of images ) {\n\t\t\tlet imageType = false;\n\n\t\t\tif ( image.includes( '\\\\pngblip' ) ) {\n\t\t\t\timageType = 'image/png';\n\t\t\t} else if ( image.includes( '\\\\jpegblip' ) ) {\n\t\t\t\timageType = 'image/jpeg';\n\t\t\t}\n\n\t\t\tif ( imageType ) {\n\t\t\t\tresult.push( {\n\t\t\t\t\thex: image.replace( regexPictureHeader, '' ).replace( /[^\\da-fA-F]/g, '' ),\n\t\t\t\t\ttype: imageType\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// Replaces `src` attribute value of all given images with the corresponding base64 image representation.\n//\n// @param {Array.<module:engine/view/element~Element>} imageElements Array of image elements which will have its source replaced.\n// @param {Array.<Object>} imagesHexSources Array of images hex sources (usually the result of `extractImageDataFromRtf()` function).\n// The array should be the same length as `imageElements` parameter.\n// @param {module:engine/view/upcastwriter~UpcastWriter} writer\nfunction replaceImagesFileSourceWithInlineRepresentation( imageElements, imagesHexSources, writer ) {\n\t// Assume there is an equal amount of image elements and images HEX sources so they can be matched accordingly based on existing order.\n\tif ( imageElements.length === imagesHexSources.length ) {\n\t\tfor ( let i = 0; i < imageElements.length; i++ ) {\n\t\t\tconst newSrc = `data:${ imagesHexSources[ i ].type };base64,${ _convertHexToBase64( imagesHexSources[ i ].hex ) }`;\n\t\t\twriter.setAttribute( 'src', newSrc, imageElements[ i ] );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/normalizers/mswordnormalizer\n */\n\nimport { parseHtml } from '../filters/parse';\nimport { transformListItemLikeElementsIntoLists } from '../filters/list';\nimport { replaceImagesSourceWithBase64 } from '../filters/image';\n\nconst msWordMatch1 = /<meta\\s*name=\"?generator\"?\\s*content=\"?microsoft\\s*word\\s*\\d+\"?\\/?>/i;\nconst msWordMatch2 = /xmlns:o=\"urn:schemas-microsoft-com/i;\n\n/**\n * Normalizer for the content pasted from Microsoft Word.\n *\n * @implements module:paste-from-office/normalizer~Normalizer\n */\nexport default class MSWordNormalizer {\n\t/**\n\t * Creates a new `MSWordNormalizer` instance.\n\t *\n\t * @param {module:engine/view/document~Document} document View document.\n\t */\n\tconstructor( document ) {\n\t\t/**\n\t\t * @readonly\n\t\t * @type {module:engine/view/document~Document}\n\t\t */\n\t\tthis.document = document;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tisActive( htmlString ) {\n\t\treturn msWordMatch1.test( htmlString ) || msWordMatch2.test( htmlString );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute( data ) {\n\t\tconst { body, stylesString } = parseHtml( data.dataTransfer.getData( 'text/html' ), this.document.stylesProcessor );\n\n\t\ttransformListItemLikeElementsIntoLists( body, stylesString );\n\t\treplaceImagesSourceWithBase64( body, data.dataTransfer.getData( 'text/rtf' ) );\n\n\t\tdata.content = body;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/utils/common\n */\n\n/**\n * A common method to update the numeric value. If a value is the default one, it will be unset.\n *\n * @param {String} key An attribute key.\n * @param {*} value The new attribute value.\n * @param {module:engine/model/item~Item} item A model item on which the attribute will be set.\n * @param {module:engine/model/writer~Writer} writer\n * @param {*} defaultValue The default attribute value. If a value is lower or equal, it will be unset.\n */\nexport function updateNumericAttribute( key, value, item, writer, defaultValue = 1 ) {\n\tif ( value > defaultValue ) {\n\t\twriter.setAttribute( key, value, item );\n\t} else {\n\t\twriter.removeAttribute( key, item );\n\t}\n}\n\n/**\n * A common method to create an empty table cell. It creates a proper model structure as a table cell must have at least one block inside.\n *\n * @param {module:engine/model/writer~Writer} writer The model writer.\n * @param {module:engine/model/position~Position} insertPosition The position at which the table cell should be inserted.\n * @param {Object} attributes The element attributes.\n * @returns {module:engine/model/element~Element} Created table cell.\n */\nexport function createEmptyTableCell( writer, insertPosition, attributes = {} ) {\n\tconst tableCell = writer.createElement( 'tableCell', attributes );\n\n\twriter.insertElement( 'paragraph', tableCell );\n\twriter.insert( tableCell, insertPosition );\n\n\treturn tableCell;\n}\n\n/**\n * Checks if a table cell belongs to the heading column section.\n *\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @param {module:engine/model/element~Element} tableCell\n * @returns {Boolean}\n */\nexport function isHeadingColumnCell( tableUtils, tableCell ) {\n\tconst table = tableCell.parent.parent;\n\tconst headingColumns = parseInt( table.getAttribute( 'headingColumns' ) || 0 );\n\tconst { column } = tableUtils.getCellLocation( tableCell );\n\n\treturn !!headingColumns && column < headingColumns;\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 table/converters/upcasttable\n */\n\nimport { createEmptyTableCell } from '../utils/common';\n\n/**\n * View table element to model table element conversion helper.\n *\n * This conversion helper converts the table element as well as table rows.\n *\n * @returns {Function} Conversion helper.\n */\nexport default function upcastTable() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:table', ( evt, data, conversionApi ) => {\n\t\t\tconst viewTable = data.viewItem;\n\n\t\t\t// When element was already consumed then skip it.\n\t\t\tif ( !conversionApi.consumable.test( viewTable, { name: true } ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst { rows, headingRows, headingColumns } = scanTable( viewTable );\n\n\t\t\t// Only set attributes if values is greater then 0.\n\t\t\tconst attributes = {};\n\n\t\t\tif ( headingColumns ) {\n\t\t\t\tattributes.headingColumns = headingColumns;\n\t\t\t}\n\n\t\t\tif ( headingRows ) {\n\t\t\t\tattributes.headingRows = headingRows;\n\t\t\t}\n\n\t\t\tconst table = conversionApi.writer.createElement( 'table', attributes );\n\n\t\t\tif ( !conversionApi.safeInsert( table, data.modelCursor ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconversionApi.consumable.consume( viewTable, { name: true } );\n\n\t\t\t// Upcast table rows in proper order (heading rows first).\n\t\t\trows.forEach( row => conversionApi.convertItem( row, conversionApi.writer.createPositionAt( table, 'end' ) ) );\n\n\t\t\t// Create one row and one table cell for empty table.\n\t\t\tif ( table.isEmpty ) {\n\t\t\t\tconst row = conversionApi.writer.createElement( 'tableRow' );\n\t\t\t\tconversionApi.writer.insert( row, conversionApi.writer.createPositionAt( table, 'end' ) );\n\n\t\t\t\tcreateEmptyTableCell( conversionApi.writer, conversionApi.writer.createPositionAt( row, 'end' ) );\n\t\t\t}\n\n\t\t\tconversionApi.updateConversionResult( table, data );\n\t\t} );\n\t};\n}\n\n/**\n * A conversion helper that skips empty <tr> elements from upcasting at the beginning of the table.\n *\n * An empty row is considered a table model error but when handling clipboard data there could be rows that contain only row-spanned cells\n * and empty TR-s are used to maintain the table structure (also {@link module:table/tablewalker~TableWalker} assumes that there are only\n * rows that have related `tableRow` elements).\n *\n * *Note:* Only the first empty rows are removed because they have no meaning and it solves the issue\n * of an improper table with all empty rows.\n *\n * @returns {Function} Conversion helper.\n */\nexport function skipEmptyTableRow() {\n\treturn dispatcher => {\n\t\tdispatcher.on( 'element:tr', ( evt, data ) => {\n\t\t\tif ( data.viewItem.isEmpty && data.modelCursor.index == 0 ) {\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t};\n}\n\n/**\n * A converter that ensures an empty paragraph is inserted in a table cell if no other content was converted.\n *\n * @returns {Function} Conversion helper.\n */\nexport function ensureParagraphInTableCell( elementName ) {\n\treturn dispatcher => {\n\t\tdispatcher.on( `element:${ elementName }`, ( evt, data, conversionApi ) => {\n\t\t\t// The default converter will create a model range on converted table cell.\n\t\t\tif ( !data.modelRange ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Ensure a paragraph in the model for empty table cells for converted table cells.\n\t\t\tif ( data.viewItem.isEmpty ) {\n\t\t\t\tconst tableCell = data.modelRange.start.nodeAfter;\n\t\t\t\tconst modelCursor = conversionApi.writer.createPositionAt( tableCell, 0 );\n\n\t\t\t\tconversionApi.writer.insertElement( 'paragraph', modelCursor );\n\t\t\t}\n\t\t}, { priority: 'low' } );\n\t};\n}\n\n// Scans table rows and extracts required metadata from the table:\n//\n// headingRows - The number of rows that go as table headers.\n// headingColumns - The maximum number of row headings.\n// rows - Sorted `<tr>` elements as they should go into the model - ie. if `<thead>` is inserted after `<tbody>` in the view.\n//\n// @param {module:engine/view/element~Element} viewTable\n// @returns {{headingRows, headingColumns, rows}}\nfunction scanTable( viewTable ) {\n\tconst tableMeta = {\n\t\theadingRows: 0,\n\t\theadingColumns: 0\n\t};\n\n\t// The `<tbody>` and `<thead>` sections in the DOM do not have to be in order `<thead>` -> `<tbody>` and there might be more than one\n\t// of them.\n\t// As the model does not have these sections, rows from different sections must be sorted.\n\t// For example, below is a valid HTML table:\n\t//\n\t//\t\t<table>\n\t//\t\t\t<tbody><tr><td>2</td></tr></tbody>\n\t//\t\t\t<thead><tr><td>1</td></tr></thead>\n\t//\t\t\t<tbody><tr><td>3</td></tr></tbody>\n\t//\t\t</table>\n\t//\n\t// But browsers will render rows in order as: 1 as the heading and 2 and 3 as the body.\n\tconst headRows = [];\n\tconst bodyRows = [];\n\n\t// Currently the editor does not support more then one <thead> section.\n\t// Only the first <thead> from the view will be used as a heading row and the others will be converted to body rows.\n\tlet firstTheadElement;\n\n\tfor ( const tableChild of Array.from( viewTable.getChildren() ) ) {\n\t\t// Only `<thead>`, `<tbody>` & `<tfoot>` from allowed table children can have `<tr>`s.\n\t\t// The else is for future purposes (mainly `<caption>`).\n\t\tif ( tableChild.name === 'tbody' || tableChild.name === 'thead' || tableChild.name === 'tfoot' ) {\n\t\t\t// Save the first `<thead>` in the table as table header - all other ones will be converted to table body rows.\n\t\t\tif ( tableChild.name === 'thead' && !firstTheadElement ) {\n\t\t\t\tfirstTheadElement = tableChild;\n\t\t\t}\n\n\t\t\t// There might be some extra empty text nodes between the `<tr>`s.\n\t\t\t// Make sure further code operates on `tr`s only. (#145)\n\t\t\tconst trs = Array.from( tableChild.getChildren() ).filter( el => el.is( 'element', 'tr' ) );\n\n\t\t\tfor ( const tr of trs ) {\n\t\t\t\t// This <tr> is a child of a first <thead> element.\n\t\t\t\tif ( tr.parent.name === 'thead' && tr.parent === firstTheadElement ) {\n\t\t\t\t\ttableMeta.headingRows++;\n\t\t\t\t\theadRows.push( tr );\n\t\t\t\t} else {\n\t\t\t\t\tbodyRows.push( tr );\n\t\t\t\t\t// For other rows check how many column headings this row has.\n\n\t\t\t\t\tconst headingCols = scanRowForHeadingColumns( tr, tableMeta, firstTheadElement );\n\n\t\t\t\t\tif ( headingCols > tableMeta.headingColumns ) {\n\t\t\t\t\t\ttableMeta.headingColumns = headingCols;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\ttableMeta.rows = [ ...headRows, ...bodyRows ];\n\n\treturn tableMeta;\n}\n\n// Scans a `<tr>` element and its children for metadata:\n// - For heading row:\n// - Adds this row to either the heading or the body rows.\n// - Updates the number of heading rows.\n// - For body rows:\n// - Calculates the number of column headings.\n//\n// @param {module:engine/view/element~Element} tr\n// @returns {Number}\nfunction scanRowForHeadingColumns( tr ) {\n\tlet headingColumns = 0;\n\tlet index = 0;\n\n\t// Filter out empty text nodes from tr children.\n\tconst children = Array.from( tr.getChildren() )\n\t\t.filter( child => child.name === 'th' || child.name === 'td' );\n\n\t// Count starting adjacent <th> elements of a <tr>.\n\twhile ( index < children.length && children[ index ].name === 'th' ) {\n\t\tconst th = children[ index ];\n\n\t\t// Adjust columns calculation by the number of spanned columns.\n\t\tconst colspan = parseInt( th.getAttribute( 'colspan' ) || 1 );\n\n\t\theadingColumns = headingColumns + colspan;\n\t\tindex++;\n\t}\n\n\treturn headingColumns;\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 table/tablewalker\n */\n\n// @if CK_DEBUG // import { CKEditorError } from 'ckeditor5/src/utils';\n\n/**\n * The table iterator class. It allows to iterate over table cells. For each cell the iterator yields\n * {@link module:table/tablewalker~TableSlot} with proper table cell attributes.\n */\nexport default class TableWalker {\n\t/**\n\t * Creates an instance of the table walker.\n\t *\n\t * The table walker iterates internally by traversing the table from row index = 0 and column index = 0.\n\t * It walks row by row and column by column in order to output values defined in the constructor.\n\t * By default it will output only the locations that are occupied by a cell. To include also spanned rows and columns,\n\t * pass the `includeAllSlots` option to the constructor.\n\t *\n\t * The most important values of the iterator are column and row indexes of a cell.\n\t *\n\t * See {@link module:table/tablewalker~TableSlot} what values are returned by the table walker.\n\t *\n\t * To iterate over a given row:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { startRow: 1, endRow: 2 } );\n\t *\n\t *\t\tfor ( const tableSlot of tableWalker ) {\n\t *\t\t\tconsole.log( 'A cell at row', tableSlot.row, 'and column', tableSlot.column );\n\t *\t\t}\n\t *\n\t * For instance the code above for the following table:\n\t *\n\t *\t\t+----+----+----+----+----+----+\n\t *\t\t| 00 | 02 | 03 | 04 | 05 |\n\t *\t\t| +----+----+----+----+\n\t *\t\t| | 12 | 14 | 15 |\n\t *\t\t| +----+----+----+ +\n\t *\t\t| | 22 | |\n\t *\t\t|----+----+----+----+----+ +\n\t *\t\t| 30 | 31 | 32 | 33 | 34 | |\n\t *\t\t+----+----+----+----+----+----+\n\t *\n\t * will log in the console:\n\t *\n\t *\t\t'A cell at row 1 and column 2'\n\t *\t\t'A cell at row 1 and column 4'\n\t *\t\t'A cell at row 1 and column 5'\n\t *\t\t'A cell at row 2 and column 2'\n\t *\n\t * To also iterate over spanned cells:\n\t *\n\t *\t\tconst tableWalker = new TableWalker( table, { row: 1, includeAllSlots: true } );\n\t *\n\t *\t\tfor ( const tableSlot of tableWalker ) {\n\t *\t\t\tconsole.log( 'Slot at', tableSlot.row, 'x', tableSlot.column, ':', tableSlot.isAnchor ? 'is anchored' : 'is spanned' );\n\t *\t\t}\n\t *\n\t * will log in the console for the table from the previous example:\n\t *\n\t *\t\t'Cell at 1 x 0 : is spanned'\n\t *\t\t'Cell at 1 x 1 : is spanned'\n\t *\t\t'Cell at 1 x 2 : is anchored'\n\t *\t\t'Cell at 1 x 3 : is spanned'\n\t *\t\t'Cell at 1 x 4 : is anchored'\n\t *\t\t'Cell at 1 x 5 : is anchored'\n\t *\n\t * **Note**: Option `row` is a shortcut that sets both `startRow` and `endRow` to the same row.\n\t * (Use either `row` or `startRow` and `endRow` but never together). Similarly the `column` option sets both `startColumn`\n\t * and `endColumn` to the same column (Use either `column` or `startColumn` and `endColumn` but never together).\n\t *\n\t * @constructor\n\t * @param {module:engine/model/element~Element} table A table over which the walker iterates.\n\t * @param {Object} [options={}] An object with configuration.\n\t * @param {Number} [options.row] A row index for which this iterator will output cells.\n\t * Can't be used together with `startRow` and `endRow`.\n\t * @param {Number} [options.startRow=0] A row index from which this iterator should start. Can't be used together with `row`.\n\t * @param {Number} [options.endRow] A row index at which this iterator should end. Can't be used together with `row`.\n\t * @param {Number} [options.column] A column index for which this iterator will output cells.\n\t * Can't be used together with `startColumn` and `endColumn`.\n\t * @param {Number} [options.startColumn=0] A column index from which this iterator should start. Can't be used together with `column`.\n\t * @param {Number} [options.endColumn] A column index at which this iterator should end. Can't be used together with `column`.\n\t * @param {Boolean} [options.includeAllSlots=false] Also return values for spanned cells.\n\t */\n\tconstructor( table, options = {} ) {\n\t\t/**\n\t\t * The walker's table element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t * @protected\n\t\t */\n\t\tthis._table = table;\n\n\t\t/**\n\t\t * A row index from which this iterator will start.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._startRow = options.row !== undefined ? options.row : options.startRow || 0;\n\n\t\t/**\n\t\t * A row index at which this iterator will end.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._endRow = options.row !== undefined ? options.row : options.endRow;\n\n\t\t/**\n\t\t * If set, the table walker will only output cells from a given column and following ones or cells that overlap them.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._startColumn = options.column !== undefined ? options.column : options.startColumn || 0;\n\n\t\t/**\n\t\t * If set, the table walker will only output cells up to a given column.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._endColumn = options.column !== undefined ? options.column : options.endColumn;\n\n\t\t/**\n\t\t * Enables output of spanned cells that are normally not yielded.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean}\n\t\t * @private\n\t\t */\n\t\tthis._includeAllSlots = !!options.includeAllSlots;\n\n\t\t/**\n\t\t * Row indexes to skip from the iteration.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Set<Number>}\n\t\t * @private\n\t\t */\n\t\tthis._skipRows = new Set();\n\n\t\t/**\n\t\t * The current row index.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._row = 0;\n\n\t\t/**\n\t\t * The current column index.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._column = 0;\n\n\t\t/**\n\t\t * The cell index in a parent row. For spanned cells when {@link #_includeAllSlots} is set to `true`,\n\t\t * this represents the index of the next table cell.\n\t\t *\n\t\t * @member {Number}\n\t\t * @protected\n\t\t */\n\t\tthis._cellIndex = 0;\n\n\t\t/**\n\t\t * Holds a map of spanned cells in a table.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Map.<Number, Map.<Number, Object>>}\n\t\t * @private\n\t\t */\n\t\tthis._spannedCells = new Map();\n\n\t\t/**\n\t\t * Index of the next column where a cell is anchored.\n\t\t *\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._nextCellAtColumn = -1;\n\t}\n\n\t/**\n\t * Iterable interface.\n\t *\n\t * @returns {Iterable.<module:table/tablewalker~TableSlot>}\n\t */\n\t[ Symbol.iterator ]() {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Gets the next table walker's value.\n\t *\n\t * @returns {module:table/tablewalker~TableSlot} The next table walker's value.\n\t */\n\tnext() {\n\t\tconst row = this._table.getChild( this._row );\n\n\t\t// Iterator is done when there's no row (table ended) or the row is after `endRow` limit.\n\t\tif ( !row || this._isOverEndRow() ) {\n\t\t\treturn { done: true };\n\t\t}\n\n\t\tif ( this._isOverEndColumn() ) {\n\t\t\treturn this._advanceToNextRow();\n\t\t}\n\n\t\tlet outValue = null;\n\n\t\tconst spanData = this._getSpanned();\n\n\t\tif ( spanData ) {\n\t\t\tif ( this._includeAllSlots && !this._shouldSkipSlot() ) {\n\t\t\t\toutValue = this._formatOutValue( spanData.cell, spanData.row, spanData.column );\n\t\t\t}\n\t\t} else {\n\t\t\tconst cell = row.getChild( this._cellIndex );\n\n\t\t\tif ( !cell ) {\n\t\t\t\t// If there are no more cells left in row advance to the next row.\n\t\t\t\treturn this._advanceToNextRow();\n\t\t\t}\n\n\t\t\tconst colspan = parseInt( cell.getAttribute( 'colspan' ) || 1 );\n\t\t\tconst rowspan = parseInt( cell.getAttribute( 'rowspan' ) || 1 );\n\n\t\t\t// Record this cell spans if it's not 1x1 cell.\n\t\t\tif ( colspan > 1 || rowspan > 1 ) {\n\t\t\t\tthis._recordSpans( cell, rowspan, colspan );\n\t\t\t}\n\n\t\t\tif ( !this._shouldSkipSlot() ) {\n\t\t\t\toutValue = this._formatOutValue( cell );\n\t\t\t}\n\n\t\t\tthis._nextCellAtColumn = this._column + colspan;\n\t\t}\n\n\t\t// Advance to the next column before returning value.\n\t\tthis._column++;\n\n\t\tif ( this._column == this._nextCellAtColumn ) {\n\t\t\tthis._cellIndex++;\n\t\t}\n\n\t\t// The current value will be returned only if current row and column are not skipped.\n\t\treturn outValue || this.next();\n\t}\n\n\t/**\n\t * Marks a row to skip in the next iteration. It will also skip cells from the current row if there are any cells from the current row\n\t * to output.\n\t *\n\t * @param {Number} row The row index to skip.\n\t */\n\tskipRow( row ) {\n\t\tthis._skipRows.add( row );\n\t}\n\n\t/**\n\t * Advances internal cursor to the next row.\n\t *\n\t * @private\n\t * @returns {module:table/tablewalker~TableSlot}\n\t */\n\t_advanceToNextRow() {\n\t\tthis._row++;\n\t\tthis._column = 0;\n\t\tthis._cellIndex = 0;\n\t\tthis._nextCellAtColumn = -1;\n\n\t\treturn this.next();\n\t}\n\n\t/**\n\t * Checks if the current row is over {@link #_endRow}.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_isOverEndRow() {\n\t\t// If #_endRow is defined skip all rows after it.\n\t\treturn this._endRow !== undefined && this._row > this._endRow;\n\t}\n\n\t/**\n\t * Checks if the current cell is over {@link #_endColumn}\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_isOverEndColumn() {\n\t\t// If #_endColumn is defined skip all cells after it.\n\t\treturn this._endColumn !== undefined && this._column > this._endColumn;\n\t}\n\n\t/**\n\t * A common method for formatting the iterator's output value.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} cell The table cell to output.\n\t * @param {Number} [anchorRow] The row index of a cell anchor slot.\n\t * @param {Number} [anchorColumn] The column index of a cell anchor slot.\n\t * @returns {{done: Boolean, value: {cell: *, row: Number, column: *, rowspan: *, colspan: *, cellIndex: Number}}}\n\t */\n\t_formatOutValue( cell, anchorRow = this._row, anchorColumn = this._column ) {\n\t\treturn {\n\t\t\tdone: false,\n\t\t\tvalue: new TableSlot( this, cell, anchorRow, anchorColumn )\n\t\t};\n\t}\n\n\t/**\n\t * Checks if the current slot should be skipped.\n\t *\n\t * @private\n\t * @returns {Boolean}\n\t */\n\t_shouldSkipSlot() {\n\t\tconst rowIsMarkedAsSkipped = this._skipRows.has( this._row );\n\t\tconst rowIsBeforeStartRow = this._row < this._startRow;\n\n\t\tconst columnIsBeforeStartColumn = this._column < this._startColumn;\n\t\tconst columnIsAfterEndColumn = this._endColumn !== undefined && this._column > this._endColumn;\n\n\t\treturn rowIsMarkedAsSkipped || rowIsBeforeStartRow || columnIsBeforeStartColumn || columnIsAfterEndColumn;\n\t}\n\n\t/**\n\t * Returns the cell element that is spanned over the current cell location.\n\t *\n\t * @private\n\t * @returns {module:engine/model/element~Element}\n\t */\n\t_getSpanned() {\n\t\tconst rowMap = this._spannedCells.get( this._row );\n\n\t\t// No spans for given row.\n\t\tif ( !rowMap ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// If spans for given rows has entry for column it means that this location if spanned by other cell.\n\t\treturn rowMap.get( this._column ) || null;\n\t}\n\n\t/**\n\t * Updates spanned cells map relative to the current cell location and its span dimensions.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} cell A cell that is spanned.\n\t * @param {Number} rowspan Cell height.\n\t * @param {Number} colspan Cell width.\n\t */\n\t_recordSpans( cell, rowspan, colspan ) {\n\t\tconst data = {\n\t\t\tcell,\n\t\t\trow: this._row,\n\t\t\tcolumn: this._column\n\t\t};\n\n\t\tfor ( let rowToUpdate = this._row; rowToUpdate < this._row + rowspan; rowToUpdate++ ) {\n\t\t\tfor ( let columnToUpdate = this._column; columnToUpdate < this._column + colspan; columnToUpdate++ ) {\n\t\t\t\tif ( rowToUpdate != this._row || columnToUpdate != this._column ) {\n\t\t\t\t\tthis._markSpannedCell( rowToUpdate, columnToUpdate, data );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Marks the cell location as spanned by another cell.\n\t *\n\t * @private\n\t * @param {Number} row The row index of the cell location.\n\t * @param {Number} column The column index of the cell location.\n\t * @param {Object} data A spanned cell details (cell element, anchor row and column).\n\t */\n\t_markSpannedCell( row, column, data ) {\n\t\tif ( !this._spannedCells.has( row ) ) {\n\t\t\tthis._spannedCells.set( row, new Map() );\n\t\t}\n\n\t\tconst rowSpans = this._spannedCells.get( row );\n\n\t\trowSpans.set( column, data );\n\t}\n}\n\n/**\n * An object returned by {@link module:table/tablewalker~TableWalker} when traversing table cells.\n */\nclass TableSlot {\n\t/**\n\t * Creates an instance of the table walker value.\n\t *\n\t * @protected\n\t * @param {module:table/tablewalker~TableWalker} tableWalker The table walker instance.\n\t * @param {module:engine/model/element~Element} cell The current table cell.\n\t * @param {Number} anchorRow The row index of a cell anchor slot.\n\t * @param {Number} anchorColumn The column index of a cell anchor slot.\n\t */\n\tconstructor( tableWalker, cell, anchorRow, anchorColumn ) {\n\t\t/**\n\t\t * The current table cell.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t */\n\t\tthis.cell = cell;\n\n\t\t/**\n\t\t * The row index of a table slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.row = tableWalker._row;\n\n\t\t/**\n\t\t * The column index of a table slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.column = tableWalker._column;\n\n\t\t/**\n\t\t * The row index of a cell anchor slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cellAnchorRow = anchorRow;\n\n\t\t/**\n\t\t * The column index of a cell anchor slot.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t */\n\t\tthis.cellAnchorColumn = anchorColumn;\n\n\t\t/**\n\t\t * The index of the current cell in the parent row.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Number}\n\t\t * @private\n\t\t */\n\t\tthis._cellIndex = tableWalker._cellIndex;\n\n\t\t/**\n\t\t * The table element.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:engine/model/element~Element}\n\t\t * @private\n\t\t */\n\t\tthis._table = tableWalker._table;\n\t}\n\n\t/**\n\t * Whether the cell is anchored in the current slot.\n\t *\n\t * @readonly\n\t * @returns {Boolean}\n\t */\n\tget isAnchor() {\n\t\treturn this.row === this.cellAnchorRow && this.column === this.cellAnchorColumn;\n\t}\n\n\t/**\n\t * The width of a cell defined by a `colspan` attribute. If the model attribute is not present, it is set to `1`.\n\t *\n\t * @readonly\n\t * @returns {Number}\n\t */\n\tget cellWidth() {\n\t\treturn parseInt( this.cell.getAttribute( 'colspan' ) || 1 );\n\t}\n\n\t/**\n\t * The height of a cell defined by a `rowspan` attribute. If the model attribute is not present, it is set to `1`.\n\t *\n\t * @readonly\n\t * @returns {Number}\n\t */\n\tget cellHeight() {\n\t\treturn parseInt( this.cell.getAttribute( 'rowspan' ) || 1 );\n\t}\n\n\t/**\n\t * Returns the {@link module:engine/model/position~Position} before the table slot.\n\t *\n\t * @returns {module:engine/model/position~Position}\n\t */\n\tgetPositionBefore() {\n\t\tconst model = this._table.root.document.model;\n\n\t\treturn model.createPositionAt( this._table.getChild( this.row ), this._cellIndex );\n\t}\n\n\t// @if CK_DEBUG // get isSpanned() { throwMissingGetterError( 'isSpanned' ); }\n\t// @if CK_DEBUG // get colspan() { throwMissingGetterError( 'colspan' ); }\n\t// @if CK_DEBUG // get rowspan() { throwMissingGetterError( 'rowspan' ); }\n\t// @if CK_DEBUG // get cellIndex() { throwMissingGetterError( 'cellIndex' ); }\n}\n\n/**\n * This `TableSlot`'s getter (property) was removed in CKEditor 5 v20.0.0.\n *\n * Check out the new `TableWalker`'s API in the documentation.\n *\n * @error tableslot-getter-removed\n * @param {String} getterName\n */\n\n// @if CK_DEBUG // function throwMissingGetterError( getterName ) {\n// @if CK_DEBUG //\t\tthrow new CKEditorError( 'tableslot-getter-removed', this, {\n// @if CK_DEBUG //\t\t\tgetterName\n// @if CK_DEBUG //\t\t} );\n// @if CK_DEBUG // }\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 table/converters/downcast\n */\n\nimport TableWalker from './../tablewalker';\nimport { setHighlightHandling, toWidget, toWidgetEditable } from 'ckeditor5/src/widget';\nimport { toArray } from 'ckeditor5/src/utils';\n\n/**\n * Model table element to view table element conversion helper.\n *\n * This conversion helper creates the whole table element with child elements.\n *\n * @param {Object} options\n * @param {Boolean} options.asWidget If set to `true`, the downcast conversion will produce a widget.\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertTable( options = {} ) {\n\treturn dispatcher => dispatcher.on( 'insert:table', ( evt, data, conversionApi ) => {\n\t\tconst table = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( table, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Consume attributes if present to not fire attribute change downcast\n\t\tconversionApi.consumable.consume( table, 'attribute:headingRows:table' );\n\t\tconversionApi.consumable.consume( table, 'attribute:headingColumns:table' );\n\n\t\tconst asWidget = options && options.asWidget;\n\n\t\tconst figureElement = conversionApi.writer.createContainerElement( 'figure', { class: 'table' } );\n\t\tconst tableElement = conversionApi.writer.createContainerElement( 'table' );\n\t\tconversionApi.writer.insert( conversionApi.writer.createPositionAt( figureElement, 0 ), tableElement );\n\n\t\tlet tableWidget;\n\n\t\tif ( asWidget ) {\n\t\t\ttableWidget = toTableWidget( figureElement, conversionApi.writer );\n\t\t}\n\n\t\tconst tableWalker = new TableWalker( table );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// Cache for created table rows.\n\t\tconst viewRows = new Map();\n\n\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\tconst { row, cell } = tableSlot;\n\n\t\t\tconst tableRow = table.getChild( row );\n\t\t\tconst trElement = viewRows.get( row ) || createTr( tableElement, tableRow, row, tableAttributes, conversionApi );\n\t\t\tviewRows.set( row, trElement );\n\n\t\t\t// Consume table cell - it will be always consumed as we convert whole table at once.\n\t\t\tconversionApi.consumable.consume( cell, 'insert' );\n\n\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, 'end' );\n\n\t\t\tcreateViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, options );\n\t\t}\n\n\t\t// Insert empty TR elements if there are any rows without anchored cells. Since the model is always normalized\n\t\t// this can happen only in the document fragment that only part of the table is down-casted.\n\t\tfor ( const tableRow of table.getChildren() ) {\n\t\t\tconst rowIndex = tableRow.index;\n\n\t\t\tif ( !viewRows.has( rowIndex ) ) {\n\t\t\t\tviewRows.set( rowIndex, createTr( tableElement, tableRow, rowIndex, tableAttributes, conversionApi ) );\n\t\t\t}\n\t\t}\n\n\t\tconst viewPosition = conversionApi.mapper.toViewPosition( data.range.start );\n\n\t\tconversionApi.mapper.bindElements( table, asWidget ? tableWidget : figureElement );\n\t\tconversionApi.writer.insert( viewPosition, asWidget ? tableWidget : figureElement );\n\t} );\n}\n\n/**\n * Model row element to view `<tr>` element conversion helper.\n *\n * This conversion helper creates the whole `<tr>` element with child elements.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertRow() {\n\treturn dispatcher => dispatcher.on( 'insert:tableRow', ( evt, data, conversionApi ) => {\n\t\tconst tableRow = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( tableRow, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst table = tableRow.parent;\n\n\t\tconst figureElement = conversionApi.mapper.toViewElement( table );\n\t\tconst tableElement = getViewTable( figureElement );\n\n\t\tconst row = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { row } );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// Cache for created table rows.\n\t\tconst viewRows = new Map();\n\n\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\tconst trElement = viewRows.get( row ) || createTr( tableElement, tableRow, row, tableAttributes, conversionApi );\n\t\t\tviewRows.set( row, trElement );\n\n\t\t\t// Consume table cell - it will be always consumed as we convert whole row at once.\n\t\t\tconversionApi.consumable.consume( tableSlot.cell, 'insert' );\n\n\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, 'end' );\n\n\t\t\tcreateViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, { asWidget: true } );\n\t\t}\n\t} );\n}\n\n/**\n * Model table cell element to view `<td>` or `<th>` element conversion helper.\n *\n * This conversion helper will create proper `<th>` elements for table cells that are in the heading section (heading row or column)\n * and `<td>` otherwise.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastInsertCell() {\n\treturn dispatcher => dispatcher.on( 'insert:tableCell', ( evt, data, conversionApi ) => {\n\t\tconst tableCell = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( tableCell, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\t\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { row: rowIndex } );\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\t// We need to iterate over a table in order to get proper row & column values from a walker\n\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\tif ( tableSlot.cell === tableCell ) {\n\t\t\t\tconst trElement = conversionApi.mapper.toViewElement( tableRow );\n\t\t\t\tconst insertPosition = conversionApi.writer.createPositionAt( trElement, tableRow.getChildIndex( tableCell ) );\n\n\t\t\t\tcreateViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, { asWidget: true } );\n\n\t\t\t\t// No need to iterate further.\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper that acts on heading column table attribute change.\n *\n * Depending on changed attributes this converter will rename `<td` to `<th>` elements or vice versa depending on the cell column index.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastTableHeadingColumnsChange() {\n\treturn dispatcher => dispatcher.on( 'attribute:headingColumns:table', ( evt, data, conversionApi ) => {\n\t\tconst table = data.item;\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableAttributes = {\n\t\t\theadingRows: table.getAttribute( 'headingRows' ) || 0,\n\t\t\theadingColumns: table.getAttribute( 'headingColumns' ) || 0\n\t\t};\n\n\t\tconst oldColumns = data.attributeOldValue;\n\t\tconst newColumns = data.attributeNewValue;\n\n\t\tconst lastColumnToCheck = ( oldColumns > newColumns ? oldColumns : newColumns ) - 1;\n\n\t\tfor ( const tableSlot of new TableWalker( table, { endColumn: lastColumnToCheck } ) ) {\n\t\t\trenameViewTableCellIfRequired( tableSlot, tableAttributes, conversionApi );\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper that acts on a removed row.\n *\n * @returns {Function} Conversion helper.\n */\nexport function downcastRemoveRow() {\n\treturn dispatcher => dispatcher.on( 'remove:tableRow', ( evt, data, conversionApi ) => {\n\t\t// Prevent default remove converter.\n\t\tevt.stop();\n\t\tconst viewWriter = conversionApi.writer;\n\t\tconst mapper = conversionApi.mapper;\n\n\t\tconst viewStart = mapper.toViewPosition( data.position ).getLastMatchingPosition( value => !value.item.is( 'element', 'tr' ) );\n\t\tconst viewItem = viewStart.nodeAfter;\n\t\tconst tableSection = viewItem.parent;\n\t\tconst viewTable = tableSection.parent;\n\n\t\t// Remove associated <tr> from the view.\n\t\tconst removeRange = viewWriter.createRangeOn( viewItem );\n\t\tconst removed = viewWriter.remove( removeRange );\n\n\t\tfor ( const child of viewWriter.createRangeIn( removed ).getItems() ) {\n\t\t\tmapper.unbindViewElement( child );\n\t\t}\n\n\t\t// Cleanup: Ensure that thead & tbody sections are removed if left empty after removing rows. See #6437, #6391.\n\t\tremoveTableSectionIfEmpty( 'thead', viewTable, conversionApi );\n\t\tremoveTableSectionIfEmpty( 'tbody', viewTable, conversionApi );\n\t}, { priority: 'higher' } );\n}\n\n/**\n * Overrides paragraph inside table cell conversion.\n *\n * This converter:\n * * should be used to override default paragraph conversion in the editing view.\n * * It will only convert <paragraph> placed directly inside <tableCell>.\n * * For a single paragraph without attributes it returns `<span>` to simulate data table.\n * * For all other cases it returns `<p>` element.\n *\n * @param {module:engine/model/element~Element} modelElement\n * @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n * @returns {module:engine/view/containerelement~ContainerElement|undefined}\n */\nexport function convertParagraphInTableCell( modelElement, conversionApi ) {\n\tconst { writer } = conversionApi;\n\n\tif ( !modelElement.parent.is( 'element', 'tableCell' ) ) {\n\t\treturn;\n\t}\n\n\tif ( isSingleParagraphWithoutAttributes( modelElement ) ) {\n\t\t// Use display:inline-block to force Chrome/Safari to limit text mutations to this element.\n\t\t// See #6062.\n\t\treturn writer.createContainerElement( 'span', { style: 'display:inline-block' } );\n\t} else {\n\t\treturn writer.createContainerElement( 'p' );\n\t}\n}\n\n/**\n * Checks if given model `<paragraph>` is an only child of a parent (`<tableCell>`) and if it has any attribute set.\n *\n * The paragraph should be converted in the editing view to:\n *\n * * If returned `true` - to a `<span style=\"display:inline-block\">`\n * * If returned `false` - to a `<p>`\n *\n * @param {module:engine/model/element~Element} modelElement\n * @returns {Boolean}\n */\nexport function isSingleParagraphWithoutAttributes( modelElement ) {\n\tconst tableCell = modelElement.parent;\n\n\tconst isSingleParagraph = tableCell.childCount === 1;\n\n\treturn isSingleParagraph && !hasAnyAttribute( modelElement );\n}\n\n// Converts a given {@link module:engine/view/element~Element} to a table widget:\n// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the table widget element.\n// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n//\n// @param {module:engine/view/element~Element} viewElement\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n// @param {String} label The element's label. It will be concatenated with the table `alt` attribute if one is present.\n// @returns {module:engine/view/element~Element}\nfunction toTableWidget( viewElement, writer ) {\n\twriter.setCustomProperty( 'table', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { hasSelectionHandle: true } );\n}\n\n// Renames an existing table cell in the view to a given element name.\n//\n// **Note** This method will not do anything if a view table cell has not been converted yet.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} desiredCellElementName\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction renameViewTableCell( tableCell, desiredCellElementName, conversionApi ) {\n\tconst viewWriter = conversionApi.writer;\n\tconst viewCell = conversionApi.mapper.toViewElement( tableCell );\n\n\tconst editable = viewWriter.createEditableElement( desiredCellElementName, viewCell.getAttributes() );\n\tconst renamedCell = toWidgetEditable( editable, viewWriter );\n\n\tsetHighlightHandling(\n\t\trenamedCell,\n\t\tviewWriter,\n\t\t( element, descriptor, writer ) => writer.addClass( toArray( descriptor.classes ), element ),\n\t\t( element, descriptor, writer ) => writer.removeClass( toArray( descriptor.classes ), element )\n\t);\n\n\tviewWriter.insert( viewWriter.createPositionAfter( viewCell ), renamedCell );\n\tviewWriter.move( viewWriter.createRangeIn( viewCell ), viewWriter.createPositionAt( renamedCell, 0 ) );\n\tviewWriter.remove( viewWriter.createRangeOn( viewCell ) );\n\n\tconversionApi.mapper.unbindViewElement( viewCell );\n\tconversionApi.mapper.bindElements( tableCell, renamedCell );\n}\n\n// Renames a table cell element in the view according to its location in the table.\n//\n// @param {module:table/tablewalker~TableSlot} tableSlot\n// @param {{headingColumns, headingRows}} tableAttributes\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction renameViewTableCellIfRequired( tableSlot, tableAttributes, conversionApi ) {\n\tconst { cell } = tableSlot;\n\n\t// Check whether current columnIndex is overlapped by table cells from previous rows.\n\tconst desiredCellElementName = getCellElementName( tableSlot, tableAttributes );\n\n\tconst viewCell = conversionApi.mapper.toViewElement( cell );\n\n\t// If in single change we're converting attribute changes and inserting cell the table cell might not be inserted into view\n\t// because of child conversion is done after parent.\n\tif ( viewCell && viewCell.name !== desiredCellElementName ) {\n\t\trenameViewTableCell( cell, desiredCellElementName, conversionApi );\n\t}\n}\n\n// Creates a table cell element in the view.\n//\n// @param {module:table/tablewalker~TableSlot} tableSlot\n// @param {module:engine/view/position~Position} insertPosition\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction createViewTableCellElement( tableSlot, tableAttributes, insertPosition, conversionApi, options ) {\n\tconst asWidget = options && options.asWidget;\n\tconst cellElementName = getCellElementName( tableSlot, tableAttributes );\n\n\tconst cellElement = asWidget ?\n\t\ttoWidgetEditable( conversionApi.writer.createEditableElement( cellElementName ), conversionApi.writer ) :\n\t\tconversionApi.writer.createContainerElement( cellElementName );\n\n\tif ( asWidget ) {\n\t\tsetHighlightHandling(\n\t\t\tcellElement,\n\t\t\tconversionApi.writer,\n\t\t\t( element, descriptor, writer ) => writer.addClass( toArray( descriptor.classes ), element ),\n\t\t\t( element, descriptor, writer ) => writer.removeClass( toArray( descriptor.classes ), element )\n\t\t);\n\t}\n\n\tconst tableCell = tableSlot.cell;\n\n\tconst firstChild = tableCell.getChild( 0 );\n\tconst isSingleParagraph = tableCell.childCount === 1 && firstChild.name === 'paragraph';\n\n\tconversionApi.writer.insert( insertPosition, cellElement );\n\n\tconversionApi.mapper.bindElements( tableCell, cellElement );\n\n\t// Additional requirement for data pipeline to have backward compatible data tables.\n\tif ( !asWidget && isSingleParagraph && !hasAnyAttribute( firstChild ) ) {\n\t\tconst innerParagraph = tableCell.getChild( 0 );\n\n\t\tconversionApi.consumable.consume( innerParagraph, 'insert' );\n\n\t\tconversionApi.mapper.bindElements( innerParagraph, cellElement );\n\t}\n}\n\n// Creates a `<tr>` view element.\n//\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/model/element~Element} tableRow\n// @param {Number} rowIndex\n// @param {{headingColumns, headingRows}} tableAttributes\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/element~Element}\nfunction createTr( tableElement, tableRow, rowIndex, tableAttributes, conversionApi ) {\n\t// Will always consume since we're converting <tableRow> element from a parent <table>.\n\tconversionApi.consumable.consume( tableRow, 'insert' );\n\n\tconst trElement = tableRow.isEmpty ?\n\t\tconversionApi.writer.createEmptyElement( 'tr' ) :\n\t\tconversionApi.writer.createContainerElement( 'tr' );\n\n\tconversionApi.mapper.bindElements( tableRow, trElement );\n\n\tconst headingRows = tableAttributes.headingRows;\n\tconst tableSection = getOrCreateTableSection( getSectionName( rowIndex, tableAttributes ), tableElement, conversionApi );\n\n\tconst offset = headingRows > 0 && rowIndex >= headingRows ? rowIndex - headingRows : rowIndex;\n\tconst position = conversionApi.writer.createPositionAt( tableSection, offset );\n\n\tconversionApi.writer.insert( position, trElement );\n\n\treturn trElement;\n}\n\n// Returns `th` for heading cells and `td` for other cells for the current table walker value.\n//\n// @param {module:table/tablewalker~TableSlot} tableSlot\n// @param {{headingColumns, headingRows}} tableAttributes\n// @returns {String}\nfunction getCellElementName( tableSlot, tableAttributes ) {\n\tconst { row, column } = tableSlot;\n\tconst { headingColumns, headingRows } = tableAttributes;\n\n\t// Column heading are all tableCells in the first `columnHeading` rows.\n\tconst isColumnHeading = headingRows && headingRows > row;\n\n\t// So a whole row gets <th> element.\n\tif ( isColumnHeading ) {\n\t\treturn 'th';\n\t}\n\n\t// Row heading are tableCells which columnIndex is lower then headingColumns.\n\tconst isRowHeading = headingColumns && headingColumns > column;\n\n\treturn isRowHeading ? 'th' : 'td';\n}\n\n// Returns the table section name for the current table walker value.\n//\n// @param {Number} row\n// @param {{headingColumns, headingRows}} tableAttributes\n// @returns {String}\nfunction getSectionName( row, tableAttributes ) {\n\treturn row < tableAttributes.headingRows ? 'thead' : 'tbody';\n}\n\n// Creates or returns an existing `<tbody>` or `<thead>` element with caching.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} viewTable\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @param {Object} cachedTableSection An object that stores cached elements.\n// @returns {module:engine/view/containerelement~ContainerElement}\nfunction getOrCreateTableSection( sectionName, viewTable, conversionApi ) {\n\tconst viewTableSection = getExistingTableSectionElement( sectionName, viewTable );\n\n\treturn viewTableSection ? viewTableSection : createTableSection( sectionName, viewTable, conversionApi );\n}\n\n// Finds an existing `<tbody>` or `<thead>` element or returns undefined.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction getExistingTableSectionElement( sectionName, tableElement ) {\n\tfor ( const tableSection of tableElement.getChildren() ) {\n\t\tif ( tableSection.name == sectionName ) {\n\t\t\treturn tableSection;\n\t\t}\n\t}\n}\n\n// Creates a table section at the end of the table.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/containerelement~ContainerElement}\nfunction createTableSection( sectionName, tableElement, conversionApi ) {\n\tconst tableChildElement = conversionApi.writer.createContainerElement( sectionName );\n\n\tconst insertPosition = conversionApi.writer.createPositionAt( tableElement, sectionName == 'tbody' ? 'end' : 0 );\n\n\tconversionApi.writer.insert( insertPosition, tableChildElement );\n\n\treturn tableChildElement;\n}\n\n// Removes an existing `<tbody>` or `<thead>` element if it is empty.\n//\n// @param {String} sectionName\n// @param {module:engine/view/element~Element} tableElement\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\nfunction removeTableSectionIfEmpty( sectionName, tableElement, conversionApi ) {\n\tconst tableSection = getExistingTableSectionElement( sectionName, tableElement );\n\n\tif ( tableSection && tableSection.childCount === 0 ) {\n\t\tconversionApi.writer.remove( conversionApi.writer.createRangeOn( tableSection ) );\n\t}\n}\n\n// Finds a '<table>' element inside the `<figure>` widget.\n//\n// @param {module:engine/view/element~Element} viewFigure\nfunction getViewTable( viewFigure ) {\n\tfor ( const child of viewFigure.getChildren() ) {\n\t\tif ( child.name === 'table' ) {\n\t\t\treturn child;\n\t\t}\n\t}\n}\n\n// Checks if an element has any attributes set.\n//\n// @param {module:engine/model/element~Element element\n// @returns {Boolean}\nfunction hasAnyAttribute( element ) {\n\treturn !![ ...element.getAttributeKeys() ].length;\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 table/commands/inserttablecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { findOptimalInsertionPosition, checkSelectionOnObject } from 'ckeditor5/src/widget';\n\n/**\n * The insert table command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTable'` editor command.\n *\n * To insert a table at the current selection, execute the command and specify the dimensions:\n *\n *\t\teditor.execute( 'insertTable', { rows: 20, columns: 5 } );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertTableCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst schema = model.schema;\n\n\t\tthis.isEnabled = isAllowedInParent( selection, schema ) &&\n\t\t\t!checkSelectionOnObject( selection, schema );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Inserts a table with the given number of rows and columns into the editor.\n\t *\n\t * @param {Object} options\n\t * @param {Number} [options.rows=2] The number of rows to create in the inserted table.\n\t * @param {Number} [options.columns=2] The number of columns to create in the inserted table.\n\t * @param {Number} [options.headingRows=0] The number of heading rows.\n\t * @param {Number} [options.headingColumns=0] The number of heading columns.\n\t * @fires execute\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tconst insertPosition = findOptimalInsertionPosition( selection, model );\n\n\t\tmodel.change( writer => {\n\t\t\tconst table = tableUtils.createTable( writer, options );\n\n\t\t\tmodel.insertContent( table, insertPosition );\n\n\t\t\twriter.setSelection( writer.createPositionAt( table.getNodeByPath( [ 0, 0, 0 ] ), 0 ) );\n\t\t} );\n\t}\n}\n\n// Checks if the table is allowed in the parent.\n//\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// @param {module:engine/model/schema~Schema} schema\n// @returns {Boolean}\nfunction isAllowedInParent( selection, schema ) {\n\tconst positionParent = selection.getFirstPosition().parent;\n\tconst validParent = positionParent === positionParent.root ? positionParent : positionParent.parent;\n\n\treturn schema.checkChild( validParent, 'table' );\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 table/utils/selection\n */\n\nimport TableWalker from '../tablewalker';\n\n/**\n * Returns all model table cells that are fully selected (from the outside)\n * within the provided model selection's ranges.\n *\n * To obtain the cells selected from the inside, use\n * {@link module:table/utils/selection~getTableCellsContainingSelection}.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getSelectedTableCells( selection ) {\n\tconst cells = [];\n\n\tfor ( const range of sortRanges( selection.getRanges() ) ) {\n\t\tconst element = range.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\tcells.push( element );\n\t\t}\n\t}\n\n\treturn cells;\n}\n\n/**\n * Returns all model table cells that the provided model selection's ranges\n * {@link module:engine/model/range~Range#start} inside.\n *\n * To obtain the cells selected from the outside, use\n * {@link module:table/utils/selection~getSelectedTableCells}.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getTableCellsContainingSelection( selection ) {\n\tconst cells = [];\n\n\tfor ( const range of selection.getRanges() ) {\n\t\tconst cellWithSelection = range.start.findAncestor( 'tableCell' );\n\n\t\tif ( cellWithSelection ) {\n\t\t\tcells.push( cellWithSelection );\n\t\t}\n\t}\n\n\treturn cells;\n}\n\n/**\n * Returns all model table cells that are either completely selected\n * by selection ranges or host selection range\n * {@link module:engine/model/range~Range#start start positions} inside them.\n *\n * Combines {@link module:table/utils/selection~getTableCellsContainingSelection} and\n * {@link module:table/utils/selection~getSelectedTableCells}.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {Array.<module:engine/model/element~Element>}\n */\nexport function getSelectionAffectedTableCells( selection ) {\n\tconst selectedCells = getSelectedTableCells( selection );\n\n\tif ( selectedCells.length ) {\n\t\treturn selectedCells;\n\t}\n\n\treturn getTableCellsContainingSelection( selection );\n}\n\n/**\n * Returns an object with the `first` and `last` row index contained in the given `tableCells`.\n *\n *\t\tconst selectedTableCells = getSelectedTableCells( editor.model.document.selection );\n *\n *\t\tconst { first, last } = getRowIndexes( selectedTableCells );\n *\n *\t\tconsole.log( `Selected rows: ${ first } to ${ last }` );\n *\n * @param {Array.<module:engine/model/element~Element>} tableCells\n * @returns {Object} Returns an object with the `first` and `last` table row indexes.\n */\nexport function getRowIndexes( tableCells ) {\n\tconst indexes = tableCells.map( cell => cell.parent.index );\n\n\treturn getFirstLastIndexesObject( indexes );\n}\n\n/**\n * Returns an object with the `first` and `last` column index contained in the given `tableCells`.\n *\n *\t\tconst selectedTableCells = getSelectedTableCells( editor.model.document.selection );\n *\n *\t\tconst { first, last } = getColumnIndexes( selectedTableCells );\n *\n *\t\tconsole.log( `Selected columns: ${ first } to ${ last }` );\n *\n * @param {Array.<module:engine/model/element~Element>} tableCells\n * @returns {Object} Returns an object with the `first` and `last` table column indexes.\n */\nexport function getColumnIndexes( tableCells ) {\n\tconst table = tableCells[ 0 ].findAncestor( 'table' );\n\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\tconst indexes = tableMap\n\t\t.filter( entry => tableCells.includes( entry.cell ) )\n\t\t.map( entry => entry.column );\n\n\treturn getFirstLastIndexesObject( indexes );\n}\n\n/**\n * Checks if the selection contains cells that do not exceed rectangular selection.\n *\n * In a table below:\n *\n *\t\t┌───┬───┬───┬───┐\n *\t\t│ a │ b │ c │ d │\n *\t\t├───┴───┼───┤ │\n *\t\t│ e │ f │ │\n *\t\t│ ├───┼───┤\n *\t\t│ │ g │ h │\n *\t\t└───────┴───┴───┘\n *\n * Valid selections are these which create a solid rectangle (without gaps), such as:\n * - a, b (two horizontal cells)\n * - c, f (two vertical cells)\n * - a, b, e (cell \"e\" spans over four cells)\n * - c, d, f (cell d spans over a cell in the row below)\n *\n * While an invalid selection would be:\n * - a, c (the unselected cell \"b\" creates a gap)\n * - f, g, h (cell \"d\" spans over a cell from the row of \"f\" cell - thus creates a gap)\n *\n * @param {Array.<module:engine/model/element~Element>} selectedTableCells\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @returns {Boolean}\n */\nexport function isSelectionRectangular( selectedTableCells, tableUtils ) {\n\tif ( selectedTableCells.length < 2 || !areCellInTheSameTableSection( selectedTableCells ) ) {\n\t\treturn false;\n\t}\n\n\t// A valid selection is a fully occupied rectangle composed of table cells.\n\t// Below we will calculate the area of a selected table cells and the area of valid selection.\n\t// The area of a valid selection is defined by top-left and bottom-right cells.\n\tconst rows = new Set();\n\tconst columns = new Set();\n\n\tlet areaOfSelectedCells = 0;\n\n\tfor ( const tableCell of selectedTableCells ) {\n\t\tconst { row, column } = tableUtils.getCellLocation( tableCell );\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\t// Record row & column indexes of current cell.\n\t\trows.add( row );\n\t\tcolumns.add( column );\n\n\t\t// For cells that spans over multiple rows add also the last row that this cell spans over.\n\t\tif ( rowspan > 1 ) {\n\t\t\trows.add( row + rowspan - 1 );\n\t\t}\n\n\t\t// For cells that spans over multiple columns add also the last column that this cell spans over.\n\t\tif ( colspan > 1 ) {\n\t\t\tcolumns.add( column + colspan - 1 );\n\t\t}\n\n\t\tareaOfSelectedCells += ( rowspan * colspan );\n\t}\n\n\t// We can only merge table cells that are in adjacent rows...\n\tconst areaOfValidSelection = getBiggestRectangleArea( rows, columns );\n\n\treturn areaOfValidSelection == areaOfSelectedCells;\n}\n\n/**\n * Returns array of sorted ranges.\n *\n * @param {Iterable.<module:engine/model/range~Range>} ranges\n * @return {Array.<module:engine/model/range~Range>}\n */\nexport function sortRanges( ranges ) {\n\treturn Array.from( ranges ).sort( compareRangeOrder );\n}\n\n// Helper method to get an object with `first` and `last` indexes from an unsorted array of indexes.\nfunction getFirstLastIndexesObject( indexes ) {\n\tconst allIndexesSorted = indexes.sort( ( indexA, indexB ) => indexA - indexB );\n\n\tconst first = allIndexesSorted[ 0 ];\n\tconst last = allIndexesSorted[ allIndexesSorted.length - 1 ];\n\n\treturn { first, last };\n}\n\nfunction compareRangeOrder( rangeA, rangeB ) {\n\t// Since table cell ranges are disjoint, it's enough to check their start positions.\n\tconst posA = rangeA.start;\n\tconst posB = rangeB.start;\n\n\t// Checking for equal position (returning 0) is not needed because this would be either:\n\t// a. Intersecting range (not allowed by model)\n\t// b. Collapsed range on the same position (allowed by model but should not happen).\n\treturn posA.isBefore( posB ) ? -1 : 1;\n}\n\n// Calculates the area of a maximum rectangle that can span over the provided row & column indexes.\n//\n// @param {Array.<Number>} rows\n// @param {Array.<Number>} columns\n// @returns {Number}\nfunction getBiggestRectangleArea( rows, columns ) {\n\tconst rowsIndexes = Array.from( rows.values() );\n\tconst columnIndexes = Array.from( columns.values() );\n\n\tconst lastRow = Math.max( ...rowsIndexes );\n\tconst firstRow = Math.min( ...rowsIndexes );\n\tconst lastColumn = Math.max( ...columnIndexes );\n\tconst firstColumn = Math.min( ...columnIndexes );\n\n\treturn ( lastRow - firstRow + 1 ) * ( lastColumn - firstColumn + 1 );\n}\n\n// Checks if the selection does not mix a header (column or row) with other cells.\n//\n// For instance, in the table below valid selections consist of cells with the same letter only.\n// So, a-a (same heading row and column) or d-d (body cells) are valid while c-d or a-b are not.\n//\n//\t\t header columns\n//\t\t ↓ ↓\n//\t\t┌───┬───┬───┬───┐\n//\t\t│ a │ a │ b │ b │ ← header row\n//\t\t├───┼───┼───┼───┤\n//\t\t│ c │ c │ d │ d │\n//\t\t├───┼───┼───┼───┤\n//\t\t│ c │ c │ d │ d │\n//\t\t└───┴───┴───┴───┘\nfunction areCellInTheSameTableSection( tableCells ) {\n\tconst table = tableCells[ 0 ].findAncestor( 'table' );\n\n\tconst rowIndexes = getRowIndexes( tableCells );\n\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\n\t// Calculating row indexes is a bit cheaper so if this check fails we can't merge.\n\tif ( !areIndexesInSameSection( rowIndexes, headingRows ) ) {\n\t\treturn false;\n\t}\n\n\tconst headingColumns = parseInt( table.getAttribute( 'headingColumns' ) || 0 );\n\tconst columnIndexes = getColumnIndexes( tableCells );\n\n\t// Similarly cells must be in same column section.\n\treturn areIndexesInSameSection( columnIndexes, headingColumns );\n}\n\n// Unified check if table rows/columns indexes are in the same heading/body section.\nfunction areIndexesInSameSection( { first, last }, headingSectionSize ) {\n\tconst firstCellIsInHeading = first < headingSectionSize;\n\tconst lastCellIsInHeading = last < headingSectionSize;\n\n\treturn firstCellIsInHeading === lastCellIsInHeading;\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 table/commands/insertrowcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The insert row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTableRowBelow'` and\n * `'insertTableRowAbove'` editor commands.\n *\n * To insert a row below the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableRowBelow' );\n *\n * To insert a row above the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableRowAbove' );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertRowCommand extends Command {\n\t/**\n\t * Creates a new `InsertRowCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} [options.order=\"below\"] The order of insertion relative to the row in which the caret is located.\n\t * Possible values: `\"above\"` and `\"below\"`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The order of insertion relative to the row in which the caret is located.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:table/commands/insertrowcommand~InsertRowCommand#order\n\t\t */\n\t\tthis.order = options.order || 'below';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst tableParent = selection.getFirstPosition().findAncestor( 'table' );\n\n\t\tthis.isEnabled = !!tableParent;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #order} value, it inserts a row `'below'` or `'above'` the row in which selection is set.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst tableUtils = editor.plugins.get( 'TableUtils' );\n\t\tconst insertAbove = this.order === 'above';\n\n\t\tconst affectedTableCells = getSelectionAffectedTableCells( selection );\n\t\tconst rowIndexes = getRowIndexes( affectedTableCells );\n\n\t\tconst row = insertAbove ? rowIndexes.first : rowIndexes.last;\n\t\tconst table = affectedTableCells[ 0 ].findAncestor( 'table' );\n\n\t\ttableUtils.insertRows( table, { at: insertAbove ? row : row + 1, copyStructureFromAbove: !insertAbove } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/insertcolumncommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The insert column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'insertTableColumnLeft'` and\n * `'insertTableColumnRight'` editor commands.\n *\n * To insert a column to the left of the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableColumnLeft' );\n *\n * To insert a column to the right of the selected cell, execute the following command:\n *\n *\t\teditor.execute( 'insertTableColumnRight' );\n *\n * @extends module:core/command~Command\n */\nexport default class InsertColumnCommand extends Command {\n\t/**\n\t * Creates a new `InsertColumnCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} [options.order=\"right\"] The order of insertion relative to the column in which the caret is located.\n\t * Possible values: `\"left\"` and `\"right\"`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The order of insertion relative to the column in which the caret is located.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} module:table/commands/insertcolumncommand~InsertColumnCommand#order\n\t\t */\n\t\tthis.order = options.order || 'right';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst tableParent = selection.getFirstPosition().findAncestor( 'table' );\n\n\t\tthis.isEnabled = !!tableParent;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #order} value, it inserts a column to the `'left'` or `'right'` of the column\n\t * in which the selection is set.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst tableUtils = editor.plugins.get( 'TableUtils' );\n\t\tconst insertBefore = this.order === 'left';\n\n\t\tconst affectedTableCells = getSelectionAffectedTableCells( selection );\n\t\tconst columnIndexes = getColumnIndexes( affectedTableCells );\n\n\t\tconst column = insertBefore ? columnIndexes.first : columnIndexes.last;\n\t\tconst table = affectedTableCells[ 0 ].findAncestor( 'table' );\n\n\t\ttableUtils.insertColumns( table, { columns: 1, at: insertBefore ? column : column + 1 } );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/splitcellcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The split cell command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'splitTableCellVertically'`\n * and `'splitTableCellHorizontally'` editor commands.\n *\n * You can split any cell vertically or horizontally by executing this command. For example, to split the selected table cell vertically:\n *\n *\t\teditor.execute( 'splitTableCellVertically' );\n *\n * @extends module:core/command~Command\n */\nexport default class SplitCellCommand extends Command {\n\t/**\n\t * Creates a new `SplitCellCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} options.direction Indicates whether the command should split cells `'horizontally'` or `'vertically'`.\n\t */\n\tconstructor( editor, options = {} ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The direction that indicates which cell will be split.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #direction\n\t\t */\n\t\tthis.direction = options.direction || 'horizontally';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\n\t\tthis.isEnabled = selectedCells.length === 1;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst tableCell = getSelectionAffectedTableCells( this.editor.model.document.selection )[ 0 ];\n\t\tconst isHorizontal = this.direction === 'horizontally';\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\tif ( isHorizontal ) {\n\t\t\ttableUtils.splitCellHorizontally( tableCell, 2 );\n\t\t} else {\n\t\t\ttableUtils.splitCellVertically( tableCell, 2 );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/utils/structure\n */\n\nimport TableWalker from '../tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from './common';\n\n/**\n * Returns a cropped table according to given dimensions.\n\n * To return a cropped table that starts at first row and first column and end in third row and column:\n *\n *\t\tconst croppedTable = cropTableToDimensions( table, {\n *\t\t\tstartRow: 1,\n *\t\t\tendRow: 1,\n *\t\t\tstartColumn: 3,\n *\t\t\tendColumn: 3\n *\t\t}, writer );\n *\n * Calling the code above for the table below:\n *\n *\t\t 0 1 2 3 4 0 1 2\n *\t\t ┌───┬───┬───┬───┬───┐\n *\t\t 0 │ a │ b │ c │ d │ e │\n *\t\t ├───┴───┤ ├───┴───┤ ┌───┬───┬───┐\n *\t\t 1 │ f │ │ g │ │ │ │ g │ 0\n *\t\t ├───┬───┴───┼───┬───┤ will return: ├───┴───┼───┤\n *\t\t 2 │ h │ i │ j │ k │ │ i │ j │ 1\n *\t\t ├───┤ ├───┤ │ │ ├───┤\n *\t\t 3 │ l │ │ m │ │ │ │ m │ 2\n *\t\t ├───┼───┬───┤ ├───┤ └───────┴───┘\n *\t\t 4 │ n │ o │ p │ │ q │\n *\t\t └───┴───┴───┴───┴───┘\n *\n * @param {module:engine/model/element~Element} sourceTable\n * @param {Object} cropDimensions\n * @param {Number} cropDimensions.startRow\n * @param {Number} cropDimensions.startColumn\n * @param {Number} cropDimensions.endRow\n * @param {Number} cropDimensions.endColumn\n * @param {module:engine/model/writer~Writer} writer\n * @returns {module:engine/model/element~Element}\n */\nexport function cropTableToDimensions( sourceTable, cropDimensions, writer ) {\n\tconst { startRow, startColumn, endRow, endColumn } = cropDimensions;\n\n\t// Create empty table with empty rows equal to crop height.\n\tconst croppedTable = writer.createElement( 'table' );\n\tconst cropHeight = endRow - startRow + 1;\n\n\tfor ( let i = 0; i < cropHeight; i++ ) {\n\t\twriter.insertElement( 'tableRow', croppedTable, 'end' );\n\t}\n\n\tconst tableMap = [ ...new TableWalker( sourceTable, { startRow, endRow, startColumn, endColumn, includeAllSlots: true } ) ];\n\n\t// Iterate over source table slots (including empty - spanned - ones).\n\tfor ( const { row: sourceRow, column: sourceColumn, cell: tableCell, isAnchor, cellAnchorRow, cellAnchorColumn } of tableMap ) {\n\t\t// Row index in cropped table.\n\t\tconst rowInCroppedTable = sourceRow - startRow;\n\t\tconst row = croppedTable.getChild( rowInCroppedTable );\n\n\t\t// For empty slots: fill the gap with empty table cell.\n\t\tif ( !isAnchor ) {\n\t\t\t// But fill the gap only if the spanning cell is anchored outside cropped area.\n\t\t\t// In the table from method jsdoc those cells are: \"c\" & \"f\".\n\t\t\tif ( cellAnchorRow < startRow || cellAnchorColumn < startColumn ) {\n\t\t\t\tcreateEmptyTableCell( writer, writer.createPositionAt( row, 'end' ) );\n\t\t\t}\n\t\t}\n\t\t// Otherwise clone the cell with all children and trim if it exceeds cropped area.\n\t\telse {\n\t\t\tconst tableCellCopy = writer.cloneElement( tableCell );\n\n\t\t\twriter.append( tableCellCopy, row );\n\n\t\t\t// Trim table if it exceeds cropped area.\n\t\t\t// In the table from method jsdoc those cells are: \"g\" & \"m\".\n\t\t\ttrimTableCellIfNeeded( tableCellCopy, sourceRow, sourceColumn, endRow, endColumn, writer );\n\t\t}\n\t}\n\n\t// Adjust heading rows & columns in cropped table if crop selection includes headings parts.\n\taddHeadingsToCroppedTable( croppedTable, sourceTable, startRow, startColumn, writer );\n\n\treturn croppedTable;\n}\n\n/**\n * Returns slot info of cells that starts above and overlaps a given row.\n *\n * In a table below, passing `overlapRow = 3`\n *\n *\t\t ┌───┬───┬───┬───┬───┐\n *\t\t0 │ a │ b │ c │ d │ e │\n *\t\t │ ├───┼───┼───┼───┤\n *\t\t1 │ │ f │ g │ h │ i │\n *\t\t ├───┤ ├───┼───┤ │\n *\t\t2 │ j │ │ k │ l │ │\n *\t\t │ │ │ ├───┼───┤\n *\t\t3 │ │ │ │ m │ n │ <- overlap row to check\n *\t\t ├───┼───┤ │ ├───│\n *\t\t4 │ o │ p │ │ │ q │\n *\t\t └───┴───┴───┴───┴───┘\n *\n * will return slot info for cells: \"j\", \"f\", \"k\".\n *\n * @param {module:engine/model/element~Element} table The table to check.\n * @param {Number} overlapRow The index of the row to check.\n * @param {Number} [startRow=0] A row to start analysis. Use it when it is known that the cells above that row will not overlap.\n * @returns {Array.<module:table/tablewalker~TableSlot>}\n */\nexport function getVerticallyOverlappingCells( table, overlapRow, startRow = 0 ) {\n\tconst cells = [];\n\n\tconst tableWalker = new TableWalker( table, { startRow, endRow: overlapRow - 1 } );\n\n\tfor ( const slotInfo of tableWalker ) {\n\t\tconst { row, cellHeight } = slotInfo;\n\t\tconst cellEndRow = row + cellHeight - 1;\n\n\t\tif ( row < overlapRow && overlapRow <= cellEndRow ) {\n\t\t\tcells.push( slotInfo );\n\t\t}\n\t}\n\n\treturn cells;\n}\n\n/**\n * Splits the table cell horizontally.\n *\n * @param {module:engine/model/element~Element} tableCell\n * @param {Number} splitRow\n * @param {module:engine/model/writer~Writer} writer\n * @returns {module:engine/model/element~Element} Created table cell.\n */\nexport function splitHorizontally( tableCell, splitRow, writer ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\tconst rowIndex = tableRow.index;\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) );\n\tconst newRowspan = splitRow - rowIndex;\n\n\tconst newCellAttributes = {};\n\tconst newCellRowSpan = rowspan - newRowspan;\n\n\tif ( newCellRowSpan > 1 ) {\n\t\tnewCellAttributes.rowspan = newCellRowSpan;\n\t}\n\n\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\tif ( colspan > 1 ) {\n\t\tnewCellAttributes.colspan = colspan;\n\t}\n\n\tconst startRow = rowIndex;\n\tconst endRow = startRow + newRowspan;\n\tconst tableMap = [ ...new TableWalker( table, { startRow, endRow, includeAllSlots: true } ) ];\n\n\tlet newCell = null;\n\tlet columnIndex;\n\n\tfor ( const tableSlot of tableMap ) {\n\t\tconst { row, column, cell } = tableSlot;\n\n\t\tif ( cell === tableCell && columnIndex === undefined ) {\n\t\t\tcolumnIndex = column;\n\t\t}\n\n\t\tif ( columnIndex !== undefined && columnIndex === column && row === endRow ) {\n\t\t\tnewCell = createEmptyTableCell( writer, tableSlot.getPositionBefore(), newCellAttributes );\n\t\t}\n\t}\n\n\t// Update the rowspan attribute after updating table.\n\tupdateNumericAttribute( 'rowspan', newRowspan, tableCell, writer );\n\n\treturn newCell;\n}\n\n/**\n * Returns slot info of cells that starts before and overlaps a given column.\n *\n * In a table below, passing `overlapColumn = 3`\n *\n *\t\t 0 1 2 3 4\n *\t\t┌───────┬───────┬───┐\n *\t\t│ a │ b │ c │\n *\t\t│───┬───┴───────┼───┤\n *\t\t│ d │ e │ f │\n *\t\t├───┼───┬───────┴───┤\n *\t\t│ g │ h │ i │\n *\t\t├───┼───┼───┬───────┤\n *\t\t│ j │ k │ l │ m │\n *\t\t├───┼───┴───┼───┬───┤\n *\t\t│ n │ o │ p │ q │\n *\t\t└───┴───────┴───┴───┘\n *\t\t ^\n *\t\t Overlap column to check\n *\n * will return slot info for cells: \"b\", \"e\", \"i\".\n *\n * @param {module:engine/model/element~Element} table The table to check.\n * @param {Number} overlapColumn The index of the column to check.\n * @returns {Array.<module:table/tablewalker~TableSlot>}\n */\nexport function getHorizontallyOverlappingCells( table, overlapColumn ) {\n\tconst cellsToSplit = [];\n\n\tconst tableWalker = new TableWalker( table );\n\n\tfor ( const slotInfo of tableWalker ) {\n\t\tconst { column, cellWidth } = slotInfo;\n\t\tconst cellEndColumn = column + cellWidth - 1;\n\n\t\tif ( column < overlapColumn && overlapColumn <= cellEndColumn ) {\n\t\t\tcellsToSplit.push( slotInfo );\n\t\t}\n\t}\n\n\treturn cellsToSplit;\n}\n\n/**\n * Splits the table cell vertically.\n *\n * @param {module:engine/model/element~Element} tableCell\n * @param {Number} columnIndex The table cell column index.\n * @param {Number} splitColumn The index of column to split cell on.\n * @param {module:engine/model/writer~Writer} writer\n * @returns {module:engine/model/element~Element} Created table cell.\n */\nexport function splitVertically( tableCell, columnIndex, splitColumn, writer ) {\n\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) );\n\tconst newColspan = splitColumn - columnIndex;\n\n\tconst newCellAttributes = {};\n\tconst newCellColSpan = colspan - newColspan;\n\n\tif ( newCellColSpan > 1 ) {\n\t\tnewCellAttributes.colspan = newCellColSpan;\n\t}\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\n\tif ( rowspan > 1 ) {\n\t\tnewCellAttributes.rowspan = rowspan;\n\t}\n\n\tconst newCell = createEmptyTableCell( writer, writer.createPositionAfter( tableCell ), newCellAttributes );\n\n\t// Update the colspan attribute after updating table.\n\tupdateNumericAttribute( 'colspan', newColspan, tableCell, writer );\n\n\treturn newCell;\n}\n\n/**\n * Adjusts table cell dimensions to not exceed limit row and column.\n *\n * If table cell width (or height) covers a column (or row) that is after a limit column (or row)\n * this method will trim \"colspan\" (or \"rowspan\") attribute so the table cell will fit in a defined limits.\n *\n * @param {module:engine/model/element~Element} tableCell\n * @param {Number} cellRow\n * @param {Number} cellColumn\n * @param {Number} limitRow\n * @param {Number} limitColumn\n * @param {module:engine/model/writer~Writer} writer\n */\nexport function trimTableCellIfNeeded( tableCell, cellRow, cellColumn, limitRow, limitColumn, writer ) {\n\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\n\tconst endColumn = cellColumn + colspan - 1;\n\n\tif ( endColumn > limitColumn ) {\n\t\tconst trimmedSpan = limitColumn - cellColumn + 1;\n\n\t\tupdateNumericAttribute( 'colspan', trimmedSpan, tableCell, writer, 1 );\n\t}\n\n\tconst endRow = cellRow + rowspan - 1;\n\n\tif ( endRow > limitRow ) {\n\t\tconst trimmedSpan = limitRow - cellRow + 1;\n\n\t\tupdateNumericAttribute( 'rowspan', trimmedSpan, tableCell, writer, 1 );\n\t}\n}\n\n// Sets proper heading attributes to a cropped table.\nfunction addHeadingsToCroppedTable( croppedTable, sourceTable, startRow, startColumn, writer ) {\n\tconst headingRows = parseInt( sourceTable.getAttribute( 'headingRows' ) || 0 );\n\n\tif ( headingRows > 0 ) {\n\t\tconst headingRowsInCrop = headingRows - startRow;\n\t\tupdateNumericAttribute( 'headingRows', headingRowsInCrop, croppedTable, writer, 0 );\n\t}\n\n\tconst headingColumns = parseInt( sourceTable.getAttribute( 'headingColumns' ) || 0 );\n\n\tif ( headingColumns > 0 ) {\n\t\tconst headingColumnsInCrop = headingColumns - startColumn;\n\t\tupdateNumericAttribute( 'headingColumns', headingColumnsInCrop, croppedTable, writer, 0 );\n\t}\n}\n\n/**\n * Removes columns that have no cells anchored.\n *\n * In table below:\n *\n * +----+----+----+----+----+----+----+\n * | 00 | 01 | 03 | 04 | 06 |\n * +----+----+----+----+ +----+\n * | 10 | 11 | 13 | | 16 |\n * +----+----+----+----+----+----+----+\n * | 20 | 21 | 23 | 24 | 26 |\n * +----+----+----+----+----+----+----+\n * ^--- empty ---^\n *\n * Will remove columns 2 and 5.\n *\n * **Note:** This is a low-level helper method for clearing invalid model state when doing table modifications.\n * To remove a column from a table use {@link module:table/tableutils~TableUtils#removeColumns `TableUtils.removeColumns()`}.\n *\n * @protected\n * @param {module:engine/model/element~Element} table\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @returns {Boolean} True if removed some columns.\n */\nexport function removeEmptyColumns( table, tableUtils ) {\n\tconst width = tableUtils.getColumns( table );\n\tconst columnsMap = new Array( width ).fill( 0 );\n\n\tfor ( const { column } of new TableWalker( table ) ) {\n\t\tcolumnsMap[ column ]++;\n\t}\n\n\tconst emptyColumns = columnsMap.reduce( ( result, cellsCount, column ) => {\n\t\treturn cellsCount ? result : [ ...result, column ];\n\t}, [] );\n\n\tif ( emptyColumns.length > 0 ) {\n\t\t// Remove only last empty column because it will recurrently trigger removing empty rows.\n\t\tconst emptyColumn = emptyColumns[ emptyColumns.length - 1 ];\n\n\t\t// @if CK_DEBUG_TABLE // console.log( `Removing empty column: ${ emptyColumn }.` );\n\t\ttableUtils.removeColumns( table, { at: emptyColumn } );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Removes rows that have no cells anchored.\n *\n * In table below:\n *\n * +----+----+----+\n * | 00 | 01 | 02 |\n * +----+----+----+\n * | 10 | 11 | 12 |\n * + + + +\n * | | | | <-- empty\n * +----+----+----+\n * | 30 | 31 | 32 |\n * +----+----+----+\n * | 40 | 42 |\n * + + +\n * | | | <-- empty\n * +----+----+----+\n * | 60 | 61 | 62 |\n * +----+----+----+\n *\n * Will remove rows 2 and 5.\n *\n * **Note:** This is a low-level helper method for clearing invalid model state when doing table modifications.\n * To remove a row from a table use {@link module:table/tableutils~TableUtils#removeRows `TableUtils.removeRows()`}.\n *\n * @protected\n * @param {module:engine/model/element~Element} table\n * @param {module:table/tableutils~TableUtils} tableUtils\n * @returns {Boolean} True if removed some rows.\n */\nexport function removeEmptyRows( table, tableUtils ) {\n\tconst emptyRows = [];\n\n\tfor ( let rowIndex = 0; rowIndex < table.childCount; rowIndex++ ) {\n\t\tconst tableRow = table.getChild( rowIndex );\n\n\t\tif ( tableRow.isEmpty ) {\n\t\t\temptyRows.push( rowIndex );\n\t\t}\n\t}\n\n\tif ( emptyRows.length > 0 ) {\n\t\t// Remove only last empty row because it will recurrently trigger removing empty columns.\n\t\tconst emptyRow = emptyRows[ emptyRows.length - 1 ];\n\n\t\t// @if CK_DEBUG_TABLE // console.log( `Removing empty row: ${ emptyRow }.` );\n\t\ttableUtils.removeRows( table, { at: emptyRow } );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Removes rows and columns that have no cells anchored.\n *\n * In table below:\n *\n * +----+----+----+----+\n * | 00 | 02 |\n * +----+----+ +\n * | 10 | |\n * +----+----+----+----+\n * | 20 | 22 | 23 |\n * + + + +\n * | | | | <-- empty row\n * +----+----+----+----+\n * ^--- empty column\n *\n * Will remove row 3 and column 1.\n *\n * **Note:** This is a low-level helper method for clearing invalid model state when doing table modifications.\n * To remove a rows from a table use {@link module:table/tableutils~TableUtils#removeRows `TableUtils.removeRows()`} and\n * {@link module:table/tableutils~TableUtils#removeColumns `TableUtils.removeColumns()`} to remove a column.\n *\n * @protected\n * @param {module:engine/model/element~Element} table\n * @param {module:table/tableutils~TableUtils} tableUtils\n */\nexport function removeEmptyRowsColumns( table, tableUtils ) {\n\tconst removedColumns = removeEmptyColumns( table, tableUtils );\n\n\t// If there was some columns removed then cleaning empty rows was already triggered.\n\tif ( !removedColumns ) {\n\t\tremoveEmptyRows( table, tableUtils );\n\t}\n}\n\n/**\n * Returns adjusted last row index if selection covers part of a row with empty slots (spanned by other cells).\n * The `dimensions.lastRow` is equal to last row index but selection might be bigger.\n *\n * This happens *only* on rectangular selection so we analyze a case like this:\n *\n * +---+---+---+---+\n * 0 | a | b | c | d |\n * + + +---+---+\n * 1 | | e | f | g |\n * + +---+ +---+\n * 2 | | h | | i | <- last row, each cell has rowspan = 2,\n * + + + + + so we need to return 3, not 2\n * 3 | | | | |\n * +---+---+---+---+\n *\n * @param {module:engine/model/element~Element} table\n * @param {Object} dimensions\n * @param {Number} dimensions.firstRow\n * @param {Number} dimensions.firstColumn\n * @param {Number} dimensions.lastRow\n * @param {Number} dimensions.lastColumn\n * @returns {Number} Adjusted last row index.\n */\nexport function adjustLastRowIndex( table, dimensions ) {\n\tconst lastRowMap = Array.from( new TableWalker( table, {\n\t\tstartColumn: dimensions.firstColumn,\n\t\tendColumn: dimensions.lastColumn,\n\t\trow: dimensions.lastRow\n\t} ) );\n\n\tconst everyCellHasSingleRowspan = lastRowMap.every( ( { cellHeight } ) => cellHeight === 1 );\n\n\t// It is a \"flat\" row, so the last row index is OK.\n\tif ( everyCellHasSingleRowspan ) {\n\t\treturn dimensions.lastRow;\n\t}\n\n\t// Otherwise get any cell's rowspan and adjust the last row index.\n\tconst rowspanAdjustment = lastRowMap[ 0 ].cellHeight - 1;\n\treturn dimensions.lastRow + rowspanAdjustment;\n}\n\n/**\n * Returns adjusted last column index if selection covers part of a column with empty slots (spanned by other cells).\n * The `dimensions.lastColumn` is equal to last column index but selection might be bigger.\n *\n * This happens *only* on rectangular selection so we analyze a case like this:\n *\n * 0 1 2 3\n * +---+---+---+---+\n * | a |\n * +---+---+---+---+\n * | b | c | d |\n * +---+---+---+---+\n * | e | f |\n * +---+---+---+---+\n * | g | h |\n * +---+---+---+---+\n * ^\n * last column, each cell has colspan = 2, so we need to return 3, not 2\n *\n * @param {module:engine/model/element~Element} table\n * @param {Object} dimensions\n * @param {Number} dimensions.firstRow\n * @param {Number} dimensions.firstColumn\n * @param {Number} dimensions.lastRow\n * @param {Number} dimensions.lastColumn\n * @returns {Number} Adjusted last column index.\n */\nexport function adjustLastColumnIndex( table, dimensions ) {\n\tconst lastColumnMap = Array.from( new TableWalker( table, {\n\t\tstartRow: dimensions.firstRow,\n\t\tendRow: dimensions.lastRow,\n\t\tcolumn: dimensions.lastColumn\n\t} ) );\n\n\tconst everyCellHasSingleColspan = lastColumnMap.every( ( { cellWidth } ) => cellWidth === 1 );\n\n\t// It is a \"flat\" column, so the last column index is OK.\n\tif ( everyCellHasSingleColspan ) {\n\t\treturn dimensions.lastColumn;\n\t}\n\n\t// Otherwise get any cell's colspan and adjust the last column index.\n\tconst colspanAdjustment = lastColumnMap[ 0 ].cellWidth - 1;\n\treturn dimensions.lastColumn + colspanAdjustment;\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 table/commands/mergecellcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport TableWalker from '../tablewalker';\nimport { getTableCellsContainingSelection } from '../utils/selection';\nimport { isHeadingColumnCell } from '../utils/common';\nimport { removeEmptyRowsColumns } from '../utils/structure';\n\n/**\n * The merge cell command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'mergeTableCellRight'`, `'mergeTableCellLeft'`,\n * `'mergeTableCellUp'` and `'mergeTableCellDown'` editor commands.\n *\n * To merge a table cell at the current selection with another cell, execute the command corresponding with the preferred direction.\n *\n * For example, to merge with a cell to the right:\n *\n *\t\teditor.execute( 'mergeTableCellRight' );\n *\n * **Note**: If a table cell has a different [`rowspan`](https://www.w3.org/TR/html50/tabular-data.html#attr-tdth-rowspan)\n * (for `'mergeTableCellRight'` and `'mergeTableCellLeft'`) or [`colspan`](https://www.w3.org/TR/html50/tabular-data.html#attr-tdth-colspan)\n * (for `'mergeTableCellUp'` and `'mergeTableCellDown'`), the command will be disabled.\n *\n * @extends module:core/command~Command\n */\nexport default class MergeCellCommand extends Command {\n\t/**\n\t * Creates a new `MergeCellCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor on which this command will be used.\n\t * @param {Object} options\n\t * @param {String} options.direction Indicates which cell to merge with the currently selected one.\n\t * Possible values are: `'left'`, `'right'`, `'up'` and `'down'`.\n\t */\n\tconstructor( editor, options ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The direction that indicates which cell will be merged with the currently selected one.\n\t\t *\n\t\t * @readonly\n\t\t * @member {String} #direction\n\t\t */\n\t\tthis.direction = options.direction;\n\n\t\t/**\n\t\t * Whether the merge is horizontal (left/right) or vertical (up/down).\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} #isHorizontal\n\t\t */\n\t\tthis.isHorizontal = this.direction == 'right' || this.direction == 'left';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst cellToMerge = this._getMergeableCell();\n\n\t\tthis.value = cellToMerge;\n\t\tthis.isEnabled = !!cellToMerge;\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * Depending on the command's {@link #direction} value, it will merge the cell that is to the `'left'`, `'right'`, `'up'` or `'down'`.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst tableCell = getTableCellsContainingSelection( doc.selection )[ 0 ];\n\n\t\tconst cellToMerge = this.value;\n\t\tconst direction = this.direction;\n\n\t\tmodel.change( writer => {\n\t\t\tconst isMergeNext = direction == 'right' || direction == 'down';\n\n\t\t\t// The merge mechanism is always the same so sort cells to be merged.\n\t\t\tconst cellToExpand = isMergeNext ? tableCell : cellToMerge;\n\t\t\tconst cellToRemove = isMergeNext ? cellToMerge : tableCell;\n\n\t\t\t// Cache the parent of cell to remove for later check.\n\t\t\tconst removedTableCellRow = cellToRemove.parent;\n\n\t\t\tmergeTableCells( cellToRemove, cellToExpand, writer );\n\n\t\t\tconst spanAttribute = this.isHorizontal ? 'colspan' : 'rowspan';\n\t\t\tconst cellSpan = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );\n\t\t\tconst cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );\n\n\t\t\t// Update table cell span attribute and merge set selection on merged contents.\n\t\t\twriter.setAttribute( spanAttribute, cellSpan + cellToMergeSpan, cellToExpand );\n\t\t\twriter.setSelection( writer.createRangeIn( cellToExpand ) );\n\n\t\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\t\tconst table = removedTableCellRow.findAncestor( 'table' );\n\n\t\t\t// Remove empty rows and columns after merging.\n\t\t\tremoveEmptyRowsColumns( table, tableUtils );\n\t\t} );\n\t}\n\n\t/**\n\t * Returns a cell that can be merged with the current cell depending on the command's direction.\n\t *\n\t * @returns {module:engine/model/element~Element|undefined}\n\t * @private\n\t */\n\t_getMergeableCell() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\t\tconst tableCell = getTableCellsContainingSelection( doc.selection )[ 0 ];\n\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\t// First get the cell on proper direction.\n\t\tconst cellToMerge = this.isHorizontal ?\n\t\t\tgetHorizontalCell( tableCell, this.direction, tableUtils ) :\n\t\t\tgetVerticalCell( tableCell, this.direction );\n\n\t\tif ( !cellToMerge ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If found check if the span perpendicular to merge direction is equal on both cells.\n\t\tconst spanAttribute = this.isHorizontal ? 'rowspan' : 'colspan';\n\t\tconst span = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );\n\n\t\tconst cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );\n\n\t\tif ( cellToMergeSpan === span ) {\n\t\t\treturn cellToMerge;\n\t\t}\n\t}\n}\n\n// Returns the cell that can be merged horizontally.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} direction\n// @returns {module:engine/model/node~Node|null}\nfunction getHorizontalCell( tableCell, direction, tableUtils ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\tconst horizontalCell = direction == 'right' ? tableCell.nextSibling : tableCell.previousSibling;\n\tconst hasHeadingColumns = ( table.getAttribute( 'headingColumns' ) || 0 ) > 0;\n\n\tif ( !horizontalCell ) {\n\t\treturn;\n\t}\n\n\t// Sort cells:\n\tconst cellOnLeft = direction == 'right' ? tableCell : horizontalCell;\n\tconst cellOnRight = direction == 'right' ? horizontalCell : tableCell;\n\n\t// Get their column indexes:\n\tconst { column: leftCellColumn } = tableUtils.getCellLocation( cellOnLeft );\n\tconst { column: rightCellColumn } = tableUtils.getCellLocation( cellOnRight );\n\n\tconst leftCellSpan = parseInt( cellOnLeft.getAttribute( 'colspan' ) || 1 );\n\n\tconst isCellOnLeftInHeadingColumn = isHeadingColumnCell( tableUtils, cellOnLeft, table );\n\tconst isCellOnRightInHeadingColumn = isHeadingColumnCell( tableUtils, cellOnRight, table );\n\n\t// We cannot merge heading columns cells with regular cells.\n\tif ( hasHeadingColumns && isCellOnLeftInHeadingColumn != isCellOnRightInHeadingColumn ) {\n\t\treturn;\n\t}\n\n\t// The cell on the right must have index that is distant to the cell on the left by the left cell's width (colspan).\n\tconst cellsAreTouching = leftCellColumn + leftCellSpan === rightCellColumn;\n\n\t// If the right cell's column index is different it means that there are rowspanned cells between them.\n\treturn cellsAreTouching ? horizontalCell : undefined;\n}\n\n// Returns the cell that can be merged vertically.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @param {String} direction\n// @returns {module:engine/model/node~Node|null}\nfunction getVerticalCell( tableCell, direction ) {\n\tconst tableRow = tableCell.parent;\n\tconst table = tableRow.parent;\n\n\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t// Don't search for mergeable cell if direction points out of the table.\n\tif ( ( direction == 'down' && rowIndex === table.childCount - 1 ) || ( direction == 'up' && rowIndex === 0 ) ) {\n\t\treturn;\n\t}\n\n\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\tconst isMergeWithBodyCell = direction == 'down' && ( rowIndex + rowspan ) === headingRows;\n\tconst isMergeWithHeadCell = direction == 'up' && rowIndex === headingRows;\n\n\t// Don't search for mergeable cell if direction points out of the current table section.\n\tif ( headingRows && ( isMergeWithBodyCell || isMergeWithHeadCell ) ) {\n\t\treturn;\n\t}\n\n\tconst currentCellRowSpan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\tconst rowOfCellToMerge = direction == 'down' ? rowIndex + currentCellRowSpan : rowIndex;\n\n\tconst tableMap = [ ...new TableWalker( table, { endRow: rowOfCellToMerge } ) ];\n\n\tconst currentCellData = tableMap.find( value => value.cell === tableCell );\n\tconst mergeColumn = currentCellData.column;\n\n\tconst cellToMergeData = tableMap.find( ( { row, cellHeight, column } ) => {\n\t\tif ( column !== mergeColumn ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( direction == 'down' ) {\n\t\t\t// If merging a cell below the mergeRow is already calculated.\n\t\t\treturn row === rowOfCellToMerge;\n\t\t} else {\n\t\t\t// If merging a cell above calculate if it spans to mergeRow.\n\t\t\treturn rowOfCellToMerge === row + cellHeight;\n\t\t}\n\t} );\n\n\treturn cellToMergeData && cellToMergeData.cell;\n}\n\n// Merges two table cells. It will ensure that after merging cells with an empty paragraph, the resulting table cell will only have one\n// paragraph. If one of the merged table cells is empty, the merged table cell will have the contents of the non-empty table cell.\n// If both are empty, the merged table cell will have only one empty paragraph.\n//\n// @param {module:engine/model/element~Element} cellToRemove\n// @param {module:engine/model/element~Element} cellToExpand\n// @param {module:engine/model/writer~Writer} writer\nfunction mergeTableCells( cellToRemove, cellToExpand, writer ) {\n\tif ( !isEmpty( cellToRemove ) ) {\n\t\tif ( isEmpty( cellToExpand ) ) {\n\t\t\twriter.remove( writer.createRangeIn( cellToExpand ) );\n\t\t}\n\n\t\twriter.move( writer.createRangeIn( cellToRemove ), writer.createPositionAt( cellToExpand, 'end' ) );\n\t}\n\n\t// Remove merged table cell.\n\twriter.remove( cellToRemove );\n}\n\n// Checks if the passed table cell contains an empty paragraph.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @returns {Boolean}\nfunction isEmpty( tableCell ) {\n\treturn tableCell.childCount == 1 && tableCell.getChild( 0 ).is( 'element', 'paragraph' ) && tableCell.getChild( 0 ).isEmpty;\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 table/commands/removerowcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The remove row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'removeTableRow'` editor command.\n *\n * To remove the row containing the selected cell, execute the command:\n *\n *\t\teditor.execute( 'removeTableRow' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\t\tconst firstCell = selectedCells[ 0 ];\n\n\t\tif ( firstCell ) {\n\t\t\tconst table = firstCell.findAncestor( 'table' );\n\t\t\tconst tableRowCount = this.editor.plugins.get( 'TableUtils' ).getRows( table );\n\t\t\tconst lastRowIndex = tableRowCount - 1;\n\n\t\t\tconst selectedRowIndexes = getRowIndexes( selectedCells );\n\n\t\t\tconst areAllRowsSelected = selectedRowIndexes.first === 0 && selectedRowIndexes.last === lastRowIndex;\n\n\t\t\t// Disallow selecting whole table -> delete whole table should be used instead.\n\t\t\tthis.isEnabled = !areAllRowsSelected;\n\t\t} else {\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst referenceCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst removedRowIndexes = getRowIndexes( referenceCells );\n\n\t\tconst firstCell = referenceCells[ 0 ];\n\t\tconst table = firstCell.findAncestor( 'table' );\n\n\t\tconst columnIndexToFocus = this.editor.plugins.get( 'TableUtils' ).getCellLocation( firstCell ).column;\n\n\t\tmodel.change( writer => {\n\t\t\tconst rowsToRemove = removedRowIndexes.last - removedRowIndexes.first + 1;\n\n\t\t\tthis.editor.plugins.get( 'TableUtils' ).removeRows( table, {\n\t\t\t\tat: removedRowIndexes.first,\n\t\t\t\trows: rowsToRemove\n\t\t\t} );\n\n\t\t\tconst cellToFocus = getCellToFocus( table, removedRowIndexes.first, columnIndexToFocus );\n\n\t\t\twriter.setSelection( writer.createPositionAt( cellToFocus, 0 ) );\n\t\t} );\n\t}\n}\n\n// Returns a cell that should be focused before removing the row, belonging to the same column as the currently focused cell.\n// * If the row was not the last one, the cell to focus will be in the row that followed it (before removal).\n// * If the row was the last one, the cell to focus will be in the row that preceded it (before removal).\nfunction getCellToFocus( table, removedRowIndex, columnToFocus ) {\n\tconst row = table.getChild( removedRowIndex ) || table.getChild( table.childCount - 1 );\n\n\t// Default to first table cell.\n\tlet cellToFocus = row.getChild( 0 );\n\tlet column = 0;\n\n\tfor ( const tableCell of row.getChildren() ) {\n\t\tif ( column > columnToFocus ) {\n\t\t\treturn cellToFocus;\n\t\t}\n\n\t\tcellToFocus = tableCell;\n\t\tcolumn += parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\t}\n\n\treturn cellToFocus;\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 table/commands/removecolumncommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport TableWalker from '../tablewalker';\nimport { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The remove column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'removeTableColumn'` editor command.\n *\n * To remove the column containing the selected cell, execute the command:\n *\n *\t\teditor.execute( 'removeTableColumn' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\t\tconst firstCell = selectedCells[ 0 ];\n\n\t\tif ( firstCell ) {\n\t\t\tconst table = firstCell.findAncestor( 'table' );\n\t\t\tconst tableColumnCount = this.editor.plugins.get( 'TableUtils' ).getColumns( table );\n\n\t\t\tconst { first, last } = getColumnIndexes( selectedCells );\n\n\t\t\tthis.isEnabled = last - first < ( tableColumnCount - 1 );\n\t\t} else {\n\t\t\tthis.isEnabled = false;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst [ firstCell, lastCell ] = getBoundaryCells( this.editor.model.document.selection );\n\t\tconst table = firstCell.parent.parent;\n\n\t\t// Cache the table before removing or updating colspans.\n\t\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\t\t// Store column indexes of removed columns.\n\t\tconst removedColumnIndexes = {\n\t\t\tfirst: tableMap.find( value => value.cell === firstCell ).column,\n\t\t\tlast: tableMap.find( value => value.cell === lastCell ).column\n\t\t};\n\n\t\tconst cellToFocus = getCellToFocus( tableMap, firstCell, lastCell, removedColumnIndexes );\n\n\t\tthis.editor.model.change( writer => {\n\t\t\tconst columnsToRemove = removedColumnIndexes.last - removedColumnIndexes.first + 1;\n\n\t\t\tthis.editor.plugins.get( 'TableUtils' ).removeColumns( table, {\n\t\t\t\tat: removedColumnIndexes.first,\n\t\t\t\tcolumns: columnsToRemove\n\t\t\t} );\n\n\t\t\twriter.setSelection( writer.createPositionAt( cellToFocus, 0 ) );\n\t\t} );\n\t}\n}\n\n// Returns a proper table cell to focus after removing a column.\n// - selection is on last table cell it will return previous cell.\nfunction getCellToFocus( tableMap, firstCell, lastCell, removedColumnIndexes ) {\n\tconst colspan = parseInt( lastCell.getAttribute( 'colspan' ) || 1 );\n\n\t// If the table cell is spanned over 2+ columns - it will be truncated so the selection should\n\t// stay in that cell.\n\tif ( colspan > 1 ) {\n\t\treturn lastCell;\n\t}\n\t// Normally, look for the cell in the same row that precedes the first cell to put selection there (\"column on the left\").\n\t// If the deleted column is the first column of the table, there will be no predecessor: use the cell\n\t// from the column that follows then (also in the same row).\n\telse if ( firstCell.previousSibling || lastCell.nextSibling ) {\n\t\treturn lastCell.nextSibling || firstCell.previousSibling;\n\t}\n\t// It can happen that table cells have no siblings in a row, for instance, when there are row spans\n\t// in the table (in the previous row). Then just look for the closest cell that is in a column\n\t// that will not be removed to put the selection there.\n\telse {\n\t\t// Look for any cell in a column that precedes the first removed column.\n\t\tif ( removedColumnIndexes.first ) {\n\t\t\treturn tableMap.reverse().find( ( { column } ) => {\n\t\t\t\treturn column < removedColumnIndexes.first;\n\t\t\t} ).cell;\n\t\t}\n\t\t// If the first removed column is the first column of the table, then\n\t\t// look for any cell that is in a column that follows the last removed column.\n\t\telse {\n\t\t\treturn tableMap.reverse().find( ( { column } ) => {\n\t\t\t\treturn column > removedColumnIndexes.last;\n\t\t\t} ).cell;\n\t\t}\n\t}\n}\n\n// Returns helper object returning the first and the last cell contained in given selection, based on DOM order.\nfunction getBoundaryCells( selection ) {\n\tconst referenceCells = getSelectionAffectedTableCells( selection );\n\tconst firstCell = referenceCells[ 0 ];\n\tconst lastCell = referenceCells.pop();\n\n\tconst returnValue = [ firstCell, lastCell ];\n\n\treturn firstCell.isBefore( lastCell ) ? returnValue : returnValue.reverse();\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 table/commands/setheaderrowcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport { updateNumericAttribute } from '../utils/common';\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\nimport { getVerticallyOverlappingCells, splitHorizontally } from '../utils/structure';\n\n/**\n * The header row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'setTableColumnHeader'` editor command.\n *\n * You can make the row containing the selected cell a [header](https://www.w3.org/TR/html50/tabular-data.html#the-th-element) by executing:\n *\n *\t\teditor.execute( 'setTableRowHeader' );\n *\n * **Note:** All preceding rows will also become headers. If the current row is already a header, executing this command\n * will make it a regular row back again (including the following rows).\n *\n * @extends module:core/command~Command\n */\nexport default class SetHeaderRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst isInTable = selectedCells.length > 0;\n\n\t\tthis.isEnabled = isInTable;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection} is in a header row.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t\tthis.value = isInTable && selectedCells.every( cell => this._isInHeading( cell, cell.parent.parent ) );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is in a non-header row, the command will set the `headingRows` table attribute to cover that row.\n\t *\n\t * When the selection is already in a header row, it will set `headingRows` so the heading section will end before that row.\n\t *\n\t * @fires execute\n\t * @param {Object} options\n\t * @param {Boolean} [options.forceValue] If set, the command will set (`true`) or unset (`false`) the header rows according to\n\t * the `forceValue` parameter instead of the current model state.\n\t */\n\texecute( options = {} ) {\n\t\tif ( options.forceValue === this.value ) {\n\t\t\treturn;\n\t\t}\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst table = selectedCells[ 0 ].findAncestor( 'table' );\n\n\t\tconst { first, last } = getRowIndexes( selectedCells );\n\t\tconst headingRowsToSet = this.value ? first : last + 1;\n\t\tconst currentHeadingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( headingRowsToSet ) {\n\t\t\t\t// Changing heading rows requires to check if any of a heading cell is overlapping vertically the table head.\n\t\t\t\t// Any table cell that has a rowspan attribute > 1 will not exceed the table head so we need to fix it in rows below.\n\t\t\t\tconst startRow = headingRowsToSet > currentHeadingRows ? currentHeadingRows : 0;\n\t\t\t\tconst overlappingCells = getVerticallyOverlappingCells( table, headingRowsToSet, startRow );\n\n\t\t\t\tfor ( const { cell } of overlappingCells ) {\n\t\t\t\t\tsplitHorizontally( cell, headingRowsToSet, writer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateNumericAttribute( 'headingRows', headingRowsToSet, table, writer, 0 );\n\t\t} );\n\t}\n\n\t/**\n\t * Checks if a table cell is in the heading section.\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {module:engine/model/element~Element} table\n\t * @returns {Boolean}\n\t * @private\n\t */\n\t_isInHeading( tableCell, table ) {\n\t\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\n\t\treturn !!headingRows && tableCell.parent.index < headingRows;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/setheadercolumncommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport {\n\tisHeadingColumnCell,\n\tupdateNumericAttribute\n} from '../utils/common';\nimport { getColumnIndexes, getSelectionAffectedTableCells } from '../utils/selection';\nimport { getHorizontallyOverlappingCells, splitVertically } from '../utils/structure';\n\n/**\n * The header column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'setTableColumnHeader'` editor command.\n *\n * You can make the column containing the selected cell a [header](https://www.w3.org/TR/html50/tabular-data.html#the-th-element)\n * by executing:\n *\n *\t\teditor.execute( 'setTableColumnHeader' );\n *\n * **Note:** All preceding columns will also become headers. If the current column is already a header, executing this command\n * will make it a regular column back again (including the following columns).\n *\n * @extends module:core/command~Command\n */\nexport default class SetHeaderColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\tconst isInTable = selectedCells.length > 0;\n\n\t\tthis.isEnabled = isInTable;\n\n\t\t/**\n\t\t * Flag indicating whether the command is active. The command is active when the\n\t\t * {@link module:engine/model/selection~Selection} is in a header column.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #value\n\t\t */\n\t\tthis.value = isInTable && selectedCells.every( cell => isHeadingColumnCell( tableUtils, cell ) );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * When the selection is in a non-header column, the command will set the `headingColumns` table attribute to cover that column.\n\t *\n\t * When the selection is already in a header column, it will set `headingColumns` so the heading section will end before that column.\n\t *\n\t * @fires execute\n\t * @param {Object} [options]\n\t * @param {Boolean} [options.forceValue] If set, the command will set (`true`) or unset (`false`) the header columns according to\n\t * the `forceValue` parameter instead of the current model state.\n\t */\n\texecute( options = {} ) {\n\t\tif ( options.forceValue === this.value ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst selectedCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst table = selectedCells[ 0 ].findAncestor( 'table' );\n\n\t\tconst { first, last } = getColumnIndexes( selectedCells );\n\t\tconst headingColumnsToSet = this.value ? first : last + 1;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( headingColumnsToSet ) {\n\t\t\t\t// Changing heading columns requires to check if any of a heading cell is overlapping horizontally the table head.\n\t\t\t\t// Any table cell that has a colspan attribute > 1 will not exceed the table head so we need to fix it in columns before.\n\t\t\t\tconst overlappingCells = getHorizontallyOverlappingCells( table, headingColumnsToSet );\n\n\t\t\t\tfor ( const { cell, column } of overlappingCells ) {\n\t\t\t\t\tsplitVertically( cell, column, headingColumnsToSet, writer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tupdateNumericAttribute( 'headingColumns', headingColumnsToSet, table, writer, 0 );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableutils\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TableWalker from './tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from './utils/common';\nimport { removeEmptyColumns, removeEmptyRows } from './utils/structure';\n\n/**\n * The table utilities plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUtils extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableUtils';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tthis.decorate( 'insertColumns' );\n\t\tthis.decorate( 'insertRows' );\n\t}\n\n\t/**\n\t * Returns the table cell location as an object with table row and table column indexes.\n\t *\n\t * For instance, in the table below:\n\t *\n\t *\t\t 0 1 2 3\n\t *\t\t +---+---+---+---+\n\t *\t\t0 | a | b | c |\n\t *\t\t + + +---+\n\t *\t\t1 | | | d |\n\t *\t\t +---+---+ +---+\n\t *\t\t2 | e | | f |\n\t *\t\t +---+---+---+---+\n\t *\n\t * the method will return:\n\t *\n\t *\t\tconst cellA = table.getNodeByPath( [ 0, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellA );\n\t *\t\t// will return { row: 0, column: 0 }\n\t *\n\t *\t\tconst cellD = table.getNodeByPath( [ 1, 0 ] );\n\t *\t\teditor.plugins.get( 'TableUtils' ).getCellLocation( cellD );\n\t *\t\t// will return { row: 1, column: 3 }\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @returns {Object} Returns a `{row, column}` object.\n\t */\n\tgetCellLocation( tableCell ) {\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowIndex = table.getChildIndex( tableRow );\n\n\t\tconst tableWalker = new TableWalker( table, { row: rowIndex } );\n\n\t\tfor ( const { cell, row, column } of tableWalker ) {\n\t\t\tif ( cell === tableCell ) {\n\t\t\t\treturn { row, column };\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an empty table with a proper structure. The table needs to be inserted into the model,\n\t * for example, by using the {@link module:engine/model/model~Model#insertContent} function.\n\t *\n\t *\t\tmodel.change( ( writer ) => {\n\t *\t\t\t// Create a table of 2 rows and 7 columns:\n\t *\t\t\tconst table = tableUtils.createTable( writer, { rows: 2, columns: 7 } );\n\t *\n\t *\t\t\t// Insert a table to the model at the best position taking the current selection:\n\t *\t\t\tmodel.insertContent( table );\n\t *\t\t}\n\t *\n\t * @param {module:engine/model/writer~Writer} writer The model writer.\n\t * @param {Object} options\n\t * @param {Number} [options.rows=2] The number of rows to create.\n\t * @param {Number} [options.columns=2] The number of columns to create.\n\t * @param {Number} [options.headingRows=0] The number of heading rows.\n\t * @param {Number} [options.headingColumns=0] The number of heading columns.\n\t * @returns {module:engine/model/element~Element} The created table element.\n\t */\n\tcreateTable( writer, options ) {\n\t\tconst table = writer.createElement( 'table' );\n\n\t\tconst rows = parseInt( options.rows ) || 2;\n\t\tconst columns = parseInt( options.columns ) || 2;\n\n\t\tcreateEmptyRows( writer, table, 0, rows, columns );\n\n\t\tif ( options.headingRows ) {\n\t\t\tupdateNumericAttribute( 'headingRows', options.headingRows, table, writer, 0 );\n\t\t}\n\n\t\tif ( options.headingColumns ) {\n\t\t\tupdateNumericAttribute( 'headingColumns', options.headingColumns, table, writer, 0 );\n\t\t}\n\n\t\treturn table;\n\t}\n\n\t/**\n\t * Inserts rows into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertRows( table, { at: 1, rows: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\trow index\n\t *\t\t 0 +---+---+---+ `at` = 1, +---+---+---+ 0\n\t *\t\t | a | b | c | `rows` = 2, | a | b | c |\n\t *\t\t 1 + +---+---+ <-- insert here + +---+---+ 1\n\t *\t\t | | d | e | | | | |\n\t *\t\t 2 + +---+---+ will give: + +---+---+ 2\n\t *\t\t | | f | g | | | | |\n\t *\t\t 3 +---+---+---+ + +---+---+ 3\n\t *\t\t | | d | e |\n\t *\t\t + +---+---+ 4\n\t *\t\t + + f | g |\n\t *\t\t +---+---+---+ 5\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the rows will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The row index at which the rows will be inserted.\n\t * @param {Number} [options.rows=1] The number of rows to insert.\n\t * @param {Boolean|undefined} [options.copyStructureFromAbove] The flag for copying row structure. Note that\n\t * the row structure will not be copied if this option is not provided.\n\t */\n\tinsertRows( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst rowsToInsert = options.rows || 1;\n\t\tconst isCopyStructure = options.copyStructureFromAbove !== undefined;\n\t\tconst copyStructureFrom = options.copyStructureFromAbove ? insertAt - 1 : insertAt;\n\n\t\tconst rows = this.getRows( table );\n\t\tconst columns = this.getColumns( table );\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t// Inserting rows inside heading section requires to update `headingRows` attribute as the heading section will grow.\n\t\t\tif ( headingRows > insertAt ) {\n\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows + rowsToInsert, table, writer, 0 );\n\t\t\t}\n\n\t\t\t// Inserting at the end or at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( !isCopyStructure && ( insertAt === 0 || insertAt === rows ) ) {\n\t\t\t\tcreateEmptyRows( writer, table, insertAt, rowsToInsert, columns );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Iterate over all the rows above the inserted rows in order to check for the row-spanned cells.\n\t\t\tconst walkerEndRow = isCopyStructure ? Math.max( insertAt, copyStructureFrom ) : insertAt;\n\t\t\tconst tableIterator = new TableWalker( table, { endRow: walkerEndRow } );\n\n\t\t\t// Store spans of the reference row to reproduce it's structure. This array is column number indexed.\n\t\t\tconst rowColSpansMap = new Array( columns ).fill( 1 );\n\n\t\t\tfor ( const { row, column, cellHeight, cellWidth, cell } of tableIterator ) {\n\t\t\t\tconst lastCellRow = row + cellHeight - 1;\n\n\t\t\t\tconst isOverlappingInsertedRow = row < insertAt && insertAt <= lastCellRow;\n\t\t\t\tconst isReferenceRow = row <= copyStructureFrom && copyStructureFrom <= lastCellRow;\n\n\t\t\t\t// If the cell is row-spanned and overlaps the inserted row, then reserve space for it in the row map.\n\t\t\t\tif ( isOverlappingInsertedRow ) {\n\t\t\t\t\t// This cell overlaps the inserted rows so we need to expand it further.\n\t\t\t\t\twriter.setAttribute( 'rowspan', cellHeight + rowsToInsert, cell );\n\n\t\t\t\t\t// Mark this cell with negative number to indicate how many cells should be skipped when adding the new cells.\n\t\t\t\t\trowColSpansMap[ column ] = -cellWidth;\n\t\t\t\t}\n\t\t\t\t// Store the colspan from reference row.\n\t\t\t\telse if ( isCopyStructure && isReferenceRow ) {\n\t\t\t\t\trowColSpansMap[ column ] = cellWidth;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( let rowIndex = 0; rowIndex < rowsToInsert; rowIndex++ ) {\n\t\t\t\tconst tableRow = writer.createElement( 'tableRow' );\n\n\t\t\t\twriter.insert( tableRow, table, insertAt );\n\n\t\t\t\tfor ( let cellIndex = 0; cellIndex < rowColSpansMap.length; cellIndex++ ) {\n\t\t\t\t\tconst colspan = rowColSpansMap[ cellIndex ];\n\t\t\t\t\tconst insertPosition = writer.createPositionAt( tableRow, 'end' );\n\n\t\t\t\t\t// Insert the empty cell only if this slot is not row-spanned from any other cell.\n\t\t\t\t\tif ( colspan > 0 ) {\n\t\t\t\t\t\tcreateEmptyTableCell( writer, insertPosition, colspan > 1 ? { colspan } : null );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Skip the col-spanned slots, there won't be any cells.\n\t\t\t\t\tcellIndex += Math.abs( colspan ) - 1;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Inserts columns into a table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).insertColumns( table, { at: 1, columns: 2 } );\n\t *\n\t * Assuming the table on the left, the above code will transform it to the table on the right:\n\t *\n\t *\t\t0 1 2 3 0 1 2 3 4 5\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t| a | b | | a | b |\n\t *\t\t+ +---+ + +---+\n\t *\t\t| | c | | | c |\n\t *\t\t+---+---+---+ will give: +---+---+---+---+---+\n\t *\t\t| d | e | f | | d | | | e | f |\n\t *\t\t+---+ +---+ +---+---+---+ +---+\n\t *\t\t| g | | h | | g | | | | h |\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t| i | | i |\n\t *\t\t+---+---+---+ +---+---+---+---+---+\n\t *\t\t ^---- insert here, `at` = 1, `columns` = 2\n\t *\n\t * @param {module:engine/model/element~Element} table The table model element where the columns will be inserted.\n\t * @param {Object} options\n\t * @param {Number} [options.at=0] The column index at which the columns will be inserted.\n\t * @param {Number} [options.columns=1] The number of columns to insert.\n\t */\n\tinsertColumns( table, options = {} ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst insertAt = options.at || 0;\n\t\tconst columnsToInsert = options.columns || 1;\n\n\t\tmodel.change( writer => {\n\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' );\n\n\t\t\t// Inserting columns inside heading section requires to update `headingColumns` attribute as the heading section will grow.\n\t\t\tif ( insertAt < headingColumns ) {\n\t\t\t\twriter.setAttribute( 'headingColumns', headingColumns + columnsToInsert, table );\n\t\t\t}\n\n\t\t\tconst tableColumns = this.getColumns( table );\n\n\t\t\t// Inserting at the end and at the beginning of a table doesn't require to calculate anything special.\n\t\t\tif ( insertAt === 0 || tableColumns === insertAt ) {\n\t\t\t\tfor ( const tableRow of table.getChildren() ) {\n\t\t\t\t\tcreateCells( columnsToInsert, writer, writer.createPositionAt( tableRow, insertAt ? 'end' : 0 ) );\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tableWalker = new TableWalker( table, { column: insertAt, includeAllSlots: true } );\n\n\t\t\tfor ( const tableSlot of tableWalker ) {\n\t\t\t\tconst { row, cell, cellAnchorColumn, cellAnchorRow, cellWidth, cellHeight } = tableSlot;\n\n\t\t\t\t// When iterating over column the table walker outputs either:\n\t\t\t\t// - cells at given column index (cell \"e\" from method docs),\n\t\t\t\t// - spanned columns (spanned cell from row between cells \"g\" and \"h\" - spanned by \"e\", only if `includeAllSlots: true`),\n\t\t\t\t// - or a cell from the same row which spans over this column (cell \"a\").\n\n\t\t\t\tif ( cellAnchorColumn < insertAt ) {\n\t\t\t\t\t// If cell is anchored in previous column, it is a cell that spans over an inserted column (cell \"a\" & \"i\").\n\t\t\t\t\t// For such cells expand them by a number of columns inserted.\n\t\t\t\t\twriter.setAttribute( 'colspan', cellWidth + columnsToInsert, cell );\n\n\t\t\t\t\t// This cell will overlap cells in rows below so skip them (because of `includeAllSlots` option) - (cell \"a\")\n\t\t\t\t\tconst lastCellRow = cellAnchorRow + cellHeight - 1;\n\n\t\t\t\t\tfor ( let i = row; i <= lastCellRow; i++ ) {\n\t\t\t\t\t\ttableWalker.skipRow( i );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// It's either cell at this column index or spanned cell by a row-spanned cell from row above.\n\t\t\t\t\t// In table above it's cell \"e\" and a spanned position from row below (empty cell between cells \"g\" and \"h\")\n\t\t\t\t\tcreateCells( columnsToInsert, writer, tableSlot.getPositionBefore() );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes rows from the given `table`.\n\t *\n\t * This method re-calculates the table geometry including `rowspan` attribute of table cells overlapping removed rows\n\t * and table headings values.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).removeRows( table, { at: 1, rows: 2 } );\n\t *\n\t * Executing the above code in the context of the table on the left will transform its structure as presented on the right:\n\t *\n\t *\t\trow index\n\t *\t\t ┌───┬───┬───┐ `at` = 1 ┌───┬───┬───┐\n\t *\t\t 0 │ a │ b │ c │ `rows` = 2 │ a │ b │ c │ 0\n\t *\t\t │ ├───┼───┤ │ ├───┼───┤\n\t *\t\t 1 │ │ d │ e │ <-- remove from here │ │ d │ g │ 1\n\t *\t\t │ │ ├───┤ will give: ├───┼───┼───┤\n\t *\t\t 2 │ │ │ f │ │ h │ i │ j │ 2\n\t *\t\t │ │ ├───┤ └───┴───┴───┘\n\t *\t\t 3 │ │ │ g │\n\t *\t\t ├───┼───┼───┤\n\t *\t\t 4 │ h │ i │ j │\n\t *\t\t └───┴───┴───┘\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @param {Object} options\n\t * @param {Number} options.at The row index at which the removing rows will start.\n\t * @param {Number} [options.rows=1] The number of rows to remove.\n\t */\n\tremoveRows( table, options ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst rowsToRemove = options.rows || 1;\n\t\tconst first = options.at;\n\t\tconst last = first + rowsToRemove - 1;\n\n\t\tmodel.change( writer => {\n\t\t\t// Removing rows from the table require that most calculations to be done prior to changing table structure.\n\t\t\t// Preparations must be done in the same enqueueChange callback to use the current table structure.\n\n\t\t\t// 1. Preparation - get row-spanned cells that have to be modified after removing rows.\n\t\t\tconst { cellsToMove, cellsToTrim } = getCellsToMoveAndTrimOnRemoveRow( table, first, last );\n\n\t\t\t// 2. Execution\n\n\t\t\t// 2a. Move cells from removed rows that extends over a removed section - must be done before removing rows.\n\t\t\t// This will fill any gaps in a rows below that previously were empty because of row-spanned cells.\n\t\t\tif ( cellsToMove.size ) {\n\t\t\t\tconst rowAfterRemovedSection = last + 1;\n\t\t\t\tmoveCellsToRow( table, rowAfterRemovedSection, cellsToMove, writer );\n\t\t\t}\n\n\t\t\t// 2b. Remove all required rows.\n\t\t\tfor ( let i = last; i >= first; i-- ) {\n\t\t\t\twriter.remove( table.getChild( i ) );\n\t\t\t}\n\n\t\t\t// 2c. Update cells from rows above that overlap removed section. Similar to step 2 but does not involve moving cells.\n\t\t\tfor ( const { rowspan, cell } of cellsToTrim ) {\n\t\t\t\tupdateNumericAttribute( 'rowspan', rowspan, cell, writer );\n\t\t\t}\n\n\t\t\t// 2d. Adjust heading rows if removed rows were in a heading section.\n\t\t\tupdateHeadingRows( table, first, last, writer );\n\n\t\t\t// 2e. Remove empty columns (without anchored cells) if there are any.\n\t\t\tif ( !removeEmptyColumns( table, this ) ) {\n\t\t\t\t// If there wasn't any empty columns then we still need to check if this wasn't called\n\t\t\t\t// because of cleaning empty rows and we only removed one of them.\n\t\t\t\tremoveEmptyRows( table, this );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Removes columns from the given `table`.\n\t *\n\t * This method re-calculates the table geometry including the `colspan` attribute of table cells overlapping removed columns\n\t * and table headings values.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).removeColumns( table, { at: 1, columns: 2 } );\n\t *\n\t * Executing the above code in the context of the table on the left will transform its structure as presented on the right:\n\t *\n\t *\t\t 0 1 2 3 4 0 1 2\n\t *\t\t┌───────────────┬───┐ ┌───────┬───┐\n\t *\t\t│ a │ b │ │ a │ b │\n\t *\t\t│ ├───┤ │ ├───┤\n\t *\t\t│ │ c │ │ │ c │\n\t *\t\t├───┬───┬───┬───┼───┤ will give: ├───┬───┼───┤\n\t *\t\t│ d │ e │ f │ g │ h │ │ d │ g │ h │\n\t *\t\t├───┼───┼───┤ ├───┤ ├───┤ ├───┤\n\t *\t\t│ i │ j │ k │ │ l │ │ i │ │ l │\n\t *\t\t├───┴───┴───┴───┴───┤ ├───┴───┴───┤\n\t *\t\t│ m │ │ m │\n\t *\t\t└───────────────────┘ └───────────┘\n\t *\t\t ^---- remove from here, `at` = 1, `columns` = 2\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @param {Object} options\n\t * @param {Number} options.at The row index at which the removing columns will start.\n\t * @param {Number} [options.columns=1] The number of columns to remove.\n\t */\n\tremoveColumns( table, options ) {\n\t\tconst model = this.editor.model;\n\t\tconst first = options.at;\n\t\tconst columnsToRemove = options.columns || 1;\n\t\tconst last = options.at + columnsToRemove - 1;\n\n\t\tmodel.change( writer => {\n\t\t\tadjustHeadingColumns( table, { first, last }, writer );\n\n\t\t\tfor ( let removedColumnIndex = last; removedColumnIndex >= first; removedColumnIndex-- ) {\n\t\t\t\tfor ( const { cell, column, cellWidth } of [ ...new TableWalker( table ) ] ) {\n\t\t\t\t\t// If colspaned cell overlaps removed column decrease its span.\n\t\t\t\t\tif ( column <= removedColumnIndex && cellWidth > 1 && column + cellWidth > removedColumnIndex ) {\n\t\t\t\t\t\tupdateNumericAttribute( 'colspan', cellWidth - 1, cell, writer );\n\t\t\t\t\t} else if ( column === removedColumnIndex ) {\n\t\t\t\t\t\t// The cell in removed column has colspan of 1.\n\t\t\t\t\t\twriter.remove( cell );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove empty rows that could appear after removing columns.\n\t\t\tif ( !removeEmptyRows( table, this ) ) {\n\t\t\t\t// If there wasn't any empty rows then we still need to check if this wasn't called\n\t\t\t\t// because of cleaning empty columns and we only removed one of them.\n\t\t\t\tremoveEmptyColumns( table, this );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell vertically into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating colspans of other cells in a column\n\t * and inserting cells (columns) after that cell.\n\t *\n\t * In the table below, if cell \"a\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * it will result in the table below:\n\t *\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| a | | | b | c |\n\t *\t\t+---+---+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+---+---+\n\t *\n\t * So cell \"d\" will get its `colspan` updated to `3` and 2 cells will be added (2 columns will be created).\n\t *\n\t * Splitting a cell that already has a `colspan` attribute set will distribute the cell `colspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `colspan=3` into 2 cells will create 1 cell with a `colspan=a` and cell \"a\" that will have `colspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | |\n\t *\t\t+---+---+---+\n\t *\t\t| b | c | d |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellVertically( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( colspan > 1 ) {\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( colspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'colspan', updatedSpan, tableCell, writer );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tconst cellsToInsert = colspan > numberOfCells ? numberOfCells - 1 : colspan - 1;\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\t\t\t}\n\n\t\t\t// Second check - the cell has colspan of 1 or we need to create more cells then the currently one spans over.\n\t\t\tif ( colspan < numberOfCells ) {\n\t\t\t\tconst cellsToInsert = numberOfCells - colspan;\n\n\t\t\t\t// First step: expand cells on the same column as split cell.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table ) ];\n\n\t\t\t\t// Get the column index of split cell.\n\t\t\t\tconst { column: splitCellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Find cells which needs to be expanded vertically - those on the same column or those that spans over split cell's column.\n\t\t\t\tconst cellsToUpdate = tableMap.filter( ( { cell, cellWidth, column } ) => {\n\t\t\t\t\tconst isOnSameColumn = cell !== tableCell && column === splitCellColumn;\n\t\t\t\t\tconst spansOverColumn = ( column < splitCellColumn && column + cellWidth > splitCellColumn );\n\n\t\t\t\t\treturn isOnSameColumn || spansOverColumn;\n\t\t\t\t} );\n\n\t\t\t\t// Expand cells vertically.\n\t\t\t\tfor ( const { cell, cellWidth } of cellsToUpdate ) {\n\t\t\t\t\twriter.setAttribute( 'colspan', cellWidth + cellsToInsert, cell );\n\t\t\t\t}\n\n\t\t\t\t// Second step: create columns after split cell.\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\n\t\t\t\t// Copy rowspan of split cell.\n\t\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = rowspan;\n\t\t\t\t}\n\n\t\t\t\tcreateCells( cellsToInsert, writer, writer.createPositionAfter( tableCell ), newCellsAttributes );\n\n\t\t\t\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tif ( headingColumns > splitCellColumn ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingColumns', headingColumns + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Divides a table cell horizontally into several ones.\n\t *\n\t * The cell will be visually split into more cells by updating rowspans of other cells in the row and inserting rows with a single cell\n\t * below.\n\t *\n\t * If in the table below cell \"b\" is split into 3 cells:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * It will result in the table below:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+ +\n\t *\t\t| | | |\n\t *\t\t+ +---+ +\n\t *\t\t| | | |\n\t *\t\t+---+---+---+\n\t *\t\t| d | e | f |\n\t *\t\t+---+---+---+\n\t *\n\t * So cells \"a\" and \"b\" will get their `rowspan` updated to `3` and 2 rows with a single cell will be added.\n\t *\n\t * Splitting a cell that already has a `rowspan` attribute set will distribute the cell `rowspan` evenly and the remainder\n\t * will be left to the original cell:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+---+\n\t *\t\t| | d | e |\n\t *\t\t+ +---+---+\n\t *\t\t| | f | g |\n\t *\t\t+ +---+---+\n\t *\t\t| | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * Splitting cell \"a\" with `rowspan=4` into 3 cells will create 2 cells with a `rowspan=1` and cell \"a\" will have `rowspan=2`:\n\t *\n\t *\t\t+---+---+---+\n\t *\t\t| a | b | c |\n\t *\t\t+ +---+---+\n\t *\t\t| | d | e |\n\t *\t\t+---+---+---+\n\t *\t\t| | f | g |\n\t *\t\t+---+---+---+\n\t *\t\t| | h | i |\n\t *\t\t+---+---+---+\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @param {Number} numberOfCells\n\t */\n\tsplitCellHorizontally( tableCell, numberOfCells = 2 ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst tableRow = tableCell.parent;\n\t\tconst table = tableRow.parent;\n\t\tconst splitCellRow = table.getChildIndex( tableRow );\n\n\t\tconst rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );\n\t\tconst colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );\n\n\t\tmodel.change( writer => {\n\t\t\t// First check - the cell spans over multiple rows so before doing anything else just split this cell.\n\t\t\tif ( rowspan > 1 ) {\n\t\t\t\t// Cache table map before updating table.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, {\n\t\t\t\t\tstartRow: splitCellRow,\n\t\t\t\t\tendRow: splitCellRow + rowspan - 1,\n\t\t\t\t\tincludeAllSlots: true\n\t\t\t\t} ) ];\n\n\t\t\t\t// Get spans of new (inserted) cells and span to update of split cell.\n\t\t\t\tconst { newCellsSpan, updatedSpan } = breakSpanEvenly( rowspan, numberOfCells );\n\n\t\t\t\tupdateNumericAttribute( 'rowspan', updatedSpan, tableCell, writer );\n\n\t\t\t\tconst { column: cellColumn } = tableMap.find( ( { cell } ) => cell === tableCell );\n\n\t\t\t\t// Each inserted cell will have the same attributes:\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Do not store default value in the model.\n\t\t\t\tif ( newCellsSpan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.rowspan = newCellsSpan;\n\t\t\t\t}\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tfor ( const tableSlot of tableMap ) {\n\t\t\t\t\tconst { column, row } = tableSlot;\n\n\t\t\t\t\t// As both newly created cells and the split cell might have rowspan,\n\t\t\t\t\t// the insertion of new cells must go to appropriate rows:\n\t\t\t\t\t//\n\t\t\t\t\t// 1. It's a row after split cell + it's height.\n\t\t\t\t\tconst isAfterSplitCell = row >= splitCellRow + updatedSpan;\n\t\t\t\t\t// 2. Is on the same column.\n\t\t\t\t\tconst isOnSameColumn = column === cellColumn;\n\t\t\t\t\t// 3. And it's row index is after previous cell height.\n\t\t\t\t\tconst isInEvenlySplitRow = ( row + splitCellRow + updatedSpan ) % newCellsSpan === 0;\n\n\t\t\t\t\tif ( isAfterSplitCell && isOnSameColumn && isInEvenlySplitRow ) {\n\t\t\t\t\t\tcreateCells( 1, writer, tableSlot.getPositionBefore(), newCellsAttributes );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Second check - the cell has rowspan of 1 or we need to create more cells than the current cell spans over.\n\t\t\tif ( rowspan < numberOfCells ) {\n\t\t\t\t// We already split the cell in check one so here we split to the remaining number of cells only.\n\t\t\t\tconst cellsToInsert = numberOfCells - rowspan;\n\n\t\t\t\t// This check is needed since we need to check if there are any cells from previous rows than spans over this cell's row.\n\t\t\t\tconst tableMap = [ ...new TableWalker( table, { startRow: 0, endRow: splitCellRow } ) ];\n\n\t\t\t\t// First step: expand cells.\n\t\t\t\tfor ( const { cell, cellHeight, row } of tableMap ) {\n\t\t\t\t\t// Expand rowspan of cells that are either:\n\t\t\t\t\t// - on the same row as current cell,\n\t\t\t\t\t// - or are below split cell row and overlaps that row.\n\t\t\t\t\tif ( cell !== tableCell && row + cellHeight > splitCellRow ) {\n\t\t\t\t\t\tconst rowspanToSet = cellHeight + cellsToInsert;\n\n\t\t\t\t\t\twriter.setAttribute( 'rowspan', rowspanToSet, cell );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Second step: create rows with single cell below split cell.\n\t\t\t\tconst newCellsAttributes = {};\n\n\t\t\t\t// Copy colspan of split cell.\n\t\t\t\tif ( colspan > 1 ) {\n\t\t\t\t\tnewCellsAttributes.colspan = colspan;\n\t\t\t\t}\n\n\t\t\t\tcreateEmptyRows( writer, table, splitCellRow + 1, cellsToInsert, 1, newCellsAttributes );\n\n\t\t\t\t// Update heading section if split cell is in heading section.\n\t\t\t\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\t\t\t\tif ( headingRows > splitCellRow ) {\n\t\t\t\t\tupdateNumericAttribute( 'headingRows', headingRows + cellsToInsert, table, writer );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the number of columns for a given table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).getColumns( table );\n\t *\n\t * @param {module:engine/model/element~Element} table The table to analyze.\n\t * @returns {Number}\n\t */\n\tgetColumns( table ) {\n\t\t// Analyze first row only as all the rows should have the same width.\n\t\tconst row = table.getChild( 0 );\n\n\t\treturn [ ...row.getChildren() ].reduce( ( columns, row ) => {\n\t\t\tconst columnWidth = parseInt( row.getAttribute( 'colspan' ) || 1 );\n\n\t\t\treturn columns + columnWidth;\n\t\t}, 0 );\n\t}\n\n\t/**\n\t * Returns the number of rows for a given table.\n\t *\n\t *\t\teditor.plugins.get( 'TableUtils' ).getRows( table );\n\t *\n\t * @param {module:engine/model/element~Element} table The table to analyze.\n\t * @returns {Number}\n\t */\n\tgetRows( table ) {\n\t\t// Simple row counting, not including rowspan due to #6427.\n\t\treturn table.childCount;\n\t}\n}\n\n// Creates empty rows at the given index in an existing table.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/element~Element} table\n// @param {Number} insertAt The row index of row insertion.\n// @param {Number} rows The number of rows to create.\n// @param {Number} tableCellToInsert The number of cells to insert in each row.\nfunction createEmptyRows( writer, table, insertAt, rows, tableCellToInsert, attributes = {} ) {\n\tfor ( let i = 0; i < rows; i++ ) {\n\t\tconst tableRow = writer.createElement( 'tableRow' );\n\n\t\twriter.insert( tableRow, table, insertAt );\n\n\t\tcreateCells( tableCellToInsert, writer, writer.createPositionAt( tableRow, 'end' ), attributes );\n\t}\n}\n\n// Creates cells at a given position.\n//\n// @param {Number} columns The number of columns to create\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/position~Position} insertPosition\nfunction createCells( cells, writer, insertPosition, attributes = {} ) {\n\tfor ( let i = 0; i < cells; i++ ) {\n\t\tcreateEmptyTableCell( writer, insertPosition, attributes );\n\t}\n}\n\n// Evenly distributes the span of a cell to a number of provided cells.\n// The resulting spans will always be integer values.\n//\n// For instance breaking a span of 7 into 3 cells will return:\n//\n//\t\t{ newCellsSpan: 2, updatedSpan: 3 }\n//\n// as two cells will have a span of 2 and the remainder will go the first cell so its span will change to 3.\n//\n// @param {Number} span The span value do break.\n// @param {Number} numberOfCells The number of resulting spans.\n// @returns {{newCellsSpan: Number, updatedSpan: Number}}\nfunction breakSpanEvenly( span, numberOfCells ) {\n\tif ( span < numberOfCells ) {\n\t\treturn { newCellsSpan: 1, updatedSpan: 1 };\n\t}\n\n\tconst newCellsSpan = Math.floor( span / numberOfCells );\n\tconst updatedSpan = ( span - newCellsSpan * numberOfCells ) + newCellsSpan;\n\n\treturn { newCellsSpan, updatedSpan };\n}\n\n// Updates heading columns attribute if removing a row from head section.\nfunction adjustHeadingColumns( table, removedColumnIndexes, writer ) {\n\tconst headingColumns = table.getAttribute( 'headingColumns' ) || 0;\n\n\tif ( headingColumns && removedColumnIndexes.first < headingColumns ) {\n\t\tconst headingsRemoved = Math.min( headingColumns - 1 /* Other numbers are 0-based */, removedColumnIndexes.last ) -\n\t\t\tremovedColumnIndexes.first + 1;\n\n\t\twriter.setAttribute( 'headingColumns', headingColumns - headingsRemoved, table );\n\t}\n}\n\n// Calculates a new heading rows value for removing rows from heading section.\nfunction updateHeadingRows( table, first, last, writer ) {\n\tconst headingRows = table.getAttribute( 'headingRows' ) || 0;\n\n\tif ( first < headingRows ) {\n\t\tconst newRows = last < headingRows ? headingRows - ( last - first + 1 ) : first;\n\n\t\tupdateNumericAttribute( 'headingRows', newRows, table, writer, 0 );\n\t}\n}\n\n// Finds cells that will be:\n// - trimmed - Cells that are \"above\" removed rows sections and overlap the removed section - their rowspan must be trimmed.\n// - moved - Cells from removed rows section might stick out of. These cells are moved to the next row after a removed section.\n//\n// Sample table with overlapping & sticking out cells:\n//\n// +----+----+----+----+----+\n// | 00 | 01 | 02 | 03 | 04 |\n// +----+ + + + +\n// | 10 | | | | |\n// +----+----+ + + +\n// | 20 | 21 | | | | <-- removed row\n// + + +----+ + +\n// | | | 32 | | | <-- removed row\n// +----+ + +----+ +\n// | 40 | | | 43 | |\n// +----+----+----+----+----+\n//\n// In a table above:\n// - cells to trim: '02', '03' & '04'.\n// - cells to move: '21' & '32'.\nfunction getCellsToMoveAndTrimOnRemoveRow( table, first, last ) {\n\tconst cellsToMove = new Map();\n\tconst cellsToTrim = [];\n\n\tfor ( const { row, column, cellHeight, cell } of new TableWalker( table, { endRow: last } ) ) {\n\t\tconst lastRowOfCell = row + cellHeight - 1;\n\n\t\tconst isCellStickingOutFromRemovedRows = row >= first && row <= last && lastRowOfCell > last;\n\n\t\tif ( isCellStickingOutFromRemovedRows ) {\n\t\t\tconst rowspanInRemovedSection = last - row + 1;\n\t\t\tconst rowSpanToSet = cellHeight - rowspanInRemovedSection;\n\n\t\t\tcellsToMove.set( column, {\n\t\t\t\tcell,\n\t\t\t\trowspan: rowSpanToSet\n\t\t\t} );\n\t\t}\n\n\t\tconst isCellOverlappingRemovedRows = row < first && lastRowOfCell >= first;\n\n\t\tif ( isCellOverlappingRemovedRows ) {\n\t\t\tlet rowspanAdjustment;\n\n\t\t\t// Cell fully covers removed section - trim it by removed rows count.\n\t\t\tif ( lastRowOfCell >= last ) {\n\t\t\t\trowspanAdjustment = last - first + 1;\n\t\t\t}\n\t\t\t// Cell partially overlaps removed section - calculate cell's span that is in removed section.\n\t\t\telse {\n\t\t\t\trowspanAdjustment = lastRowOfCell - first + 1;\n\t\t\t}\n\n\t\t\tcellsToTrim.push( {\n\t\t\t\tcell,\n\t\t\t\trowspan: cellHeight - rowspanAdjustment\n\t\t\t} );\n\t\t}\n\t}\n\treturn { cellsToMove, cellsToTrim };\n}\n\nfunction moveCellsToRow( table, targetRowIndex, cellsToMove, writer ) {\n\tconst tableWalker = new TableWalker( table, {\n\t\tincludeAllSlots: true,\n\t\trow: targetRowIndex\n\t} );\n\n\tconst tableRowMap = [ ...tableWalker ];\n\tconst row = table.getChild( targetRowIndex );\n\n\tlet previousCell;\n\n\tfor ( const { column, cell, isAnchor } of tableRowMap ) {\n\t\tif ( cellsToMove.has( column ) ) {\n\t\t\tconst { cell: cellToMove, rowspan } = cellsToMove.get( column );\n\n\t\t\tconst targetPosition = previousCell ?\n\t\t\t\twriter.createPositionAfter( previousCell ) :\n\t\t\t\twriter.createPositionAt( row, 0 );\n\n\t\t\twriter.move( writer.createRangeOn( cellToMove ), targetPosition );\n\t\t\tupdateNumericAttribute( 'rowspan', rowspan, cellToMove, writer );\n\n\t\t\tpreviousCell = cellToMove;\n\t\t} else if ( isAnchor ) {\n\t\t\t// If cell is spanned then `cell` holds reference to overlapping cell. See ckeditor/ckeditor5#6502.\n\t\t\tpreviousCell = cell;\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/mergecellscommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport TableUtils from '../tableutils';\nimport { getSelectedTableCells, isSelectionRectangular } from '../utils/selection';\nimport { updateNumericAttribute } from '../utils/common';\nimport { removeEmptyRowsColumns } from '../utils/structure';\n\n/**\n * The merge cells command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'mergeTableCells'` editor command.\n *\n * For example, to merge selected table cells:\n *\n *\t\teditor.execute( 'mergeTableCells' );\n *\n * @extends module:core/command~Command\n */\nexport default class MergeCellsCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedTableCells = getSelectedTableCells( this.editor.model.document.selection );\n\t\tthis.isEnabled = isSelectionRectangular( selectedTableCells, this.editor.plugins.get( TableUtils ) );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst tableUtils = this.editor.plugins.get( TableUtils );\n\n\t\tmodel.change( writer => {\n\t\t\tconst selectedTableCells = getSelectedTableCells( model.document.selection );\n\n\t\t\t// All cells will be merged into the first one.\n\t\t\tconst firstTableCell = selectedTableCells.shift();\n\n\t\t\t// Update target cell dimensions.\n\t\t\tconst { mergeWidth, mergeHeight } = getMergeDimensions( firstTableCell, selectedTableCells, tableUtils );\n\t\t\tupdateNumericAttribute( 'colspan', mergeWidth, firstTableCell, writer );\n\t\t\tupdateNumericAttribute( 'rowspan', mergeHeight, firstTableCell, writer );\n\n\t\t\tfor ( const tableCell of selectedTableCells ) {\n\t\t\t\tmergeTableCells( tableCell, firstTableCell, writer );\n\t\t\t}\n\n\t\t\tconst table = firstTableCell.findAncestor( 'table' );\n\n\t\t\t// Remove rows and columns that become empty (have no anchored cells).\n\t\t\tremoveEmptyRowsColumns( table, tableUtils );\n\n\t\t\twriter.setSelection( firstTableCell, 'in' );\n\t\t} );\n\t}\n}\n\n// Merges two table cells. It will ensure that after merging cells with empty paragraphs the resulting table cell will only have one\n// paragraph. If one of the merged table cells is empty, the merged table cell will have contents of the non-empty table cell.\n// If both are empty, the merged table cell will have only one empty paragraph.\n//\n// @param {module:engine/model/element~Element} cellBeingMerged\n// @param {module:engine/model/element~Element} targetCell\n// @param {module:engine/model/writer~Writer} writer\nfunction mergeTableCells( cellBeingMerged, targetCell, writer ) {\n\tif ( !isEmpty( cellBeingMerged ) ) {\n\t\tif ( isEmpty( targetCell ) ) {\n\t\t\twriter.remove( writer.createRangeIn( targetCell ) );\n\t\t}\n\n\t\twriter.move( writer.createRangeIn( cellBeingMerged ), writer.createPositionAt( targetCell, 'end' ) );\n\t}\n\n\t// Remove merged table cell.\n\twriter.remove( cellBeingMerged );\n}\n\n// Checks if the passed table cell contains an empty paragraph.\n//\n// @param {module:engine/model/element~Element} tableCell\n// @returns {Boolean}\nfunction isEmpty( tableCell ) {\n\treturn tableCell.childCount == 1 && tableCell.getChild( 0 ).is( 'element', 'paragraph' ) && tableCell.getChild( 0 ).isEmpty;\n}\n\nfunction getMergeDimensions( firstTableCell, selectedTableCells, tableUtils ) {\n\tlet maxWidthOffset = 0;\n\tlet maxHeightOffset = 0;\n\n\tfor ( const tableCell of selectedTableCells ) {\n\t\tconst { row, column } = tableUtils.getCellLocation( tableCell );\n\n\t\tmaxWidthOffset = getMaxOffset( tableCell, column, maxWidthOffset, 'colspan' );\n\t\tmaxHeightOffset = getMaxOffset( tableCell, row, maxHeightOffset, 'rowspan' );\n\t}\n\n\t// Update table cell span attribute and merge set selection on a merged contents.\n\tconst { row: firstCellRow, column: firstCellColumn } = tableUtils.getCellLocation( firstTableCell );\n\n\tconst mergeWidth = maxWidthOffset - firstCellColumn;\n\tconst mergeHeight = maxHeightOffset - firstCellRow;\n\n\treturn { mergeWidth, mergeHeight };\n}\n\nfunction getMaxOffset( tableCell, start, currentMaxOffset, which ) {\n\tconst dimensionValue = parseInt( tableCell.getAttribute( which ) || 1 );\n\n\treturn Math.max( currentMaxOffset, start + dimensionValue );\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 table/commands/selectrowcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The select row command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'selectTableRow'` editor command.\n *\n * To select the rows containing the selected cells, execute the command:\n *\n *\t\teditor.execute( 'selectTableRow' );\n *\n * @extends module:core/command~Command\n */\nexport default class SelectRowCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\n\t\tthis.isEnabled = selectedCells.length > 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst referenceCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst rowIndexes = getRowIndexes( referenceCells );\n\n\t\tconst table = referenceCells[ 0 ].findAncestor( 'table' );\n\t\tconst rangesToSelect = [];\n\n\t\tfor ( let rowIndex = rowIndexes.first; rowIndex <= rowIndexes.last; rowIndex++ ) {\n\t\t\tfor ( const cell of table.getChild( rowIndex ).getChildren() ) {\n\t\t\t\trangesToSelect.push( model.createRangeOn( cell ) );\n\t\t\t}\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( rangesToSelect );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/commands/selectcolumncommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport TableWalker from '../tablewalker';\nimport { getSelectionAffectedTableCells } from '../utils/selection';\n\n/**\n * The select column command.\n *\n * The command is registered by {@link module:table/tableediting~TableEditing} as the `'selectTableColumn'` editor command.\n *\n * To select the columns containing the selected cells, execute the command:\n *\n *\t\teditor.execute( 'selectTableColumn' );\n *\n * @extends module:core/command~Command\n */\nexport default class SelectColumnCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );\n\n\t\tthis.isEnabled = selectedCells.length > 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst referenceCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst firstCell = referenceCells[ 0 ];\n\t\tconst lastCell = referenceCells.pop();\n\t\tconst table = firstCell.findAncestor( 'table' );\n\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\tconst startLocation = tableUtils.getCellLocation( firstCell );\n\t\tconst endLocation = tableUtils.getCellLocation( lastCell );\n\n\t\tconst startColumn = Math.min( startLocation.column, endLocation.column );\n\t\tconst endColumn = Math.max( startLocation.column, endLocation.column );\n\n\t\tconst rangesToSelect = [];\n\n\t\tfor ( const cellInfo of new TableWalker( table, { startColumn, endColumn } ) ) {\n\t\t\trangesToSelect.push( model.createRangeOn( cellInfo.cell ) );\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( rangesToSelect );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/table-layout-post-fixer\n */\n\nimport TableWalker from './../tablewalker';\nimport { createEmptyTableCell, updateNumericAttribute } from '../utils/common';\n\n/**\n * Injects a table layout post-fixer into the model.\n *\n * The role of the table layout post-fixer is to ensure that the table rows have the correct structure\n * after a {@link module:engine/model/model~Model#change `change()`} block was executed.\n *\n * The correct structure means that:\n *\n * * All table rows have the same size.\n * * None of the table cells extend vertically beyond their section (either header or body).\n * * A table cell has always at least one element as a child.\n *\n * If the table structure is not correct, the post-fixer will automatically correct it in two steps:\n *\n * 1. It will clip table cells that extend beyond their section.\n * 2. It will add empty table cells to the rows that are narrower than the widest table row.\n *\n * ## Clipping overlapping table cells\n *\n * Such situation may occur when pasting a table (or a part of a table) to the editor from external sources.\n *\n * For example, see the following table which has a cell (FOO) with the rowspan attribute (2):\n *\n *\t\t<table headingRows=\"1\">\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell rowspan=\"2\"><paragraph>FOO</paragraph></tableCell>\n *\t\t\t\t<tableCell colspan=\"2\"><paragraph>BAR</paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell><paragraph>BAZ</paragraph></tableCell>\n *\t\t\t\t<tableCell><paragraph>XYZ</paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * It will be rendered in the view as:\n *\n *\t\t<table>\n *\t\t\t<thead>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td rowspan=\"2\">FOO</td>\n *\t\t\t\t\t<td colspan=\"2\">BAR</td>\n *\t\t\t\t</tr>\n *\t\t\t</thead>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>BAZ</td>\n *\t\t\t\t\t<td>XYZ</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * In the above example the table will be rendered as a table with two rows: one in the header and second one in the body.\n * The table cell (FOO) cannot span over multiple rows as it would extend from the header to the body section.\n * The `rowspan` attribute must be changed to (1). The value (1) is the default value of the `rowspan` attribute\n * so the `rowspan` attribute will be removed from the model.\n *\n * The table cell with BAZ in the content will be in the first column of the table.\n *\n * ## Adding missing table cells\n *\n * The table post-fixer will insert empty table cells to equalize table row sizes (the number of columns).\n * The size of a table row is calculated by counting column spans of table cells, both horizontal (from the same row) and\n * vertical (from the rows above).\n *\n * In the above example, the table row in the body section of the table is narrower then the row from the header: it has two cells\n * with the default colspan (1). The header row has one cell with colspan (1) and the second with colspan (2).\n * The table cell (FOO) does not extend beyond the head section (and as such will be fixed in the first step of this post-fixer).\n * The post-fixer will add a missing table cell to the row in the body section of the table.\n *\n * The table from the above example will be fixed and rendered to the view as below:\n *\n *\t\t<table>\n *\t\t\t<thead>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td rowspan=\"2\">FOO</td>\n *\t\t\t\t\t<td colspan=\"2\">BAR</td>\n *\t\t\t\t</tr>\n *\t\t\t</thead>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>BAZ</td>\n *\t\t\t\t\t<td>XYZ</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * ## Collaboration and undo - Expectations vs post-fixer results\n *\n * The table post-fixer only ensures proper structure without a deeper analysis of the nature of the change. As such, it might lead\n * to a structure which was not intended by the user. In particular, it will also fix undo steps (in conjunction with collaboration)\n * in which the editor content might not return to the original state.\n *\n * This will usually happen when one or more users change the size of the table.\n *\n * As an example see the table below:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * and the user actions:\n *\n * 1. Both users have a table with two rows and two columns.\n * 2. User A adds a column at the end of the table. This will insert empty table cells to two rows.\n * 3. User B adds a row at the end of the table. This will insert a row with two empty table cells.\n * 4. Both users will have a table as below:\n *\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * The last row is shorter then others so the table post-fixer will add an empty row to the last row:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by A)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by the post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * Unfortunately undo does not know the nature of the changes and depending on which user applies the post-fixer changes, undoing them\n * might lead to a broken table. If User B undoes inserting the column to the table, the undo engine will undo only the operations of\n * inserting empty cells to rows from the initial table state (row 1 and 2) but the cell in the post-fixed row will remain:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n *\n * After undo, the table post-fixer will detect that two rows are shorter than others and will fix the table to:\n *\n *\t\t<table>\n *\t\t\t<tbody>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>11</td>\n *\t\t\t\t\t<td>12</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer after undo)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>21</td>\n *\t\t\t\t\t<td>22</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer after undo)</td>\n *\t\t\t\t</tr>\n *\t\t\t\t<tr>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by B)</td>\n *\t\t\t\t\t<td>(empty, inserted by a post-fixer)</td>\n *\t\t\t\t</tr>\n *\t\t\t</tbody>\n *\t\t</table>\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableLayoutPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => tableLayoutPostFixer( writer, model ) );\n}\n\n// The table layout post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction tableLayoutPostFixer( writer, model ) {\n\tconst changes = model.document.differ.getChanges();\n\n\tlet wasFixed = false;\n\n\t// Do not analyze the same table more then once - may happen for multiple changes in the same table.\n\tconst analyzedTables = new Set();\n\n\tfor ( const entry of changes ) {\n\t\tlet table;\n\n\t\tif ( entry.name == 'table' && entry.type == 'insert' ) {\n\t\t\ttable = entry.position.nodeAfter;\n\t\t}\n\n\t\t// Fix table on adding/removing table cells and rows.\n\t\tif ( entry.name == 'tableRow' || entry.name == 'tableCell' ) {\n\t\t\ttable = entry.position.findAncestor( 'table' );\n\t\t}\n\n\t\t// Fix table on any table's attribute change - including attributes of table cells.\n\t\tif ( isTableAttributeEntry( entry ) ) {\n\t\t\ttable = entry.range.start.findAncestor( 'table' );\n\t\t}\n\n\t\tif ( table && !analyzedTables.has( table ) ) {\n\t\t\t// Step 1: correct rowspans of table cells if necessary.\n\t\t\t// The wasFixed flag should be true if any of tables in batch was fixed - might be more then one.\n\t\t\twasFixed = fixTableCellsRowspan( table, writer ) || wasFixed;\n\t\t\t// Step 2: fix table rows sizes.\n\t\t\twasFixed = fixTableRowsSizes( table, writer ) || wasFixed;\n\n\t\t\tanalyzedTables.add( table );\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes the invalid value of the `rowspan` attribute because a table cell cannot vertically extend beyond the table section it belongs to.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean} Returns `true` if the table was fixed.\nfunction fixTableCellsRowspan( table, writer ) {\n\tlet wasFixed = false;\n\n\tconst cellsToTrim = findCellsToTrim( table );\n\n\tif ( cellsToTrim.length ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: trimming cells row-spans (${ cellsToTrim.length }).` );\n\n\t\twasFixed = true;\n\n\t\tfor ( const data of cellsToTrim ) {\n\t\t\tupdateNumericAttribute( 'rowspan', data.rowspan, data.cell, writer, 1 );\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Makes all table rows in a table the same size.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean} Returns `true` if the table was fixed.\nfunction fixTableRowsSizes( table, writer ) {\n\tlet wasFixed = false;\n\n\tconst rowsLengths = getRowsLengths( table );\n\tconst rowsToRemove = [];\n\n\t// Find empty rows.\n\tfor ( const [ rowIndex, size ] of rowsLengths.entries() ) {\n\t\tif ( !size ) {\n\t\t\trowsToRemove.push( rowIndex );\n\t\t}\n\t}\n\n\t// Remove empty rows.\n\tif ( rowsToRemove.length ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: remove empty rows (${ rowsToRemove.length }).` );\n\n\t\twasFixed = true;\n\n\t\tfor ( const rowIndex of rowsToRemove.reverse() ) {\n\t\t\twriter.remove( table.getChild( rowIndex ) );\n\t\t\trowsLengths.splice( rowIndex, 1 );\n\t\t}\n\t}\n\n\t// Verify if all the rows have the same number of columns.\n\tconst tableSize = rowsLengths[ 0 ];\n\tconst isValid = rowsLengths.every( length => length === tableSize );\n\n\tif ( !isValid ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( 'Post-fixing table: adding missing cells.' );\n\n\t\t// Find the maximum number of columns.\n\t\tconst maxColumns = rowsLengths.reduce( ( prev, current ) => current > prev ? current : prev, 0 );\n\n\t\tfor ( const [ rowIndex, size ] of rowsLengths.entries() ) {\n\t\t\tconst columnsToInsert = maxColumns - size;\n\n\t\t\tif ( columnsToInsert ) {\n\t\t\t\tfor ( let i = 0; i < columnsToInsert; i++ ) {\n\t\t\t\t\tcreateEmptyTableCell( writer, writer.createPositionAt( table.getChild( rowIndex ), 'end' ) );\n\t\t\t\t}\n\n\t\t\t\twasFixed = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Searches for table cells that extend beyond the table section to which they belong to. It will return an array of objects\n// that stores table cells to be trimmed and the correct value of the `rowspan` attribute to set.\n//\n// @param {module:engine/model/element~Element} table\n// @returns {Array.<{{cell, rowspan}}>}\nfunction findCellsToTrim( table ) {\n\tconst headingRows = parseInt( table.getAttribute( 'headingRows' ) || 0 );\n\tconst maxRows = table.childCount;\n\n\tconst cellsToTrim = [];\n\n\tfor ( const { row, cell, cellHeight } of new TableWalker( table ) ) {\n\t\t// Skip cells that do not expand over its row.\n\t\tif ( cellHeight < 2 ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst isInHeader = row < headingRows;\n\n\t\t// Row limit is either end of header section or whole table as table body is after the header.\n\t\tconst rowLimit = isInHeader ? headingRows : maxRows;\n\n\t\t// If table cell expands over its limit reduce it height to proper value.\n\t\tif ( row + cellHeight > rowLimit ) {\n\t\t\tconst newRowspan = rowLimit - row;\n\n\t\t\tcellsToTrim.push( { cell, rowspan: newRowspan } );\n\t\t}\n\t}\n\n\treturn cellsToTrim;\n}\n\n// Returns an array with lengths of rows assigned to the corresponding row index.\n//\n// @param {module:engine/model/element~Element} table\n// @returns {Array.<Number>}\nfunction getRowsLengths( table ) {\n\t// TableWalker will not provide items for the empty rows, we need to pre-fill this array.\n\tconst lengths = new Array( table.childCount ).fill( 0 );\n\n\tfor ( const { row } of new TableWalker( table, { includeAllSlots: true } ) ) {\n\t\tlengths[ row ]++;\n\t}\n\n\treturn lengths;\n}\n\n// Checks if the differ entry for an attribute change is one of the table's attributes.\n//\n// @param entry\n// @returns {Boolean}\nfunction isTableAttributeEntry( entry ) {\n\tconst isAttributeType = entry.type === 'attribute';\n\tconst key = entry.attributeKey;\n\n\treturn isAttributeType && ( key === 'headingRows' || key === 'colspan' || key === 'rowspan' );\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 table/converters/table-cell-paragraph-post-fixer\n */\n\n/**\n * Injects a table cell post-fixer into the model which inserts a `paragraph` element into empty table cells.\n *\n * A table cell must contain at least one block element as a child. An empty table cell will have an empty `paragraph` as a child.\n *\n *\t\t<table>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * Will be fixed to:\n *\n *\t\t<table>\n *\t\t\t<tableRow>\n *\t\t\t\t<tableCell><paragraph></paragraph></tableCell>\n *\t\t\t</tableRow>\n *\t\t</table>\n *\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableCellParagraphPostFixer( model ) {\n\tmodel.document.registerPostFixer( writer => tableCellContentsPostFixer( writer, model ) );\n}\n\n// The table cell contents post-fixer.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/model~Model} model\nfunction tableCellContentsPostFixer( writer, model ) {\n\tconst changes = model.document.differ.getChanges();\n\n\tlet wasFixed = false;\n\n\tfor ( const entry of changes ) {\n\t\tif ( entry.type == 'insert' && entry.name == 'table' ) {\n\t\t\twasFixed = fixTable( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( entry.type == 'insert' && entry.name == 'tableRow' ) {\n\t\t\twasFixed = fixTableRow( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( entry.type == 'insert' && entry.name == 'tableCell' ) {\n\t\t\twasFixed = fixTableCellContent( entry.position.nodeAfter, writer ) || wasFixed;\n\t\t}\n\n\t\tif ( checkTableCellChange( entry ) ) {\n\t\t\twasFixed = fixTableCellContent( entry.position.parent, writer ) || wasFixed;\n\t\t}\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cells in a table.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\nfunction fixTable( table, writer ) {\n\tlet wasFixed = false;\n\n\tfor ( const row of table.getChildren() ) {\n\t\twasFixed = fixTableRow( row, writer ) || wasFixed;\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cells in a table row.\n//\n// @param {module:engine/model/element~Element} tableRow\n// @param {module:engine/model/writer~Writer} writer\nfunction fixTableRow( tableRow, writer ) {\n\tlet wasFixed = false;\n\n\tfor ( const tableCell of tableRow.getChildren() ) {\n\t\twasFixed = fixTableCellContent( tableCell, writer ) || wasFixed;\n\t}\n\n\treturn wasFixed;\n}\n\n// Fixes all table cell content by:\n// - Adding a paragraph to a table cell without any child.\n// - Wrapping direct $text in a `<paragraph>`.\n//\n// @param {module:engine/model/element~Element} table\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean}\nfunction fixTableCellContent( tableCell, writer ) {\n\t// Insert paragraph to an empty table cell.\n\tif ( tableCell.childCount == 0 ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( 'Post-fixing table: insert paragraph in empty cell.' );\n\n\t\twriter.insertElement( 'paragraph', tableCell );\n\n\t\treturn true;\n\t}\n\n\t// Check table cell children for directly placed text nodes.\n\t// Temporary solution. See https://github.com/ckeditor/ckeditor5/issues/1464.\n\tconst textNodes = Array.from( tableCell.getChildren() ).filter( child => child.is( '$text' ) );\n\n\t// @if CK_DEBUG_TABLE // textNodes.length && console.log( 'Post-fixing table: wrap cell content with paragraph.' );\n\n\tfor ( const child of textNodes ) {\n\t\twriter.wrap( writer.createRangeOn( child ), 'paragraph' );\n\t}\n\n\t// Return true when there were text nodes to fix.\n\treturn !!textNodes.length;\n}\n\n// Checks if a differ change should fix the table cell. This happens on:\n// - Removing content from the table cell (i.e. `tableCell` can be left empty).\n// - Adding a text node directly into a table cell.\n//\n// @param {Object} differ change entry\n// @returns {Boolean}\nfunction checkTableCellChange( entry ) {\n\tif ( !entry.position || !entry.position.parent.is( 'element', 'tableCell' ) ) {\n\t\treturn false;\n\t}\n\n\treturn entry.type == 'insert' && entry.name == '$text' || entry.type == 'remove';\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 table/converters/table-cell-refresh-post-fixer\n */\n\nimport { isSingleParagraphWithoutAttributes } from './downcast';\n\n/**\n * Injects a table cell post-fixer into the model which marks the table cell in the differ to have it re-rendered.\n *\n * Model `paragraph` inside a table cell can be rendered as `<span>` or `<p>`. It is rendered as `<span>` if this is the only block\n * element in that table cell and it does not have any attributes. It is rendered as `<p>` otherwise.\n *\n * When table cell content changes, for example a second `paragraph` element is added, we need to ensure that the first `paragraph` is\n * re-rendered so it changes from `<span>` to `<p>`. The easiest way to do it is to re-render the entire table cell.\n *\n * @param {module:engine/model/model~Model} model\n * @param {module:engine/conversion/mapper~Mapper} mapper\n */\nexport default function injectTableCellRefreshPostFixer( model, mapper ) {\n\tmodel.document.registerPostFixer( () => tableCellRefreshPostFixer( model.document.differ, mapper ) );\n}\n\nfunction tableCellRefreshPostFixer( differ, mapper ) {\n\t// Stores cells to be refreshed, so the table cell will be refreshed once for multiple changes.\n\n\t// 1. Gather all changes inside table cell.\n\tconst cellsToCheck = new Set();\n\n\tfor ( const change of differ.getChanges() ) {\n\t\tconst parent = change.type == 'attribute' ? change.range.start.parent : change.position.parent;\n\n\t\tif ( parent.is( 'element', 'tableCell' ) ) {\n\t\t\tcellsToCheck.add( parent );\n\t\t}\n\t}\n\n\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: Checking table cell to refresh (${ cellsToCheck.size }).` );\n\t// @if CK_DEBUG_TABLE // let paragraphsRefreshed = 0;\n\n\tfor ( const tableCell of cellsToCheck.values() ) {\n\t\tfor ( const paragraph of [ ...tableCell.getChildren() ].filter( child => shouldRefresh( child, mapper ) ) ) {\n\t\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: refreshing paragraph in table cell (${++paragraphsRefreshed}).` );\n\t\t\tdiffer.refreshItem( paragraph );\n\t\t}\n\t}\n\n\t// Always return false to prevent the refresh post-fixer from re-running on the same set of changes and going into an infinite loop.\n\t// This \"post-fixer\" does not change the model structure so there shouldn't be need to run other post-fixers again.\n\t// See https://github.com/ckeditor/ckeditor5/issues/1936 & https://github.com/ckeditor/ckeditor5/issues/8200.\n\treturn false;\n}\n\n// Check if given model element needs refreshing.\n//\n// @param {module:engine/model/element~Element} modelElement\n// @param {module:engine/conversion/mapper~Mapper} mapper\n// @returns {Boolean}\nfunction shouldRefresh( child, mapper ) {\n\tif ( !child.is( 'element', 'paragraph' ) ) {\n\t\treturn false;\n\t}\n\n\tconst viewElement = mapper.toViewElement( child );\n\n\tif ( !viewElement ) {\n\t\treturn false;\n\t}\n\n\treturn isSingleParagraphWithoutAttributes( child ) !== viewElement.is( 'element', 'span' );\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 table/converters/table-heading-rows-refresh-post-fixer\n */\n\n/**\n * Injects a table post-fixer into the model which marks the table in the differ to have it re-rendered.\n *\n * Table heading rows are represented in the model by a `headingRows` attribute. However, in the view, it's represented as separate\n * sections of the table (`<thead>` or `<tbody>`) and changing `headingRows` attribute requires moving table rows between two sections.\n * This causes problems with structural changes in a table (like adding and removing rows) thus atomic converters cannot be used.\n *\n * When table `headingRows` attribute changes, the entire table is re-rendered.\n *\n * @param {module:engine/model/model~Model} model\n */\nexport default function injectTableHeadingRowsRefreshPostFixer( model ) {\n\tmodel.document.registerPostFixer( () => tableHeadingRowsRefreshPostFixer( model ) );\n}\n\nfunction tableHeadingRowsRefreshPostFixer( model ) {\n\tconst differ = model.document.differ;\n\n\t// Stores tables to be refreshed so the table will be refreshed once for multiple changes.\n\tconst tablesToRefresh = new Set();\n\n\tfor ( const change of differ.getChanges() ) {\n\t\tif ( change.type != 'attribute' ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst element = change.range.start.nodeAfter;\n\n\t\tif ( element && element.is( 'element', 'table' ) && change.attributeKey == 'headingRows' ) {\n\t\t\ttablesToRefresh.add( element );\n\t\t}\n\t}\n\n\tif ( tablesToRefresh.size ) {\n\t\t// @if CK_DEBUG_TABLE // console.log( `Post-fixing table: refreshing heading rows (${ tablesToRefresh.size }).` );\n\n\t\tfor ( const table of tablesToRefresh.values() ) {\n\t\t\t// Should be handled by a `triggerBy` configuration. See: https://github.com/ckeditor/ckeditor5/issues/8138.\n\t\t\tdiffer.refreshItem( table );\n\t\t}\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport upcastTable, { ensureParagraphInTableCell, skipEmptyTableRow } from './converters/upcasttable';\nimport {\n\tconvertParagraphInTableCell,\n\tdowncastInsertCell,\n\tdowncastInsertRow,\n\tdowncastInsertTable,\n\tdowncastRemoveRow,\n\tdowncastTableHeadingColumnsChange\n} from './converters/downcast';\n\nimport InsertTableCommand from './commands/inserttablecommand';\nimport InsertRowCommand from './commands/insertrowcommand';\nimport InsertColumnCommand from './commands/insertcolumncommand';\nimport SplitCellCommand from './commands/splitcellcommand';\nimport MergeCellCommand from './commands/mergecellcommand';\nimport RemoveRowCommand from './commands/removerowcommand';\nimport RemoveColumnCommand from './commands/removecolumncommand';\nimport SetHeaderRowCommand from './commands/setheaderrowcommand';\nimport SetHeaderColumnCommand from './commands/setheadercolumncommand';\nimport MergeCellsCommand from './commands/mergecellscommand';\nimport SelectRowCommand from './commands/selectrowcommand';\nimport SelectColumnCommand from './commands/selectcolumncommand';\nimport TableUtils from '../src/tableutils';\n\nimport injectTableLayoutPostFixer from './converters/table-layout-post-fixer';\nimport injectTableCellParagraphPostFixer from './converters/table-cell-paragraph-post-fixer';\nimport injectTableCellRefreshPostFixer from './converters/table-cell-refresh-post-fixer';\nimport injectTableHeadingRowsRefreshPostFixer from './converters/table-heading-rows-refresh-post-fixer';\n\nimport '../theme/tableediting.css';\n\n/**\n * The table editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst schema = model.schema;\n\t\tconst conversion = editor.conversion;\n\n\t\tschema.register( 'table', {\n\t\t\tallowWhere: '$block',\n\t\t\tallowAttributes: [ 'headingRows', 'headingColumns' ],\n\t\t\tisObject: true,\n\t\t\tisBlock: true\n\t\t} );\n\n\t\tschema.register( 'tableRow', {\n\t\t\tallowIn: 'table',\n\t\t\tisLimit: true\n\t\t} );\n\n\t\tschema.register( 'tableCell', {\n\t\t\tallowIn: 'tableRow',\n\t\t\tallowAttributes: [ 'colspan', 'rowspan' ],\n\t\t\tisLimit: true,\n\t\t\tisSelectable: true\n\t\t} );\n\n\t\t// Allow all $block content inside a table cell.\n\t\tschema.extend( '$block', { allowIn: 'tableCell' } );\n\n\t\t// Table conversion.\n\t\tconversion.for( 'upcast' ).add( upcastTable() );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertTable( { asWidget: true } ) );\n\t\tconversion.for( 'dataDowncast' ).add( downcastInsertTable() );\n\n\t\t// Table row conversion.\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableRow', view: 'tr' } );\n\t\tconversion.for( 'upcast' ).add( skipEmptyTableRow() );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertRow() );\n\t\tconversion.for( 'editingDowncast' ).add( downcastRemoveRow() );\n\n\t\t// Table cell conversion.\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableCell', view: 'td' } );\n\t\tconversion.for( 'upcast' ).elementToElement( { model: 'tableCell', view: 'th' } );\n\t\tconversion.for( 'upcast' ).add( ensureParagraphInTableCell( 'td' ) );\n\t\tconversion.for( 'upcast' ).add( ensureParagraphInTableCell( 'th' ) );\n\n\t\tconversion.for( 'editingDowncast' ).add( downcastInsertCell() );\n\n\t\t// Duplicates code - needed to properly refresh paragraph inside a table cell.\n\t\teditor.conversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'paragraph',\n\t\t\tview: convertParagraphInTableCell,\n\t\t\tconverterPriority: 'high'\n\t\t} );\n\n\t\t// Table attributes conversion.\n\t\tconversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );\n\t\tconversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );\n\n\t\t// Table heading columns conversion (a change of heading rows requires a reconversion of the whole table).\n\t\tconversion.for( 'editingDowncast' ).add( downcastTableHeadingColumnsChange() );\n\n\t\t// Define all the commands.\n\t\teditor.commands.add( 'insertTable', new InsertTableCommand( editor ) );\n\t\teditor.commands.add( 'insertTableRowAbove', new InsertRowCommand( editor, { order: 'above' } ) );\n\t\teditor.commands.add( 'insertTableRowBelow', new InsertRowCommand( editor, { order: 'below' } ) );\n\t\teditor.commands.add( 'insertTableColumnLeft', new InsertColumnCommand( editor, { order: 'left' } ) );\n\t\teditor.commands.add( 'insertTableColumnRight', new InsertColumnCommand( editor, { order: 'right' } ) );\n\n\t\teditor.commands.add( 'removeTableRow', new RemoveRowCommand( editor ) );\n\t\teditor.commands.add( 'removeTableColumn', new RemoveColumnCommand( editor ) );\n\n\t\teditor.commands.add( 'splitTableCellVertically', new SplitCellCommand( editor, { direction: 'vertically' } ) );\n\t\teditor.commands.add( 'splitTableCellHorizontally', new SplitCellCommand( editor, { direction: 'horizontally' } ) );\n\n\t\teditor.commands.add( 'mergeTableCells', new MergeCellsCommand( editor ) );\n\n\t\teditor.commands.add( 'mergeTableCellRight', new MergeCellCommand( editor, { direction: 'right' } ) );\n\t\teditor.commands.add( 'mergeTableCellLeft', new MergeCellCommand( editor, { direction: 'left' } ) );\n\t\teditor.commands.add( 'mergeTableCellDown', new MergeCellCommand( editor, { direction: 'down' } ) );\n\t\teditor.commands.add( 'mergeTableCellUp', new MergeCellCommand( editor, { direction: 'up' } ) );\n\n\t\teditor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );\n\t\teditor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );\n\n\t\teditor.commands.add( 'selectTableRow', new SelectRowCommand( editor ) );\n\t\teditor.commands.add( 'selectTableColumn', new SelectColumnCommand( editor ) );\n\n\t\tinjectTableHeadingRowsRefreshPostFixer( model );\n\t\tinjectTableLayoutPostFixer( model );\n\t\tinjectTableCellRefreshPostFixer( model, editor.editing.mapper );\n\t\tinjectTableCellParagraphPostFixer( model );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableUtils ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/ui/inserttableview\n */\n\nimport { View } from 'ckeditor5/src/ui';\n\nimport './../../theme/inserttable.css';\n\n/**\n * The table size view.\n *\n * It renders a 10x10 grid to choose the inserted table size.\n *\n * @extends module:ui/view~View\n * @implements module:ui/dropdown/dropdownpanelfocusable~DropdownPanelFocusable\n */\nexport default class InsertTableView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * A collection of table size box items.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this._createGridCollection();\n\n\t\t/**\n\t\t * The currently selected number of rows of the new table.\n\t\t *\n\t\t * @observable\n\t\t * @member {Number} #rows\n\t\t */\n\t\tthis.set( 'rows', 0 );\n\n\t\t/**\n\t\t * The currently selected number of columns of the new table.\n\t\t *\n\t\t * @observable\n\t\t * @member {Number} #columns\n\t\t */\n\t\tthis.set( 'columns', 0 );\n\n\t\t/**\n\t\t * The label text displayed under the boxes.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.bind( 'label' )\n\t\t\t.to( this, 'columns', this, 'rows', ( columns, rows ) => `${ rows } × ${ columns }` );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [ 'ck' ]\n\t\t\t},\n\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [ 'ck-insert-table-dropdown__grid' ]\n\t\t\t\t\t},\n\t\t\t\t\ton: {\n\t\t\t\t\t\t'mouseover@.ck-insert-table-dropdown-grid-box': bind.to( 'boxover' )\n\t\t\t\t\t},\n\t\t\t\t\tchildren: this.items\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [ 'ck-insert-table-dropdown__label' ]\n\t\t\t\t\t},\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttext: bind.to( 'label' )\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t],\n\n\t\t\ton: {\n\t\t\t\tmousedown: bind.to( evt => {\n\t\t\t\t\tevt.preventDefault();\n\t\t\t\t} ),\n\n\t\t\t\tclick: bind.to( () => {\n\t\t\t\t\tthis.fire( 'execute' );\n\t\t\t\t} )\n\t\t\t}\n\t\t} );\n\n\t\tthis.on( 'boxover', ( evt, domEvt ) => {\n\t\t\tconst { row, column } = domEvt.target.dataset;\n\n\t\t\t// As row & column indexes are zero-based transform it to number of selected rows & columns.\n\t\t\tthis.set( {\n\t\t\t\trows: parseInt( row ),\n\t\t\t\tcolumns: parseInt( column )\n\t\t\t} );\n\t\t} );\n\n\t\tthis.on( 'change:columns', () => {\n\t\t\tthis._highlightGridBoxes();\n\t\t} );\n\n\t\tthis.on( 'change:rows', () => {\n\t\t\tthis._highlightGridBoxes();\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfocus() {\n\t\t// The dropdown panel expects DropdownPanelFocusable interface on views passed to dropdown panel. See #30.\n\t\t// The method should be implemented while working on keyboard support for this view. See #22.\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tfocusLast() {\n\t\t// The dropdown panel expects DropdownPanelFocusable interface on views passed to dropdown panel. See #30.\n\t\t// The method should be implemented while working on keyboard support for this view. See #22.\n\t}\n\n\t/**\n\t * Highlights grid boxes depending on rows and columns selected.\n\t *\n\t * @private\n\t */\n\t_highlightGridBoxes() {\n\t\tconst rows = this.rows;\n\t\tconst columns = this.columns;\n\n\t\tthis.items.map( ( boxView, index ) => {\n\t\t\t// Translate box index to the row & column index.\n\t\t\tconst itemRow = Math.floor( index / 10 );\n\t\t\tconst itemColumn = index % 10;\n\n\t\t\t// Grid box is highlighted when its row & column index belongs to selected number of rows & columns.\n\t\t\tconst isOn = itemRow < rows && itemColumn < columns;\n\n\t\t\tboxView.set( 'isOn', isOn );\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t * @returns {module:ui/viewcollection~ViewCollection} A view collection containing boxes to be placed in a table grid.\n\t */\n\t_createGridCollection() {\n\t\tconst boxes = [];\n\n\t\t// Add grid boxes to table selection view.\n\t\tfor ( let index = 0; index < 100; index++ ) {\n\t\t\tconst row = Math.floor( index / 10 );\n\t\t\tconst column = index % 10;\n\n\t\t\tboxes.push( new TableSizeGridBoxView( this.locale, row + 1, column + 1 ) );\n\t\t}\n\n\t\treturn this.createCollection( boxes );\n\t}\n\n\t/**\n\t * Fired when the mouse hover over one of the {@link #items child grid boxes}.\n\t *\n\t * @event boxover\n\t */\n}\n\n/**\n * A single grid box view element.\n *\n * This class is used to render the table size selection grid in {@link module:table/ui/inserttableview~InsertTableView}.\n *\n * @private\n */\nclass TableSizeGridBoxView extends View {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale, row, column ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * Controls whether the grid box view is \"on\".\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isOn\n\t\t */\n\t\tthis.set( 'isOn', false );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-insert-table-dropdown-grid-box',\n\t\t\t\t\tbind.if( 'isOn', 'ck-on' )\n\t\t\t\t],\n\t\t\t\t'data-row': row,\n\t\t\t\t'data-column': column\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { addListToDropdown, createDropdown, Model, SplitButtonView } from 'ckeditor5/src/ui';\nimport { Collection } from 'ckeditor5/src/utils';\n\nimport InsertTableView from './ui/inserttableview';\n\nimport tableIcon from './../theme/icons/table.svg';\nimport tableColumnIcon from './../theme/icons/table-column.svg';\nimport tableRowIcon from './../theme/icons/table-row.svg';\nimport tableMergeCellIcon from './../theme/icons/table-merge-cell.svg';\n\n/**\n * The table UI plugin. It introduces:\n *\n * * The `'insertTable'` dropdown,\n * * The `'tableColumn'` dropdown,\n * * The `'tableRow'` dropdown,\n * * The `'mergeTableCells'` split button.\n *\n * The `'tableColumn'`, `'tableRow'` and `'mergeTableCells'` dropdowns work best with {@link module:table/tabletoolbar~TableToolbar}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = this.editor.t;\n\t\tconst contentLanguageDirection = editor.locale.contentLanguageDirection;\n\t\tconst isContentLtr = contentLanguageDirection === 'ltr';\n\n\t\teditor.ui.componentFactory.add( 'insertTable', locale => {\n\t\t\tconst command = editor.commands.get( 'insertTable' );\n\t\t\tconst dropdownView = createDropdown( locale );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).to( command );\n\n\t\t\t// Decorate dropdown's button.\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\ticon: tableIcon,\n\t\t\t\tlabel: t( 'Insert table' ),\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tlet insertTableView;\n\n\t\t\tdropdownView.on( 'change:isOpen', () => {\n\t\t\t\tif ( insertTableView ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Prepare custom view for dropdown's panel.\n\t\t\t\tinsertTableView = new InsertTableView( locale );\n\t\t\t\tdropdownView.panelView.children.add( insertTableView );\n\n\t\t\t\tinsertTableView.delegate( 'execute' ).to( dropdownView );\n\n\t\t\t\tdropdownView.buttonView.on( 'open', () => {\n\t\t\t\t\t// Reset the chooser before showing it to the user.\n\t\t\t\t\tinsertTableView.rows = 0;\n\t\t\t\t\tinsertTableView.columns = 0;\n\t\t\t\t} );\n\n\t\t\t\tdropdownView.on( 'execute', () => {\n\t\t\t\t\teditor.execute( 'insertTable', { rows: insertTableView.rows, columns: insertTableView.columns } );\n\t\t\t\t\teditor.editing.view.focus();\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'tableColumn', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'switchbutton',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'setTableColumnHeader',\n\t\t\t\t\t\tlabel: t( 'Header column' ),\n\t\t\t\t\t\tbindIsOn: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'insertTableColumnLeft' : 'insertTableColumnRight',\n\t\t\t\t\t\tlabel: t( 'Insert column left' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'insertTableColumnRight' : 'insertTableColumnLeft',\n\t\t\t\t\t\tlabel: t( 'Insert column right' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'removeTableColumn',\n\t\t\t\t\t\tlabel: t( 'Delete column' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'selectTableColumn',\n\t\t\t\t\t\tlabel: t( 'Select column' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareDropdown( t( 'Column' ), tableColumnIcon, options, locale );\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'tableRow', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'switchbutton',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'setTableRowHeader',\n\t\t\t\t\t\tlabel: t( 'Header row' ),\n\t\t\t\t\t\tbindIsOn: true\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'insertTableRowAbove',\n\t\t\t\t\t\tlabel: t( 'Insert row above' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'insertTableRowBelow',\n\t\t\t\t\t\tlabel: t( 'Insert row below' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'removeTableRow',\n\t\t\t\t\t\tlabel: t( 'Delete row' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'selectTableRow',\n\t\t\t\t\t\tlabel: t( 'Select row' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareDropdown( t( 'Row' ), tableRowIcon, options, locale );\n\t\t} );\n\n\t\teditor.ui.componentFactory.add( 'mergeTableCells', locale => {\n\t\t\tconst options = [\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'mergeTableCellUp',\n\t\t\t\t\t\tlabel: t( 'Merge cell up' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'mergeTableCellRight' : 'mergeTableCellLeft',\n\t\t\t\t\t\tlabel: t( 'Merge cell right' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'mergeTableCellDown',\n\t\t\t\t\t\tlabel: t( 'Merge cell down' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: isContentLtr ? 'mergeTableCellLeft' : 'mergeTableCellRight',\n\t\t\t\t\t\tlabel: t( 'Merge cell left' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ type: 'separator' },\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'splitTableCellVertically',\n\t\t\t\t\t\tlabel: t( 'Split cell vertically' )\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'button',\n\t\t\t\t\tmodel: {\n\t\t\t\t\t\tcommandName: 'splitTableCellHorizontally',\n\t\t\t\t\t\tlabel: t( 'Split cell horizontally' )\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t];\n\n\t\t\treturn this._prepareMergeSplitButtonDropdown( t( 'Merge cells' ), tableMergeCellIcon, options, locale );\n\t\t} );\n\t}\n\n\t/**\n\t * Creates a dropdown view from a set of options.\n\t *\n\t * @private\n\t * @param {String} label The dropdown button label.\n\t * @param {String} icon An icon for the dropdown button.\n\t * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.\n\t * @param {module:utils/locale~Locale} locale\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_prepareDropdown( label, icon, options, locale ) {\n\t\tconst editor = this.editor;\n\t\tconst dropdownView = createDropdown( locale );\n\t\tconst commands = this._fillDropdownWithListOptions( dropdownView, options );\n\n\t\t// Decorate dropdown's button.\n\t\tdropdownView.buttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\t// Make dropdown button disabled when all options are disabled.\n\t\tdropdownView.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => {\n\t\t\treturn areEnabled.some( isEnabled => isEnabled );\n\t\t} );\n\n\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\teditor.execute( evt.source.commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn dropdownView;\n\t}\n\n\t/**\n\t * Creates a dropdown view with a {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} for\n\t * merge (and split)related commands.\n\t *\n\t * @private\n\t * @param {String} label The dropdown button label.\n\t * @param {String} icon An icon for the dropdown button.\n\t * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.\n\t * @param {module:utils/locale~Locale} locale\n\t * @returns {module:ui/dropdown/dropdownview~DropdownView}\n\t */\n\t_prepareMergeSplitButtonDropdown( label, icon, options, locale ) {\n\t\tconst editor = this.editor;\n\t\tconst dropdownView = createDropdown( locale, SplitButtonView );\n\t\tconst mergeCommandName = 'mergeTableCells';\n\n\t\tthis._fillDropdownWithListOptions( dropdownView, options );\n\n\t\tdropdownView.buttonView.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true,\n\t\t\tisEnabled: true\n\t\t} );\n\n\t\t// Merge selected table cells when the main part of the split button is clicked.\n\t\tthis.listenTo( dropdownView.buttonView, 'execute', () => {\n\t\t\teditor.execute( mergeCommandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\t// Execute commands for events coming from the list in the dropdown panel.\n\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\teditor.execute( evt.source.commandName );\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn dropdownView;\n\t}\n\n\t/**\n\t * Injects a {@link module:ui/list/listview~ListView} into the passed dropdown with buttons\n\t * which execute editor commands as configured in passed options.\n\t *\n\t * @private\n\t * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView\n\t * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.\n\t * @returns {Array.<module:core/command~Command>} Commands the list options are interacting with.\n\t */\n\t_fillDropdownWithListOptions( dropdownView, options ) {\n\t\tconst editor = this.editor;\n\t\tconst commands = [];\n\t\tconst itemDefinitions = new Collection();\n\n\t\tfor ( const option of options ) {\n\t\t\taddListOption( option, editor, commands, itemDefinitions );\n\t\t}\n\n\t\taddListToDropdown( dropdownView, itemDefinitions, editor.ui.componentFactory );\n\n\t\treturn commands;\n\t}\n}\n\n// Adds an option to a list view.\n//\n// @param {module:table/tableui~DropdownOption} option A configuration option.\n// @param {module:core/editor/editor~Editor} editor\n// @param {Array.<module:core/command~Command>} commands The list of commands to update.\n// @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} itemDefinitions\n// A collection of dropdown items to update with the given option.\nfunction addListOption( option, editor, commands, itemDefinitions ) {\n\tconst model = option.model = new Model( option.model );\n\tconst { commandName, bindIsOn } = option.model;\n\n\tif ( option.type === 'button' || option.type === 'switchbutton' ) {\n\t\tconst command = editor.commands.get( commandName );\n\n\t\tcommands.push( command );\n\n\t\tmodel.set( { commandName } );\n\n\t\tmodel.bind( 'isEnabled' ).to( command );\n\n\t\tif ( bindIsOn ) {\n\t\t\tmodel.bind( 'isOn' ).to( command, 'value' );\n\t\t}\n\t}\n\n\tmodel.set( {\n\t\twithText: true\n\t} );\n\n\titemDefinitions.add( option );\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 6v3h4V6H3zm0 4v3h4v-3H3zm0 4v3h4v-3H3zm5 3h4v-3H8v3zm5 0h4v-3h-4v3zm4-4v-3h-4v3h4zm0-4V6h-4v3h4zm1.5 8a1.5 1.5 0 0 1-1.5 1.5H3A1.5 1.5 0 0 1 1.5 17V4c.222-.863 1.068-1.5 2-1.5h13c.932 0 1.778.637 2 1.5v13zM12 13v-3H8v3h4zm0-4V6H8v3h4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M18 7v1H2V7h16zm0 5v1H2v-1h16z\\\" opacity=\\\".6\\\"/><path d=\\\"M14 1v18a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1zm-2 1H8v4h4V2zm0 6H8v4h4V8zm0 6H8v4h4v-4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 2h1v16H7V2zm5 0h1v16h-1V2z\\\" opacity=\\\".6\\\"/><path d=\\\"M1 6h18a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1zm1 2v4h4V8H2zm6 0v4h4V8H8zm6 0v4h4V8h-4z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2.5 1h15A1.5 1.5 0 0 1 19 2.5v15a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1zM2 2v16h16V2H2z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 2h1v16H7V2zm5 0h1v7h-1V2zm6 5v1H2V7h16zM8 12v1H2v-1h6z\\\" opacity=\\\".6\\\"/><path d=\\\"M7 7h12a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1zm1 2v9h10V9H8z\\\"/></svg>\";","/**\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 table/tableselection\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\nimport TableWalker from './tablewalker';\nimport TableUtils from './tableutils';\n\nimport { cropTableToDimensions, adjustLastRowIndex, adjustLastColumnIndex } from './utils/structure';\nimport { getColumnIndexes, getRowIndexes, getSelectedTableCells, isSelectionRectangular } from './utils/selection';\n\nimport '../theme/tableselection.css';\n\n/**\n * This plugin enables the advanced table cells, rows and columns selection.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableSelection extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableSelection';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableUtils ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tthis.listenTo( model, 'deleteContent', ( evt, args ) => this._handleDeleteContent( evt, args ), { priority: 'high' } );\n\n\t\tthis._defineSelectionConverter();\n\t\tthis._enablePluginDisabling(); // sic!\n\t}\n\n\t/**\n\t * Returns the currently selected table cells or `null` if it is not a table cells selection.\n\t *\n\t * @returns {Array.<module:engine/model/element~Element>|null}\n\t */\n\tgetSelectedTableCells() {\n\t\tconst selection = this.editor.model.document.selection;\n\n\t\tconst selectedCells = getSelectedTableCells( selection );\n\n\t\tif ( selectedCells.length == 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// This should never happen, but let's know if it ever happens.\n\t\t// @if CK_DEBUG //\t/* istanbul ignore next */\n\t\t// @if CK_DEBUG //\tif ( selectedCells.length != selection.rangeCount ) {\n\t\t// @if CK_DEBUG //\t\tconsole.warn( 'Mixed selection warning. The selection contains table cells and some other ranges.' );\n\t\t// @if CK_DEBUG //\t}\n\n\t\treturn selectedCells;\n\t}\n\n\t/**\n\t * Returns the selected table fragment as a document fragment.\n\t *\n\t * @returns {module:engine/model/documentfragment~DocumentFragment|null}\n\t */\n\tgetSelectionAsFragment() {\n\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\tif ( !selectedCells ) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.editor.model.change( writer => {\n\t\t\tconst documentFragment = writer.createDocumentFragment();\n\t\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\n\t\t\tconst { first: firstColumn, last: lastColumn } = getColumnIndexes( selectedCells );\n\t\t\tconst { first: firstRow, last: lastRow } = getRowIndexes( selectedCells );\n\n\t\t\tconst sourceTable = selectedCells[ 0 ].findAncestor( 'table' );\n\n\t\t\tlet adjustedLastRow = lastRow;\n\t\t\tlet adjustedLastColumn = lastColumn;\n\n\t\t\t// If the selection is rectangular there could be a case of all cells in the last row/column spanned over\n\t\t\t// next row/column so the real lastRow/lastColumn should be updated.\n\t\t\tif ( isSelectionRectangular( selectedCells, tableUtils ) ) {\n\t\t\t\tconst dimensions = {\n\t\t\t\t\tfirstColumn,\n\t\t\t\t\tlastColumn,\n\t\t\t\t\tfirstRow,\n\t\t\t\t\tlastRow\n\t\t\t\t};\n\n\t\t\t\tadjustedLastRow = adjustLastRowIndex( sourceTable, dimensions );\n\t\t\t\tadjustedLastColumn = adjustLastColumnIndex( sourceTable, dimensions );\n\t\t\t}\n\n\t\t\tconst cropDimensions = {\n\t\t\t\tstartRow: firstRow,\n\t\t\t\tstartColumn: firstColumn,\n\t\t\t\tendRow: adjustedLastRow,\n\t\t\t\tendColumn: adjustedLastColumn\n\t\t\t};\n\n\t\t\tconst table = cropTableToDimensions( sourceTable, cropDimensions, writer );\n\n\t\t\twriter.insert( table, documentFragment, 0 );\n\n\t\t\treturn documentFragment;\n\t\t} );\n\t}\n\n\t/**\n\t * Sets the model selection based on given anchor and target cells (can be the same cell).\n\t * Takes care of setting the backward flag.\n\t *\n\t *\t\tconst modelRoot = editor.model.document.getRoot();\n\t *\t\tconst firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] );\n\t *\t\tconst lastCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] );\n\t *\n\t *\t\tconst tableSelection = editor.plugins.get( 'TableSelection' );\n\t *\t\ttableSelection.setCellSelection( firstCell, lastCell );\n\t *\n\t * @param {module:engine/model/element~Element} anchorCell\n\t * @param {module:engine/model/element~Element} targetCell\n\t */\n\tsetCellSelection( anchorCell, targetCell ) {\n\t\tconst cellsToSelect = this._getCellsToSelect( anchorCell, targetCell );\n\n\t\tthis.editor.model.change( writer => {\n\t\t\twriter.setSelection(\n\t\t\t\tcellsToSelect.cells.map( cell => writer.createRangeOn( cell ) ),\n\t\t\t\t{ backward: cellsToSelect.backward }\n\t\t\t);\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the focus cell from the current selection.\n\t *\n\t * @returns {module:engine/model/element~Element}\n\t */\n\tgetFocusCell() {\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst focusCellRange = [ ...selection.getRanges() ].pop();\n\t\tconst element = focusCellRange.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Returns the anchor cell from the current selection.\n\t *\n\t * @returns {module:engine/model/element~Element} anchorCell\n\t */\n\tgetAnchorCell() {\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst anchorCellRange = first( selection.getRanges() );\n\t\tconst element = anchorCellRange.getContainedElement();\n\n\t\tif ( element && element.is( 'element', 'tableCell' ) ) {\n\t\t\treturn element;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Defines a selection converter which marks the selected cells with a specific class.\n\t *\n\t * The real DOM selection is put in the last cell. Since the order of ranges is dependent on whether the\n\t * selection is backward or not, the last cell will usually be close to the \"focus\" end of the selection\n\t * (a selection has anchor and focus).\n\t *\n\t * The real DOM selection is then hidden with CSS.\n\t *\n\t * @private\n\t */\n\t_defineSelectionConverter() {\n\t\tconst editor = this.editor;\n\t\tconst highlighted = new Set();\n\n\t\teditor.conversion.for( 'editingDowncast' ).add( dispatcher => dispatcher.on( 'selection', ( evt, data, conversionApi ) => {\n\t\t\tconst viewWriter = conversionApi.writer;\n\n\t\t\tclearHighlightedTableCells( viewWriter );\n\n\t\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\t\tif ( !selectedCells ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor ( const tableCell of selectedCells ) {\n\t\t\t\tconst viewElement = conversionApi.mapper.toViewElement( tableCell );\n\n\t\t\t\tviewWriter.addClass( 'ck-editor__editable_selected', viewElement );\n\t\t\t\thighlighted.add( viewElement );\n\t\t\t}\n\n\t\t\tconst lastViewCell = conversionApi.mapper.toViewElement( selectedCells[ selectedCells.length - 1 ] );\n\t\t\tviewWriter.setSelection( lastViewCell, 0 );\n\t\t}, { priority: 'lowest' } ) );\n\n\t\tfunction clearHighlightedTableCells( writer ) {\n\t\t\tfor ( const previouslyHighlighted of highlighted ) {\n\t\t\t\twriter.removeClass( 'ck-editor__editable_selected', previouslyHighlighted );\n\t\t\t}\n\n\t\t\thighlighted.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Creates a listener that reacts to changes in {@link #isEnabled} and, if the plugin was disabled,\n\t * it collapses the multi-cell selection to a regular selection placed inside a table cell.\n\t *\n\t * This listener helps features that disable the table selection plugin bring the selection\n\t * to a clear state they can work with (for instance, because they don't support multiple cell selection).\n\t */\n\t_enablePluginDisabling() {\n\t\tconst editor = this.editor;\n\n\t\tthis.on( 'change:isEnabled', () => {\n\t\t\tif ( !this.isEnabled ) {\n\t\t\t\tconst selectedCells = this.getSelectedTableCells();\n\n\t\t\t\tif ( !selectedCells ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\tconst position = writer.createPositionAt( selectedCells[ 0 ], 0 );\n\t\t\t\t\tconst range = editor.model.schema.getNearestSelectionRange( position );\n\n\t\t\t\t\twriter.setSelection( range );\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Overrides the default `model.deleteContent()` behavior over a selected table fragment.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} event\n\t * @param {Array.<*>} args Delete content method arguments.\n\t */\n\t_handleDeleteContent( event, args ) {\n\t\tconst [ selection, options ] = args;\n\t\tconst model = this.editor.model;\n\t\tconst isBackward = !options || options.direction == 'backward';\n\t\tconst selectedTableCells = getSelectedTableCells( selection );\n\n\t\tif ( !selectedTableCells.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent.stop();\n\n\t\tmodel.change( writer => {\n\t\t\tconst tableCellToSelect = selectedTableCells[ isBackward ? selectedTableCells.length - 1 : 0 ];\n\n\t\t\tmodel.change( writer => {\n\t\t\t\tfor ( const tableCell of selectedTableCells ) {\n\t\t\t\t\tmodel.deleteContent( writer.createSelection( tableCell, 'in' ) );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tconst rangeToSelect = model.schema.getNearestSelectionRange( writer.createPositionAt( tableCellToSelect, 0 ) );\n\n\t\t\t// Note: we ignore the case where rangeToSelect may be null because deleteContent() will always (unless someone broke it)\n\t\t\t// create an empty paragraph to accommodate the selection.\n\n\t\t\tif ( selection.is( 'documentSelection' ) ) {\n\t\t\t\twriter.setSelection( rangeToSelect );\n\t\t\t} else {\n\t\t\t\tselection.setTo( rangeToSelect );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns an array of table cells that should be selected based on the\n\t * given anchor cell and target (focus) cell.\n\t *\n\t * The cells are returned in a reverse direction if the selection is backward.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} anchorCell\n\t * @param {module:engine/model/element~Element} targetCell\n\t * @returns {Array.<module:engine/model/element~Element>}\n\t */\n\t_getCellsToSelect( anchorCell, targetCell ) {\n\t\tconst tableUtils = this.editor.plugins.get( 'TableUtils' );\n\t\tconst startLocation = tableUtils.getCellLocation( anchorCell );\n\t\tconst endLocation = tableUtils.getCellLocation( targetCell );\n\n\t\tconst startRow = Math.min( startLocation.row, endLocation.row );\n\t\tconst endRow = Math.max( startLocation.row, endLocation.row );\n\n\t\tconst startColumn = Math.min( startLocation.column, endLocation.column );\n\t\tconst endColumn = Math.max( startLocation.column, endLocation.column );\n\n\t\t// 2-dimensional array of the selected cells to ease flipping the order of cells for backward selections.\n\t\tconst selectionMap = new Array( endRow - startRow + 1 ).fill( null ).map( () => [] );\n\n\t\tconst walkerOptions = {\n\t\t\tstartRow,\n\t\t\tendRow,\n\t\t\tstartColumn,\n\t\t\tendColumn\n\t\t};\n\n\t\tfor ( const { row, cell } of new TableWalker( anchorCell.findAncestor( 'table' ), walkerOptions ) ) {\n\t\t\tselectionMap[ row - startRow ].push( cell );\n\t\t}\n\n\t\tconst flipVertically = endLocation.row < startLocation.row;\n\t\tconst flipHorizontally = endLocation.column < startLocation.column;\n\n\t\tif ( flipVertically ) {\n\t\t\tselectionMap.reverse();\n\t\t}\n\n\t\tif ( flipHorizontally ) {\n\t\t\tselectionMap.forEach( row => row.reverse() );\n\t\t}\n\n\t\treturn {\n\t\t\tcells: selectionMap.flat(),\n\t\t\tbackward: flipVertically || flipHorizontally\n\t\t};\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableclipboard\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TableSelection from './tableselection';\nimport TableWalker from './tablewalker';\nimport TableUtils from './tableutils';\nimport { getColumnIndexes, getRowIndexes, getSelectionAffectedTableCells, isSelectionRectangular, sortRanges } from './utils/selection';\nimport {\n\tcropTableToDimensions,\n\tgetHorizontallyOverlappingCells,\n\tgetVerticallyOverlappingCells,\n\tremoveEmptyRowsColumns,\n\tsplitHorizontally,\n\tsplitVertically,\n\ttrimTableCellIfNeeded,\n\tadjustLastRowIndex,\n\tadjustLastColumnIndex\n} from './utils/structure';\n\n/**\n * This plugin adds support for copying/cutting/pasting fragments of tables.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableClipboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableClipboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection, TableUtils ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\n\t\tthis.listenTo( viewDocument, 'copy', ( evt, data ) => this._onCopyCut( evt, data ) );\n\t\tthis.listenTo( viewDocument, 'cut', ( evt, data ) => this._onCopyCut( evt, data ) );\n\t\tthis.listenTo( editor.model, 'insertContent', ( evt, args ) => this._onInsertContent( evt, ...args ), { priority: 'high' } );\n\n\t\tthis.decorate( '_replaceTableSlotCell' );\n\t}\n\n\t/**\n\t * Copies table content to a clipboard on \"copy\" & \"cut\" events.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} evt An object containing information about the handled event.\n\t * @param {Object} data Clipboard event data.\n\t */\n\t_onCopyCut( evt, data ) {\n\t\tconst tableSelection = this.editor.plugins.get( TableSelection );\n\n\t\tif ( !tableSelection.getSelectedTableCells() ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( evt.name == 'cut' && this.editor.isReadOnly ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdata.preventDefault();\n\t\tevt.stop();\n\n\t\tconst dataController = this.editor.data;\n\t\tconst viewDocument = this.editor.editing.view.document;\n\n\t\tconst content = dataController.toView( tableSelection.getSelectionAsFragment() );\n\n\t\tviewDocument.fire( 'clipboardOutput', {\n\t\t\tdataTransfer: data.dataTransfer,\n\t\t\tcontent,\n\t\t\tmethod: evt.name\n\t\t} );\n\t}\n\n\t/**\n\t * Overrides default {@link module:engine/model/model~Model#insertContent `model.insertContent()`} method to handle pasting table inside\n\t * selected table fragment.\n\t *\n\t * Depending on selected table fragment:\n\t * - If a selected table fragment is smaller than paste table it will crop pasted table to match dimensions.\n\t * - If dimensions are equal it will replace selected table fragment with a pasted table contents.\n\t *\n\t * @private\n\t * @param evt\n\t * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n\t * @param {module:engine/model/selection~Selectable} [selectable=model.document.selection]\n\t * The selection into which the content should be inserted. If not provided the current model document selection will be used.\n\t */\n\t_onInsertContent( evt, content, selectable ) {\n\t\tif ( selectable && !selectable.is( 'documentSelection' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\t\tconst tableUtils = this.editor.plugins.get( TableUtils );\n\n\t\t// We might need to crop table before inserting so reference might change.\n\t\tlet pastedTable = getTableIfOnlyTableInContent( content, model );\n\n\t\tif ( !pastedTable ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectedTableCells = getSelectionAffectedTableCells( model.document.selection );\n\n\t\tif ( !selectedTableCells.length ) {\n\t\t\tremoveEmptyRowsColumns( pastedTable, tableUtils );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Override default model.insertContent() handling at this point.\n\t\tevt.stop();\n\n\t\tmodel.change( writer => {\n\t\t\tconst pastedDimensions = {\n\t\t\t\twidth: tableUtils.getColumns( pastedTable ),\n\t\t\t\theight: tableUtils.getRows( pastedTable )\n\t\t\t};\n\n\t\t\t// Prepare the table for pasting.\n\t\t\tconst selection = prepareTableForPasting( selectedTableCells, pastedDimensions, writer, tableUtils );\n\n\t\t\t// Beyond this point we operate on a fixed content table with rectangular selection and proper last row/column values.\n\n\t\t\tconst selectionHeight = selection.lastRow - selection.firstRow + 1;\n\t\t\tconst selectionWidth = selection.lastColumn - selection.firstColumn + 1;\n\n\t\t\t// Crop pasted table if:\n\t\t\t// - Pasted table dimensions exceeds selection area.\n\t\t\t// - Pasted table has broken layout (ie some cells sticks out by the table dimensions established by the first and last row).\n\t\t\t//\n\t\t\t// Note: The table dimensions are established by the width of the first row and the total number of rows.\n\t\t\t// It is possible to programmatically create a table that has rows which would have cells anchored beyond first row width but\n\t\t\t// such table will not be created by other editing solutions.\n\t\t\tconst cropDimensions = {\n\t\t\t\tstartRow: 0,\n\t\t\t\tstartColumn: 0,\n\t\t\t\tendRow: Math.min( selectionHeight, pastedDimensions.height ) - 1,\n\t\t\t\tendColumn: Math.min( selectionWidth, pastedDimensions.width ) - 1\n\t\t\t};\n\n\t\t\tpastedTable = cropTableToDimensions( pastedTable, cropDimensions, writer );\n\n\t\t\t// Content table to which we insert a pasted table.\n\t\t\tconst selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );\n\n\t\t\tconst cellsToSelect = this._replaceSelectedCellsWithPasted( pastedTable, pastedDimensions, selectedTable, selection, writer );\n\n\t\t\tif ( this.editor.plugins.get( 'TableSelection' ).isEnabled ) {\n\t\t\t\t// Selection ranges must be sorted because the first and last selection ranges are considered\n\t\t\t\t// as anchor/focus cell ranges for multi-cell selection.\n\t\t\t\tconst selectionRanges = sortRanges( cellsToSelect.map( cell => writer.createRangeOn( cell ) ) );\n\n\t\t\t\twriter.setSelection( selectionRanges );\n\t\t\t} else {\n\t\t\t\t// Set selection inside first cell if multi-cell selection is disabled.\n\t\t\t\twriter.setSelection( cellsToSelect[ 0 ], 0 );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Replaces the part of selectedTable with pastedTable.\n\t *\n\t * @private\n\t * @param {module:engine/model/element~Element} pastedTable\n\t * @param {Object} pastedDimensions\n\t * @param {Number} pastedDimensions.height\n\t * @param {Number} pastedDimensions.width\n\t * @param {module:engine/model/element~Element} selectedTable\n\t * @param {Object} selection\n\t * @param {Number} selection.firstColumn\n\t * @param {Number} selection.firstRow\n\t * @param {Number} selection.lastColumn\n\t * @param {Number} selection.lastRow\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @returns {Array.<module:engine/model/element~Element>}\n\t */\n\t_replaceSelectedCellsWithPasted( pastedTable, pastedDimensions, selectedTable, selection, writer ) {\n\t\tconst { width: pastedWidth, height: pastedHeight } = pastedDimensions;\n\n\t\t// Holds two-dimensional array that is addressed by [ row ][ column ] that stores cells anchored at given location.\n\t\tconst pastedTableLocationMap = createLocationMap( pastedTable, pastedWidth, pastedHeight );\n\n\t\tconst selectedTableMap = [ ...new TableWalker( selectedTable, {\n\t\t\tstartRow: selection.firstRow,\n\t\t\tendRow: selection.lastRow,\n\t\t\tstartColumn: selection.firstColumn,\n\t\t\tendColumn: selection.lastColumn,\n\t\t\tincludeAllSlots: true\n\t\t} ) ];\n\n\t\t// Selection must be set to pasted cells (some might be removed or new created).\n\t\tconst cellsToSelect = [];\n\n\t\t// Store next cell insert position.\n\t\tlet insertPosition;\n\n\t\t// Content table replace cells algorithm iterates over a selected table fragment and:\n\t\t//\n\t\t// - Removes existing table cells at current slot (location).\n\t\t// - Inserts cell from a pasted table for a matched slots.\n\t\t//\n\t\t// This ensures proper table geometry after the paste\n\t\tfor ( const tableSlot of selectedTableMap ) {\n\t\t\tconst { row, column } = tableSlot;\n\n\t\t\t// Save the insert position for current row start.\n\t\t\tif ( column === selection.firstColumn ) {\n\t\t\t\tinsertPosition = tableSlot.getPositionBefore();\n\t\t\t}\n\n\t\t\t// Map current table slot location to an pasted table slot location.\n\t\t\tconst pastedRow = row - selection.firstRow;\n\t\t\tconst pastedColumn = column - selection.firstColumn;\n\t\t\tconst pastedCell = pastedTableLocationMap[ pastedRow % pastedHeight ][ pastedColumn % pastedWidth ];\n\n\t\t\t// Clone cell to insert (to duplicate its attributes and children).\n\t\t\t// Cloning is required to support repeating pasted table content when inserting to a bigger selection.\n\t\t\tconst cellToInsert = pastedCell ? writer.cloneElement( pastedCell ) : null;\n\n\t\t\t// Replace the cell from the current slot with new table cell.\n\t\t\tconst newTableCell = this._replaceTableSlotCell( tableSlot, cellToInsert, insertPosition, writer );\n\n\t\t\t// The cell was only removed.\n\t\t\tif ( !newTableCell ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Trim the cell if it's row/col-spans would exceed selection area.\n\t\t\ttrimTableCellIfNeeded( newTableCell, row, column, selection.lastRow, selection.lastColumn, writer );\n\n\t\t\tcellsToSelect.push( newTableCell );\n\n\t\t\tinsertPosition = writer.createPositionAfter( newTableCell );\n\t\t}\n\n\t\t// If there are any headings, all the cells that overlap from heading must be splitted.\n\t\tconst headingRows = parseInt( selectedTable.getAttribute( 'headingRows' ) || 0 );\n\t\tconst headingColumns = parseInt( selectedTable.getAttribute( 'headingColumns' ) || 0 );\n\n\t\tconst areHeadingRowsIntersectingSelection = selection.firstRow < headingRows && headingRows <= selection.lastRow;\n\t\tconst areHeadingColumnsIntersectingSelection = selection.firstColumn < headingColumns && headingColumns <= selection.lastColumn;\n\n\t\tif ( areHeadingRowsIntersectingSelection ) {\n\t\t\tconst columnsLimit = { first: selection.firstColumn, last: selection.lastColumn };\n\t\t\tconst newCells = doHorizontalSplit( selectedTable, headingRows, columnsLimit, writer, selection.firstRow );\n\n\t\t\tcellsToSelect.push( ...newCells );\n\t\t}\n\n\t\tif ( areHeadingColumnsIntersectingSelection ) {\n\t\t\tconst rowsLimit = { first: selection.firstRow, last: selection.lastRow };\n\t\t\tconst newCells = doVerticalSplit( selectedTable, headingColumns, rowsLimit, writer );\n\n\t\t\tcellsToSelect.push( ...newCells );\n\t\t}\n\n\t\treturn cellsToSelect;\n\t}\n\n\t/**\n\t * Replaces a single table slot.\n\t *\n\t * @private\n\t * @param {module:table/tablewalker~TableSlot} tableSlot\n\t * @param {module:engine/model/element~Element} cellToInsert\n\t * @param {module:engine/model/position~Position} insertPosition\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @returns {module:engine/model/element~Element|null} Inserted table cell or null if slot should remain empty.\n\t */\n\t_replaceTableSlotCell( tableSlot, cellToInsert, insertPosition, writer ) {\n\t\tconst { cell, isAnchor } = tableSlot;\n\n\t\t// If the slot is occupied by a cell in a selected table - remove it.\n\t\t// The slot of this cell will be either:\n\t\t// - Replaced by a pasted table cell.\n\t\t// - Spanned by a previously pasted table cell.\n\t\tif ( isAnchor ) {\n\t\t\twriter.remove( cell );\n\t\t}\n\n\t\t// There is no cell to insert (might be spanned by other cell in a pasted table) - advance to the next content table slot.\n\t\tif ( !cellToInsert ) {\n\t\t\treturn null;\n\t\t}\n\n\t\twriter.insert( cellToInsert, insertPosition );\n\n\t\treturn cellToInsert;\n\t}\n}\n\n/**\n * Extract table for pasting into table.\n *\n * @private\n * @param {module:engine/model/documentfragment~DocumentFragment|module:engine/model/item~Item} content The content to insert.\n * @param {module:engine/model/model~Model} model The editor model.\n * @returns {module:engine/model/element~Element|null}\n */\nexport function getTableIfOnlyTableInContent( content, model ) {\n\tif ( !content.is( 'documentFragment' ) && !content.is( 'element' ) ) {\n\t\treturn null;\n\t}\n\n\t// Table passed directly.\n\tif ( content.is( 'element', 'table' ) ) {\n\t\treturn content;\n\t}\n\n\t// We do not support mixed content when pasting table into table.\n\t// See: https://github.com/ckeditor/ckeditor5/issues/6817.\n\tif ( content.childCount == 1 && content.getChild( 0 ).is( 'element', 'table' ) ) {\n\t\treturn content.getChild( 0 );\n\t}\n\n\t// If there are only whitespaces around a table then use that table for pasting.\n\n\tconst contentRange = model.createRangeIn( content );\n\n\tfor ( const element of contentRange.getItems() ) {\n\t\tif ( element.is( 'element', 'table' ) ) {\n\t\t\t// Stop checking if there is some content before table.\n\t\t\tconst rangeBefore = model.createRange( contentRange.start, model.createPositionBefore( element ) );\n\n\t\t\tif ( model.hasContent( rangeBefore, { ignoreWhitespaces: true } ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Stop checking if there is some content after table.\n\t\t\tconst rangeAfter = model.createRange( model.createPositionAfter( element ), contentRange.end );\n\n\t\t\tif ( model.hasContent( rangeAfter, { ignoreWhitespaces: true } ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// There wasn't any content neither before nor after.\n\t\t\treturn element;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Prepares a table for pasting and returns adjusted selection dimensions.\n//\n// @param {Array.<module:engine/model/element~Element>} selectedTableCells\n// @param {Object} pastedDimensions\n// @param {Number} pastedDimensions.height\n// @param {Number} pastedDimensions.width\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:table/tableutils~TableUtils} tableUtils\n// @returns {Object} selection\n// @returns {Number} selection.firstColumn\n// @returns {Number} selection.firstRow\n// @returns {Number} selection.lastColumn\n// @returns {Number} selection.lastRow\nfunction prepareTableForPasting( selectedTableCells, pastedDimensions, writer, tableUtils ) {\n\tconst selectedTable = selectedTableCells[ 0 ].findAncestor( 'table' );\n\n\tconst columnIndexes = getColumnIndexes( selectedTableCells );\n\tconst rowIndexes = getRowIndexes( selectedTableCells );\n\n\tconst selection = {\n\t\tfirstColumn: columnIndexes.first,\n\t\tlastColumn: columnIndexes.last,\n\t\tfirstRow: rowIndexes.first,\n\t\tlastRow: rowIndexes.last\n\t};\n\n\t// Single cell selected - expand selection to pasted table dimensions.\n\tconst shouldExpandSelection = selectedTableCells.length === 1;\n\n\tif ( shouldExpandSelection ) {\n\t\tselection.lastRow += pastedDimensions.height - 1;\n\t\tselection.lastColumn += pastedDimensions.width - 1;\n\n\t\texpandTableSize( selectedTable, selection.lastRow + 1, selection.lastColumn + 1, tableUtils );\n\t}\n\n\t// In case of expanding selection we do not reset the selection so in this case we will always try to fix selection\n\t// like in the case of a non-rectangular area. This might be fixed by re-setting selected cells array but this shortcut is safe.\n\tif ( shouldExpandSelection || !isSelectionRectangular( selectedTableCells, tableUtils ) ) {\n\t\t// For a non-rectangular selection (ie in which some cells sticks out from a virtual selection rectangle) we need to create\n\t\t// a table layout that has a rectangular selection. This will split cells so the selection become rectangular.\n\t\t// Beyond this point we will operate on fixed content table.\n\t\tsplitCellsToRectangularSelection( selectedTable, selection, writer );\n\t}\n\t// However a selected table fragment might be invalid if examined alone. Ie such table fragment:\n\t//\n\t// +---+---+---+---+\n\t// 0 | a | b | c | d |\n\t// + + +---+---+\n\t// 1 | | e | f | g |\n\t// + +---+ +---+\n\t// 2 | | h | | i | <- last row, each cell has rowspan = 2,\n\t// + + + + + so we need to return 3, not 2\n\t// 3 | | | | |\n\t// +---+---+---+---+\n\t//\n\t// is invalid as the cells \"h\" and \"i\" have rowspans.\n\t// This case needs only adjusting the selection dimension as the rest of the algorithm operates on empty slots also.\n\telse {\n\t\tselection.lastRow = adjustLastRowIndex( selectedTable, selection );\n\t\tselection.lastColumn = adjustLastColumnIndex( selectedTable, selection );\n\t}\n\n\treturn selection;\n}\n\n// Expand table (in place) to expected size.\nfunction expandTableSize( table, expectedHeight, expectedWidth, tableUtils ) {\n\tconst tableWidth = tableUtils.getColumns( table );\n\tconst tableHeight = tableUtils.getRows( table );\n\n\tif ( expectedWidth > tableWidth ) {\n\t\ttableUtils.insertColumns( table, {\n\t\t\tat: tableWidth,\n\t\t\tcolumns: expectedWidth - tableWidth\n\t\t} );\n\t}\n\n\tif ( expectedHeight > tableHeight ) {\n\t\ttableUtils.insertRows( table, {\n\t\t\tat: tableHeight,\n\t\t\trows: expectedHeight - tableHeight\n\t\t} );\n\t}\n}\n\n// Returns two-dimensional array that is addressed by [ row ][ column ] that stores cells anchored at given location.\n//\n// At given row & column location it might be one of:\n//\n// * cell - cell from pasted table anchored at this location.\n// * null - if no cell is anchored at this location.\n//\n// For instance, from a table below:\n//\n//\t\t+----+----+----+----+\n//\t\t| 00 | 01 | 02 | 03 |\n//\t\t+ +----+----+----+\n//\t\t| | 11 | 13 |\n//\t\t+----+ +----+\n//\t\t| 20 | | 23 |\n//\t\t+----+----+----+----+\n//\n// The method will return an array (numbers represents cell element):\n//\n//\tconst map = [\n//\t\t[ '00', '01', '02', '03' ],\n//\t\t[ null, '11', null, '13' ],\n//\t\t[ '20', null, null, '23' ]\n//\t]\n//\n// This allows for a quick access to table at give row & column. For instance to access table cell \"13\" from pasted table call:\n//\n//\t\tconst cell = map[ 1 ][ 3 ]\n//\nfunction createLocationMap( table, width, height ) {\n\t// Create height x width (row x column) two-dimensional table to store cells.\n\tconst map = new Array( height ).fill( null )\n\t\t.map( () => new Array( width ).fill( null ) );\n\n\tfor ( const { column, row, cell } of new TableWalker( table ) ) {\n\t\tmap[ row ][ column ] = cell;\n\t}\n\n\treturn map;\n}\n\n// Make selected cells rectangular by splitting the cells that stand out from a rectangular selection.\n//\n// In the table below a selection is shown with \"::\" and slots with anchor cells are named.\n//\n// +----+----+----+----+----+ +----+----+----+----+----+\n// | 00 | 01 | 02 | 03 | | 00 | 01 | 02 | 03 |\n// + +----+ +----+----+ | ::::::::::::::::----+\n// | | 11 | | 13 | 14 | | ::11 | | 13:: 14 | <- first row\n// +----+----+ + +----+ +----::---| | ::----+\n// | 20 | 21 | | | 24 | select cells: | 20 ::21 | | :: 24 |\n// +----+----+ +----+----+ 11 -> 33 +----::---| |---::----+\n// | 30 | | 33 | 34 | | 30 :: | | 33:: 34 | <- last row\n// + + +----+ + | :::::::::::::::: +\n// | | | 43 | | | | | 43 | |\n// +----+----+----+----+----+ +----+----+----+----+----+\n// ^ ^\n// first & last columns\n//\n// Will update table to:\n//\n// +----+----+----+----+----+\n// | 00 | 01 | 02 | 03 |\n// + +----+----+----+----+\n// | | 11 | | 13 | 14 |\n// +----+----+ + +----+\n// | 20 | 21 | | | 24 |\n// +----+----+ +----+----+\n// | 30 | | | 33 | 34 |\n// + +----+----+----+ +\n// | | | | 43 | |\n// +----+----+----+----+----+\n//\n// In th example above:\n// - Cell \"02\" which have `rowspan = 4` must be trimmed at first and at after last row.\n// - Cell \"03\" which have `rowspan = 2` and `colspan = 2` must be trimmed at first column and after last row.\n// - Cells \"00\", \"03\" & \"30\" which cannot be cut by this algorithm as they are outside the trimmed area.\n// - Cell \"13\" cannot be cut as it is inside the trimmed area.\nfunction splitCellsToRectangularSelection( table, dimensions, writer ) {\n\tconst { firstRow, lastRow, firstColumn, lastColumn } = dimensions;\n\n\tconst rowIndexes = { first: firstRow, last: lastRow };\n\tconst columnIndexes = { first: firstColumn, last: lastColumn };\n\n\t// 1. Split cells vertically in two steps as first step might create cells that needs to split again.\n\tdoVerticalSplit( table, firstColumn, rowIndexes, writer );\n\tdoVerticalSplit( table, lastColumn + 1, rowIndexes, writer );\n\n\t// 2. Split cells horizontally in two steps as first step might create cells that needs to split again.\n\tdoHorizontalSplit( table, firstRow, columnIndexes, writer );\n\tdoHorizontalSplit( table, lastRow + 1, columnIndexes, writer, firstRow );\n}\n\nfunction doHorizontalSplit( table, splitRow, limitColumns, writer, startRow = 0 ) {\n\t// If selection starts at first row then no split is needed.\n\tif ( splitRow < 1 ) {\n\t\treturn;\n\t}\n\n\tconst overlappingCells = getVerticallyOverlappingCells( table, splitRow, startRow );\n\n\t// Filter out cells that are not touching insides of the rectangular selection.\n\tconst cellsToSplit = overlappingCells.filter( ( { column, cellWidth } ) => isAffectedBySelection( column, cellWidth, limitColumns ) );\n\n\treturn cellsToSplit.map( ( { cell } ) => splitHorizontally( cell, splitRow, writer ) );\n}\n\nfunction doVerticalSplit( table, splitColumn, limitRows, writer ) {\n\t// If selection starts at first column then no split is needed.\n\tif ( splitColumn < 1 ) {\n\t\treturn;\n\t}\n\n\tconst overlappingCells = getHorizontallyOverlappingCells( table, splitColumn );\n\n\t// Filter out cells that are not touching insides of the rectangular selection.\n\tconst cellsToSplit = overlappingCells.filter( ( { row, cellHeight } ) => isAffectedBySelection( row, cellHeight, limitRows ) );\n\n\treturn cellsToSplit.map( ( { cell, column } ) => splitVertically( cell, column, splitColumn, writer ) );\n}\n\n// Checks if cell at given row (column) is affected by a rectangular selection defined by first/last column (row).\n//\n// The same check is used for row as for column.\nfunction isAffectedBySelection( index, span, limit ) {\n\tconst endIndex = index + span - 1;\n\tconst { first, last } = limit;\n\n\tconst isInsideSelection = index >= first && index <= last;\n\tconst overlapsSelectionFromOutside = index < first && endIndex >= first;\n\n\treturn isInsideSelection || overlapsSelectionFromOutside;\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 table/tablekeyboard\n */\n\nimport TableSelection from './tableselection';\nimport TableWalker from './tablewalker';\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { getLocalizedArrowKeyCodeDirection } from 'ckeditor5/src/utils';\nimport { getSelectedTableCells, getTableCellsContainingSelection } from './utils/selection';\n\n/**\n * This plugin enables keyboard navigation for tables.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableKeyboard extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableKeyboard';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst view = this.editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\t// Handle Tab key navigation.\n\t\tthis.editor.keystrokes.set( 'Tab', ( ...args ) => this._handleTabOnSelectedTable( ...args ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Tab', this._getTabHandler( true ), { priority: 'low' } );\n\t\tthis.editor.keystrokes.set( 'Shift+Tab', this._getTabHandler( false ), { priority: 'low' } );\n\n\t\tthis.listenTo( viewDocument, 'arrowKey', ( ...args ) => this._onArrowKey( ...args ), { context: 'table' } );\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events for the <kbd>Tab</kbd> key executed\n\t * when the table widget is selected.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/keyobserver~KeyEventData} data Key event data.\n\t * @param {Function} cancel The stop/stopPropagation/preventDefault function.\n\t */\n\t_handleTabOnSelectedTable( data, cancel ) {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\t\tconst selectedElement = selection.getSelectedElement();\n\n\t\tif ( !selectedElement || !selectedElement.is( 'element', 'table' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcancel();\n\n\t\teditor.model.change( writer => {\n\t\t\twriter.setSelection( writer.createRangeIn( selectedElement.getChild( 0 ).getChild( 0 ) ) );\n\t\t} );\n\t}\n\n\t/**\n\t * Returns a handler for {@link module:engine/view/document~Document#event:keydown keydown} events for the <kbd>Tab</kbd> key executed\n\t * inside table cells.\n\t *\n\t * @private\n\t * @param {Boolean} isForward Whether this handler will move the selection to the next or the previous cell.\n\t */\n\t_getTabHandler( isForward ) {\n\t\tconst editor = this.editor;\n\n\t\treturn ( domEventData, cancel ) => {\n\t\t\tconst selection = editor.model.document.selection;\n\t\t\tlet tableCell = getTableCellsContainingSelection( selection )[ 0 ];\n\n\t\t\tif ( !tableCell ) {\n\t\t\t\ttableCell = this.editor.plugins.get( 'TableSelection' ).getFocusCell();\n\t\t\t}\n\n\t\t\tif ( !tableCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcancel();\n\n\t\t\tconst tableRow = tableCell.parent;\n\t\t\tconst table = tableRow.parent;\n\n\t\t\tconst currentRowIndex = table.getChildIndex( tableRow );\n\t\t\tconst currentCellIndex = tableRow.getChildIndex( tableCell );\n\n\t\t\tconst isFirstCellInRow = currentCellIndex === 0;\n\n\t\t\tif ( !isForward && isFirstCellInRow && currentRowIndex === 0 ) {\n\t\t\t\t// Set the selection over the whole table if the selection was in the first table cell.\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t\t} );\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst isLastCellInRow = currentCellIndex === tableRow.childCount - 1;\n\t\t\tconst isLastRow = currentRowIndex === table.childCount - 1;\n\n\t\t\tif ( isForward && isLastRow && isLastCellInRow ) {\n\t\t\t\teditor.execute( 'insertTableRowBelow' );\n\n\t\t\t\t// Check if the command actually added a row. If `insertTableRowBelow` execution didn't add a row (because it was disabled\n\t\t\t\t// or it got overwritten) set the selection over the whole table to mirror the first cell case.\n\t\t\t\tif ( currentRowIndex === table.childCount - 1 ) {\n\t\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t\t\t} );\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet cellToFocus;\n\n\t\t\t// Move to the first cell in the next row.\n\t\t\tif ( isForward && isLastCellInRow ) {\n\t\t\t\tconst nextRow = table.getChild( currentRowIndex + 1 );\n\n\t\t\t\tcellToFocus = nextRow.getChild( 0 );\n\t\t\t}\n\t\t\t// Move to the last cell in the previous row.\n\t\t\telse if ( !isForward && isFirstCellInRow ) {\n\t\t\t\tconst previousRow = table.getChild( currentRowIndex - 1 );\n\n\t\t\t\tcellToFocus = previousRow.getChild( previousRow.childCount - 1 );\n\t\t\t}\n\t\t\t// Move to the next/previous cell.\n\t\t\telse {\n\t\t\t\tcellToFocus = tableRow.getChild( currentCellIndex + ( isForward ? 1 : -1 ) );\n\t\t\t}\n\n\t\t\teditor.model.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeIn( cellToFocus ) );\n\t\t\t} );\n\t\t};\n\t}\n\n\t/**\n\t * Handles {@link module:engine/view/document~Document#event:keydown keydown} events.\n\t *\n\t * @private\n\t * @param {module:utils/eventinfo~EventInfo} eventInfo\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t */\n\t_onArrowKey( eventInfo, domEventData ) {\n\t\tconst editor = this.editor;\n\t\tconst keyCode = domEventData.keyCode;\n\n\t\tconst direction = getLocalizedArrowKeyCodeDirection( keyCode, editor.locale.contentLanguageDirection );\n\t\tconst wasHandled = this._handleArrowKeys( direction, domEventData.shiftKey );\n\n\t\tif ( wasHandled ) {\n\t\t\tdomEventData.preventDefault();\n\t\t\tdomEventData.stopPropagation();\n\t\t\teventInfo.stop();\n\t\t}\n\t}\n\n\t/**\n\t * Handles arrow keys to move the selection around the table.\n\t *\n\t * @private\n\t * @param {'left'|'up'|'right'|'down'} direction The direction of the arrow key.\n\t * @param {Boolean} expandSelection If the current selection should be expanded.\n\t * @returns {Boolean} Returns `true` if key was handled.\n\t */\n\t_handleArrowKeys( direction, expandSelection ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst isForward = [ 'right', 'down' ].includes( direction );\n\n\t\t// In case one or more table cells are selected (from outside),\n\t\t// move the selection to a cell adjacent to the selected table fragment.\n\t\tconst selectedCells = getSelectedTableCells( selection );\n\n\t\tif ( selectedCells.length ) {\n\t\t\tlet focusCell;\n\n\t\t\tif ( expandSelection ) {\n\t\t\t\tfocusCell = this.editor.plugins.get( 'TableSelection' ).getFocusCell();\n\t\t\t} else {\n\t\t\t\tfocusCell = isForward ? selectedCells[ selectedCells.length - 1 ] : selectedCells[ 0 ];\n\t\t\t}\n\n\t\t\tthis._navigateFromCellInDirection( focusCell, direction, expandSelection );\n\n\t\t\treturn true;\n\t\t}\n\n\t\t// Abort if we're not in a table cell.\n\t\tconst tableCell = selection.focus.findAncestor( 'tableCell' );\n\n\t\t/* istanbul ignore if: paranoid check */\n\t\tif ( !tableCell ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Navigation is in the opposite direction than the selection direction so this is shrinking of the selection.\n\t\t// Selection for sure will not approach cell edge.\n\t\tif ( expandSelection && !selection.isCollapsed && selection.isBackward == isForward ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Let's check if the selection is at the beginning/end of the cell.\n\t\tif ( this._isSelectionAtCellEdge( selection, tableCell, isForward ) ) {\n\t\t\tthis._navigateFromCellInDirection( tableCell, direction, expandSelection );\n\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * Returns `true` if the selection is at the boundary of a table cell according to the navigation direction.\n\t *\n\t * @private\n\t * @param {module:engine/model/selection~Selection} selection The current selection.\n\t * @param {module:engine/model/element~Element} tableCell The current table cell element.\n\t * @param {Boolean} isForward The expected navigation direction.\n\t * @returns {Boolean}\n\t */\n\t_isSelectionAtCellEdge( selection, tableCell, isForward ) {\n\t\tconst model = this.editor.model;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst focus = isForward ? selection.getLastPosition() : selection.getFirstPosition();\n\n\t\t// If the current limit element is not table cell we are for sure not at the cell edge.\n\t\t// Also `modifySelection` will not let us out of it.\n\t\tif ( !schema.getLimitElement( focus ).is( 'element', 'tableCell' ) ) {\n\t\t\tconst boundaryPosition = model.createPositionAt( tableCell, isForward ? 'end' : 0 );\n\n\t\t\treturn boundaryPosition.isTouching( focus );\n\t\t}\n\n\t\tconst probe = model.createSelection( focus );\n\n\t\tmodel.modifySelection( probe, { direction: isForward ? 'forward' : 'backward' } );\n\n\t\t// If there was no change in the focus position, then it's not possible to move the selection there.\n\t\treturn focus.isEqual( probe.focus );\n\t}\n\n\t/**\n\t * Moves the selection from the given table cell in the specified direction.\n\t *\n\t * @protected\n\t * @param {module:engine/model/element~Element} focusCell The table cell that is current multi-cell selection focus.\n\t * @param {'left'|'up'|'right'|'down'} direction Direction in which selection should move.\n\t * @param {Boolean} [expandSelection=false] If the current selection should be expanded.\n\t */\n\t_navigateFromCellInDirection( focusCell, direction, expandSelection = false ) {\n\t\tconst model = this.editor.model;\n\n\t\tconst table = focusCell.findAncestor( 'table' );\n\t\tconst tableMap = [ ...new TableWalker( table, { includeAllSlots: true } ) ];\n\t\tconst { row: lastRow, column: lastColumn } = tableMap[ tableMap.length - 1 ];\n\n\t\tconst currentCellInfo = tableMap.find( ( { cell } ) => cell == focusCell );\n\t\tlet { row, column } = currentCellInfo;\n\n\t\tswitch ( direction ) {\n\t\t\tcase 'left':\n\t\t\t\tcolumn--;\n\t\t\t\tbreak;\n\n\t\t\tcase 'up':\n\t\t\t\trow--;\n\t\t\t\tbreak;\n\n\t\t\tcase 'right':\n\t\t\t\tcolumn += currentCellInfo.cellWidth;\n\t\t\t\tbreak;\n\n\t\t\tcase 'down':\n\t\t\t\trow += currentCellInfo.cellHeight;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst isOutsideVertically = row < 0 || row > lastRow;\n\t\tconst isBeforeFirstCell = column < 0 && row <= 0;\n\t\tconst isAfterLastCell = column > lastColumn && row >= lastRow;\n\n\t\t// Note that if the table cell at the end of a row is row-spanned then isAfterLastCell will never be true.\n\t\t// However, we don't know if user was navigating on the last row or not, so let's stay in the table.\n\n\t\tif ( isOutsideVertically || isBeforeFirstCell || isAfterLastCell ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( writer.createRangeOn( table ) );\n\t\t\t} );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( column < 0 ) {\n\t\t\tcolumn = expandSelection ? 0 : lastColumn;\n\t\t\trow--;\n\t\t} else if ( column > lastColumn ) {\n\t\t\tcolumn = expandSelection ? lastColumn : 0;\n\t\t\trow++;\n\t\t}\n\n\t\tconst cellToSelect = tableMap.find( cellInfo => cellInfo.row == row && cellInfo.column == column ).cell;\n\t\tconst isForward = [ 'right', 'down' ].includes( direction );\n\t\tconst tableSelection = this.editor.plugins.get( 'TableSelection' );\n\n\t\tif ( expandSelection && tableSelection.isEnabled ) {\n\t\t\tconst anchorCell = tableSelection.getAnchorCell() || focusCell;\n\n\t\t\ttableSelection.setCellSelection( anchorCell, cellToSelect );\n\t\t} else {\n\t\t\tconst positionToSelect = model.createPositionAt( cellToSelect, isForward ? 0 : 'end' );\n\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( positionToSelect );\n\t\t\t} );\n\t\t}\n\t}\n}\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 table/tableselection/mouseeventsobserver\n */\n\nimport { DomEventObserver } from 'ckeditor5/src/engine';\n\n/**\n * The mouse selection event observer.\n *\n * It registers listeners for the following DOM events:\n *\n * - `'mousemove'`\n * - `'mouseup'`\n * - `'mouseleave'`\n *\n * Note that this observer is disabled by default. To enable this observer, it needs to be added to\n * {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * The observer is registered by the {@link module:table/tableselection~TableSelection} plugin.\n *\n * @extends module:engine/view/observer/domeventobserver~DomEventObserver\n */\nexport default class MouseEventsObserver extends DomEventObserver {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( view ) {\n\t\tsuper( view );\n\n\t\tthis.domEventType = [ 'mousemove', 'mouseleave' ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tonDomEvent( domEvent ) {\n\t\tthis.fire( domEvent.type, domEvent );\n\t}\n}\n\n/**\n * Fired when the mouse is moved over one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mousemove\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\n */\n\n/**\n * Fired when the mouse is moved out of one of the editables.\n *\n * Introduced by {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver}.\n *\n * Note that this event is not available by default. To make it available,\n * {@link module:table/tableselection/mouseeventsobserver~MouseEventsObserver} needs to be added\n * to {@link module:engine/view/view~View} using the {@link module:engine/view/view~View#addObserver} method.\n *\n * @see module:table/tableselection/mouseeventsobserver~MouseEventsObserver\n * @event module:engine/view/document~Document#event:mouseleave\n * @param {module:engine/view/observer/domeventdata~DomEventData} data Event data.\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 table/tablemouse\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TableSelection from './tableselection';\nimport MouseEventsObserver from './tablemouse/mouseeventsobserver';\n\nimport { getTableCellsContainingSelection } from './utils/selection';\n\n/**\n * This plugin enables a table cells' selection with the mouse.\n * It is loaded automatically by the {@link module:table/table~Table} plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableMouse extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableMouse';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableSelection ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Currently the MouseObserver only handles `mousedown` and `mouseup` events.\n\t\t// TODO move to the engine?\n\t\teditor.editing.view.addObserver( MouseEventsObserver );\n\n\t\tthis._enableShiftClickSelection();\n\t\tthis._enableMouseDragSelection();\n\t}\n\n\t/**\n\t * Enables making cells selection by <kbd>Shift</kbd>+click. Creates a selection from the cell which previously held\n\t * the selection to the cell which was clicked. It can be the same cell, in which case it selects a single cell.\n\t *\n\t * @private\n\t */\n\t_enableShiftClickSelection() {\n\t\tconst editor = this.editor;\n\t\tlet blockSelectionChange = false;\n\n\t\tconst tableSelection = editor.plugins.get( TableSelection );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tif ( !this.isEnabled || !tableSelection.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !domEventData.domEvent.shiftKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst anchorCell = tableSelection.getAnchorCell() || getTableCellsContainingSelection( editor.model.document.selection )[ 0 ];\n\n\t\t\tif ( !anchorCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst targetCell = this._getModelTableCellFromDomEvent( domEventData );\n\n\t\t\tif ( targetCell && haveSameTableParent( anchorCell, targetCell ) ) {\n\t\t\t\tblockSelectionChange = true;\n\t\t\t\ttableSelection.setCellSelection( anchorCell, targetCell );\n\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t}\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mouseup', () => {\n\t\t\tblockSelectionChange = false;\n\t\t} );\n\n\t\t// We need to ignore a `selectionChange` event that is fired after we render our new table cells selection.\n\t\t// When downcasting table cells selection to the view, we put the view selection in the last selected cell\n\t\t// in a place that may not be natively a \"correct\" location. This is we put it directly in the `<td>` element.\n\t\t// All browsers fire the native `selectionchange` event.\n\t\t// However, all browsers except Safari return the selection in the exact place where we put it\n\t\t// (even though it's visually normalized). Safari returns `<td><p>^foo` that makes our selection observer\n\t\t// fire our `selectionChange` event (because the view selection that we set in the first step differs from the DOM selection).\n\t\t// Since `selectionChange` is fired, we automatically update the model selection that moves it that paragraph.\n\t\t// This breaks our dear cells selection.\n\t\t//\n\t\t// Theoretically this issue concerns only Safari that is the only browser that do normalize the selection.\n\t\t// However, to avoid code branching and to have a good coverage for this event blocker, I enabled it for all browsers.\n\t\t//\n\t\t// Note: I'm keeping the `blockSelectionChange` state separately for shift+click and mouse drag (exact same logic)\n\t\t// so I don't have to try to analyze whether they don't overlap in some weird cases. Probably they don't.\n\t\t// But I have other things to do, like writing this comment.\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', evt => {\n\t\t\tif ( blockSelectionChange ) {\n\t\t\t\t// @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' );\n\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Enables making cells selection by dragging.\n\t *\n\t * The selection is made only on mousemove. Mouse tracking is started on mousedown.\n\t * However, the cells selection is enabled only after the mouse cursor left the anchor cell.\n\t * Thanks to that normal text selection within one cell works just fine. However, you can still select\n\t * just one cell by leaving the anchor cell and moving back to it.\n\t *\n\t * @private\n\t */\n\t_enableMouseDragSelection() {\n\t\tconst editor = this.editor;\n\t\tlet anchorCell, targetCell;\n\t\tlet beganCellSelection = false;\n\t\tlet blockSelectionChange = false;\n\n\t\tconst tableSelection = editor.plugins.get( TableSelection );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => {\n\t\t\tif ( !this.isEnabled || !tableSelection.isEnabled ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Make sure to not conflict with the shift+click listener and any other possible handler.\n\t\t\tif ( domEventData.domEvent.shiftKey || domEventData.domEvent.ctrlKey || domEventData.domEvent.altKey ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tanchorCell = this._getModelTableCellFromDomEvent( domEventData );\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mousemove', ( evt, domEventData ) => {\n\t\t\tif ( !domEventData.domEvent.buttons ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !anchorCell ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newTargetCell = this._getModelTableCellFromDomEvent( domEventData );\n\n\t\t\tif ( newTargetCell && haveSameTableParent( anchorCell, newTargetCell ) ) {\n\t\t\t\ttargetCell = newTargetCell;\n\n\t\t\t\t// Switch to the cell selection mode after the mouse cursor left the anchor cell.\n\t\t\t\t// Switch off only on mouseup (makes selecting a single cell possible).\n\t\t\t\tif ( !beganCellSelection && targetCell != anchorCell ) {\n\t\t\t\t\tbeganCellSelection = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Yep, not making a cell selection yet. See method docs.\n\t\t\tif ( !beganCellSelection ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tblockSelectionChange = true;\n\t\t\ttableSelection.setCellSelection( anchorCell, targetCell );\n\n\t\t\tdomEventData.preventDefault();\n\t\t} );\n\n\t\tthis.listenTo( editor.editing.view.document, 'mouseup', () => {\n\t\t\tbeganCellSelection = false;\n\t\t\tblockSelectionChange = false;\n\t\t\tanchorCell = null;\n\t\t\ttargetCell = null;\n\t\t} );\n\n\t\t// See the explanation in `_enableShiftClickSelection()`.\n\t\tthis.listenTo( editor.editing.view.document, 'selectionChange', evt => {\n\t\t\tif ( blockSelectionChange ) {\n\t\t\t\t// @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' );\n\n\t\t\t\tevt.stop();\n\t\t\t}\n\t\t}, { priority: 'highest' } );\n\t}\n\n\t/**\n\t * Returns the model table cell element based on the target element of the passed DOM event.\n\t *\n\t * @private\n\t * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData\n\t * @returns {module:engine/model/element~Element|undefined} Returns the table cell or `undefined`.\n\t */\n\t_getModelTableCellFromDomEvent( domEventData ) {\n\t\t// Note: Work with positions (not element mapping) because the target element can be an attribute or other non-mapped element.\n\t\tconst viewTargetElement = domEventData.target;\n\t\tconst viewPosition = this.editor.editing.view.createPositionAt( viewTargetElement, 0 );\n\t\tconst modelPosition = this.editor.editing.mapper.toModelPosition( viewPosition );\n\t\tconst modelElement = modelPosition.parent;\n\n\t\treturn modelElement.findAncestor( 'tableCell', { includeSelf: true } );\n\t}\n}\n\nfunction haveSameTableParent( cellA, cellB ) {\n\treturn cellA.parent.parent == cellB.parent.parent;\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 table/utils/ui/widget\n */\n\nimport { isWidget } from 'ckeditor5/src/widget';\n\n/**\n * Returns a table widget editing view element if one is selected.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getSelectedTableWidget( selection ) {\n\tconst viewElement = selection.getSelectedElement();\n\n\tif ( viewElement && isTableWidget( viewElement ) ) {\n\t\treturn viewElement;\n\t}\n\n\treturn null;\n}\n\n/**\n * Returns a table widget editing view element if one is among the selection's ancestors.\n *\n * @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection\n * @returns {module:engine/view/element~Element|null}\n */\nexport function getTableWidgetAncestor( selection ) {\n\tconst parentTable = findAncestor( 'table', selection.getFirstPosition() );\n\n\tif ( parentTable && isTableWidget( parentTable.parent ) ) {\n\t\treturn parentTable.parent;\n\t}\n\n\treturn null;\n}\n\n// Checks if a given view element is a table widget.\n//\n// @param {module:engine/view/element~Element} viewElement\n// @returns {Boolean}\nfunction isTableWidget( viewElement ) {\n\treturn !!viewElement.getCustomProperty( 'table' ) && isWidget( viewElement );\n}\n\nfunction findAncestor( parentName, positionOrElement ) {\n\tlet parent = positionOrElement.parent;\n\n\twhile ( parent ) {\n\t\tif ( parent.name === parentName ) {\n\t\t\treturn parent;\n\t\t}\n\n\t\tparent = parent.parent;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/converters/tableproperites\n */\n\n/**\n * Conversion helper for upcasting attributes using normalized styles.\n *\n * @param {module:engine/conversion/conversion~Conversion} conversion\n * @param {String} modelElement\n * @param {String} modelAttribute\n * @param {String} styleName\n */\nexport function upcastStyleToAttribute( conversion, modelElement, modelAttribute, styleName ) {\n\tconversion.for( 'upcast' ).attributeToAttribute( {\n\t\tview: {\n\t\t\tstyles: {\n\t\t\t\t[ styleName ]: /[\\s\\S]+/\n\t\t\t}\n\t\t},\n\t\tmodel: {\n\t\t\tname: modelElement,\n\t\t\tkey: modelAttribute,\n\t\t\tvalue: viewElement => viewElement.getNormalizedStyle( styleName )\n\t\t}\n\t} );\n}\n\n/**\n * Conversion helper for upcasting border styles for view elements.\n *\n * @param {module:engine/conversion/conversion~Conversion} conversion\n * @param {String} viewElementName\n */\nexport function upcastBorderStyles( conversion, viewElementName ) {\n\tconversion.for( 'upcast' ).add( dispatcher => dispatcher.on( 'element:' + viewElementName, ( evt, data, conversionApi ) => {\n\t\t// If the element was not converted by element-to-element converter,\n\t\t// we should not try to convert the style. See #8393.\n\t\tif ( !data.modelRange ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// TODO: this is counter-intuitive: ie.: if only `border-top` is defined then `hasStyle( 'border' )` also returns true.\n\t\t// TODO: this might needs to be fixed in styles normalizer.\n\t\tconst stylesToConsume = [\n\t\t\t'border-top',\n\t\t\t'border-right',\n\t\t\t'border-bottom',\n\t\t\t'border-left'\n\t\t].filter( styleName => data.viewItem.hasStyle( styleName ) );\n\n\t\tif ( !stylesToConsume.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst matcherPattern = {\n\t\t\tstyles: stylesToConsume\n\t\t};\n\n\t\t// Try to consume appropriate values from consumable values list.\n\t\tif ( !conversionApi.consumable.test( data.viewItem, matcherPattern ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelElement = [ ...data.modelRange.getItems( { shallow: true } ) ].pop();\n\n\t\tconversionApi.consumable.consume( data.viewItem, matcherPattern );\n\n\t\tconversionApi.writer.setAttribute( 'borderStyle', data.viewItem.getNormalizedStyle( 'border-style' ), modelElement );\n\t\tconversionApi.writer.setAttribute( 'borderColor', data.viewItem.getNormalizedStyle( 'border-color' ), modelElement );\n\t\tconversionApi.writer.setAttribute( 'borderWidth', data.viewItem.getNormalizedStyle( 'border-width' ), modelElement );\n\t} ) );\n}\n\n/**\n * Conversion helper for downcasting an attribute to a style.\n *\n * @param {module:engine/conversion/conversion~Conversion} conversion\n * @param {String} modelElement\n * @param {String} modelAttribute\n * @param {String} styleName\n */\nexport function downcastAttributeToStyle( conversion, modelElement, modelAttribute, styleName ) {\n\tconversion.for( 'downcast' ).attributeToAttribute( {\n\t\tmodel: {\n\t\t\tname: modelElement,\n\t\t\tkey: modelAttribute\n\t\t},\n\t\tview: modelAttributeValue => ( {\n\t\t\tkey: 'style',\n\t\t\tvalue: {\n\t\t\t\t[ styleName ]: modelAttributeValue\n\t\t\t}\n\t\t} )\n\t} );\n}\n\n/**\n * Conversion helper for downcasting attributes from the model table to a view table (not to `<figure>`).\n *\n * @param {module:engine/conversion/conversion~Conversion} conversion\n * @param {String} modelAttribute\n * @param {String} styleName\n */\nexport function downcastTableAttribute( conversion, modelAttribute, styleName ) {\n\tconversion.for( 'downcast' ).add( dispatcher => dispatcher.on( `attribute:${ modelAttribute }:table`, ( evt, data, conversionApi ) => {\n\t\tconst { item, attributeNewValue } = data;\n\t\tconst { mapper, writer } = conversionApi;\n\n\t\tif ( !conversionApi.consumable.consume( data.item, evt.name ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst table = [ ...mapper.toViewElement( item ).getChildren() ].find( child => child.is( 'element', 'table' ) );\n\n\t\tif ( attributeNewValue ) {\n\t\t\twriter.setStyle( styleName, attributeNewValue, table );\n\t\t} else {\n\t\t\twriter.removeStyle( styleName, table );\n\t\t}\n\t} ) );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablepropertycommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\n/**\n * The table cell attribute command.\n *\n * This command is a base command for other table property commands.\n *\n * @extends module:core/command~Command\n */\nexport default class TablePropertyCommand extends Command {\n\t/**\n\t * Creates a new `TablePropertyCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t * @param {String} attributeName Table cell attribute name.\n\t */\n\tconstructor( editor, attributeName ) {\n\t\tsuper( editor );\n\n\t\tthis.attributeName = attributeName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst editor = this.editor;\n\t\tconst selection = editor.model.document.selection;\n\n\t\tconst table = selection.getFirstPosition().findAncestor( 'table' );\n\n\t\tthis.isEnabled = !!table;\n\t\tthis.value = this._getValue( table );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} [options]\n\t * @param {*} [options.value] If set, the command will set the attribute on the selected table.\n\t * If not set, the command will remove the attribute from the selected table.\n\t * @param {module:engine/model/batch~Batch} [options.batch] Pass the model batch instance to the command to aggregate changes,\n\t * for example, to allow a single undo step for multiple executions.\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\n\t\tconst { value, batch } = options;\n\n\t\tconst table = selection.getFirstPosition().findAncestor( 'table' );\n\t\tconst valueToSet = this._getValueToSet( value );\n\n\t\tmodel.enqueueChange( batch || 'default', writer => {\n\t\t\tif ( valueToSet ) {\n\t\t\t\twriter.setAttribute( this.attributeName, valueToSet, table );\n\t\t\t} else {\n\t\t\t\twriter.removeAttribute( this.attributeName, table );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the attribute value for a table.\n\t *\n\t * @param {module:engine/model/element~Element} table\n\t * @returns {String|undefined}\n\t * @private\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn table.getAttribute( this.attributeName );\n\t}\n\n\t/**\n\t * Returns the proper model value. It can be used to add a default unit to numeric values.\n\t *\n\t * @private\n\t * @param {*} value\n\t * @returns {*}\n\t */\n\t_getValueToSet( value ) {\n\t\treturn value;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablebackgroundcolorcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\n\n/**\n * The table background color command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBackgroundColor'` editor command.\n *\n * To change the background color of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBackgroundColor', {\n *\t\t\tvalue: '#f00'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBackgroundColorCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBackgroundColorCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'backgroundColor' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/utils/table-properties\n */\n\nimport { isObject } from 'lodash-es';\n\n/**\n * Returns a string if all four values of box sides are equal.\n *\n * If a string is passed, it is treated as a single value (pass-through).\n *\n *\t\t// Returns 'foo':\n *\t\tgetSingleValue( { top: 'foo', right: 'foo', bottom: 'foo', left: 'foo' } );\n *\t\tgetSingleValue( 'foo' );\n *\n *\t\t// Returns undefined:\n *\t\tgetSingleValue( { top: 'foo', right: 'foo', bottom: 'bar', left: 'foo' } );\n *\t\tgetSingleValue( { top: 'foo', right: 'foo' } );\n *\n * @param objectOrString\n * @returns {module:engine/view/stylesmap~BoxSides|String}\n */\nexport function getSingleValue( objectOrString ) {\n\tif ( !objectOrString || !isObject( objectOrString ) ) {\n\t\treturn objectOrString;\n\t}\n\n\tconst { top, right, bottom, left } = objectOrString;\n\n\tif ( top == right && right == bottom && bottom == left ) {\n\t\treturn top;\n\t}\n}\n\n/**\n * Adds a unit to a value if the value is a number or a string representing a number.\n *\n * **Note**: It does nothing to non-numeric values.\n *\n *\t\tgetSingleValue( 25, 'px' );\t\t// '25px'\n *\t\tgetSingleValue( 25, 'em' );\t\t// '25em'\n *\t\tgetSingleValue( '25em', 'px' );\t// '25em'\n *\t\tgetSingleValue( 'foo', 'px' );\t// 'foo'\n *\n * @param {*} value\n * @param {String} defaultUnit A default unit added to a numeric value.\n * @returns {String|*}\n */\nexport function addDefaultUnitToNumericValue( value, defaultUnit ) {\n\tconst numericValue = parseFloat( value );\n\n\tif ( Number.isNaN( numericValue ) ) {\n\t\treturn value;\n\t}\n\n\tif ( String( numericValue ) !== String( value ) ) {\n\t\treturn value;\n\t}\n\n\treturn `${ numericValue }${ defaultUnit }`;\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 table/tableproperties/commands/tablebordercolorcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table border color command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBorderColor'` editor command.\n *\n * To change the border color of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBorderColor', {\n *\t\t\tvalue: '#f00'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBorderColorCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBorderColorCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderColor' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( table.getAttribute( this.attributeName ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tableborderstylecommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table style border command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBorderStyle'` editor command.\n *\n * To change the border style of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBorderStyle', {\n *\t\t\tvalue: 'dashed'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBorderStyleCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBorderStyleCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderStyle' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( table.getAttribute( this.attributeName ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tableborderwidthcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { addDefaultUnitToNumericValue, getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table width border command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableBorderWidth'` editor command.\n *\n * To change the border width of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableBorderWidth', {\n *\t\t\tvalue: '5px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableBorderWidth', {\n *\t\t\tvalue: '5'\n *\t\t} );\n *\n * will set the `borderWidth` attribute to `'5px'` in the model.\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableBorderWidthCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableBorderWidthCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderWidth' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValue( table ) {\n\t\tif ( !table ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( table.getAttribute( this.attributeName ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablewidthcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { addDefaultUnitToNumericValue } from '../../utils/table-properties';\n\n/**\n * The table width command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableWidth'` editor command.\n *\n * To change the width of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableWidth', {\n *\t\t\tvalue: '400px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableWidth', {\n *\t\t\tvalue: '50'\n *\t\t} );\n *\n * will set the `width` attribute to `'50px'` in the model.\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableWidthCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableWidthCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'width' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tableheightcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\nimport { addDefaultUnitToNumericValue } from '../../utils/table-properties';\n\n/**\n * The table height command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableHeight'` editor command.\n *\n * To change the height of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableHeight', {\n *\t\t\tvalue: '500px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableHeight', {\n *\t\t\tvalue: '50'\n *\t\t} );\n *\n * will set the `height` attribute to `'50px'` in the model.\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableHeightCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableHeightCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'height' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/commands/tablealignmentcommand\n */\n\nimport TablePropertyCommand from './tablepropertycommand';\n\n/**\n * The table alignment command.\n *\n * The command is registered by the {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing} as\n * the `'tableAlignment'` editor command.\n *\n * To change the alignment of the selected table, execute the command:\n *\n *\t\teditor.execute( 'tableAlignment', {\n *\t\t\tvalue: 'right'\n *\t\t} );\n *\n * @extends module:table/tableproperties/commands/tablepropertycommand~TablePropertyCommand\n */\nexport default class TableAlignmentCommand extends TablePropertyCommand {\n\t/**\n\t * Creates a new `TableAlignmentCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'alignment' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/tablepropertiesediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { addBackgroundRules, addBorderRules } from 'ckeditor5/src/engine';\n\nimport TableEditing from '../tableediting';\nimport {\n\tdowncastAttributeToStyle,\n\tdowncastTableAttribute,\n\tupcastBorderStyles,\n\tupcastStyleToAttribute\n} from '../converters/tableproperties';\nimport TableBackgroundColorCommand from './commands/tablebackgroundcolorcommand';\nimport TableBorderColorCommand from './commands/tablebordercolorcommand';\nimport TableBorderStyleCommand from './commands/tableborderstylecommand';\nimport TableBorderWidthCommand from './commands/tableborderwidthcommand';\nimport TableWidthCommand from './commands/tablewidthcommand';\nimport TableHeightCommand from './commands/tableheightcommand';\nimport TableAlignmentCommand from './commands/tablealignmentcommand';\n\nconst ALIGN_VALUES_REG_EXP = /^(left|right)$/;\n\n/**\n * The table properties editing feature.\n *\n * Introduces table's model attributes and their conversion:\n *\n * - border: `borderStyle`, `borderColor` and `borderWidth`\n * - background color: `backgroundColor`\n * - horizontal alignment: `alignment`\n * - width & height: `width` & `height`\n *\n * It also registers commands used to manipulate the above attributes:\n *\n * - border: `'tableBorderStyle'`, `'tableBorderColor'` and `'tableBorderWidth'` commands\n * - background color: `'tableBackgroundColor'`\n * - horizontal alignment: `'tableAlignment'`\n * - width & height: `'tableWidth'` & `'tableHeight'`\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TablePropertiesEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TablePropertiesEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\n\t\teditor.data.addStyleProcessorRules( addBorderRules );\n\t\tenableBorderProperties( schema, conversion );\n\t\teditor.commands.add( 'tableBorderColor', new TableBorderColorCommand( editor ) );\n\t\teditor.commands.add( 'tableBorderStyle', new TableBorderStyleCommand( editor ) );\n\t\teditor.commands.add( 'tableBorderWidth', new TableBorderWidthCommand( editor ) );\n\n\t\tenableAlignmentProperty( schema, conversion );\n\t\teditor.commands.add( 'tableAlignment', new TableAlignmentCommand( editor ) );\n\n\t\tenableTableToFigureProperty( schema, conversion, 'width', 'width' );\n\t\teditor.commands.add( 'tableWidth', new TableWidthCommand( editor ) );\n\n\t\tenableTableToFigureProperty( schema, conversion, 'height', 'height' );\n\t\teditor.commands.add( 'tableHeight', new TableHeightCommand( editor ) );\n\n\t\teditor.data.addStyleProcessorRules( addBackgroundRules );\n\t\tenableProperty( schema, conversion, 'backgroundColor', 'background-color' );\n\t\teditor.commands.add( 'tableBackgroundColor', new TableBackgroundColorCommand( editor ) );\n\t}\n}\n\n// Enables `'borderStyle'`, `'borderColor'` and `'borderWidth'` attributes for table.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableBorderProperties( schema, conversion ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ 'borderWidth', 'borderColor', 'borderStyle' ]\n\t} );\n\tupcastBorderStyles( conversion, 'table' );\n\tdowncastTableAttribute( conversion, 'borderColor', 'border-color' );\n\tdowncastTableAttribute( conversion, 'borderStyle', 'border-style' );\n\tdowncastTableAttribute( conversion, 'borderWidth', 'border-width' );\n}\n\n// Enables the `'alignment'` attribute for table.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableAlignmentProperty( schema, conversion ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ 'alignment' ]\n\t} );\n\n\tconversion\n\t\t.attributeToAttribute( {\n\t\t\tmodel: {\n\t\t\t\tname: 'table',\n\t\t\t\tkey: 'alignment',\n\t\t\t\tvalues: [ 'left', 'right' ]\n\t\t\t},\n\t\t\tview: {\n\t\t\t\tleft: {\n\t\t\t\t\tkey: 'style',\n\t\t\t\t\tvalue: {\n\t\t\t\t\t\tfloat: 'left'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tright: {\n\t\t\t\t\tkey: 'style',\n\t\t\t\t\tvalue: {\n\t\t\t\t\t\tfloat: 'right'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tconverterPriority: 'high'\n\t\t} );\n\n\tconversion.for( 'upcast' )\n\t\t// Support for backwards compatibility and pasting from other sources.\n\t\t.attributeToAttribute( {\n\t\t\tview: {\n\t\t\t\tattributes: {\n\t\t\t\t\talign: ALIGN_VALUES_REG_EXP\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tname: 'table',\n\t\t\t\tkey: 'alignment',\n\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'align' )\n\t\t\t}\n\t\t} );\n}\n\n// Enables conversion for an attribute for simple view-model mappings.\n//\n// @param {String} modelAttribute\n// @param {String} styleName\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableProperty( schema, conversion, modelAttribute, styleName ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ modelAttribute ]\n\t} );\n\tupcastStyleToAttribute( conversion, 'table', modelAttribute, styleName );\n\tdowncastTableAttribute( conversion, modelAttribute, styleName );\n}\n\n// Enables conversion for an attribute for simple view (figure) to model (table) mappings.\n//\n// @param {String} modelAttribute\n// @param {String} styleName\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableTableToFigureProperty( schema, conversion, modelAttribute, styleName ) {\n\tschema.extend( 'table', {\n\t\tallowAttributes: [ modelAttribute ]\n\t} );\n\tupcastStyleToAttribute( conversion, 'table', modelAttribute, styleName );\n\tdowncastAttributeToStyle( conversion, 'table', modelAttribute, styleName );\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 table/ui/colorinputview\n */\n\nimport { View, InputTextView, ButtonView, createDropdown, ColorGridView } from 'ckeditor5/src/ui';\nimport { icons } from 'ckeditor5/src/core';\n\nimport '../../theme/colorinput.css';\n\n/**\n * The color input view class. It allows the user to type in a color (hex, rgb, etc.)\n * or choose it from the configurable color palette with a preview.\n *\n * @private\n * @extends module:ui/view~View\n */\nexport default class ColorInputView extends View {\n\t/**\n\t * Creates an instance of the color input view.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance.\n\t * @param {Object} options The input options.\n\t * @param {module:ui/colorgrid/colorgrid~ColorDefinition} options.colorDefinitions The colors to be displayed\n\t * in the palette inside the input's dropdown.\n\t * @param {Number} options.columns The number of columns in which the colors will be displayed.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * The value of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #value\n\t\t * @default ''\n\t\t */\n\t\tthis.set( 'value', '' );\n\n\t\t/**\n\t\t * The `id` attribute of the input (i.e. to pair with the `<label>` element).\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #id\n\t\t */\n\t\tthis.set( 'id' );\n\n\t\t/**\n\t\t * Controls whether the input view is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t * @default false\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * Set to `true` when the field has some error. Usually controlled via\n\t\t * {@link module:ui/labeledinput/labeledinputview~LabeledInputView#errorText}.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #hasError\n\t\t * @default false\n\t\t */\n\t\tthis.set( 'hasError', false );\n\n\t\t/**\n\t\t * An observable flag set to `true` when the input is focused by the user.\n\t\t * `false` otherwise.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isFocused\n\t\t * @default false\n\t\t */\n\t\tthis.set( 'isFocused', false );\n\n\t\t/**\n\t\t * An observable flag set to `true` when the input contains no text.\n\t\t *\n\t\t * @readonly\n\t\t * @observable\n\t\t * @member {Boolean} #isEmpty\n\t\t * @default true\n\t\t */\n\t\tthis.set( 'isEmpty', true );\n\n\t\t/**\n\t\t * The `id` of the element describing this field. When the field has\n\t\t * some error, it helps screen readers read the error text.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #ariaDescribedById\n\t\t */\n\t\tthis.set( 'ariaDescribedById' );\n\n\t\t/**\n\t\t * A cached reference to the options passed to the constructor.\n\t\t *\n\t\t * @member {Object}\n\t\t */\n\t\tthis.options = options;\n\n\t\t/**\n\t\t * An instance of the dropdown allowing to select a color from a grid.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:ui/dropdown/dropdown~DropdownView}\n\t\t */\n\t\tthis._dropdownView = this._createDropdownView( locale );\n\n\t\t/**\n\t\t * An instance of the input allowing the user to type a color value.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis._inputView = this._createInputTextView( locale );\n\n\t\t/**\n\t\t * The flag that indicates whether the user is still typing.\n\t\t * If set to true, it means that the text input field ({@link #_inputView}) still has the focus.\n\t\t * So, we should interrupt the user by replacing the input's value.\n\t\t *\n\t\t * @protected\n\t\t * @member {Boolean}\n\t\t */\n\t\tthis._stillTyping = false;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-input-color',\n\t\t\t\t\tbind.if( 'hasError', 'ck-error' )\n\t\t\t\t],\n\t\t\t\tid: bind.to( 'id' ),\n\t\t\t\t'aria-invalid': bind.if( 'hasError', true ),\n\t\t\t\t'aria-describedby': bind.to( 'ariaDescribedById' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis._dropdownView,\n\t\t\t\tthis._inputView\n\t\t\t]\n\t\t} );\n\n\t\tthis.on( 'change:value', ( evt, name, inputValue ) => this._setInputValue( inputValue ) );\n\t}\n\n\t/**\n\t * Focuses the input.\n\t */\n\tfocus() {\n\t\tthis._inputView.focus();\n\t}\n\n\t/**\n\t * Creates and configures the {@link #_dropdownView}.\n\t *\n\t * @private\n\t */\n\t_createDropdownView() {\n\t\tconst locale = this.locale;\n\t\tconst t = locale.t;\n\t\tconst bind = this.bindTemplate;\n\t\tconst colorGrid = this._createColorGrid( locale );\n\t\tconst dropdown = createDropdown( locale );\n\t\tconst colorPreview = new View();\n\t\tconst removeColorButton = this._createRemoveColorButton( locale );\n\n\t\tcolorPreview.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-input-color__button__preview'\n\t\t\t\t],\n\t\t\t\tstyle: {\n\t\t\t\t\tbackgroundColor: bind.to( 'value' )\n\t\t\t\t}\n\t\t\t},\n\t\t\tchildren: [ {\n\t\t\t\ttag: 'span',\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t'ck-input-color__button__preview__no-color-indicator',\n\t\t\t\t\t\tbind.if( 'value', 'ck-hidden', value => value != '' )\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} ]\n\t\t} );\n\n\t\tdropdown.buttonView.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-input-color__button'\n\t\t\t}\n\t\t} );\n\n\t\tdropdown.buttonView.children.add( colorPreview );\n\t\tdropdown.buttonView.tooltip = t( 'Color picker' );\n\n\t\tdropdown.panelPosition = locale.uiLanguageDirection === 'rtl' ? 'se' : 'sw';\n\t\tdropdown.panelView.children.add( removeColorButton );\n\t\tdropdown.panelView.children.add( colorGrid );\n\t\tdropdown.bind( 'isEnabled' ).to( this, 'isReadOnly', value => !value );\n\n\t\treturn dropdown;\n\t}\n\n\t/**\n\t * Creates and configures an instance of {@link module:ui/inputtext/inputtextview~InputTextView}.\n\t *\n\t * @private\n\t * @returns {module:ui/inputtext/inputtextview~InputTextView} A configured instance to be set as {@link #_inputView}.\n\t */\n\t_createInputTextView() {\n\t\tconst locale = this.locale;\n\t\tconst inputView = new InputTextView( locale );\n\n\t\tinputView.extendTemplate( {\n\t\t\ton: {\n\t\t\t\tblur: inputView.bindTemplate.to( 'blur' )\n\t\t\t}\n\t\t} );\n\n\t\tinputView.value = this.value;\n\t\tinputView.bind( 'isReadOnly', 'hasError' ).to( this );\n\t\tthis.bind( 'isFocused', 'isEmpty' ).to( inputView );\n\n\t\tinputView.on( 'input', () => {\n\t\t\tconst inputValue = inputView.element.value;\n\t\t\t// Check if the value matches one of our defined colors' label.\n\t\t\tconst mappedColor = this.options.colorDefinitions.find( def => inputValue === def.label );\n\n\t\t\tthis._stillTyping = true;\n\t\t\tthis.value = mappedColor && mappedColor.color || inputValue;\n\t\t} );\n\n\t\tinputView.on( 'blur', () => {\n\t\t\tthis._stillTyping = false;\n\t\t\tthis._setInputValue( inputView.element.value );\n\t\t} );\n\n\t\tinputView.delegate( 'input' ).to( this );\n\n\t\treturn inputView;\n\t}\n\n\t/**\n\t * Creates and configures the button that clears the color.\n\t *\n\t * @private\n\t */\n\t_createRemoveColorButton() {\n\t\tconst locale = this.locale;\n\t\tconst t = locale.t;\n\t\tconst removeColorButton = new ButtonView( locale );\n\n\t\tremoveColorButton.class = 'ck-input-color__remove-color';\n\t\tremoveColorButton.withText = true;\n\t\tremoveColorButton.icon = icons.eraser;\n\t\tremoveColorButton.label = t( 'Remove color' );\n\t\tremoveColorButton.on( 'execute', () => {\n\t\t\tthis.value = '';\n\t\t\tthis._dropdownView.isOpen = false;\n\t\t\tthis.fire( 'input' );\n\t\t} );\n\n\t\treturn removeColorButton;\n\t}\n\n\t/**\n\t * Creates and configures the color grid inside the {@link #_dropdownView}.\n\t *\n\t * @private\n\t */\n\t_createColorGrid( locale ) {\n\t\tconst colorGrid = new ColorGridView( locale, {\n\t\t\tcolorDefinitions: this.options.colorDefinitions,\n\t\t\tcolumns: this.options.columns\n\t\t} );\n\n\t\tcolorGrid.on( 'execute', ( evtData, data ) => {\n\t\t\tthis.value = data.value;\n\t\t\tthis._dropdownView.isOpen = false;\n\t\t\tthis.fire( 'input' );\n\t\t} );\n\t\tcolorGrid.bind( 'selectedColor' ).to( this, 'value' );\n\n\t\treturn colorGrid;\n\t}\n\n\t/**\n\t * Sets {@link #_inputView}'s value property to the color value or color label,\n\t * if there is one and the user is not typing.\n\t *\n\t * Handles cases like:\n\t *\n\t * * Someone picks the color in the grid.\n\t * * The color is set from the plugin level.\n\t *\n\t * @private\n\t * @param {String} inputValue Color value to be set.\n\t */\n\t_setInputValue( inputValue ) {\n\t\tif ( !this._stillTyping ) {\n\t\t\tconst normalizedInputValue = normalizeColor( inputValue );\n\t\t\t// Check if the value matches one of our defined colors.\n\t\t\tconst mappedColor = this.options.colorDefinitions.find( def => normalizedInputValue === normalizeColor( def.color ) );\n\n\t\t\tif ( mappedColor ) {\n\t\t\t\tthis._inputView.value = mappedColor.label;\n\t\t\t} else {\n\t\t\t\tthis._inputView.value = inputValue || '';\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Normalizes color value, by stripping extensive whitespace.\n// For example., transforms:\n// * ` rgb( 25 50 0 )` to `rgb(25 50 0)`,\n// * \"\\t rgb( 25 , 50,0 )\t\t\" to `rgb(25 50 0)`.\n//\n// @param {String} colorString The value to be normalized.\n// @returns {String}\nfunction normalizeColor( colorString ) {\n\treturn colorString\n\t\t// Remove any whitespace right after `(` or `,`.\n\t\t.replace( /([(,])\\s+/g, '$1' )\n\t\t// Remove any whitespace at the beginning or right before the end, `)`, `,`, or another whitespace.\n\t\t.replace( /^\\s+|\\s+(?=[),\\s]|$)/g, '' )\n\t\t// Then, replace `,` or whitespace with a single space.\n\t\t.replace( /,|\\s/g, ' ' );\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 table/utils/ui/table-properties\n */\n\nimport { ButtonView, Model } from 'ckeditor5/src/ui';\nimport { Collection } from 'ckeditor5/src/utils';\nimport { isColor, isLength, isPercentage } from 'ckeditor5/src/engine';\n\nimport ColorInputView from '../../ui/colorinputview';\n\nconst isEmpty = val => val === '';\n\n/**\n * Returns an object containing pairs of CSS border style values and their localized UI\n * labels. Used by {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView}\n * and {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView}.\n *\n * @param {module:utils/locale~Locale#t} t The \"t\" function provided by the editor\n * that is used to localize strings.\n * @returns {Object.<String,String>}\n */\nexport function getBorderStyleLabels( t ) {\n\treturn {\n\t\tnone: t( 'None' ),\n\t\tsolid: t( 'Solid' ),\n\t\tdotted: t( 'Dotted' ),\n\t\tdashed: t( 'Dashed' ),\n\t\tdouble: t( 'Double' ),\n\t\tgroove: t( 'Groove' ),\n\t\tridge: t( 'Ridge' ),\n\t\tinset: t( 'Inset' ),\n\t\toutset: t( 'Outset' )\n\t};\n}\n\n/**\n * Returns a localized error string that can be displayed next to color (background, border)\n * fields that have an invalid value.\n *\n * @param {module:utils/locale~Locale#t} t The \"t\" function provided by the editor\n * that is used to localize strings.\n * @returns {String}\n */\nexport function getLocalizedColorErrorText( t ) {\n\treturn t( 'The color is invalid. Try \"#FF0000\" or \"rgb(255,0,0)\" or \"red\".' );\n}\n\n/**\n * Returns a localized error string that can be displayed next to length (padding, border width)\n * fields that have an invalid value.\n *\n * @param {module:utils/locale~Locale#t} t The \"t\" function provided by the editor\n * that is used to localize strings.\n * @returns {String}\n */\nexport function getLocalizedLengthErrorText( t ) {\n\treturn t( 'The value is invalid. Try \"10px\" or \"2em\" or simply \"2\".' );\n}\n\n/**\n * Returns `true` when the passed value is an empty string or a valid CSS color expression.\n * Otherwise, `false` is returned.\n *\n * See {@link module:engine/view/styles/utils~isColor}.\n *\n * @param {String} value\n * @returns {Boolean}\n */\nexport function colorFieldValidator( value ) {\n\tvalue = value.trim();\n\n\treturn isEmpty( value ) || isColor( value );\n}\n\n/**\n * Returns `true` when the passed value is an empty string, a number without a unit or a valid CSS length expression.\n * Otherwise, `false` is returned.\n *\n * See {@link module:engine/view/styles/utils~isLength}.\n * See {@link module:engine/view/styles/utils~isPercentage}.\n *\n * @param {String} value\n * @returns {Boolean}\n */\nexport function lengthFieldValidator( value ) {\n\tvalue = value.trim();\n\n\treturn isEmpty( value ) || isNumberString( value ) || isLength( value ) || isPercentage( value );\n}\n\n/**\n * Returns `true` when the passed value is an empty string, a number without a unit or a valid CSS length expression.\n * Otherwise, `false` is returned.\n *\n * See {@link module:engine/view/styles/utils~isLength}.\n *\n * @param {String} value\n * @returns {Boolean}\n */\nexport function lineWidthFieldValidator( value ) {\n\tvalue = value.trim();\n\n\treturn isEmpty( value ) || isNumberString( value ) || isLength( value );\n}\n\n/**\n * Generates item definitions for a UI dropdown that allows changing the border style of a table or a table cell.\n *\n * @param {module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView|\n * module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} view\n * @returns {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>}\n */\nexport function getBorderStyleDefinitions( view ) {\n\tconst itemDefinitions = new Collection();\n\tconst styleLabels = getBorderStyleLabels( view.t );\n\n\tfor ( const style in styleLabels ) {\n\t\tconst definition = {\n\t\t\ttype: 'button',\n\t\t\tmodel: new Model( {\n\t\t\t\t_borderStyleValue: style === 'none' ? '' : style,\n\t\t\t\tlabel: styleLabels[ style ],\n\t\t\t\twithText: true\n\t\t\t} )\n\t\t};\n\n\t\tif ( style === 'none' ) {\n\t\t\tdefinition.model.bind( 'isOn' ).to( view, 'borderStyle', value => !value );\n\t\t} else {\n\t\t\tdefinition.model.bind( 'isOn' ).to( view, 'borderStyle', value => {\n\t\t\t\treturn value === style;\n\t\t\t} );\n\t\t}\n\n\t\titemDefinitions.add( definition );\n\t}\n\n\treturn itemDefinitions;\n}\n\n/**\n * A helper that fills a toolbar with buttons that:\n *\n * * have some labels,\n * * have some icons,\n * * set a certain UI view property value upon execution.\n *\n * @param {Object} options\n * @param {module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView|\n * module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} options.view\n * @param {Array.<String>} options.icons\n * @param {module:ui/toolbar/toolbarview~ToolbarView} options.toolbar\n * @param {Object.<String,String>} labels\n * @param {String} propertyName\n * @param {Function} nameToValue A function that maps a button name to a value. By default names are the same as values.\n */\nexport function fillToolbar( { view, icons, toolbar, labels, propertyName, nameToValue } ) {\n\tfor ( const name in labels ) {\n\t\tconst button = new ButtonView( view.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel: labels[ name ],\n\t\t\ticon: icons[ name ],\n\t\t\ttooltip: labels[ name ]\n\t\t} );\n\n\t\tbutton.bind( 'isOn' ).to( view, propertyName, value => {\n\t\t\treturn value === nameToValue( name );\n\t\t} );\n\n\t\tbutton.on( 'execute', () => {\n\t\t\tview[ propertyName ] = nameToValue( name );\n\t\t} );\n\n\t\ttoolbar.items.add( button );\n\t}\n}\n\n/**\n * A default color palette used by various user interfaces related to tables, for instance,\n * by {@link module:table/tablecellproperties/tablecellpropertiesui~TableCellPropertiesUI} or\n * {@link module:table/tableproperties/tablepropertiesui~TablePropertiesUI}.\n *\n * The color palette follows the {@link module:table/table~TableColorConfig table color configuration format}\n * and contains the following color definitions:\n *\n *\t\tconst defaultColors = [\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n *\t\t\t\tlabel: 'Black'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n *\t\t\t\tlabel: 'Dim grey'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\tlabel: 'Grey'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\tlabel: 'Light grey'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\tlabel: 'White',\n *\t\t\t\thasBorder: true\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n *\t\t\t\tlabel: 'Red'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n *\t\t\t\tlabel: 'Orange'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n *\t\t\t\tlabel: 'Yellow'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n *\t\t\t\tlabel: 'Light green'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\tlabel: 'Green'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n *\t\t\t\tlabel: 'Aquamarine'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n *\t\t\t\tlabel: 'Turquoise'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n *\t\t\t\tlabel: 'Light blue'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n *\t\t\t\tlabel: 'Blue'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n *\t\t\t\tlabel: 'Purple'\n *\t\t\t}\n *\t\t];\n */\nexport const defaultColors = [\n\t{\n\t\tcolor: 'hsl(0, 0%, 0%)',\n\t\tlabel: 'Black'\n\t},\n\t{\n\t\tcolor: 'hsl(0, 0%, 30%)',\n\t\tlabel: 'Dim grey'\n\t},\n\t{\n\t\tcolor: 'hsl(0, 0%, 60%)',\n\t\tlabel: 'Grey'\n\t},\n\t{\n\t\tcolor: 'hsl(0, 0%, 90%)',\n\t\tlabel: 'Light grey'\n\t},\n\t{\n\t\tcolor: 'hsl(0, 0%, 100%)',\n\t\tlabel: 'White',\n\t\thasBorder: true\n\t},\n\t{\n\t\tcolor: 'hsl(0, 75%, 60%)',\n\t\tlabel: 'Red'\n\t},\n\t{\n\t\tcolor: 'hsl(30, 75%, 60%)',\n\t\tlabel: 'Orange'\n\t},\n\t{\n\t\tcolor: 'hsl(60, 75%, 60%)',\n\t\tlabel: 'Yellow'\n\t},\n\t{\n\t\tcolor: 'hsl(90, 75%, 60%)',\n\t\tlabel: 'Light green'\n\t},\n\t{\n\t\tcolor: 'hsl(120, 75%, 60%)',\n\t\tlabel: 'Green'\n\t},\n\t{\n\t\tcolor: 'hsl(150, 75%, 60%)',\n\t\tlabel: 'Aquamarine'\n\t},\n\t{\n\t\tcolor: 'hsl(180, 75%, 60%)',\n\t\tlabel: 'Turquoise'\n\t},\n\t{\n\t\tcolor: 'hsl(210, 75%, 60%)',\n\t\tlabel: 'Light blue'\n\t},\n\t{\n\t\tcolor: 'hsl(240, 75%, 60%)',\n\t\tlabel: 'Blue'\n\t},\n\t{\n\t\tcolor: 'hsl(270, 75%, 60%)',\n\t\tlabel: 'Purple'\n\t}\n];\n\n/**\n * Returns a creator for a color input with a label.\n *\n * For given options, it returns a function that creates an instance of a\n * {@link module:table/ui/colorinputview~ColorInputView color input} logically related to\n * a {@link module:ui/labeledfield/labeledfieldview~LabeledFieldView labeled view} in the DOM.\n *\n * The helper does the following:\n *\n * * It sets the color input `id` and `ariaDescribedById` attributes.\n * * It binds the color input `isReadOnly` to the labeled view.\n * * It binds the color input `hasError` to the labeled view.\n * * It enables a logic that cleans up the error when the user starts typing in the color input.\n *\n * Usage:\n *\n *\t\tconst colorInputCreator = getLabeledColorInputCreator( {\n *\t\t\tcolorConfig: [ ... ],\n *\t\t\tcolumns: 3,\n *\t\t} );\n *\n *\t\tconst labeledInputView = new LabeledFieldView( locale, colorInputCreator );\n *\t\tconsole.log( labeledInputView.view ); // A color input instance.\n *\n * @private\n * @param options Color input options.\n * @param {module:table/table~TableColorConfig} options.colorConfig The configuration of the color palette\n * displayed in the input's dropdown.\n * @param {Number} options.columns The configuration of the number of columns the color palette consists of\n * in the input's dropdown.\n * @returns {Function}\n */\nexport function getLabeledColorInputCreator( options ) {\n\treturn ( labeledFieldView, viewUid, statusUid ) => {\n\t\tconst inputView = new ColorInputView( labeledFieldView.locale, {\n\t\t\tcolorDefinitions: colorConfigToColorGridDefinitions( options.colorConfig ),\n\t\t\tcolumns: options.columns\n\t\t} );\n\n\t\tinputView.set( {\n\t\t\tid: viewUid,\n\t\t\tariaDescribedById: statusUid\n\t\t} );\n\n\t\tinputView.bind( 'isReadOnly' ).to( labeledFieldView, 'isEnabled', value => !value );\n\t\tinputView.bind( 'hasError' ).to( labeledFieldView, 'errorText', value => !!value );\n\n\t\tinputView.on( 'input', () => {\n\t\t\t// UX: Make the error text disappear and disable the error indicator as the user\n\t\t\t// starts fixing the errors.\n\t\t\tlabeledFieldView.errorText = null;\n\t\t} );\n\n\t\tlabeledFieldView.bind( 'isEmpty', 'isFocused' ).to( inputView );\n\n\t\treturn inputView;\n\t};\n}\n\n// A simple helper method to detect number strings.\n// I allows full number notation, so omitting 0 is not allowed:\nfunction isNumberString( value ) {\n\tconst parsedValue = parseFloat( value );\n\n\treturn !Number.isNaN( parsedValue ) && value === String( parsedValue );\n}\n\n// @param {Array.<Object>} colorConfig\n// @returns {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>}\nfunction colorConfigToColorGridDefinitions( colorConfig ) {\n\treturn colorConfig.map( item => ( {\n\t\tcolor: item.model,\n\t\tlabel: item.label,\n\t\toptions: {\n\t\t\thasBorder: item.hasBorder\n\t\t}\n\t} ) );\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/ui/formrowview\n */\n\nimport { View } from 'ckeditor5/src/ui';\n\nimport '../../theme/formrow.css';\n\n/**\n * The class representing a single row in a complex form,\n * used by {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView}.\n *\n * **Note**: For now this class is private. When more use cases arrive (beyond ckeditor5-table),\n * it will become a component in ckeditor5-ui.\n *\n * @private\n * @extends module:ui/view~View\n */\nexport default class FormRowView extends View {\n\t/**\n\t * Creates an instance of the form row class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance.\n\t * @param {Object} options\n\t * @param {Array.<module:ui/view~View>} options.children\n\t * @param {String} [options.class]\n\t * @param {module:ui/view~View} [options.labelView] When passed, the row gets the `group` and `aria-labelledby`\n\t * DOM attributes and gets described by the label.\n\t */\n\tconstructor( locale, options = {} ) {\n\t\tsuper( locale );\n\n\t\tconst bind = this.bindTemplate;\n\n\t\t/**\n\t\t * An additional CSS class added to the {@link #element}.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #class\n\t\t */\n\t\tthis.set( 'class', options.class || null );\n\n\t\t/**\n\t\t * A collection of row items (buttons, dropdowns, etc.).\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\tif ( options.children ) {\n\t\t\toptions.children.forEach( child => this.children.add( child ) );\n\t\t}\n\n\t\t/**\n\t\t * The role property reflected by the `role` DOM attribute of the {@link #element}.\n\t\t *\n\t\t * **Note**: Used only when a `labelView` is passed to constructor `options`.\n\t\t *\n\t\t * @private\n\t\t * @observable\n\t\t * @member {String} #role\n\t\t */\n\t\tthis.set( '_role', null );\n\n\t\t/**\n\t\t * The ARIA property reflected by the `aria-labelledby` DOM attribute of the {@link #element}.\n\t\t *\n\t\t * **Note**: Used only when a `labelView` is passed to constructor `options`.\n\t\t *\n\t\t * @private\n\t\t * @observable\n\t\t * @member {String} #ariaLabelledBy\n\t\t */\n\t\tthis.set( '_ariaLabelledBy', null );\n\n\t\tif ( options.labelView ) {\n\t\t\tthis.set( {\n\t\t\t\t_role: 'group',\n\t\t\t\t_ariaLabelledBy: options.labelView.id\n\t\t\t} );\n\t\t}\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-form__row',\n\t\t\t\t\tbind.to( 'class' )\n\t\t\t\t],\n\t\t\t\trole: bind.to( '_role' ),\n\t\t\t\t'aria-labelledby': bind.to( '_ariaLabelledBy' )\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tableproperties/ui/tablepropertiesview\n */\n\nimport {\n\tButtonView,\n\tFocusCycler,\n\tFormHeaderView,\n\tLabelView,\n\tLabeledFieldView,\n\tToolbarView,\n\tView,\n\tViewCollection,\n\taddListToDropdown,\n\tcreateLabeledDropdown,\n\tcreateLabeledInputText,\n\tsubmitHandler\n} from 'ckeditor5/src/ui';\nimport { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\nimport {\n\tfillToolbar,\n\tgetBorderStyleDefinitions,\n\tgetBorderStyleLabels,\n\tgetLabeledColorInputCreator\n} from '../../utils/ui/table-properties';\nimport FormRowView from '../../ui/formrowview';\n\nimport '../../../theme/form.css';\nimport '../../../theme/tableform.css';\nimport '../../../theme/tableproperties.css';\n\nconst ALIGNMENT_ICONS = {\n\tleft: icons.objectLeft,\n\tcenter: icons.objectCenter,\n\tright: icons.objectRight\n};\n\n/**\n * The class representing a table properties form, allowing users to customize\n * certain style aspects of a table, for instance, border, background color, alignment, etc..\n *\n * @extends module:ui/view~View\n */\nexport default class TablePropertiesView extends View {\n\t/**\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n\t * @param {Object} options Additional configuration of the view.\n\t * @param {module:table/table~TableColorConfig} options.borderColors A configuration of the border\n\t * color palette used by the\n\t * {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView#borderColorInput}.\n\t * @param {module:table/table~TableColorConfig} options.backgroundColors A configuration of the background\n\t * color palette used by the\n\t * {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView#backgroundInput}.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tthis.set( {\n\t\t\t/**\n\t\t\t * The value of the border style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderStyle\n\t\t\t */\n\t\t\tborderStyle: '',\n\n\t\t\t/**\n\t\t\t * The value of the border width style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderWidth\n\t\t\t */\n\t\t\tborderWidth: '',\n\n\t\t\t/**\n\t\t\t * The value of the border color style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderColor\n\t\t\t */\n\t\t\tborderColor: '',\n\n\t\t\t/**\n\t\t\t * The value of the background color style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #backgroundColor\n\t\t\t */\n\t\t\tbackgroundColor: '',\n\n\t\t\t/**\n\t\t\t * The value of the table width style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #width\n\t\t\t */\n\t\t\twidth: '',\n\n\t\t\t/**\n\t\t\t * The value of the table height style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #height\n\t\t\t */\n\t\t\theight: '',\n\n\t\t\t/**\n\t\t\t * The value of the table alignment style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #alignment\n\t\t\t */\n\t\t\talignment: ''\n\t\t} );\n\n\t\t/**\n\t\t * Options passed to the view. See {@link #constructor} to learn more.\n\t\t *\n\t\t * @protected\n\t\t * @member {Object}\n\t\t */\n\t\tthis.options = options;\n\n\t\tconst { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();\n\t\tconst { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();\n\t\tconst { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();\n\t\tconst { alignmentToolbar, alignmentLabel } = this._createAlignmentFields();\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * A collection of child views in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * A dropdown that allows selecting the style of the table border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownview~DropdownView}\n\t\t */\n\t\tthis.borderStyleDropdown = borderStyleDropdown;\n\n\t\t/**\n\t\t * An input that allows specifying the width of the table border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.borderWidthInput = borderWidthInput;\n\n\t\t/**\n\t\t * An input that allows specifying the color of the table border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:table/ui/colorinputview~ColorInputView}\n\t\t */\n\t\tthis.borderColorInput = borderColorInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table background color.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:table/ui/colorinputview~ColorInputView}\n\t\t */\n\t\tthis.backgroundInput = backgroundInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table width.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.widthInput = widthInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table height.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.heightInput = heightInput;\n\n\t\t/**\n\t\t * A toolbar with buttons that allow changing the alignment of an entire table.\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbar~ToolbarView}\n\t\t */\n\t\tthis.alignmentToolbar = alignmentToolbar;\n\n\t\t// Defer creating to make sure other fields are present and the Save button can\n\t\t// bind its #isEnabled to their error messages so there's no way to save unless all\n\t\t// fields are valid.\n\t\tconst { saveButtonView, cancelButtonView } = this._createActionButtons();\n\n\t\t/**\n\t\t * The \"Save\" button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.saveButtonView = saveButtonView;\n\n\t\t/**\n\t\t * The \"Cancel\" button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.cancelButtonView = cancelButtonView;\n\n\t\t/**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\t// Form header.\n\t\tthis.children.add( new FormHeaderView( locale, {\n\t\t\tlabel: this.t( 'Table properties' )\n\t\t} ) );\n\n\t\t// Border row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tlabelView: borderRowLabel,\n\t\t\tchildren: [\n\t\t\t\tborderRowLabel,\n\t\t\t\tborderStyleDropdown,\n\t\t\t\tborderColorInput,\n\t\t\t\tborderWidthInput\n\t\t\t],\n\t\t\tclass: 'ck-table-form__border-row'\n\t\t} ) );\n\n\t\t// Background row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tlabelView: backgroundRowLabel,\n\t\t\tchildren: [\n\t\t\t\tbackgroundRowLabel,\n\t\t\t\tbackgroundInput\n\t\t\t],\n\t\t\tclass: 'ck-table-form__background-row'\n\t\t} ) );\n\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tchildren: [\n\t\t\t\t// Dimensions row.\n\t\t\t\tnew FormRowView( locale, {\n\t\t\t\t\tlabelView: dimensionsLabel,\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tdimensionsLabel,\n\t\t\t\t\t\twidthInput,\n\t\t\t\t\t\toperatorLabel,\n\t\t\t\t\t\theightInput\n\t\t\t\t\t],\n\t\t\t\t\tclass: 'ck-table-form__dimensions-row'\n\t\t\t\t} ),\n\t\t\t\t// Alignment row.\n\t\t\t\tnew FormRowView( locale, {\n\t\t\t\t\tlabelView: alignmentLabel,\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\talignmentLabel,\n\t\t\t\t\t\talignmentToolbar\n\t\t\t\t\t],\n\t\t\t\t\tclass: 'ck-table-properties-form__alignment-row'\n\t\t\t\t} )\n\t\t\t]\n\t\t} ) );\n\n\t\t// Action row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tchildren: [\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t],\n\t\t\tclass: 'ck-table-form__action-row'\n\t\t} ) );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-form',\n\t\t\t\t\t'ck-table-form',\n\t\t\t\t\t'ck-table-properties-form'\n\t\t\t\t],\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/90\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Enable the \"submit\" event for this view. It can be triggered by the #saveButtonView\n\t\t// which is of the \"submit\" DOM \"type\".\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\t[\n\t\t\tthis.borderStyleDropdown,\n\t\t\tthis.borderColorInput,\n\t\t\tthis.borderWidthInput,\n\t\t\tthis.backgroundInput,\n\t\t\tthis.widthInput,\n\t\t\tthis.heightInput,\n\t\t\tthis.alignmentToolbar,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t].forEach( view => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( view );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( view.element );\n\t\t} );\n\n\t\t// Mainly for closing using \"Esc\" and navigation using \"Tab\".\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the fist focusable field in the form.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #borderStyleDropdown},\n\t * * {@link #borderWidthInput},\n\t * * {@link #borderColorInput}.\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createBorderFields() {\n\t\tconst colorInputCreator = getLabeledColorInputCreator( {\n\t\t\tcolorConfig: this.options.borderColors,\n\t\t\tcolumns: 5\n\t\t} );\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Group label ---------------------------------------------\n\n\t\tconst borderRowLabel = new LabelView( locale );\n\t\tborderRowLabel.text = t( 'Border' );\n\n\t\t// -- Style ---------------------------------------------------\n\n\t\tconst styleLabels = getBorderStyleLabels( this.t );\n\t\tconst borderStyleDropdown = new LabeledFieldView( locale, createLabeledDropdown );\n\t\tborderStyleDropdown.set( {\n\t\t\tlabel: t( 'Style' ),\n\t\t\tclass: 'ck-table-form__border-style'\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.buttonView.set( {\n\t\t\tisOn: false,\n\t\t\twithText: true,\n\t\t\ttooltip: t( 'Style' )\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.buttonView.bind( 'label' ).to( this, 'borderStyle', value => {\n\t\t\treturn styleLabels[ value ? value : 'none' ];\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.on( 'execute', evt => {\n\t\t\tthis.borderStyle = evt.source._borderStyleValue;\n\t\t} );\n\n\t\tborderStyleDropdown.bind( 'isEmpty' ).to( this, 'borderStyle', value => !value );\n\n\t\taddListToDropdown( borderStyleDropdown.fieldView, getBorderStyleDefinitions( this ) );\n\n\t\t// -- Width ---------------------------------------------------\n\n\t\tconst borderWidthInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\tborderWidthInput.set( {\n\t\t\tlabel: t( 'Width' ),\n\t\t\tclass: 'ck-table-form__border-width'\n\t\t} );\n\n\t\tborderWidthInput.fieldView.bind( 'value' ).to( this, 'borderWidth' );\n\t\tborderWidthInput.bind( 'isEnabled' ).to( this, 'borderStyle', isBorderStyleSet );\n\t\tborderWidthInput.fieldView.on( 'input', () => {\n\t\t\tthis.borderWidth = borderWidthInput.fieldView.element.value;\n\t\t} );\n\n\t\t// -- Color ---------------------------------------------------\n\n\t\tconst borderColorInput = new LabeledFieldView( locale, colorInputCreator );\n\n\t\tborderColorInput.set( {\n\t\t\tlabel: t( 'Color' ),\n\t\t\tclass: 'ck-table-form__border-color'\n\t\t} );\n\n\t\tborderColorInput.fieldView.bind( 'value' ).to( this, 'borderColor' );\n\t\tborderColorInput.bind( 'isEnabled' ).to( this, 'borderStyle', isBorderStyleSet );\n\n\t\tborderColorInput.fieldView.on( 'input', () => {\n\t\t\tthis.borderColor = borderColorInput.fieldView.value;\n\t\t} );\n\n\t\t// Reset the border color and width fields when style is \"none\".\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6227\n\t\tthis.on( 'change:borderStyle', ( evt, name, value ) => {\n\t\t\tif ( !isBorderStyleSet( value ) ) {\n\t\t\t\tthis.borderColor = '';\n\t\t\t\tthis.borderWidth = '';\n\t\t\t}\n\t\t} );\n\n\t\treturn {\n\t\t\tborderRowLabel,\n\t\t\tborderStyleDropdown,\n\t\t\tborderColorInput,\n\t\t\tborderWidthInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #backgroundInput}.\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createBackgroundFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Group label ---------------------------------------------\n\n\t\tconst backgroundRowLabel = new LabelView( locale );\n\t\tbackgroundRowLabel.text = t( 'Background' );\n\n\t\t// -- Background color input -----------------------------------\n\n\t\tconst backgroundInputCreator = getLabeledColorInputCreator( {\n\t\t\tcolorConfig: this.options.backgroundColors,\n\t\t\tcolumns: 5\n\t\t} );\n\n\t\tconst backgroundInput = new LabeledFieldView( locale, backgroundInputCreator );\n\n\t\tbackgroundInput.set( {\n\t\t\tlabel: t( 'Color' ),\n\t\t\tclass: 'ck-table-properties-form__background'\n\t\t} );\n\n\t\tbackgroundInput.fieldView.bind( 'value' ).to( this, 'backgroundColor' );\n\t\tbackgroundInput.fieldView.on( 'input', () => {\n\t\t\tthis.backgroundColor = backgroundInput.fieldView.value;\n\t\t} );\n\n\t\treturn {\n\t\t\tbackgroundRowLabel,\n\t\t\tbackgroundInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #widthInput}.\n\t * * {@link #heightInput}.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t */\n\t_createDimensionFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Label ---------------------------------------------------\n\n\t\tconst dimensionsLabel = new LabelView( locale );\n\t\tdimensionsLabel.text = t( 'Dimensions' );\n\n\t\t// -- Width ---------------------------------------------------\n\n\t\tconst widthInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\twidthInput.set( {\n\t\t\tlabel: t( 'Width' ),\n\t\t\tclass: 'ck-table-form__dimensions-row__width'\n\t\t} );\n\n\t\twidthInput.fieldView.bind( 'value' ).to( this, 'width' );\n\t\twidthInput.fieldView.on( 'input', () => {\n\t\t\tthis.width = widthInput.fieldView.element.value;\n\t\t} );\n\n\t\t// -- Operator ---------------------------------------------------\n\n\t\tconst operatorLabel = new View( locale );\n\t\toperatorLabel.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-table-form__dimension-operator'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{ text: '×' }\n\t\t\t]\n\t\t} );\n\n\t\t// -- Height ---------------------------------------------------\n\n\t\tconst heightInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\theightInput.set( {\n\t\t\tlabel: t( 'Height' ),\n\t\t\tclass: 'ck-table-form__dimensions-row__height'\n\t\t} );\n\n\t\theightInput.fieldView.bind( 'value' ).to( this, 'height' );\n\t\theightInput.fieldView.on( 'input', () => {\n\t\t\tthis.height = heightInput.fieldView.element.value;\n\t\t} );\n\n\t\treturn {\n\t\t\tdimensionsLabel,\n\t\t\twidthInput,\n\t\t\toperatorLabel,\n\t\t\theightInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #alignmentToolbar},\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createAlignmentFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Label ---------------------------------------------------\n\n\t\tconst alignmentLabel = new LabelView( locale );\n\t\talignmentLabel.text = t( 'Alignment' );\n\n\t\t// -- Toolbar ---------------------------------------------------\n\n\t\tconst alignmentToolbar = new ToolbarView( locale );\n\t\talignmentToolbar.set( {\n\t\t\tisCompact: true,\n\t\t\tariaLabel: t( 'Table alignment toolbar' )\n\t\t} );\n\n\t\tfillToolbar( {\n\t\t\tview: this,\n\t\t\ticons: ALIGNMENT_ICONS,\n\t\t\ttoolbar: alignmentToolbar,\n\t\t\tlabels: this._alignmentLabels,\n\t\t\tpropertyName: 'alignment',\n\t\t\tnameToValue: name => {\n\t\t\t\treturn name === 'center' ? '' : name;\n\t\t\t}\n\t\t} );\n\n\t\treturn {\n\t\t\talignmentLabel,\n\t\t\talignmentToolbar\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form controls:\n\t *\n\t * * {@link #saveButtonView},\n\t * * {@link #cancelButtonView}.\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createActionButtons() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\tconst saveButtonView = new ButtonView( locale );\n\t\tconst cancelButtonView = new ButtonView( locale );\n\t\tconst fieldsThatShouldValidateToSave = [\n\t\t\tthis.borderWidthInput,\n\t\t\tthis.borderColorInput,\n\t\t\tthis.backgroundInput,\n\t\t\tthis.widthInput,\n\t\t\tthis.heightInput\n\t\t];\n\n\t\tsaveButtonView.set( {\n\t\t\tlabel: t( 'Save' ),\n\t\t\ticon: icons.check,\n\t\t\tclass: 'ck-button-save',\n\t\t\ttype: 'submit',\n\t\t\twithText: true\n\t\t} );\n\n\t\tsaveButtonView.bind( 'isEnabled' ).toMany( fieldsThatShouldValidateToSave, 'errorText', ( ...errorTexts ) => {\n\t\t\treturn errorTexts.every( errorText => !errorText );\n\t\t} );\n\n\t\tcancelButtonView.set( {\n\t\t\tlabel: t( 'Cancel' ),\n\t\t\ticon: icons.cancel,\n\t\t\tclass: 'ck-button-cancel',\n\t\t\ttype: 'cancel',\n\t\t\twithText: true\n\t\t} );\n\n\t\tcancelButtonView.delegate( 'execute' ).to( this, 'cancel' );\n\n\t\treturn {\n\t\t\tsaveButtonView, cancelButtonView\n\t\t};\n\t}\n\n\t/**\n\t * Provides localized labels for {@link #alignmentToolbar} buttons.\n\t *\n\t * @private\n\t * @type {Object.<String,String>}\n\t */\n\tget _alignmentLabels() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\tconst left = t( 'Align table to the left' );\n\t\tconst center = t( 'Center table' );\n\t\tconst right = t( 'Align table to the right' );\n\n\t\t// Returns object with a proper order of labels.\n\t\tif ( locale.uiLanguageDirection === 'rtl' ) {\n\t\t\treturn { right, center, left };\n\t\t} else {\n\t\t\treturn { left, center, right };\n\t\t}\n\t}\n}\n\nfunction isBorderStyleSet( value ) {\n\treturn !!value;\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 table/utils/ui/contextualballoon\n */\n\nimport { centeredBalloonPositionForLongWidgets } from 'ckeditor5/src/widget';\nimport { Rect } from 'ckeditor5/src/utils';\nimport { BalloonPanelView } from 'ckeditor5/src/ui';\n\nimport { getTableWidgetAncestor } from './widget';\n\nconst DEFAULT_BALLOON_POSITIONS = BalloonPanelView.defaultPositions;\n\nconst BALLOON_POSITIONS = [\n\tDEFAULT_BALLOON_POSITIONS.northArrowSouth,\n\tDEFAULT_BALLOON_POSITIONS.northArrowSouthWest,\n\tDEFAULT_BALLOON_POSITIONS.northArrowSouthEast,\n\tDEFAULT_BALLOON_POSITIONS.southArrowNorth,\n\tDEFAULT_BALLOON_POSITIONS.southArrowNorthWest,\n\tDEFAULT_BALLOON_POSITIONS.southArrowNorthEast\n];\n\nconst TABLE_PROPERTIES_BALLOON_POSITIONS = [\n\t...BALLOON_POSITIONS,\n\tcenteredBalloonPositionForLongWidgets\n];\n\n/**\n * A helper utility that positions the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} instance\n * with respect to the table in the editor content, if one is selected.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @param {String} target Either \"cell\" or \"table\". Determines the target the balloon will\n * be attached to.\n */\nexport function repositionContextualBalloon( editor, target ) {\n\tconst balloon = editor.plugins.get( 'ContextualBalloon' );\n\n\tif ( getTableWidgetAncestor( editor.editing.view.document.selection ) ) {\n\t\tlet position;\n\n\t\tif ( target === 'cell' ) {\n\t\t\tposition = getBalloonCellPositionData( editor );\n\t\t} else {\n\t\t\tposition = getBalloonTablePositionData( editor );\n\t\t}\n\n\t\tballoon.updatePosition( position );\n\t}\n}\n\n/**\n * Returns the positioning options that control the geometry of the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} with respect\n * to the selected table in the editor content.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @returns {module:utils/dom/position~Options}\n */\nexport function getBalloonTablePositionData( editor ) {\n\tconst firstPosition = editor.model.document.selection.getFirstPosition();\n\tconst modelTable = firstPosition.findAncestor( 'table' );\n\tconst viewTable = editor.editing.mapper.toViewElement( modelTable );\n\n\treturn {\n\t\ttarget: editor.editing.view.domConverter.viewToDom( viewTable ),\n\t\tpositions: TABLE_PROPERTIES_BALLOON_POSITIONS\n\t};\n}\n\n/**\n * Returns the positioning options that control the geometry of the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon} with respect\n * to the selected table cell in the editor content.\n *\n * @param {module:core/editor/editor~Editor} editor The editor instance.\n * @returns {module:utils/dom/position~Options}\n */\nexport function getBalloonCellPositionData( editor ) {\n\tconst mapper = editor.editing.mapper;\n\tconst domConverter = editor.editing.view.domConverter;\n\tconst selection = editor.model.document.selection;\n\n\tif ( selection.rangeCount > 1 ) {\n\t\treturn {\n\t\t\ttarget: () => createBoundingRect( selection.getRanges(), editor ),\n\t\t\tpositions: BALLOON_POSITIONS\n\t\t};\n\t}\n\n\tconst modelTableCell = getTableCellAtPosition( selection.getFirstPosition() );\n\tconst viewTableCell = mapper.toViewElement( modelTableCell );\n\n\treturn {\n\t\ttarget: domConverter.viewToDom( viewTableCell ),\n\t\tpositions: BALLOON_POSITIONS\n\t};\n}\n\n// Returns the first selected table cell from a multi-cell or in-cell selection.\n//\n// @param {module:engine/model/position~Position} position Document position.\n// @returns {module:engine/model/element~Element}\nfunction getTableCellAtPosition( position ) {\n\tconst isTableCellSelected = position.nodeAfter && position.nodeAfter.is( 'element', 'tableCell' );\n\n\treturn isTableCellSelected ? position.nodeAfter : position.findAncestor( 'tableCell' );\n}\n\n// Returns bounding rectangle for given model ranges.\n//\n// @param {Iterable.<module:engine/model/range~Range>} ranges Model ranges that the bounding rect should be returned for.\n// @param {module:core/editor/editor~Editor} editor The editor instance.\n// @returns {module:utils/dom/rect~Rect}\nfunction createBoundingRect( ranges, editor ) {\n\tconst mapper = editor.editing.mapper;\n\tconst domConverter = editor.editing.view.domConverter;\n\tconst rects = Array.from( ranges ).map( range => {\n\t\tconst modelTableCell = getTableCellAtPosition( range.start );\n\t\tconst viewTableCell = mapper.toViewElement( modelTableCell );\n\t\treturn new Rect( domConverter.viewToDom( viewTableCell ) );\n\t} );\n\n\treturn Rect.getBoundingRect( rects );\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 table/tableproperties/tablepropertiesui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView, ContextualBalloon, clickOutsideHandler, getLocalizedColorOptions, normalizeColorOptions } from 'ckeditor5/src/ui';\n\nimport { debounce } from 'lodash-es';\n\nimport TablePropertiesView from './ui/tablepropertiesview';\nimport tableProperties from './../../theme/icons/table-properties.svg';\nimport {\n\tcolorFieldValidator,\n\tgetLocalizedColorErrorText,\n\tgetLocalizedLengthErrorText,\n\tlengthFieldValidator,\n\tlineWidthFieldValidator,\n\tdefaultColors\n} from '../utils/ui/table-properties';\nimport { getTableWidgetAncestor } from '../utils/ui/widget';\nimport { getBalloonTablePositionData, repositionContextualBalloon } from '../utils/ui/contextualballoon';\n\nconst ERROR_TEXT_TIMEOUT = 500;\n\n// Map of view properties and related commands.\nconst propertyToCommandMap = {\n\tborderStyle: 'tableBorderStyle',\n\tborderColor: 'tableBorderColor',\n\tborderWidth: 'tableBorderWidth',\n\tbackgroundColor: 'tableBackgroundColor',\n\twidth: 'tableWidth',\n\theight: 'tableHeight',\n\talignment: 'tableAlignment'\n};\n\n/**\n * The table properties UI plugin. It introduces the `'tableProperties'` button\n * that opens a form allowing to specify visual styling of an entire table.\n *\n * It uses the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TablePropertiesUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TablePropertiesUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'table.tableProperties', {\n\t\t\tborderColors: defaultColors,\n\t\t\tbackgroundColors: defaultColors\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t/**\n\t\t * The properties form view displayed inside the balloon.\n\t\t *\n\t\t * @member {module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView}\n\t\t */\n\t\tthis.view = this._createPropertiesView();\n\n\t\t/**\n\t\t * The batch used to undo all changes made by the form (which are live, as the user types)\n\t\t * when \"Cancel\" was pressed. Each time the view is shown, a new batch is created.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/model/batch~Batch}\n\t\t */\n\t\tthis._undoStepBatch = null;\n\n\t\teditor.ui.componentFactory.add( 'tableProperties', locale => {\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Table properties' ),\n\t\t\t\ticon: tableProperties,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tthis.listenTo( view, 'execute', () => this._showView() );\n\n\t\t\tconst commands = Object.values( propertyToCommandMap )\n\t\t\t\t.map( commandName => editor.commands.get( commandName ) );\n\n\t\t\tview.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => (\n\t\t\t\tareEnabled.some( isCommandEnabled => isCommandEnabled )\n\t\t\t) );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1341.\n\t\tthis.view.destroy();\n\t}\n\n\t/**\n\t * Creates the {@link module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} instance.\n\t *\n\t * @private\n\t * @returns {module:table/tableproperties/ui/tablepropertiesview~TablePropertiesView} The table\n\t * properties form view instance.\n\t */\n\t_createPropertiesView() {\n\t\tconst editor = this.editor;\n\t\tconst config = editor.config.get( 'table.tableProperties' );\n\t\tconst borderColorsConfig = normalizeColorOptions( config.borderColors );\n\t\tconst localizedBorderColors = getLocalizedColorOptions( editor.locale, borderColorsConfig );\n\t\tconst backgroundColorsConfig = normalizeColorOptions( config.backgroundColors );\n\t\tconst localizedBackgroundColors = getLocalizedColorOptions( editor.locale, backgroundColorsConfig );\n\t\tconst view = new TablePropertiesView( editor.locale, {\n\t\t\tborderColors: localizedBorderColors,\n\t\t\tbackgroundColors: localizedBackgroundColors\n\t\t} );\n\t\tconst t = editor.t;\n\n\t\t// Render the view so its #element is available for the clickOutsideHandler.\n\t\tview.render();\n\n\t\tthis.listenTo( view, 'submit', () => {\n\t\t\tthis._hideView();\n\t\t} );\n\n\t\tthis.listenTo( view, 'cancel', () => {\n\t\t\t// https://github.com/ckeditor/ckeditor5/issues/6180\n\t\t\tif ( this._undoStepBatch.operations.length ) {\n\t\t\t\teditor.execute( 'undo', this._undoStepBatch );\n\t\t\t}\n\n\t\t\tthis._hideView();\n\t\t} );\n\n\t\t// Close the balloon on Esc key press.\n\t\tview.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._hideView();\n\t\t\tcancel();\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: view,\n\t\t\tactivator: () => this._isViewInBalloon,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideView()\n\t\t} );\n\n\t\tconst colorErrorText = getLocalizedColorErrorText( t );\n\t\tconst lengthErrorText = getLocalizedLengthErrorText( t );\n\n\t\t// Create the \"UI -> editor data\" binding.\n\t\t// These listeners update the editor data (via table commands) when any observable\n\t\t// property of the view has changed. They also validate the value and display errors in the UI\n\t\t// when necessary. This makes the view live, which means the changes are\n\t\t// visible in the editing as soon as the user types or changes fields' values.\n\t\tview.on( 'change:borderStyle', this._getPropertyChangeCallback( 'tableBorderStyle' ) );\n\n\t\tview.on( 'change:borderColor', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.borderColorInput,\n\t\t\tcommandName: 'tableBorderColor',\n\t\t\terrorText: colorErrorText,\n\t\t\tvalidator: colorFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:borderWidth', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.borderWidthInput,\n\t\t\tcommandName: 'tableBorderWidth',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lineWidthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:backgroundColor', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.backgroundInput,\n\t\t\tcommandName: 'tableBackgroundColor',\n\t\t\terrorText: colorErrorText,\n\t\t\tvalidator: colorFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:width', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.widthInput,\n\t\t\tcommandName: 'tableWidth',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lengthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:height', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.heightInput,\n\t\t\tcommandName: 'tableHeight',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lengthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:alignment', this._getPropertyChangeCallback( 'tableAlignment' ) );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * In this method the \"editor data -> UI\" binding is happening.\n\t *\n\t * When executed, this method obtains selected table property values from various table commands\n\t * and passes them to the {@link #view}.\n\t *\n\t * This way, the UI stays uptodate with the editor data.\n\t *\n\t * @private\n\t */\n\t_fillViewFormFromCommandValues() {\n\t\tconst commands = this.editor.commands;\n\n\t\tObject.entries( propertyToCommandMap )\n\t\t\t.map( ( [ property, commandName ] ) => [ property, commands.get( commandName ).value || '' ] )\n\t\t\t.forEach( ( [ property, value ] ) => this.view.set( property, value ) );\n\t}\n\n\t/**\n\t * Shows the {@link #view} in the {@link #_balloon}.\n\t *\n\t * **Note**: Each time a view is shown, the new {@link #_undoStepBatch} is created that contains\n\t * all changes made to the document when the view is visible, allowing a single undo step\n\t * for all of them.\n\t *\n\t * @protected\n\t */\n\t_showView() {\n\t\tconst editor = this.editor;\n\n\t\tthis.listenTo( editor.ui, 'update', () => {\n\t\t\tthis._updateView();\n\t\t} );\n\n\t\t// Update the view with the model values.\n\t\tthis._fillViewFormFromCommandValues();\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.view,\n\t\t\tposition: getBalloonTablePositionData( editor )\n\t\t} );\n\n\t\t// Create a new batch. Clicking \"Cancel\" will undo this batch.\n\t\tthis._undoStepBatch = editor.model.createBatch();\n\n\t\t// Basic a11y.\n\t\tthis.view.focus();\n\t}\n\n\t/**\n\t * Removes the {@link #view} from the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_hideView() {\n\t\tconst editor = this.editor;\n\n\t\tthis.stopListening( editor.ui, 'update' );\n\n\t\t// Blur any input element before removing it from DOM to prevent issues in some browsers.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1501.\n\t\tthis.view.saveButtonView.focus();\n\n\t\tthis._balloon.remove( this.view );\n\n\t\t// Make sure the focus is not lost in the process by putting it directly\n\t\t// into the editing view.\n\t\tthis.editor.editing.view.focus();\n\t}\n\n\t/**\n\t * Repositions the {@link #_balloon} or hides the {@link #view} if a table is no longer selected.\n\t *\n\t * @protected\n\t */\n\t_updateView() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\n\t\tif ( !getTableWidgetAncestor( viewDocument.selection ) ) {\n\t\t\tthis._hideView();\n\t\t} else if ( this._isViewVisible ) {\n\t\t\trepositionContextualBalloon( editor, 'table' );\n\t\t}\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #view} is the visible in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isViewVisible() {\n\t\treturn this._balloon.visibleView === this.view;\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #view} is in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isViewInBalloon() {\n\t\treturn this._balloon.hasView( this.view );\n\t}\n\n\t/**\n\t * Creates a callback that when executed upon {@link #view view's} property change\n\t * executes a related editor command with the new property value.\n\t *\n\t * @private\n\t * @param {String} commandName\n\t * @returns {Function}\n\t */\n\t_getPropertyChangeCallback( commandName ) {\n\t\treturn ( evt, propertyName, newValue ) => {\n\t\t\tthis.editor.execute( commandName, {\n\t\t\t\tvalue: newValue,\n\t\t\t\tbatch: this._undoStepBatch\n\t\t\t} );\n\t\t};\n\t}\n\n\t/**\n\t * Creates a callback that when executed upon {@link #view view's} property change:\n\t * * executes a related editor command with the new property value if the value is valid,\n\t * * or sets the error text next to the invalid field, if the value did not pass the validation.\n\t *\n\t * @private\n\t * @param {Object} options\n\t * @param {String} options.commandName\n\t * @param {module:ui/view~View} options.viewField\n\t * @param {Function} options.validator\n\t * @param {String} options.errorText\n\t * @returns {Function}\n\t */\n\t_getValidatedPropertyChangeCallback( { commandName, viewField, validator, errorText } ) {\n\t\tconst setErrorTextDebounced = debounce( () => {\n\t\t\tviewField.errorText = errorText;\n\t\t}, ERROR_TEXT_TIMEOUT );\n\n\t\treturn ( evt, propertyName, newValue ) => {\n\t\t\tsetErrorTextDebounced.cancel();\n\n\t\t\tif ( validator( newValue ) ) {\n\t\t\t\tthis.editor.execute( commandName, {\n\t\t\t\t\tvalue: newValue,\n\t\t\t\t\tbatch: this._undoStepBatch\n\t\t\t\t} );\n\n\t\t\t\tviewField.errorText = null;\n\t\t\t} else {\n\t\t\t\tsetErrorTextDebounced();\n\t\t\t}\n\t\t};\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M8 2v5h4V2h1v5h5v1h-5v4h.021l-.172.351-1.916.28-.151.027c-.287.063-.54.182-.755.341L8 13v5H7v-5H2v-1h5V8H2V7h5V2h1zm4 6H8v4h4V8z\\\" opacity=\\\".6\\\"/><path d=\\\"m15.5 11.5 1.323 2.68 2.957.43-2.14 2.085.505 2.946L15.5 18.25l-2.645 1.39.505-2.945-2.14-2.086 2.957-.43L15.5 11.5zM17 1a2 2 0 0 1 2 2v9.475l-.85-.124-.857-1.736a2.048 2.048 0 0 0-.292-.44L17 3H3v14h7.808l.402.392L10.935 19H3a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h14z\\\"/></svg>\";","/**\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 table/tablecellproperties/ui/tablecellpropertiesview\n */\n\nimport {\n\tLabeledFieldView,\n\tcreateLabeledDropdown,\n\tcreateLabeledInputText,\n\tLabelView,\n\taddListToDropdown,\n\tToolbarView,\n\tButtonView,\n\tFocusCycler,\n\tView,\n\tViewCollection,\n\tFormHeaderView,\n\tsubmitHandler\n} from 'ckeditor5/src/ui';\nimport { KeystrokeHandler, FocusTracker } from 'ckeditor5/src/utils';\nimport { icons } from 'ckeditor5/src/core';\n\nimport {\n\tfillToolbar,\n\tgetBorderStyleDefinitions,\n\tgetBorderStyleLabels,\n\tgetLabeledColorInputCreator\n} from '../../utils/ui/table-properties';\nimport FormRowView from '../../ui/formrowview';\n\nimport '../../../theme/form.css';\nimport '../../../theme/tableform.css';\nimport '../../../theme/tablecellproperties.css';\n\nconst ALIGNMENT_ICONS = {\n\tleft: icons.alignLeft,\n\tcenter: icons.alignCenter,\n\tright: icons.alignRight,\n\tjustify: icons.alignJustify,\n\ttop: icons.alignTop,\n\tmiddle: icons.alignMiddle,\n\tbottom: icons.alignBottom\n};\n\n/**\n * The class representing a table cell properties form, allowing users to customize\n * certain style aspects of a table cell, for instance, border, padding, text alignment, etc..\n *\n * @extends module:ui/view~View\n */\nexport default class TableCellPropertiesView extends View {\n\t/**\n\t * @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\n\t * @param {Object} options Additional configuration of the view.\n\t * @param {module:table/table~TableColorConfig} options.borderColors A configuration of the border\n\t * color palette used by the\n\t * {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView#borderColorInput}.\n\t * @param {module:table/table~TableColorConfig} options.backgroundColors A configuration of the background\n\t * color palette used by the\n\t * {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView#backgroundInput}.\n\t */\n\tconstructor( locale, options ) {\n\t\tsuper( locale );\n\n\t\tthis.set( {\n\t\t\t/**\n\t\t\t * The value of the cell border style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderStyle\n\t\t\t */\n\t\t\tborderStyle: '',\n\n\t\t\t/**\n\t\t\t * The value of the cell border width style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderWidth\n\t\t\t */\n\t\t\tborderWidth: '',\n\n\t\t\t/**\n\t\t\t * The value of the cell border color style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #borderColor\n\t\t\t */\n\t\t\tborderColor: '',\n\n\t\t\t/**\n\t\t\t * The value of the cell padding style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #padding\n\t\t\t */\n\t\t\tpadding: '',\n\n\t\t\t/**\n\t\t\t * The value of the cell background color style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #backgroundColor\n\t\t\t */\n\t\t\tbackgroundColor: '',\n\n\t\t\t/**\n\t\t\t * The value of the table cell width style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #width\n\t\t\t */\n\t\t\twidth: '',\n\n\t\t\t/**\n\t\t\t * The value of the table cell height style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #height\n\t\t\t */\n\t\t\theight: '',\n\n\t\t\t/**\n\t\t\t * The value of the horizontal text alignment style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #horizontalAlignment\n\t\t\t */\n\t\t\thorizontalAlignment: '',\n\n\t\t\t/**\n\t\t\t * The value of the vertical text alignment style.\n\t\t\t *\n\t\t\t * @observable\n\t\t\t * @default ''\n\t\t\t * @member #verticalAlignment\n\t\t\t */\n\t\t\tverticalAlignment: ''\n\t\t} );\n\n\t\t/**\n\t\t * Options passed to the view. See {@link #constructor} to learn more.\n\t\t *\n\t\t * @member {Object}\n\t\t */\n\t\tthis.options = options;\n\n\t\tconst { borderStyleDropdown, borderWidthInput, borderColorInput, borderRowLabel } = this._createBorderFields();\n\t\tconst { backgroundRowLabel, backgroundInput } = this._createBackgroundFields();\n\t\tconst { widthInput, operatorLabel, heightInput, dimensionsLabel } = this._createDimensionFields();\n\t\tconst { horizontalAlignmentToolbar, verticalAlignmentToolbar, alignmentLabel } = this._createAlignmentFields();\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * A collection of child views in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @type {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.children = this.createCollection();\n\n\t\t/**\n\t\t * A dropdown that allows selecting the style of the table cell border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/dropdown/dropdownview~DropdownView}\n\t\t */\n\t\tthis.borderStyleDropdown = borderStyleDropdown;\n\n\t\t/**\n\t\t * An input that allows specifying the width of the table cell border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.borderWidthInput = borderWidthInput;\n\n\t\t/**\n\t\t * An input that allows specifying the color of the table cell border.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:table/ui/colorinputview~ColorInputView}\n\t\t */\n\t\tthis.borderColorInput = borderColorInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table cell background color.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:table/ui/colorinputview~ColorInputView}\n\t\t */\n\t\tthis.backgroundInput = backgroundInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table cell padding.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.paddingInput = this._createPaddingField();\n\n\t\t/**\n\t\t * An input that allows specifying the table cell width.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.widthInput = widthInput;\n\n\t\t/**\n\t\t * An input that allows specifying the table cell height.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView}\n\t\t */\n\t\tthis.heightInput = heightInput;\n\n\t\t/**\n\t\t * A toolbar with buttons that allow changing the horizontal text alignment in a table cell.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbar~ToolbarView}\n\t\t */\n\t\tthis.horizontalAlignmentToolbar = horizontalAlignmentToolbar;\n\n\t\t/**\n\t\t * A toolbar with buttons that allow changing the vertical text alignment in a table cell.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/toolbar/toolbar~ToolbarView}\n\t\t */\n\t\tthis.verticalAlignmentToolbar = verticalAlignmentToolbar;\n\n\t\t// Defer creating to make sure other fields are present and the Save button can\n\t\t// bind its #isEnabled to their error messages so there's no way to save unless all\n\t\t// fields are valid.\n\t\tconst { saveButtonView, cancelButtonView } = this._createActionButtons();\n\n\t\t/**\n\t\t * The \"Save\" button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.saveButtonView = saveButtonView;\n\n\t\t/**\n\t\t * The \"Cancel\" button view.\n\t\t *\n\t\t * @member {module:ui/button/buttonview~ButtonView}\n\t\t */\n\t\tthis.cancelButtonView = cancelButtonView;\n\n\t\t/**\n\t\t * A collection of views that can be focused in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis._focusables = new ViewCollection();\n\n\t\t/**\n\t\t * Helps cycling over {@link #_focusables} in the form.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate form fields backwards using the Shift + Tab keystroke.\n\t\t\t\tfocusPrevious: 'shift + tab',\n\n\t\t\t\t// Navigate form fields forwards using the Tab key.\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\n\t\t// Form header.\n\t\tthis.children.add( new FormHeaderView( locale, {\n\t\t\tlabel: this.t( 'Cell properties' )\n\t\t} ) );\n\n\t\t// Border row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tlabelView: borderRowLabel,\n\t\t\tchildren: [\n\t\t\t\tborderRowLabel,\n\t\t\t\tborderStyleDropdown,\n\t\t\t\tborderColorInput,\n\t\t\t\tborderWidthInput\n\t\t\t],\n\t\t\tclass: 'ck-table-form__border-row'\n\t\t} ) );\n\n\t\t// Background.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tlabelView: backgroundRowLabel,\n\t\t\tchildren: [\n\t\t\t\tbackgroundRowLabel,\n\t\t\t\tbackgroundInput\n\t\t\t],\n\t\t\tclass: 'ck-table-form__background-row'\n\t\t} ) );\n\n\t\t// Dimensions row and padding.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tchildren: [\n\t\t\t\t// Dimensions row.\n\t\t\t\tnew FormRowView( locale, {\n\t\t\t\t\tlabelView: dimensionsLabel,\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tdimensionsLabel,\n\t\t\t\t\t\twidthInput,\n\t\t\t\t\t\toperatorLabel,\n\t\t\t\t\t\theightInput\n\t\t\t\t\t],\n\t\t\t\t\tclass: 'ck-table-form__dimensions-row'\n\t\t\t\t} ),\n\t\t\t\t// Padding row.\n\t\t\t\tnew FormRowView( locale, {\n\t\t\t\t\tchildren: [\n\t\t\t\t\t\tthis.paddingInput\n\t\t\t\t\t],\n\t\t\t\t\tclass: 'ck-table-cell-properties-form__padding-row'\n\t\t\t\t} )\n\t\t\t]\n\t\t} ) );\n\n\t\t// Text alignment row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tlabelView: alignmentLabel,\n\t\t\tchildren: [\n\t\t\t\talignmentLabel,\n\t\t\t\thorizontalAlignmentToolbar,\n\t\t\t\tverticalAlignmentToolbar\n\t\t\t],\n\t\t\tclass: 'ck-table-cell-properties-form__alignment-row'\n\t\t} ) );\n\n\t\t// Action row.\n\t\tthis.children.add( new FormRowView( locale, {\n\t\t\tchildren: [\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t],\n\t\t\tclass: 'ck-table-form__action-row'\n\t\t} ) );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-form',\n\t\t\t\t\t'ck-table-form',\n\t\t\t\t\t'ck-table-cell-properties-form'\n\t\t\t\t],\n\t\t\t\t// https://github.com/ckeditor/ckeditor5-link/issues/90\n\t\t\t\ttabindex: '-1'\n\t\t\t},\n\t\t\tchildren: this.children\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Enable the \"submit\" event for this view. It can be triggered by the #saveButtonView\n\t\t// which is of the \"submit\" DOM \"type\".\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\t[\n\t\t\tthis.borderStyleDropdown,\n\t\t\tthis.borderColorInput,\n\t\t\tthis.borderWidthInput,\n\t\t\tthis.backgroundInput,\n\t\t\tthis.widthInput,\n\t\t\tthis.heightInput,\n\t\t\tthis.paddingInput,\n\t\t\tthis.horizontalAlignmentToolbar,\n\t\t\tthis.verticalAlignmentToolbar,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t].forEach( view => {\n\t\t\t// Register the view as focusable.\n\t\t\tthis._focusables.add( view );\n\n\t\t\t// Register the view in the focus tracker.\n\t\t\tthis.focusTracker.add( view.element );\n\t\t} );\n\n\t\t// Mainly for closing using \"Esc\" and navigation using \"Tab\".\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Focuses the fist focusable field in the form.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #borderStyleDropdown},\n\t * * {@link #borderWidthInput},\n\t * * {@link #borderColorInput}.\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createBorderFields() {\n\t\tconst colorInputCreator = getLabeledColorInputCreator( {\n\t\t\tcolorConfig: this.options.borderColors,\n\t\t\tcolumns: 5\n\t\t} );\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Group label ---------------------------------------------\n\n\t\tconst borderRowLabel = new LabelView( locale );\n\t\tborderRowLabel.text = t( 'Border' );\n\n\t\t// -- Style ---------------------------------------------------\n\n\t\tconst styleLabels = getBorderStyleLabels( t );\n\t\tconst borderStyleDropdown = new LabeledFieldView( locale, createLabeledDropdown );\n\t\tborderStyleDropdown.set( {\n\t\t\tlabel: t( 'Style' ),\n\t\t\tclass: 'ck-table-form__border-style'\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.buttonView.set( {\n\t\t\tisOn: false,\n\t\t\twithText: true,\n\t\t\ttooltip: t( 'Style' )\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.buttonView.bind( 'label' ).to( this, 'borderStyle', value => {\n\t\t\treturn styleLabels[ value ? value : 'none' ];\n\t\t} );\n\n\t\tborderStyleDropdown.fieldView.on( 'execute', evt => {\n\t\t\tthis.borderStyle = evt.source._borderStyleValue;\n\t\t} );\n\n\t\tborderStyleDropdown.bind( 'isEmpty' ).to( this, 'borderStyle', value => !value );\n\n\t\taddListToDropdown( borderStyleDropdown.fieldView, getBorderStyleDefinitions( this ) );\n\n\t\t// -- Width ---------------------------------------------------\n\n\t\tconst borderWidthInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\tborderWidthInput.set( {\n\t\t\tlabel: t( 'Width' ),\n\t\t\tclass: 'ck-table-form__border-width'\n\t\t} );\n\n\t\tborderWidthInput.fieldView.bind( 'value' ).to( this, 'borderWidth' );\n\t\tborderWidthInput.bind( 'isEnabled' ).to( this, 'borderStyle', isBorderStyleSet );\n\t\tborderWidthInput.fieldView.on( 'input', () => {\n\t\t\tthis.borderWidth = borderWidthInput.fieldView.element.value;\n\t\t} );\n\n\t\t// -- Color ---------------------------------------------------\n\n\t\tconst borderColorInput = new LabeledFieldView( locale, colorInputCreator );\n\n\t\tborderColorInput.set( {\n\t\t\tlabel: t( 'Color' ),\n\t\t\tclass: 'ck-table-form__border-color'\n\t\t} );\n\n\t\tborderColorInput.fieldView.bind( 'value' ).to( this, 'borderColor' );\n\t\tborderColorInput.bind( 'isEnabled' ).to( this, 'borderStyle', isBorderStyleSet );\n\n\t\tborderColorInput.fieldView.on( 'input', () => {\n\t\t\tthis.borderColor = borderColorInput.fieldView.value;\n\t\t} );\n\n\t\t// Reset the border color and width fields when style is \"none\".\n\t\t// https://github.com/ckeditor/ckeditor5/issues/6227\n\t\tthis.on( 'change:borderStyle', ( evt, name, value ) => {\n\t\t\tif ( !isBorderStyleSet( value ) ) {\n\t\t\t\tthis.borderColor = '';\n\t\t\t\tthis.borderWidth = '';\n\t\t\t}\n\t\t} );\n\n\t\treturn {\n\t\t\tborderRowLabel,\n\t\t\tborderStyleDropdown,\n\t\t\tborderColorInput,\n\t\t\tborderWidthInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #backgroundInput}.\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createBackgroundFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Group label ---------------------------------------------\n\n\t\tconst backgroundRowLabel = new LabelView( locale );\n\t\tbackgroundRowLabel.text = t( 'Background' );\n\n\t\t// -- Background color input -----------------------------------\n\n\t\tconst colorInputCreator = getLabeledColorInputCreator( {\n\t\t\tcolorConfig: this.options.backgroundColors,\n\t\t\tcolumns: 5\n\t\t} );\n\n\t\tconst backgroundInput = new LabeledFieldView( locale, colorInputCreator );\n\n\t\tbackgroundInput.set( {\n\t\t\tlabel: t( 'Color' ),\n\t\t\tclass: 'ck-table-cell-properties-form__background'\n\t\t} );\n\n\t\tbackgroundInput.fieldView.bind( 'value' ).to( this, 'backgroundColor' );\n\t\tbackgroundInput.fieldView.on( 'input', () => {\n\t\t\tthis.backgroundColor = backgroundInput.fieldView.value;\n\t\t} );\n\n\t\treturn {\n\t\t\tbackgroundRowLabel,\n\t\t\tbackgroundInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #widthInput}.\n\t * * {@link #heightInput}.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t */\n\t_createDimensionFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\t// -- Label ---------------------------------------------------\n\n\t\tconst dimensionsLabel = new LabelView( locale );\n\t\tdimensionsLabel.text = t( 'Dimensions' );\n\n\t\t// -- Width ---------------------------------------------------\n\n\t\tconst widthInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\twidthInput.set( {\n\t\t\tlabel: t( 'Width' ),\n\t\t\tclass: 'ck-table-form__dimensions-row__width'\n\t\t} );\n\n\t\twidthInput.fieldView.bind( 'value' ).to( this, 'width' );\n\t\twidthInput.fieldView.on( 'input', () => {\n\t\t\tthis.width = widthInput.fieldView.element.value;\n\t\t} );\n\n\t\t// -- Operator ---------------------------------------------------\n\n\t\tconst operatorLabel = new View( locale );\n\t\toperatorLabel.setTemplate( {\n\t\t\ttag: 'span',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-table-form__dimension-operator'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{ text: '×' }\n\t\t\t]\n\t\t} );\n\n\t\t// -- Height ---------------------------------------------------\n\n\t\tconst heightInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\theightInput.set( {\n\t\t\tlabel: t( 'Height' ),\n\t\t\tclass: 'ck-table-form__dimensions-row__height'\n\t\t} );\n\n\t\theightInput.fieldView.bind( 'value' ).to( this, 'height' );\n\t\theightInput.fieldView.on( 'input', () => {\n\t\t\tthis.height = heightInput.fieldView.element.value;\n\t\t} );\n\n\t\treturn {\n\t\t\tdimensionsLabel,\n\t\t\twidthInput,\n\t\t\toperatorLabel,\n\t\t\theightInput\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #paddingInput}.\n\t *\n\t * @private\n\t * @returns {module:ui/labeledfield/labeledfieldview~LabeledFieldView}\n\t */\n\t_createPaddingField() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\tconst paddingInput = new LabeledFieldView( locale, createLabeledInputText );\n\n\t\tpaddingInput.set( {\n\t\t\tlabel: t( 'Padding' ),\n\t\t\tclass: 'ck-table-cell-properties-form__padding'\n\t\t} );\n\n\t\tpaddingInput.fieldView.bind( 'value' ).to( this, 'padding' );\n\t\tpaddingInput.fieldView.on( 'input', () => {\n\t\t\tthis.padding = paddingInput.fieldView.element.value;\n\t\t} );\n\n\t\treturn paddingInput;\n\t}\n\n\t/**\n\t * Creates the following form fields:\n\t *\n\t * * {@link #horizontalAlignmentToolbar},\n\t * * {@link #verticalAlignmentToolbar}.\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createAlignmentFields() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\tconst alignmentLabel = new LabelView( locale );\n\n\t\talignmentLabel.text = t( 'Table cell text alignment' );\n\n\t\t// -- Horizontal ---------------------------------------------------\n\n\t\tconst horizontalAlignmentToolbar = new ToolbarView( locale );\n\t\tconst isContentRTL = this.locale.contentLanguageDirection === 'rtl';\n\n\t\thorizontalAlignmentToolbar.set( {\n\t\t\tisCompact: true,\n\t\t\tariaLabel: t( 'Horizontal text alignment toolbar' )\n\t\t} );\n\n\t\tfillToolbar( {\n\t\t\tview: this,\n\t\t\ticons: ALIGNMENT_ICONS,\n\t\t\ttoolbar: horizontalAlignmentToolbar,\n\t\t\tlabels: this._horizontalAlignmentLabels,\n\t\t\tpropertyName: 'horizontalAlignment',\n\t\t\tnameToValue: name => {\n\t\t\t\treturn name === ( isContentRTL ? 'right' : 'left' ) ? '' : name;\n\t\t\t}\n\t\t} );\n\n\t\t// -- Vertical -----------------------------------------------------\n\n\t\tconst verticalAlignmentToolbar = new ToolbarView( locale );\n\n\t\tverticalAlignmentToolbar.set( {\n\t\t\tisCompact: true,\n\t\t\tariaLabel: t( 'Vertical text alignment toolbar' )\n\t\t} );\n\n\t\tfillToolbar( {\n\t\t\tview: this,\n\t\t\ticons: ALIGNMENT_ICONS,\n\t\t\ttoolbar: verticalAlignmentToolbar,\n\t\t\tlabels: this._verticalAlignmentLabels,\n\t\t\tpropertyName: 'verticalAlignment',\n\t\t\tnameToValue: name => {\n\t\t\t\treturn name === 'middle' ? '' : name;\n\t\t\t}\n\t\t} );\n\n\t\treturn {\n\t\t\thorizontalAlignmentToolbar,\n\t\t\tverticalAlignmentToolbar,\n\t\t\talignmentLabel\n\t\t};\n\t}\n\n\t/**\n\t * Creates the following form controls:\n\t *\n\t * * {@link #saveButtonView},\n\t * * {@link #cancelButtonView}.\n\t *\n\t * @private\n\t * @returns {Object.<String,module:ui/view~View>}\n\t */\n\t_createActionButtons() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\t\tconst saveButtonView = new ButtonView( locale );\n\t\tconst cancelButtonView = new ButtonView( locale );\n\t\tconst fieldsThatShouldValidateToSave = [\n\t\t\tthis.borderWidthInput,\n\t\t\tthis.borderColorInput,\n\t\t\tthis.backgroundInput,\n\t\t\tthis.paddingInput\n\t\t];\n\n\t\tsaveButtonView.set( {\n\t\t\tlabel: t( 'Save' ),\n\t\t\ticon: icons.check,\n\t\t\tclass: 'ck-button-save',\n\t\t\ttype: 'submit',\n\t\t\twithText: true\n\t\t} );\n\n\t\tsaveButtonView.bind( 'isEnabled' ).toMany( fieldsThatShouldValidateToSave, 'errorText', ( ...errorTexts ) => {\n\t\t\treturn errorTexts.every( errorText => !errorText );\n\t\t} );\n\n\t\tcancelButtonView.set( {\n\t\t\tlabel: t( 'Cancel' ),\n\t\t\ticon: icons.cancel,\n\t\t\tclass: 'ck-button-cancel',\n\t\t\ttype: 'cancel',\n\t\t\twithText: true\n\t\t} );\n\n\t\tcancelButtonView.delegate( 'execute' ).to( this, 'cancel' );\n\n\t\treturn {\n\t\t\tsaveButtonView, cancelButtonView\n\t\t};\n\t}\n\n\t/**\n\t * Provides localized labels for {@link #horizontalAlignmentToolbar} buttons.\n\t *\n\t * @private\n\t * @type {Object.<String,String>}\n\t */\n\tget _horizontalAlignmentLabels() {\n\t\tconst locale = this.locale;\n\t\tconst t = this.t;\n\n\t\tconst left = t( 'Align cell text to the left' );\n\t\tconst center = t( 'Align cell text to the center' );\n\t\tconst right = t( 'Align cell text to the right' );\n\t\tconst justify = t( 'Justify cell text' );\n\n\t\t// Returns object with a proper order of labels.\n\t\tif ( locale.uiLanguageDirection === 'rtl' ) {\n\t\t\treturn { right, center, left, justify };\n\t\t} else {\n\t\t\treturn { left, center, right, justify };\n\t\t}\n\t}\n\n\t/**\n\t * Provides localized labels for {@link #verticalAlignmentToolbar} buttons.\n\t *\n\t * @private\n\t * @type {Object.<String,String>}\n\t */\n\tget _verticalAlignmentLabels() {\n\t\tconst t = this.t;\n\n\t\treturn {\n\t\t\ttop: t( 'Align cell text to the top' ),\n\t\t\tmiddle: t( 'Align cell text to the middle' ),\n\t\t\tbottom: t( 'Align cell text to the bottom' )\n\t\t};\n\t}\n}\n\nfunction isBorderStyleSet( value ) {\n\treturn !!value;\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 table/tablecellproperties/tablecellpropertiesui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView, clickOutsideHandler, ContextualBalloon, getLocalizedColorOptions, normalizeColorOptions } from 'ckeditor5/src/ui';\n\nimport TableCellPropertiesView from './ui/tablecellpropertiesview';\nimport {\n\tcolorFieldValidator,\n\tgetLocalizedColorErrorText,\n\tgetLocalizedLengthErrorText,\n\tdefaultColors,\n\tlengthFieldValidator,\n\tlineWidthFieldValidator\n} from '../utils/ui/table-properties';\nimport { debounce } from 'lodash-es';\nimport { getTableWidgetAncestor } from '../utils/ui/widget';\nimport { getBalloonCellPositionData, repositionContextualBalloon } from '../utils/ui/contextualballoon';\n\nimport tableCellProperties from './../../theme/icons/table-cell-properties.svg';\n\nconst ERROR_TEXT_TIMEOUT = 500;\n\n// Map of view properties and related commands.\nconst propertyToCommandMap = {\n\tborderStyle: 'tableCellBorderStyle',\n\tborderColor: 'tableCellBorderColor',\n\tborderWidth: 'tableCellBorderWidth',\n\twidth: 'tableCellWidth',\n\theight: 'tableCellHeight',\n\tpadding: 'tableCellPadding',\n\tbackgroundColor: 'tableCellBackgroundColor',\n\thorizontalAlignment: 'tableCellHorizontalAlignment',\n\tverticalAlignment: 'tableCellVerticalAlignment'\n};\n\n/**\n * The table cell properties UI plugin. It introduces the `'tableCellProperties'` button\n * that opens a form allowing to specify the visual styling of a table cell.\n *\n * It uses the\n * {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon contextual balloon plugin}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableCellPropertiesUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableCellPropertiesUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'table.tableCellProperties', {\n\t\t\tborderColors: defaultColors,\n\t\t\tbackgroundColors: defaultColors\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t/**\n\t\t * The cell properties form view displayed inside the balloon.\n\t\t *\n\t\t * @member {module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView}\n\t\t */\n\t\tthis.view = this._createPropertiesView();\n\n\t\t/**\n\t\t * The batch used to undo all changes made by the form (which are live, as the user types)\n\t\t * when \"Cancel\" was pressed. Each time the view is shown, a new batch is created.\n\t\t *\n\t\t * @protected\n\t\t * @member {module:engine/model/batch~Batch}\n\t\t */\n\t\tthis._undoStepBatch = null;\n\n\t\teditor.ui.componentFactory.add( 'tableCellProperties', locale => {\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Cell properties' ),\n\t\t\t\ticon: tableCellProperties,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tthis.listenTo( view, 'execute', () => this._showView() );\n\n\t\t\tconst commands = Object.values( propertyToCommandMap )\n\t\t\t\t.map( commandName => editor.commands.get( commandName ) );\n\n\t\t\tview.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => (\n\t\t\t\tareEnabled.some( isCommandEnabled => isCommandEnabled )\n\t\t\t) );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1341.\n\t\tthis.view.destroy();\n\t}\n\n\t/**\n\t * Creates the {@link module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} instance.\n\t *\n\t * @private\n\t * @returns {module:table/tablecellproperties/ui/tablecellpropertiesview~TableCellPropertiesView} The cell\n\t * properties form view instance.\n\t */\n\t_createPropertiesView() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\t\tconst config = editor.config.get( 'table.tableCellProperties' );\n\t\tconst borderColorsConfig = normalizeColorOptions( config.borderColors );\n\t\tconst localizedBorderColors = getLocalizedColorOptions( editor.locale, borderColorsConfig );\n\t\tconst backgroundColorsConfig = normalizeColorOptions( config.backgroundColors );\n\t\tconst localizedBackgroundColors = getLocalizedColorOptions( editor.locale, backgroundColorsConfig );\n\t\tconst view = new TableCellPropertiesView( editor.locale, {\n\t\t\tborderColors: localizedBorderColors,\n\t\t\tbackgroundColors: localizedBackgroundColors\n\t\t} );\n\t\tconst t = editor.t;\n\n\t\t// Render the view so its #element is available for the clickOutsideHandler.\n\t\tview.render();\n\n\t\tthis.listenTo( view, 'submit', () => {\n\t\t\tthis._hideView();\n\t\t} );\n\n\t\tthis.listenTo( view, 'cancel', () => {\n\t\t\t// https://github.com/ckeditor/ckeditor5/issues/6180\n\t\t\tif ( this._undoStepBatch.operations.length ) {\n\t\t\t\teditor.execute( 'undo', this._undoStepBatch );\n\t\t\t}\n\n\t\t\tthis._hideView();\n\t\t} );\n\n\t\t// Close the balloon on Esc key press.\n\t\tview.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tthis._hideView();\n\t\t\tcancel();\n\t\t} );\n\n\t\t// Reposition the balloon or hide the form if a table cell is no longer selected.\n\t\tthis.listenTo( editor.ui, 'update', () => {\n\t\t\tif ( !getTableWidgetAncestor( viewDocument.selection ) ) {\n\t\t\t\tthis._hideView();\n\t\t\t} else if ( this._isViewVisible ) {\n\t\t\t\trepositionContextualBalloon( editor, 'cell' );\n\t\t\t}\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: view,\n\t\t\tactivator: () => this._isViewInBalloon,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideView()\n\t\t} );\n\n\t\tconst colorErrorText = getLocalizedColorErrorText( t );\n\t\tconst lengthErrorText = getLocalizedLengthErrorText( t );\n\n\t\t// Create the \"UI -> editor data\" binding.\n\t\t// These listeners update the editor data (via table commands) when any observable\n\t\t// property of the view has changed. They also validate the value and display errors in the UI\n\t\t// when necessary. This makes the view live, which means the changes are\n\t\t// visible in the editing as soon as the user types or changes fields' values.\n\t\tview.on( 'change:borderStyle', this._getPropertyChangeCallback( 'tableCellBorderStyle' ) );\n\n\t\tview.on( 'change:borderColor', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.borderColorInput,\n\t\t\tcommandName: 'tableCellBorderColor',\n\t\t\terrorText: colorErrorText,\n\t\t\tvalidator: colorFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:borderWidth', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.borderWidthInput,\n\t\t\tcommandName: 'tableCellBorderWidth',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lineWidthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:padding', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.paddingInput,\n\t\t\tcommandName: 'tableCellPadding',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lengthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:width', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.widthInput,\n\t\t\tcommandName: 'tableCellWidth',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lengthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:height', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.heightInput,\n\t\t\tcommandName: 'tableCellHeight',\n\t\t\terrorText: lengthErrorText,\n\t\t\tvalidator: lengthFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:backgroundColor', this._getValidatedPropertyChangeCallback( {\n\t\t\tviewField: view.backgroundInput,\n\t\t\tcommandName: 'tableCellBackgroundColor',\n\t\t\terrorText: colorErrorText,\n\t\t\tvalidator: colorFieldValidator\n\t\t} ) );\n\n\t\tview.on( 'change:horizontalAlignment', this._getPropertyChangeCallback( 'tableCellHorizontalAlignment' ) );\n\t\tview.on( 'change:verticalAlignment', this._getPropertyChangeCallback( 'tableCellVerticalAlignment' ) );\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * In this method the \"editor data -> UI\" binding is happening.\n\t *\n\t * When executed, this method obtains selected cell property values from various table commands\n\t * and passes them to the {@link #view}.\n\t *\n\t * This way, the UI stays uptodate with the editor data.\n\t *\n\t * @private\n\t */\n\t_fillViewFormFromCommandValues() {\n\t\tconst commands = this.editor.commands;\n\n\t\tObject.entries( propertyToCommandMap )\n\t\t\t.map( ( [ property, commandName ] ) => [ property, commands.get( commandName ).value || '' ] )\n\t\t\t.forEach( ( [ property, value ] ) => this.view.set( property, value ) );\n\t}\n\n\t/**\n\t * Shows the {@link #view} in the {@link #_balloon}.\n\t *\n\t * **Note**: Each time a view is shown, a new {@link #_undoStepBatch} is created. It contains\n\t * all changes made to the document when the view is visible, allowing a single undo step\n\t * for all of them.\n\t *\n\t * @protected\n\t */\n\t_showView() {\n\t\tconst editor = this.editor;\n\n\t\t// Update the view with the model values.\n\t\tthis._fillViewFormFromCommandValues();\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.view,\n\t\t\tposition: getBalloonCellPositionData( editor )\n\t\t} );\n\n\t\t// Create a new batch. Clicking \"Cancel\" will undo this batch.\n\t\tthis._undoStepBatch = editor.model.createBatch();\n\n\t\t// Basic a11y.\n\t\tthis.view.focus();\n\t}\n\n\t/**\n\t * Removes the {@link #view} from the {@link #_balloon}.\n\t *\n\t * @protected\n\t */\n\t_hideView() {\n\t\tif ( !this._isViewInBalloon ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\n\t\tthis.stopListening( editor.ui, 'update' );\n\n\t\t// Blur any input element before removing it from DOM to prevent issues in some browsers.\n\t\t// See https://github.com/ckeditor/ckeditor5/issues/1501.\n\t\tthis.view.saveButtonView.focus();\n\n\t\tthis._balloon.remove( this.view );\n\n\t\t// Make sure the focus is not lost in the process by putting it directly\n\t\t// into the editing view.\n\t\tthis.editor.editing.view.focus();\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #view} is visible in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isViewVisible() {\n\t\treturn this._balloon.visibleView === this.view;\n\t}\n\n\t/**\n\t * Returns `true` when the {@link #view} is in the {@link #_balloon}.\n\t *\n\t * @private\n\t * @type {Boolean}\n\t */\n\tget _isViewInBalloon() {\n\t\treturn this._balloon.hasView( this.view );\n\t}\n\n\t/**\n\t * Creates a callback that when executed upon the {@link #view view's} property change\n\t * executes a related editor command with the new property value.\n\t *\n\t * @private\n\t * @param {String} commandName\n\t * @returns {Function}\n\t */\n\t_getPropertyChangeCallback( commandName ) {\n\t\treturn ( evt, propertyName, newValue ) => {\n\t\t\tthis.editor.execute( commandName, {\n\t\t\t\tvalue: newValue,\n\t\t\t\tbatch: this._undoStepBatch\n\t\t\t} );\n\t\t};\n\t}\n\n\t/**\n\t * Creates a callback that when executed upon the {@link #view view's} property change:\n\t * * Executes a related editor command with the new property value if the value is valid,\n\t * * Or sets the error text next to the invalid field, if the value did not pass the validation.\n\t *\n\t * @private\n\t * @param {Object} options\n\t * @param {String} options.commandName\n\t * @param {module:ui/view~View} options.viewField\n\t * @param {Function} options.validator\n\t * @param {String} options.errorText\n\t * @returns {Function}\n\t */\n\t_getValidatedPropertyChangeCallback( { commandName, viewField, validator, errorText } ) {\n\t\tconst setErrorTextDebounced = debounce( () => {\n\t\t\tviewField.errorText = errorText;\n\t\t}, ERROR_TEXT_TIMEOUT );\n\n\t\treturn ( evt, propertyName, newValue ) => {\n\t\t\tsetErrorTextDebounced.cancel();\n\n\t\t\tif ( validator( newValue ) ) {\n\t\t\t\tthis.editor.execute( commandName, {\n\t\t\t\t\tvalue: newValue,\n\t\t\t\t\tbatch: this._undoStepBatch\n\t\t\t\t} );\n\n\t\t\t\tviewField.errorText = null;\n\t\t\t} else {\n\t\t\t\tsetErrorTextDebounced();\n\t\t\t}\n\t\t};\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m11.105 18-.17 1H2.5A1.5 1.5 0 0 1 1 17.5v-15A1.5 1.5 0 0 1 2.5 1h15A1.5 1.5 0 0 1 19 2.5v9.975l-.85-.124-.15-.302V8h-5v4h.021l-.172.351-1.916.28-.151.027c-.287.063-.54.182-.755.341L8 13v5h3.105zM2 12h5V8H2v4zm10-4H8v4h4V8zM2 2v5h5V2H2zm0 16h5v-5H2v5zM13 7h5V2h-5v5zM8 2v5h4V2H8z\\\" opacity=\\\".6\\\"/><path d=\\\"m15.5 11.5 1.323 2.68 2.957.43-2.14 2.085.505 2.946L15.5 18.25l-2.645 1.39.505-2.945-2.14-2.086 2.957-.43L15.5 11.5zM13 6a1 1 0 0 1 1 1v3.172a2.047 2.047 0 0 0-.293.443l-.858 1.736-1.916.28-.151.027A1.976 1.976 0 0 0 9.315 14H7a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h6zm-1 2H8v4h4V8z\\\"/></svg>\";","/**\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 table/tablecellproperties/commands/tablecellpropertycommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { getSelectionAffectedTableCells } from '../../utils/selection';\n\n/**\n * The table cell attribute command.\n *\n * The command is a base command for other table cell property commands.\n *\n * @extends module:core/command~Command\n */\nexport default class TableCellPropertyCommand extends Command {\n\t/**\n\t * Creates a new `TableCellPropertyCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t * @param {String} attributeName Table cell attribute name.\n\t */\n\tconstructor( editor, attributeName ) {\n\t\tsuper( editor );\n\n\t\tthis.attributeName = attributeName;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst editor = this.editor;\n\t\tconst selectedTableCells = getSelectionAffectedTableCells( editor.model.document.selection );\n\n\t\tthis.isEnabled = !!selectedTableCells.length;\n\t\tthis.value = this._getSingleValue( selectedTableCells );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t * @param {Object} [options]\n\t * @param {*} [options.value] If set, the command will set the attribute on selected table cells.\n\t * If it is not set, the command will remove the attribute from the selected table cells.\n\t * @param {module:engine/model/batch~Batch} [options.batch] Pass the model batch instance to the command to aggregate changes,\n\t * for example to allow a single undo step for multiple executions.\n\t */\n\texecute( options = {} ) {\n\t\tconst { value, batch } = options;\n\t\tconst model = this.editor.model;\n\t\tconst tableCells = getSelectionAffectedTableCells( model.document.selection );\n\t\tconst valueToSet = this._getValueToSet( value );\n\n\t\tmodel.enqueueChange( batch || 'default', writer => {\n\t\t\tif ( valueToSet ) {\n\t\t\t\ttableCells.forEach( tableCell => writer.setAttribute( this.attributeName, valueToSet, tableCell ) );\n\t\t\t} else {\n\t\t\t\ttableCells.forEach( tableCell => writer.removeAttribute( this.attributeName, tableCell ) );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns the attribute value for a table cell.\n\t *\n\t * @param {module:engine/model/element~Element} tableCell\n\t * @returns {String|undefined}\n\t * @private\n\t */\n\t_getAttribute( tableCell ) {\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn tableCell.getAttribute( this.attributeName );\n\t}\n\n\t/**\n\t * Returns the proper model value. It can be used to add a default unit to numeric values.\n\t *\n\t * @private\n\t * @param {*} value\n\t * @returns {*}\n\t */\n\t_getValueToSet( value ) {\n\t\treturn value;\n\t}\n\n\t/**\n\t * Returns a single value for all selected table cells. If the value is the same for all cells,\n\t * it will be returned (`undefined` otherwise).\n\t *\n\t * @param {Array.<module:engine/model/element~Element>} tableCell\n\t * @returns {*}\n\t * @private\n\t */\n\t_getSingleValue( tableCell ) {\n\t\tconst firstCellValue = this._getAttribute( tableCell[ 0 ] );\n\n\t\tconst everyCellHasAttribute = tableCell.every( tableCell => this._getAttribute( tableCell ) === firstCellValue );\n\n\t\treturn everyCellHasAttribute ? firstCellValue : undefined;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellpaddingcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\nimport { addDefaultUnitToNumericValue, getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table cell padding command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellPadding'` editor command.\n *\n * To change the padding of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellPadding', {\n *\t\t\tvalue: '5px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableCellPadding', {\n *\t\t\tvalue: '5'\n *\t\t} );\n *\n * will set the `padding` attribute to `'5px'` in the model.\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellPaddingCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellPaddingCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'padding' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getAttribute( tableCell ) {\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( tableCell.getAttribute( this.attributeName ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellwidthcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\nimport { addDefaultUnitToNumericValue } from '../../utils/table-properties';\n\n/**\n * The table cell width command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellWidth'` editor command.\n *\n * To change the width of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellWidth', {\n *\t\t\tvalue: '50px'\n *\t\t} );\n *\n * **Note**: This command adds a default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableCellWidth', {\n *\t\t\tvalue: '50'\n *\t\t} );\n *\n * will set the `width` attribute to `'50px'` in the model.\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellWidthCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellWidthCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'width' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellheightcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\nimport { addDefaultUnitToNumericValue } from '../../utils/table-properties';\n\n/**\n * The table cell height command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellHeight'` editor command.\n *\n * To change the height of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellHeight', {\n *\t\t\tvalue: '50px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableCellHeight', {\n *\t\t\tvalue: '50'\n *\t\t} );\n *\n * will set the `height` attribute to `'50px'` in the model.\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellHeightCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellHeightCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'height' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellbackgroundcolorcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\n\n/**\n * The table cell background color command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellBackgroundColor'` editor command.\n *\n * To change the background color of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellBackgroundColor', {\n *\t\t\tvalue: '#f00'\n *\t\t} );\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellBackgroundColorCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellBackgroundColorCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'backgroundColor' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellverticalalignmentcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\n\n/**\n * The table cell vertical alignment command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellVerticalAlignment'` editor command.\n *\n * To change the vertical text alignment of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellVerticalAlignment', {\n *\t\t\tvalue: 'top'\n *\t\t} );\n *\n * The following values, corresponding to the\n * [`vertical-align` CSS attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/vertical-align), are allowed:\n *\n * * `'top'`\n * * `'bottom'`\n *\n * The `'middle'` value is the default one so there is no need to set it.\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellVerticalAlignmentCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellVerticalAlignmentCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'verticalAlignment' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellhorizontalalignmentcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\n\n/**\n * The table cell horizontal alignment command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellHorizontalAlignment'` editor command.\n *\n * To change the horizontal text alignment of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellHorizontalAlignment', {\n *\t\t\tvalue: 'right'\n *\t\t} );\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellHorizontalAlignmentCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellHorizontalAlignmentCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'horizontalAlignment' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellborderstylecommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\nimport { getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table cell border style command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellBorderStyle'` editor command.\n *\n * To change the border style of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellBorderStyle', {\n *\t\t\tvalue: 'dashed'\n *\t\t} );\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellBorderStyleCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellBorderStyleCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderStyle' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getAttribute( tableCell ) {\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( tableCell.getAttribute( this.attributeName ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellbordercolorcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\nimport { getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table cell border color command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellBorderColor'` editor command.\n *\n * To change the border color of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellBorderColor', {\n *\t\t\tvalue: '#f00'\n *\t\t} );\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellBorderColorCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellBorderColorCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderColor' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getAttribute( tableCell ) {\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( tableCell.getAttribute( this.attributeName ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/commands/tablecellborderwidthcommand\n */\n\nimport TableCellPropertyCommand from './tablecellpropertycommand';\nimport { addDefaultUnitToNumericValue, getSingleValue } from '../../utils/table-properties';\n\n/**\n * The table cell border width command.\n *\n * The command is registered by the {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing} as\n * the `'tableCellBorderWidth'` editor command.\n *\n * To change the border width of selected cells, execute the command:\n *\n *\t\teditor.execute( 'tableCellBorderWidth', {\n *\t\t\tvalue: '5px'\n *\t\t} );\n *\n * **Note**: This command adds the default `'px'` unit to numeric values. Executing:\n *\n *\t\teditor.execute( 'tableCellBorderWidth', {\n *\t\t\tvalue: '5'\n *\t\t} );\n *\n * will set the `borderWidth` attribute to `'5px'` in the model.\n *\n * @extends module:table/tablecellproperties/commands/tablecellpropertycommand~TableCellPropertyCommand\n */\nexport default class TableCellBorderWidthCommand extends TableCellPropertyCommand {\n\t/**\n\t * Creates a new `TableCellBorderWidthCommand` instance.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor An editor in which this command will be used.\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, 'borderWidth' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getAttribute( tableCell ) {\n\t\tif ( !tableCell ) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn getSingleValue( tableCell.getAttribute( this.attributeName ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\t_getValueToSet( value ) {\n\t\treturn addDefaultUnitToNumericValue( value, 'px' );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/tablecellproperties/tablecellpropertiesediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { addBorderRules, addPaddingRules, addBackgroundRules } from 'ckeditor5/src/engine';\n\nimport { downcastAttributeToStyle, upcastStyleToAttribute, upcastBorderStyles } from './../converters/tableproperties';\nimport TableEditing from './../tableediting';\nimport TableCellPaddingCommand from './commands/tablecellpaddingcommand';\nimport TableCellWidthCommand from './commands/tablecellwidthcommand';\nimport TableCellHeightCommand from './commands/tablecellheightcommand';\nimport TableCellBackgroundColorCommand from './commands/tablecellbackgroundcolorcommand';\nimport TableCellVerticalAlignmentCommand from './commands/tablecellverticalalignmentcommand';\nimport TableCellHorizontalAlignmentCommand from './commands/tablecellhorizontalalignmentcommand';\nimport TableCellBorderStyleCommand from './commands/tablecellborderstylecommand';\nimport TableCellBorderColorCommand from './commands/tablecellbordercolorcommand';\nimport TableCellBorderWidthCommand from './commands/tablecellborderwidthcommand';\n\nconst VALIGN_VALUES_REG_EXP = /^(top|bottom)$/;\n\n/**\n * The table cell properties editing feature.\n *\n * Introduces table cell model attributes and their conversion:\n *\n * - border: `borderStyle`, `borderColor` and `borderWidth`\n * - background color: `backgroundColor`\n * - cell padding: `padding`\n * - horizontal and vertical alignment: `horizontalAlignment`, `verticalAlignment`\n * - cell width and height: `width`, `height`\n *\n * It also registers commands used to manipulate the above attributes:\n *\n * - border: the `'tableCellBorderStyle'`, `'tableCellBorderColor'` and `'tableCellBorderWidth'` commands\n * - background color: the `'tableCellBackgroundColor'` command\n * - cell padding: the `'tableCellPadding'` command\n * - horizontal and vertical alignment: the `'tableCellHorizontalAlignment'` and `'tableCellVerticalAlignment'` commands\n * - width and height: the `'tableCellWidth'` and `'tableCellHeight'` commands\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableCellPropertiesEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableCellPropertiesEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst conversion = editor.conversion;\n\t\tconst locale = editor.locale;\n\n\t\teditor.data.addStyleProcessorRules( addBorderRules );\n\t\tenableBorderProperties( schema, conversion );\n\t\teditor.commands.add( 'tableCellBorderStyle', new TableCellBorderStyleCommand( editor ) );\n\t\teditor.commands.add( 'tableCellBorderColor', new TableCellBorderColorCommand( editor ) );\n\t\teditor.commands.add( 'tableCellBorderWidth', new TableCellBorderWidthCommand( editor ) );\n\n\t\tenableHorizontalAlignmentProperty( schema, conversion, locale );\n\t\teditor.commands.add( 'tableCellHorizontalAlignment', new TableCellHorizontalAlignmentCommand( editor ) );\n\n\t\tenableProperty( schema, conversion, 'width', 'width' );\n\t\teditor.commands.add( 'tableCellWidth', new TableCellWidthCommand( editor ) );\n\n\t\tenableProperty( schema, conversion, 'height', 'height' );\n\t\teditor.commands.add( 'tableCellHeight', new TableCellHeightCommand( editor ) );\n\n\t\teditor.data.addStyleProcessorRules( addPaddingRules );\n\t\tenableProperty( schema, conversion, 'padding', 'padding' );\n\t\teditor.commands.add( 'tableCellPadding', new TableCellPaddingCommand( editor ) );\n\n\t\teditor.data.addStyleProcessorRules( addBackgroundRules );\n\t\tenableProperty( schema, conversion, 'backgroundColor', 'background-color' );\n\t\teditor.commands.add( 'tableCellBackgroundColor', new TableCellBackgroundColorCommand( editor ) );\n\n\t\tenableVerticalAlignmentProperty( schema, conversion );\n\t\teditor.commands.add( 'tableCellVerticalAlignment', new TableCellVerticalAlignmentCommand( editor ) );\n\t}\n}\n\n// Enables the `'borderStyle'`, `'borderColor'` and `'borderWidth'` attributes for table cells.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableBorderProperties( schema, conversion ) {\n\tschema.extend( 'tableCell', {\n\t\tallowAttributes: [ 'borderWidth', 'borderColor', 'borderStyle' ]\n\t} );\n\tupcastBorderStyles( conversion, 'td' );\n\tupcastBorderStyles( conversion, 'th' );\n\tdowncastAttributeToStyle( conversion, 'tableCell', 'borderStyle', 'border-style' );\n\tdowncastAttributeToStyle( conversion, 'tableCell', 'borderColor', 'border-color' );\n\tdowncastAttributeToStyle( conversion, 'tableCell', 'borderWidth', 'border-width' );\n}\n\n// Enables the `'horizontalAlignment'` attribute for table cells.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\n// @param {module:utils/locale~Locale} locale The {@link module:core/editor/editor~Editor#locale} instance.\nfunction enableHorizontalAlignmentProperty( schema, conversion, locale ) {\n\tschema.extend( 'tableCell', {\n\t\tallowAttributes: [ 'horizontalAlignment' ]\n\t} );\n\n\tconst options = [ locale.contentLanguageDirection == 'rtl' ? 'left' : 'right', 'center', 'justify' ];\n\n\tconversion.attributeToAttribute( {\n\t\tmodel: {\n\t\t\tname: 'tableCell',\n\t\t\tkey: 'horizontalAlignment',\n\t\t\tvalues: options\n\t\t},\n\t\tview: options.reduce( ( result, option ) => ( {\n\t\t\t...result,\n\t\t\t[ option ]: {\n\t\t\t\tkey: 'style',\n\t\t\t\tvalue: {\n\t\t\t\t\t'text-align': option\n\t\t\t\t}\n\t\t\t}\n\t\t} ), {} )\n\t} );\n}\n\n// Enables the `'verticalAlignment'` attribute for table cells.\n//\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableVerticalAlignmentProperty( schema, conversion ) {\n\tschema.extend( 'tableCell', {\n\t\tallowAttributes: [ 'verticalAlignment' ]\n\t} );\n\n\tconversion.attributeToAttribute( {\n\t\tmodel: {\n\t\t\tname: 'tableCell',\n\t\t\tkey: 'verticalAlignment',\n\t\t\tvalues: [ 'top', 'bottom' ]\n\t\t},\n\t\tview: {\n\t\t\ttop: {\n\t\t\t\tkey: 'style',\n\t\t\t\tvalue: {\n\t\t\t\t\t'vertical-align': 'top'\n\t\t\t\t}\n\t\t\t},\n\t\t\tbottom: {\n\t\t\t\tkey: 'style',\n\t\t\t\tvalue: {\n\t\t\t\t\t'vertical-align': 'bottom'\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} );\n\n\tconversion.for( 'upcast' )\n\t\t// Support for backwards compatibility and pasting from other sources.\n\t\t.attributeToAttribute( {\n\t\t\tview: {\n\t\t\t\tattributes: {\n\t\t\t\t\tvalign: VALIGN_VALUES_REG_EXP\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tname: 'tableCell',\n\t\t\t\tkey: 'verticalAlignment',\n\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'valign' )\n\t\t\t}\n\t\t} );\n}\n\n// Enables conversion for an attribute for simple view-model mappings.\n//\n// @param {String} modelAttribute\n// @param {String} styleName\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/conversion/conversion~Conversion} conversion\nfunction enableProperty( schema, conversion, modelAttribute, styleName ) {\n\tschema.extend( 'tableCell', {\n\t\tallowAttributes: [ modelAttribute ]\n\t} );\n\tupcastStyleToAttribute( conversion, 'tableCell', modelAttribute, styleName );\n\tdowncastAttributeToStyle( conversion, 'tableCell', modelAttribute, styleName );\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 heading/headingbuttonsui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport { getLocalizedOptions } from './utils';\nimport iconHeading1 from '../theme/icons/heading1.svg';\nimport iconHeading2 from '../theme/icons/heading2.svg';\nimport iconHeading3 from '../theme/icons/heading3.svg';\nimport iconHeading4 from '../theme/icons/heading4.svg';\nimport iconHeading5 from '../theme/icons/heading5.svg';\nimport iconHeading6 from '../theme/icons/heading6.svg';\n\nconst defaultIcons = {\n\theading1: iconHeading1,\n\theading2: iconHeading2,\n\theading3: iconHeading3,\n\theading4: iconHeading4,\n\theading5: iconHeading5,\n\theading6: iconHeading6\n};\n\n/**\n * The `HeadingButtonsUI` plugin defines a set of UI buttons that can be used instead of the\n * standard drop down component.\n *\n * This feature is not enabled by default by the {@link module:heading/heading~Heading} plugin and needs to be\n * installed manually to the editor configuration.\n *\n * Plugin introduces button UI elements, which names are same as `model` property from {@link module:heading/heading~HeadingOption}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n *\t\t\t\tplugins: [ ..., Heading, Paragraph, HeadingButtonsUI, ParagraphButtonUI ]\n *\t\t\t\theading: {\n *\t\t\t\t\toptions: [\n *\t\t\t\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n *\t\t\t\t\t\t{ model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },\n *\t\t\t\t\t\t{ model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },\n *\t\t\t\t\t\t{ model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }\n *\t\t\t\t\t]\n * \t\t\t\t},\n * \t\t\t\ttoolbar: [ 'paragraph', 'heading1', 'heading2', 'heading3' ]\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * NOTE: The `'paragraph'` button is defined in by the {@link module:paragraph/paragraphbuttonui~ParagraphButtonUI} plugin\n * which needs to be loaded manually as well.\n *\n * It is possible to use custom icons by providing `icon` config option in {@link module:heading/heading~HeadingOption}.\n * For the default configuration standard icons are used.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HeadingButtonsUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst options = getLocalizedOptions( this.editor );\n\n\t\toptions\n\t\t\t.filter( item => item.model !== 'paragraph' )\n\t\t\t.map( item => this._createButton( item ) );\n\t}\n\n\t/**\n\t * Creates single button view from provided configuration option.\n\t *\n\t * @private\n\t * @param {Object} option\n\t */\n\t_createButton( option ) {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( option.model, locale => {\n\t\t\tconst view = new ButtonView( locale );\n\t\t\tconst command = editor.commands.get( 'heading' );\n\n\t\t\tview.label = option.title;\n\t\t\tview.icon = option.icon || defaultIcons[ option.model ];\n\t\t\tview.tooltip = true;\n\t\t\tview.isToggleable = true;\n\t\t\tview.bind( 'isEnabled' ).to( command );\n\t\t\tview.bind( 'isOn' ).to( command, 'value', value => value == option.model );\n\n\t\t\tview.on( 'execute', () => {\n\t\t\t\teditor.execute( 'heading', { value: option.model } );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M19 9v10h-2v-8h-2V9h4zM4 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1H10a1 1 0 0 1-1-1V11H4v4.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1H3a1 1 0 0 1 1 1v4.5z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V11H3v4.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1H2a1 1 0 0 1 1 1v4.5zm16.076 8.343V18.5h-6.252c.067-.626.27-1.22.61-1.78.338-.561 1.006-1.305 2.005-2.232.804-.749 1.297-1.257 1.479-1.523.245-.368.368-.732.368-1.092 0-.398-.107-.703-.32-.917-.214-.214-.51-.32-.886-.32-.372 0-.669.111-.889.336-.22.224-.347.596-.38 1.117l-1.778-.178c.106-.982.438-1.686.997-2.114.558-.427 1.257-.64 2.095-.64.918 0 1.64.247 2.164.742.525.495.787 1.11.787 1.847 0 .419-.075.818-.225 1.197-.15.378-.388.775-.714 1.19-.216.275-.605.67-1.168 1.187-.563.516-.92.859-1.07 1.028a3.11 3.11 0 0 0-.365.495h3.542z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V11H3v4.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1H2a1 1 0 0 1 1 1v4.5zm9.989 7.53 1.726-.209c.055.44.203.777.445 1.01.24.232.533.349.876.349.368 0 .678-.14.93-.42.251-.279.377-.655.377-1.13 0-.448-.12-.803-.362-1.066a1.153 1.153 0 0 0-.882-.393c-.228 0-.501.044-.819.133l.197-1.453c.482.012.85-.092 1.105-.315.253-.222.38-.517.38-.885 0-.313-.093-.563-.279-.75-.186-.185-.434-.278-.743-.278a1.07 1.07 0 0 0-.78.317c-.216.212-.347.52-.394.927l-1.644-.28c.114-.562.287-1.012.517-1.348.231-.337.553-.601.965-.794a3.24 3.24 0 0 1 1.387-.289c.876 0 1.579.28 2.108.838.436.457.653.973.653 1.549 0 .817-.446 1.468-1.339 1.955.533.114.96.37 1.28.768.319.398.478.878.478 1.441 0 .817-.298 1.513-.895 2.088-.596.576-1.339.864-2.228.864-.842 0-1.54-.243-2.094-.727-.555-.485-.876-1.118-.965-1.901z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3.5 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V11h-5v4.5a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v4.5zm13.55 10v-1.873h-3.81v-1.561l4.037-5.91h1.498v5.904h1.156v1.567h-1.156V18.5H17.05zm0-3.44v-3.18l-2.14 3.18h2.14z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3.5 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V11h-5v4.5a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v4.5zm9.578 7.607 1.777-.184c.05.402.201.72.45.955a1.223 1.223 0 0 0 1.81-.101c.258-.303.387-.759.387-1.368 0-.572-.128-1-.384-1.286-.256-.285-.59-.428-1-.428-.512 0-.971.226-1.377.679l-1.448-.21.915-4.843h4.716v1.67H15.56l-.28 1.58a2.697 2.697 0 0 1 1.219-.298 2.68 2.68 0 0 1 2.012.863c.55.576.825 1.323.825 2.241a3.36 3.36 0 0 1-.666 2.05c-.605.821-1.445 1.232-2.52 1.232-.86 0-1.56-.23-2.101-.692-.542-.461-.866-1.081-.971-1.86z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M3.5 8.5h5V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v11.5a1 1 0 0 1-1 1h-.5a1 1 0 0 1-1-1V11h-5v4.5a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h.5a1 1 0 0 1 1 1v4.5zm15.595 2.973-1.726.19c-.043-.355-.153-.617-.33-.787-.178-.169-.409-.253-.692-.253-.377 0-.695.169-.956.507-.26.339-.424 1.043-.492 2.114.445-.525.997-.787 1.657-.787.745 0 1.383.284 1.914.85.531.568.797 1.3.797 2.197 0 .952-.28 1.716-.838 2.291-.559.576-1.276.864-2.152.864-.94 0-1.712-.365-2.317-1.095-.605-.73-.908-1.927-.908-3.59 0-1.705.316-2.935.946-3.688.63-.753 1.45-1.13 2.457-1.13.706 0 1.291.198 1.755.594.463.395.758.97.885 1.723zm-4.043 3.891c0 .58.133 1.028.4 1.343.266.315.57.473.914.473.33 0 .605-.13.825-.388.22-.258.33-.68.33-1.27 0-.604-.118-1.047-.355-1.329a1.115 1.115 0 0 0-.89-.422c-.342 0-.632.134-.869.403s-.355.666-.355 1.19z\\\"/></svg>\";","/**\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 font/fontcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\n/**\n * The base font command.\n *\n * @extends module:core/command~Command\n */\nexport default class FontCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor Editor instance.\n\t * @param {String} attributeKey The name of a model attribute on which this command operates.\n\t */\n\tconstructor( editor, attributeKey ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * When set, it reflects the {@link #attributeKey} value of the selection.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {String} module:font/fontcommand~FontCommand#value\n\t\t */\n\n\t\t/**\n\t\t * A model attribute on which this command operates.\n\t\t *\n\t\t * @readonly\n\t\t * @member {Boolean} module:font/fontcommand~FontCommand#attributeKey\n\t\t */\n\t\tthis.attributeKey = attributeKey;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.value = doc.selection.getAttribute( this.attributeKey );\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, this.attributeKey );\n\t}\n\n\t/**\n\t * Executes the command. Applies the `value` of the {@link #attributeKey} to the selection.\n\t * If no `value` is passed, it removes the attribute from the selection.\n\t *\n\t * @protected\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {String} [options.value] The value to apply.\n\t * @fires execute\n\t */\n\texecute( options = {} ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst value = options.value;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( selection.isCollapsed ) {\n\t\t\t\tif ( value ) {\n\t\t\t\t\twriter.setSelectionAttribute( this.attributeKey, value );\n\t\t\t\t} else {\n\t\t\t\t\twriter.removeSelectionAttribute( this.attributeKey );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst ranges = model.schema.getValidRanges( selection.getRanges(), this.attributeKey );\n\n\t\t\t\tfor ( const range of ranges ) {\n\t\t\t\t\tif ( value ) {\n\t\t\t\t\t\twriter.setAttribute( this.attributeKey, value, range );\n\t\t\t\t\t} else {\n\t\t\t\t\t\twriter.removeAttribute( this.attributeKey, range );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/documentcolorcollection\n */\n\nimport { Collection, ObservableMixin, mix } from 'ckeditor5/src/utils';\n\n/**\n * A collection to store document colors. It enforces colors to be unique.\n *\n * @mixes module:utils/observablemixin~ObservableMixin\n * @extends module:utils/collection~Collection\n */\nexport default class DocumentColorCollection extends Collection {\n\tconstructor( options ) {\n\t\tsuper( options );\n\n\t\t/**\n\t\t * Indicates whether the document color collection is empty.\n\t\t *\n\t\t * @observable\n\t\t * @readonly\n\t\t * @member {Boolean} #isEmpty\n\t\t */\n\t\tthis.set( 'isEmpty', true );\n\n\t\tthis.on( 'change', () => {\n\t\t\tthis.set( 'isEmpty', this.length === 0 );\n\t\t} );\n\t}\n\n\t/**\n\t * Adds a color to the document color collection.\n\t *\n\t * This method ensures that no color duplicates are inserted (compared using\n\t * the color value of the {@link module:ui/colorgrid/colorgrid~ColorDefinition}).\n\t *\n\t * If the item does not have an ID, it will be automatically generated and set on the item.\n\t *\n\t * @chainable\n\t * @param {module:ui/colorgrid/colorgrid~ColorDefinition} item\n\t * @param {Number} [index] The position of the item in the collection. The item\n\t * is pushed to the collection when `index` is not specified.\n\t * @fires add\n\t * @fires change\n\t */\n\tadd( item, index ) {\n\t\tif ( this.find( element => element.color === item.color ) ) {\n\t\t\t// No duplicates are allowed.\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.add( item, index );\n\t}\n\n\t/**\n\t * Checks if an object with given colors is present in the document color collection.\n\t *\n\t * @param {String} color\n\t * @returns {Boolean}\n\t */\n\thasColor( color ) {\n\t\treturn !!this.find( item => item.color === color );\n\t}\n}\n\nmix( DocumentColorCollection, ObservableMixin );\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 font/ui/colortableview\n */\n\nimport { icons } from 'ckeditor5/src/core';\nimport { ButtonView, ColorGridView, ColorTileView, FocusCycler, LabelView, Template, View } from 'ckeditor5/src/ui';\nimport { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils';\n\nimport DocumentColorCollection from '../documentcolorcollection';\n\nimport '../../theme/fontcolor.css';\n\n/**\n * A class which represents a view with the following subcomponents:\n *\n * * A remove color button,\n * * A static {@link module:ui/colorgrid/colorgrid~ColorGridView} of colors defined in the configuration,\n * * A dynamic {@link module:ui/colorgrid/colorgrid~ColorGridView} of colors used in the document.\n *\n * @extends module:ui/view~View\n */\nexport default class ColorTableView extends View {\n\t/**\n\t * Creates a view to be inserted as a child of {@link module:ui/dropdown/dropdownview~DropdownView}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {Object} config The configuration object.\n\t * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} config.colors An array with definitions of colors to\n\t * be displayed in the table.\n\t * @param {Number} config.columns The number of columns in the color grid.\n\t * @param {String} config.removeButtonLabel The label of the button responsible for removing the color.\n\t * @param {String} config.documentColorsLabel The label for the section with the document colors.\n\t * @param {String} config.documentColorsCount The number of colors in the document colors section inside the color dropdown.\n\t */\n\tconstructor( locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount } ) {\n\t\tsuper( locale );\n\n\t\t/**\n\t\t * A collection of the children of the table.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/viewcollection~ViewCollection}\n\t\t */\n\t\tthis.items = this.createCollection();\n\n\t\t/**\n\t\t * An array with objects representing colors to be displayed in the grid.\n\t\t *\n\t\t * @type {Arrray.<module:ui/colorgrid/colorgrid~ColorDefinition>}\n\t\t */\n\t\tthis.colorDefinitions = colors;\n\n\t\t/**\n\t\t * Tracks information about the DOM focus in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/focustracker~FocusTracker}\n\t\t */\n\t\tthis.focusTracker = new FocusTracker();\n\n\t\t/**\n\t\t * An instance of the {@link module:utils/keystrokehandler~KeystrokeHandler}.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:utils/keystrokehandler~KeystrokeHandler}\n\t\t */\n\t\tthis.keystrokes = new KeystrokeHandler();\n\n\t\t/**\n\t\t * Keeps the value of the command associated with the table for the current selection.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.set( 'selectedColor' );\n\n\t\t/**\n\t\t * The label of the button responsible for removing color attributes.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.removeButtonLabel = removeButtonLabel;\n\n\t\t/**\n\t\t * The number of columns in the color grid.\n\t\t *\n\t\t * @type {Number}\n\t\t */\n\t\tthis.columns = columns;\n\n\t\t/**\n\t\t * A collection of definitions that store the document colors.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:font/documentcolorcollection~DocumentColorCollection}\n\t\t */\n\t\tthis.documentColors = new DocumentColorCollection();\n\n\t\t/**\n\t\t * The maximum number of colors in the document colors section.\n\t\t * If it equals 0, the document colors section is not added.\n\t\t *\n\t\t * @readonly\n\t\t * @type {Number}\n\t\t */\n\t\tthis.documentColorsCount = documentColorsCount;\n\n\t\t/**\n\t\t * Preserves the reference to {@link module:ui/colorgrid/colorgrid~ColorGridView} used to create\n\t\t * the default (static) color set.\n\t\t *\n\t\t * The property is loaded once the the parent dropdown is opened the first time.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/colorgrid/colorgrid~ColorGridView|undefined} #staticColorsGrid\n\t\t */\n\n\t\t/**\n\t\t * Preserves the reference to {@link module:ui/colorgrid/colorgrid~ColorGridView} used to create\n\t\t * the document colors. It remains undefined if the document colors feature is disabled.\n\t\t *\n\t\t * The property is loaded once the the parent dropdown is opened the first time.\n\t\t *\n\t\t * @readonly\n\t\t * @member {module:ui/colorgrid/colorgrid~ColorGridView|undefined} #documentColorsGrid\n\t\t */\n\n\t\t/**\n\t\t * Helps cycling over focusable {@link #items} in the list.\n\t\t *\n\t\t * @readonly\n\t\t * @protected\n\t\t * @member {module:ui/focuscycler~FocusCycler}\n\t\t */\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this.items,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\t// Navigate list items backwards using the Arrow Up key.\n\t\t\t\tfocusPrevious: 'arrowup',\n\n\t\t\t\t// Navigate list items forwards using the Arrow Down key.\n\t\t\t\tfocusNext: 'arrowdown'\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Document color section's label.\n\t\t *\n\t\t * @private\n\t\t * @readonly\n\t\t * @type {String}\n\t\t */\n\t\tthis._documentColorsLabel = documentColorsLabel;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-color-table'\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: this.items\n\t\t} );\n\n\t\tthis.items.add( this._removeColorButton() );\n\t}\n\n\t/**\n\t * Scans through the editor model and searches for text node attributes with the given attribute name.\n\t * Found entries are set as document colors.\n\t *\n\t * All the previously stored document colors will be lost in the process.\n\t *\n\t * @param {module:engine/model/model~Model} model The model used as a source to obtain the document colors.\n\t * @param {String} attributeName Determines the name of the related model's attribute for a given dropdown.\n\t */\n\tupdateDocumentColors( model, attributeName ) {\n\t\tconst document = model.document;\n\t\tconst maxCount = this.documentColorsCount;\n\n\t\tthis.documentColors.clear();\n\n\t\tfor ( const rootName of document.getRootNames() ) {\n\t\t\tconst root = document.getRoot( rootName );\n\t\t\tconst range = model.createRangeIn( root );\n\n\t\t\tfor ( const node of range.getItems() ) {\n\t\t\t\tif ( node.is( '$textProxy' ) && node.hasAttribute( attributeName ) ) {\n\t\t\t\t\tthis._addColorToDocumentColors( node.getAttribute( attributeName ) );\n\n\t\t\t\t\tif ( this.documentColors.length >= maxCount ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Refreshes the state of the selected color in one or both {@link module:ui/colorgrid/colorgrid~ColorGridView}s\n\t * available in the {@link module:font/ui/colortableview~ColorTableView}. It guarantees that the selection will occur only in one\n\t * of them.\n\t */\n\tupdateSelectedColors() {\n\t\tconst documentColorsGrid = this.documentColorsGrid;\n\t\tconst staticColorsGrid = this.staticColorsGrid;\n\t\tconst selectedColor = this.selectedColor;\n\n\t\tstaticColorsGrid.selectedColor = selectedColor;\n\n\t\tif ( documentColorsGrid ) {\n\t\t\tdocumentColorsGrid.selectedColor = selectedColor;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\t// Items added before rendering should be known to the #focusTracker.\n\t\tfor ( const item of this.items ) {\n\t\t\tthis.focusTracker.add( item.element );\n\t\t}\n\n\t\t// Start listening for the keystrokes coming from #element.\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\t/**\n\t * Appends {@link #staticColorsGrid} and {@link #documentColorsGrid} views.\n\t */\n\tappendGrids() {\n\t\tif ( this.staticColorsGrid ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.staticColorsGrid = this._createStaticColorsGrid();\n\n\t\tthis.items.add( this.staticColorsGrid );\n\n\t\tif ( this.documentColorsCount ) {\n\t\t\t// Create a label for document colors.\n\t\t\tconst bind = Template.bind( this.documentColors, this.documentColors );\n\t\t\tconst label = new LabelView( this.locale );\n\t\t\tlabel.text = this._documentColorsLabel;\n\t\t\tlabel.extendTemplate( {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck',\n\t\t\t\t\t\t'ck-color-grid__label',\n\t\t\t\t\t\tbind.if( 'isEmpty', 'ck-hidden' )\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\t\t\tthis.items.add( label );\n\t\t\tthis.documentColorsGrid = this._createDocumentColorsGrid();\n\t\t\tthis.items.add( this.documentColorsGrid );\n\t\t}\n\t}\n\n\t/**\n\t * Focuses the first focusable element in {@link #items}.\n\t */\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\t/**\n\t * Focuses the last focusable element in {@link #items}.\n\t */\n\tfocusLast() {\n\t\tthis._focusCycler.focusLast();\n\t}\n\n\t/**\n\t * Adds the remove color button as a child of the current view.\n\t *\n\t * @private\n\t * @returns {module:ui/button/buttonview~ButtonView}\n\t */\n\t_removeColorButton() {\n\t\tconst buttonView = new ButtonView();\n\n\t\tbuttonView.set( {\n\t\t\twithText: true,\n\t\t\ticon: icons.eraser,\n\t\t\ttooltip: true,\n\t\t\tlabel: this.removeButtonLabel\n\t\t} );\n\n\t\tbuttonView.class = 'ck-color-table__remove-color';\n\t\tbuttonView.on( 'execute', () => {\n\t\t\tthis.fire( 'execute', { value: null } );\n\t\t} );\n\n\t\treturn buttonView;\n\t}\n\n\t/**\n\t * Creates a static color table grid based on the editor configuration.\n\t *\n\t * @private\n\t * @returns {module:ui/colorgrid/colorgrid~ColorGridView}\n\t */\n\t_createStaticColorsGrid() {\n\t\tconst colorGrid = new ColorGridView( this.locale, {\n\t\t\tcolorDefinitions: this.colorDefinitions,\n\t\t\tcolumns: this.columns\n\t\t} );\n\n\t\tcolorGrid.delegate( 'execute' ).to( this );\n\n\t\treturn colorGrid;\n\t}\n\n\t/**\n\t * Creates the document colors section view and binds it to {@link #documentColors}.\n\t *\n\t * @private\n\t * @returns {module:ui/colorgrid/colorgrid~ColorGridView}\n\t */\n\t_createDocumentColorsGrid() {\n\t\tconst bind = Template.bind( this.documentColors, this.documentColors );\n\t\tconst documentColorsGrid = new ColorGridView( this.locale, {\n\t\t\tcolumns: this.columns\n\t\t} );\n\n\t\tdocumentColorsGrid.delegate( 'execute' ).to( this );\n\n\t\tdocumentColorsGrid.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: bind.if( 'isEmpty', 'ck-hidden' )\n\t\t\t}\n\t\t} );\n\n\t\tdocumentColorsGrid.items.bindTo( this.documentColors ).using(\n\t\t\tcolorObj => {\n\t\t\t\tconst colorTile = new ColorTileView();\n\n\t\t\t\tcolorTile.set( {\n\t\t\t\t\tcolor: colorObj.color,\n\t\t\t\t\thasBorder: colorObj.options && colorObj.options.hasBorder\n\t\t\t\t} );\n\n\t\t\t\tif ( colorObj.label ) {\n\t\t\t\t\tcolorTile.set( {\n\t\t\t\t\t\tlabel: colorObj.label,\n\t\t\t\t\t\ttooltip: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tcolorTile.on( 'execute', () => {\n\t\t\t\t\tthis.fire( 'execute', {\n\t\t\t\t\t\tvalue: colorObj.color\n\t\t\t\t\t} );\n\t\t\t\t} );\n\n\t\t\t\treturn colorTile;\n\t\t\t}\n\t\t);\n\n\t\t// Selected color should be cleared when document colors became empty.\n\t\tthis.documentColors.on( 'change:isEmpty', ( evt, name, val ) => {\n\t\t\tif ( val ) {\n\t\t\t\tdocumentColorsGrid.selectedColor = null;\n\t\t\t}\n\t\t} );\n\n\t\treturn documentColorsGrid;\n\t}\n\n\t/**\n\t * Adds a given color to the document colors list. If possible, the method will attempt to use\n\t * data from the {@link #colorDefinitions} (label, color options).\n\t *\n\t * @private\n\t * @param {String} color A string that stores the value of the recently applied color.\n\t */\n\t_addColorToDocumentColors( color ) {\n\t\tconst predefinedColor = this.colorDefinitions\n\t\t\t.find( definition => definition.color === color );\n\n\t\tif ( !predefinedColor ) {\n\t\t\tthis.documentColors.add( {\n\t\t\t\tcolor,\n\t\t\t\tlabel: color,\n\t\t\t\toptions: {\n\t\t\t\t\thasBorder: false\n\t\t\t\t}\n\t\t\t} );\n\t\t} else {\n\t\t\tthis.documentColors.add( Object.assign( {}, predefinedColor ) );\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/utils\n */\n\nimport ColorTableView from './ui/colortableview';\n\n/**\n * The name of the font size plugin.\n */\nexport const FONT_SIZE = 'fontSize';\n\n/**\n * The name of the font family plugin.\n */\nexport const FONT_FAMILY = 'fontFamily';\n\n/**\n * The name of the font color plugin.\n */\nexport const FONT_COLOR = 'fontColor';\n\n/**\n * The name of the font background color plugin.\n */\nexport const FONT_BACKGROUND_COLOR = 'fontBackgroundColor';\n\n/**\n * Builds a proper {@link module:engine/conversion/conversion~ConverterDefinition converter definition} out of input data.\n *\n * @param {String} modelAttributeKey Key\n * @param {Array.<module:font/fontfamily~FontFamilyOption>|Array.<module:font/fontsize~FontSizeOption>} options\n * @returns {module:engine/conversion/conversion~ConverterDefinition}\n */\nexport function buildDefinition( modelAttributeKey, options ) {\n\tconst definition = {\n\t\tmodel: {\n\t\t\tkey: modelAttributeKey,\n\t\t\tvalues: []\n\t\t},\n\t\tview: {},\n\t\tupcastAlso: {}\n\t};\n\n\tfor ( const option of options ) {\n\t\tdefinition.model.values.push( option.model );\n\t\tdefinition.view[ option.model ] = option.view;\n\n\t\tif ( option.upcastAlso ) {\n\t\t\tdefinition.upcastAlso[ option.model ] = option.upcastAlso;\n\t\t}\n\t}\n\n\treturn definition;\n}\n\n/**\n * A {@link module:font/fontcolor~FontColor font color} and\n * {@link module:font/fontbackgroundcolor~FontBackgroundColor font background color} helper\n * responsible for upcasting data to the model.\n *\n * **Note**: The `styleAttr` parameter should be either `'color'` or `'background-color'`.\n *\n * @param {String} styleAttr\n * @return {String}\n */\nexport function renderUpcastAttribute( styleAttr ) {\n\treturn viewElement => normalizeColorCode( viewElement.getStyle( styleAttr ) );\n}\n\n/**\n * A {@link module:font/fontcolor~FontColor font color} and\n * {@link module:font/fontbackgroundcolor~FontBackgroundColor font background color} helper\n * responsible for downcasting a color attribute to a `<span>` element.\n *\n * **Note**: The `styleAttr` parameter should be either `'color'` or `'background-color'`.\n *\n * @param {String} styleAttr\n */\nexport function renderDowncastElement( styleAttr ) {\n\treturn ( modelAttributeValue, { writer } ) => writer.createAttributeElement( 'span', {\n\t\tstyle: `${ styleAttr }:${ modelAttributeValue }`\n\t}, { priority: 7 } );\n}\n\n/**\n * A helper that adds {@link module:font/ui/colortableview~ColorTableView} to the color dropdown with proper initial values.\n *\n * @param {Object} config The configuration object.\n * @param {module:ui/dropdown/dropdownview~DropdownView} config.dropdownView The dropdown view to which\n * a {@link module:font/ui/colortableview~ColorTableView} will be added.\n * @param {Array.<module:ui/colorgrid/colorgrid~ColorDefinition>} config.colors An array with definitions\n * representing colors to be displayed in the color table.\n * @param {String} config.removeButtonLabel The label for the button responsible for removing the color.\n * @param {String} config.documentColorsLabel The label for the section with document colors.\n * @param {String} config.documentColorsCount The number of document colors inside the dropdown.\n * @returns {module:font/ui/colortableview~ColorTableView} The new color table view.\n */\nexport function addColorTableToDropdown( { dropdownView, colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount } ) {\n\tconst locale = dropdownView.locale;\n\tconst colorTableView = new ColorTableView( locale, { colors, columns, removeButtonLabel, documentColorsLabel, documentColorsCount } );\n\n\tdropdownView.colorTableView = colorTableView;\n\tdropdownView.panelView.children.add( colorTableView );\n\n\tcolorTableView.delegate( 'execute' ).to( dropdownView, 'execute' );\n\n\treturn colorTableView;\n}\n\n// Fixes the color value string.\n//\n// @param {String} value\n// @returns {String}\nfunction normalizeColorCode( value ) {\n\treturn value.replace( /\\s/g, '' );\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 font/fontfamily/fontfamilycommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_FAMILY } from '../utils';\n\n/**\n * The font family command. It is used by {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing}\n * to apply the font family.\n *\n *\t\teditor.execute( 'fontFamily', { value: 'Arial' } );\n *\n * **Note**: Executing the command without the value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontFamilyCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_FAMILY );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontfamily/utils\n */\n\n/**\n * Normalizes the {@link module:font/fontfamily~FontFamilyConfig#options configuration options}\n * to the {@link module:font/fontfamily~FontFamilyOption} format.\n *\n * @param {Array.<String|Object>} configuredOptions An array of options taken from the configuration.\n * @returns {Array.<module:font/fontfamily~FontFamilyOption>}\n */\nexport function normalizeOptions( configuredOptions ) {\n\t// Convert options to objects.\n\treturn configuredOptions\n\t\t.map( getOptionDefinition )\n\t\t// Filter out undefined values that `getOptionDefinition` might return.\n\t\t.filter( option => !!option );\n}\n\n// Returns an option definition either created from string shortcut.\n// If object is passed then this method will return it without alternating it. Returns undefined for item than cannot be parsed.\n//\n// @param {String|Object} option\n// @returns {undefined|module:font/fontfamily~FontFamilyOption}\nfunction getOptionDefinition( option ) {\n\t// Treat any object as full item definition provided by user in configuration.\n\tif ( typeof option === 'object' ) {\n\t\treturn option;\n\t}\n\n\t// Handle 'default' string as a special case. It will be used to remove the fontFamily attribute.\n\tif ( option === 'default' ) {\n\t\treturn {\n\t\t\ttitle: 'Default',\n\t\t\tmodel: undefined\n\t\t};\n\t}\n\n\t// Ignore values that we cannot parse to a definition.\n\tif ( typeof option !== 'string' ) {\n\t\treturn;\n\t}\n\n\t// Return font family definition from font string.\n\treturn generateFontPreset( option );\n}\n\n// Creates a predefined preset for pixel size. It deconstructs font-family like string into full configuration option.\n// A font definition is passed as coma delimited set of font family names. Font names might be quoted.\n//\n// @param {String} A font definition form configuration.\nfunction generateFontPreset( fontDefinition ) {\n\t// Remove quotes from font names. They will be normalized later.\n\tconst fontNames = fontDefinition.replace( /\"|'/g, '' ).split( ',' );\n\n\t// The first matched font name will be used as dropdown list item title and as model value.\n\tconst firstFontName = fontNames[ 0 ];\n\n\t// CSS-compatible font names.\n\tconst cssFontNames = fontNames.map( normalizeFontNameForCSS ).join( ', ' );\n\n\treturn {\n\t\ttitle: firstFontName,\n\t\tmodel: cssFontNames,\n\t\tview: {\n\t\t\tname: 'span',\n\t\t\tstyles: {\n\t\t\t\t'font-family': cssFontNames\n\t\t\t},\n\t\t\tpriority: 7\n\t\t}\n\t};\n}\n\n// Normalizes font name for the style attribute. It adds braces (') if font name contains spaces.\n//\n// @param {String} fontName\n// @returns {String}\nfunction normalizeFontNameForCSS( fontName ) {\n\tfontName = fontName.trim();\n\n\t// Compound font names should be quoted.\n\tif ( fontName.indexOf( ' ' ) > 0 ) {\n\t\tfontName = `'${ fontName }'`;\n\t}\n\n\treturn fontName;\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 font/fontfamily/fontfamilyediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport FontFamilyCommand from './fontfamilycommand';\nimport { normalizeOptions } from './utils';\nimport { buildDefinition, FONT_FAMILY } from '../utils';\n\n/**\n * The font family editing feature.\n *\n * It introduces the {@link module:font/fontfamily/fontfamilycommand~FontFamilyCommand command} and\n * the `fontFamily` attribute in the {@link module:engine/model/model~Model model} which renders\n * in the {@link module:engine/view/view view} as an inline `<span>` element (`<span style=\"font-family: Arial\">`),\n * depending on the {@link module:font/fontfamily~FontFamilyConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontFamilyEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontFamilyEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t// Define default configuration using font families shortcuts.\n\t\teditor.config.define( FONT_FAMILY, {\n\t\t\toptions: [\n\t\t\t\t'default',\n\t\t\t\t'Arial, Helvetica, sans-serif',\n\t\t\t\t'Courier New, Courier, monospace',\n\t\t\t\t'Georgia, serif',\n\t\t\t\t'Lucida Sans Unicode, Lucida Grande, sans-serif',\n\t\t\t\t'Tahoma, Geneva, sans-serif',\n\t\t\t\t'Times New Roman, Times, serif',\n\t\t\t\t'Trebuchet MS, Helvetica, sans-serif',\n\t\t\t\t'Verdana, Geneva, sans-serif'\n\t\t\t],\n\t\t\tsupportAllValues: false\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow fontFamily attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_FAMILY } );\n\t\teditor.model.schema.setAttributeProperties( FONT_FAMILY, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\t// Get configured font family options without \"default\" option.\n\t\tconst options = normalizeOptions( editor.config.get( 'fontFamily.options' ) ).filter( item => item.model );\n\t\tconst definition = buildDefinition( FONT_FAMILY, options );\n\n\t\t// Set-up the two-way conversion.\n\t\tif ( editor.config.get( 'fontFamily.supportAllValues' ) ) {\n\t\t\tthis._prepareAnyValueConverters();\n\t\t\tthis._prepareCompatibilityConverter();\n\t\t} else {\n\t\t\teditor.conversion.attributeToElement( definition );\n\t\t}\n\n\t\teditor.commands.add( FONT_FAMILY, new FontFamilyCommand( editor ) );\n\t}\n\n\t/**\n\t * These converters enable keeping any value found as `style=\"font-family: *\"` as a value of an attribute on a text even\n\t * if it is not defined in the plugin configuration.\n\t *\n\t * @private\n\t */\n\t_prepareAnyValueConverters() {\n\t\tconst editor = this.editor;\n\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: FONT_FAMILY,\n\t\t\tview: ( attributeValue, { writer } ) => {\n\t\t\t\treturn writer.createAttributeElement( 'span', { style: 'font-family:' + attributeValue }, { priority: 7 } );\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_FAMILY,\n\t\t\t\tvalue: viewElement => viewElement.getStyle( 'font-family' )\n\t\t\t},\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\t'font-family': /.*/\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Adds support for legacy `<font face=\"..\">` formatting.\n\t *\n\t * @private\n\t */\n\t_prepareCompatibilityConverter() {\n\t\tconst editor = this.editor;\n\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'font',\n\t\t\t\tattributes: {\n\t\t\t\t\t'face': /.*/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_FAMILY,\n\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'face' )\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontfamily/fontfamilyui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Collection } from 'ckeditor5/src/utils';\nimport { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui';\n\nimport { normalizeOptions } from './utils';\nimport { FONT_FAMILY } from '../utils';\n\nimport fontFamilyIcon from '../../theme/icons/font-family.svg';\n\n/**\n * The font family UI plugin. It introduces the `'fontFamily'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontFamilyUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontFamilyUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\tconst options = this._getLocalizedOptions();\n\n\t\tconst command = editor.commands.get( FONT_FAMILY );\n\n\t\t// Register UI component.\n\t\teditor.ui.componentFactory.add( FONT_FAMILY, locale => {\n\t\t\tconst dropdownView = createDropdown( locale );\n\t\t\taddListToDropdown( dropdownView, _prepareListOptions( options, command ) );\n\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\tlabel: t( 'Font Family' ),\n\t\t\t\ticon: fontFamilyIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tdropdownView.extendTemplate( {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: 'ck-font-family-dropdown'\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).to( command );\n\n\t\t\t// Execute command when an item from the dropdown is selected.\n\t\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\t\teditor.execute( evt.source.commandName, { value: evt.source.commandParam } );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\t}\n\n\t/**\n\t * Returns options as defined in `config.fontFamily.options` but processed to account for\n\t * editor localization, i.e. to display {@link module:font/fontfamily~FontFamilyOption}\n\t * in the correct language.\n\t *\n\t * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n\t * when the user configuration is defined because the editor does not exist yet.\n\t *\n\t * @private\n\t * @returns {Array.<module:font/fontfamily~FontFamilyOption>}.\n\t */\n\t_getLocalizedOptions() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\tconst options = normalizeOptions( editor.config.get( FONT_FAMILY ).options );\n\n\t\treturn options.map( option => {\n\t\t\t// The only title to localize is \"Default\" others are font names.\n\t\t\tif ( option.title === 'Default' ) {\n\t\t\t\toption.title = t( 'Default' );\n\t\t\t}\n\n\t\t\treturn option;\n\t\t} );\n\t}\n}\n\n// Prepares FontFamily dropdown items.\n// @private\n// @param {Array.<module:font/fontsize~FontSizeOption>} options\n// @param {module:font/fontsize/fontsizecommand~FontSizeCommand} command\nfunction _prepareListOptions( options, command ) {\n\tconst itemDefinitions = new Collection();\n\n\t// Create dropdown items.\n\tfor ( const option of options ) {\n\t\tconst def = {\n\t\t\ttype: 'button',\n\t\t\tmodel: new Model( {\n\t\t\t\tcommandName: FONT_FAMILY,\n\t\t\t\tcommandParam: option.model,\n\t\t\t\tlabel: option.title,\n\t\t\t\twithText: true\n\t\t\t} )\n\t\t};\n\n\t\tdef.model.bind( 'isOn' ).to( command, 'value', value => {\n\t\t\t// \"Default\" or check in strict font-family converters mode.\n\t\t\tif ( value === option.model ) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif ( !value || !option.model ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn value.split( ',' )[ 0 ].replace( /'/g, '' ).toLowerCase() === option.model.toLowerCase();\n\t\t} );\n\n\t\t// Try to set a dropdown list item style.\n\t\tif ( option.view && option.view.styles ) {\n\t\t\tdef.model.set( 'labelStyle', `font-family: ${ option.view.styles[ 'font-family' ] }` );\n\t\t}\n\n\t\titemDefinitions.add( def );\n\t}\n\treturn itemDefinitions;\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M11.03 3h6.149a.75.75 0 1 1 0 1.5h-5.514L11.03 3zm1.27 3h4.879a.75.75 0 1 1 0 1.5h-4.244L12.3 6zm1.27 3h3.609a.75.75 0 1 1 0 1.5h-2.973L13.57 9zm-2.754 2.5L8.038 4.785 5.261 11.5h5.555zm.62 1.5H4.641l-1.666 4.028H1.312l5.789-14h1.875l5.789 14h-1.663L11.436 13z\\\"/></svg>\";","/**\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 font/fontfamily\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport FontFamilyEditing from './fontfamily/fontfamilyediting';\nimport FontFamilyUI from './fontfamily/fontfamilyui';\n\n/**\n * The font family plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentatiom\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} and\n * {@link module:font/fontfamily/fontfamilyui~FontFamilyUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontFamily extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontFamilyEditing, FontFamilyUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontFamily';\n\t}\n}\n\n/**\n * The font family option descriptor.\n *\n * @typedef {Object} module:font/fontfamily~FontFamilyOption\n *\n * @property {String} title The user-readable title of the option.\n * @property {String} model The attribute's unique value in the model.\n * @property {module:engine/view/elementdefinition~ElementDefinition} view View element configuration.\n * @property {Array.<module:engine/view/elementdefinition~ElementDefinition>} [upcastAlso] An array with all matched elements that\n * the view-to-model conversion should also accept.\n */\n\n/**\n * The configuration of the font family feature.\n * It is introduced by the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} feature.\n *\n * Read more in {@link module:font/fontfamily~FontFamilyConfig}.\n *\n * @member {module:font/fontfamily~FontFamilyConfig} module:core/editor/editorconfig~EditorConfig#fontFamily\n */\n\n/**\n * The configuration of the font family feature.\n * This option is used by the {@link module:font/fontfamily/fontfamilyediting~FontFamilyEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n * \t\t\t\tfontFamily: ... // Font family feature configuration.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface module:font/fontfamily~FontFamilyConfig\n */\n\n/**\n * Available font family options defined as an array of strings. The default value is:\n *\n *\t\tconst fontFamilyConfig = {\n *\t\t\toptions: [\n *\t\t\t\t'default',\n *\t\t\t\t'Arial, Helvetica, sans-serif',\n *\t\t\t\t'Courier New, Courier, monospace',\n *\t\t\t\t'Georgia, serif',\n *\t\t\t\t'Lucida Sans Unicode, Lucida Grande, sans-serif',\n *\t\t\t\t'Tahoma, Geneva, sans-serif',\n *\t\t\t\t'Times New Roman, Times, serif',\n *\t\t\t\t'Trebuchet MS, Helvetica, sans-serif',\n *\t\t\t\t'Verdana, Geneva, sans-serif'\n *\t\t\t]\n *\t\t};\n *\n * which configures 8 font family options. Each option consists of one or more commaseparated font family names. The first font name is\n * used as the dropdown item description in the UI.\n *\n * **Note:** The family names that consist of spaces should not have quotes (as opposed to the CSS standard). The necessary quotes\n * will be added automatically in the view. For example, the `\"Lucida Sans Unicode\"` will render as follows:\n *\n * \t\t<span style=\"font-family:'Lucida Sans Unicode', 'Lucida Grande', sans-serif\">...</span>\n *\n * The \"default\" option removes the `fontFamily` attribute from the selection. In such case, the text will\n * be rendered in the view using the default font family defined in the styles of the web page.\n *\n * Font family can be applied using the command API. To do that, use the `fontFamily` command and pass the desired family as a `value`.\n * For example, the following code will apply the `fontFamily` attribute with the `'Arial'` `value` to the current selection:\n *\n *\t\teditor.execute( 'fontFamily', { value: 'Arial' } );\n *\n * Executing the `'fontFamily'` command without any value will remove the `fontFamily` attribute from the current selection.\n *\n * @member {Array.<String|module:font/fontfamily~FontFamilyOption>} module:font/fontfamily~FontFamilyConfig#options\n */\n\n/**\n * By default the plugin removes any `font-family` value that does not match the plugin's configuration. It means that if you paste content\n * with font families that the editor does not understand, the `font-family` attribute will be removed and the content will be displayed\n * with the default font.\n *\n * You can preserve pasted font family values by switching the `supportAllValues` option to `true`:\n *\n *\t\tconst fontFamilyConfig = {\n *\t\t\tsupportAllValues: true\n *\t\t};\n *\n * With this configuration font families not specified in the editor configuration will not be removed when pasting the content.\n *\n * @member {Boolean} module:font/fontfamily~FontFamilyConfig#supportAllValues\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 font/fontsize/fontsizecommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_SIZE } from '../utils';\n\n/**\n * The font size command. It is used by {@link module:font/fontsize/fontsizeediting~FontSizeEditing}\n * to apply the font size.\n *\n *\t\teditor.execute( 'fontSize', { value: 'small' } );\n *\n * **Note**: Executing the command without the value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontSizeCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_SIZE );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontsize/utils\n */\n\nimport { CKEditorError } from 'ckeditor5/src/utils';\n\n/**\n * Normalizes and translates the {@link module:font/fontsize~FontSizeConfig#options configuration options}\n * to the {@link module:font/fontsize~FontSizeOption} format.\n *\n * @param {Array.<String|Number|Object>} configuredOptions An array of options taken from the configuration.\n * @returns {Array.<module:font/fontsize~FontSizeOption>}\n */\nexport function normalizeOptions( configuredOptions ) {\n\t// Convert options to objects.\n\treturn configuredOptions\n\t\t.map( item => getOptionDefinition( item ) )\n\t\t// Filter out undefined values that `getOptionDefinition` might return.\n\t\t.filter( option => !!option );\n}\n\n// Default named presets map. Always create a new instance of the preset object in order to avoid modifying references.\nconst namedPresets = {\n\tget tiny() {\n\t\treturn {\n\t\t\ttitle: 'Tiny',\n\t\t\tmodel: 'tiny',\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tclasses: 'text-tiny',\n\t\t\t\tpriority: 7\n\t\t\t}\n\t\t};\n\t},\n\tget small() {\n\t\treturn {\n\t\t\ttitle: 'Small',\n\t\t\tmodel: 'small',\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tclasses: 'text-small',\n\t\t\t\tpriority: 7\n\t\t\t}\n\t\t};\n\t},\n\tget big() {\n\t\treturn {\n\t\t\ttitle: 'Big',\n\t\t\tmodel: 'big',\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tclasses: 'text-big',\n\t\t\t\tpriority: 7\n\t\t\t}\n\t\t};\n\t},\n\tget huge() {\n\t\treturn {\n\t\t\ttitle: 'Huge',\n\t\t\tmodel: 'huge',\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tclasses: 'text-huge',\n\t\t\t\tpriority: 7\n\t\t\t}\n\t\t};\n\t}\n};\n\n// Returns an option definition either from preset or creates one from number shortcut.\n// If object is passed then this method will return it without alternating it. Returns undefined for item than cannot be parsed.\n//\n// @param {String|Number|Object} item\n// @returns {undefined|module:font/fontsize~FontSizeOption}\nfunction getOptionDefinition( option ) {\n\t// Check whether passed option is a full item definition provided by user in configuration.\n\tif ( isFullItemDefinition( option ) ) {\n\t\treturn attachPriority( option );\n\t}\n\n\tconst preset = findPreset( option );\n\n\t// Item is a named preset.\n\tif ( preset ) {\n\t\treturn attachPriority( preset );\n\t}\n\n\t// 'Default' font size. It will be used to remove the fontSize attribute.\n\tif ( option === 'default' ) {\n\t\treturn {\n\t\t\tmodel: undefined,\n\t\t\ttitle: 'Default'\n\t\t};\n\t}\n\n\t// At this stage we probably have numerical value to generate a preset so parse it's value.\n\t// Discard any faulty values.\n\tif ( isNumericalDefinition( option ) ) {\n\t\treturn;\n\t}\n\n\t// Return font size definition from size value.\n\treturn generatePixelPreset( option );\n}\n\n// Creates a predefined preset for pixel size.\n//\n// @param {Number} definition Font size in pixels.\n// @returns {module:font/fontsize~FontSizeOption}\nfunction generatePixelPreset( definition ) {\n\t// Extend a short (numeric value) definition.\n\tif ( typeof definition === 'number' || typeof definition === 'string' ) {\n\t\tdefinition = {\n\t\t\ttitle: String( definition ),\n\t\t\tmodel: `${ parseFloat( definition ) }px`\n\t\t};\n\t}\n\n\tdefinition.view = {\n\t\tname: 'span',\n\t\tstyles: {\n\t\t\t'font-size': definition.model\n\t\t}\n\t};\n\n\treturn attachPriority( definition );\n}\n\n// Adds the priority to the view element definition if missing. It's required due to ckeditor/ckeditor5#2291\n//\n// @param {Object} definition\n// @param {Object} definition.title\n// @param {Object} definition.model\n// @param {Object} definition.view\n// @returns {Object}\nfunction attachPriority( definition ) {\n\tif ( !definition.view.priority ) {\n\t\tdefinition.view.priority = 7;\n\t}\n\n\treturn definition;\n}\n\n// Returns a prepared preset definition. If passed an object, a name of preset should be defined as `model` value.\n//\n// @param {String|Object} definition\n// @param {String} definition.model A preset name.\n// @returns {Object|undefined}\nfunction findPreset( definition ) {\n\treturn namedPresets[ definition ] || namedPresets[ definition.model ];\n}\n\n// We treat `definition` as completed if it is an object that contains `title`, `model` and `view` values.\n//\n// @param {Object} definition\n// @param {String} definition.title\n// @param {String} definition.model\n// @param {Object} definition.view\n// @returns {Boolean}\nfunction isFullItemDefinition( definition ) {\n\treturn typeof definition === 'object' && definition.title && definition.model && definition.view;\n}\n\n// We treat `definition` as numerical if it is a number, number-like (string) or an object with the `title` key.\n//\n// @param {Object|Number|String} definition\n// @param {Object} definition.title\n// @returns {Boolean}\nfunction isNumericalDefinition( definition ) {\n\tlet numberValue;\n\n\tif ( typeof definition === 'object' ) {\n\t\tif ( !definition.model ) {\n\t\t\t/**\n\t\t\t * Provided value as an option for {@link module:font/fontsize~FontSize} seems to invalid.\n\t\t\t *\n\t\t\t * See valid examples described in the {@link module:font/fontsize~FontSizeConfig#options plugin configuration}.\n\t\t\t *\n\t\t\t * @error font-size-invalid-definition\n\t\t\t */\n\t\t\tthrow new CKEditorError( 'font-size-invalid-definition', null, definition );\n\t\t} else {\n\t\t\tnumberValue = parseFloat( definition.model );\n\t\t}\n\t} else {\n\t\tnumberValue = parseFloat( definition );\n\t}\n\n\treturn isNaN( numberValue );\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 font/fontsize/fontsizeediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { CKEditorError } from 'ckeditor5/src/utils';\nimport { isLength, isPercentage } from 'ckeditor5/src/engine';\n\nimport FontSizeCommand from './fontsizecommand';\nimport { normalizeOptions } from './utils';\nimport { buildDefinition, FONT_SIZE } from '../utils';\n\n// Mapping of `<font size=\"..\">` styling to CSS's `font-size` values.\nconst styleFontSize = [\n\t'x-small', // Size \"0\" equal to \"1\".\n\t'x-small',\n\t'small',\n\t'medium',\n\t'large',\n\t'x-large',\n\t'xx-large',\n\t'xxx-large'\n];\n\n/**\n * The font size editing feature.\n *\n * It introduces the {@link module:font/fontsize/fontsizecommand~FontSizeCommand command} and the `fontSize`\n * attribute in the {@link module:engine/model/model~Model model} which renders in the {@link module:engine/view/view view}\n * as a `<span>` element with either:\n * * a style attribute (`<span style=\"font-size:12px\">...</span>`),\n * * or a class attribute (`<span class=\"text-small\">...</span>`)\n *\n * depending on the {@link module:font/fontsize~FontSizeConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontSizeEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontSizeEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t// Define default configuration using named presets.\n\t\teditor.config.define( FONT_SIZE, {\n\t\t\toptions: [\n\t\t\t\t'tiny',\n\t\t\t\t'small',\n\t\t\t\t'default',\n\t\t\t\t'big',\n\t\t\t\t'huge'\n\t\t\t],\n\t\t\tsupportAllValues: false\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Allow fontSize attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_SIZE } );\n\t\teditor.model.schema.setAttributeProperties( FONT_SIZE, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\n\t\tconst supportAllValues = editor.config.get( 'fontSize.supportAllValues' );\n\n\t\t// Define view to model conversion.\n\t\tconst options = normalizeOptions( this.editor.config.get( 'fontSize.options' ) )\n\t\t\t.filter( item => item.model );\n\t\tconst definition = buildDefinition( FONT_SIZE, options );\n\n\t\t// Set-up the two-way conversion.\n\t\tif ( supportAllValues ) {\n\t\t\tthis._prepareAnyValueConverters( definition );\n\t\t\tthis._prepareCompatibilityConverter();\n\t\t} else {\n\t\t\teditor.conversion.attributeToElement( definition );\n\t\t}\n\n\t\t// Add FontSize command.\n\t\teditor.commands.add( FONT_SIZE, new FontSizeCommand( editor ) );\n\t}\n\n\t/**\n\t * These converters enable keeping any value found as `style=\"font-size: *\"` as a value of an attribute on a text even\n\t * if it is not defined in the plugin configuration.\n\t *\n\t * @param {Object} definition {@link module:engine/conversion/conversion~ConverterDefinition Converter definition} out of input data.\n\t * @private\n\t */\n\t_prepareAnyValueConverters( definition ) {\n\t\tconst editor = this.editor;\n\n\t\t// If `fontSize.supportAllValues=true`, we do not allow to use named presets in the plugin's configuration.\n\t\tconst presets = definition.model.values.filter( value => {\n\t\t\treturn !isLength( String( value ) ) && !isPercentage( String( value ) );\n\t\t} );\n\n\t\tif ( presets.length ) {\n\t\t\t/**\n\t\t\t * If {@link module:font/fontsize~FontSizeConfig#supportAllValues `config.fontSize.supportAllValues`} is `true`,\n\t\t\t * you need to use numerical values as font size options.\n\t\t\t *\n\t\t\t * See valid examples described in the {@link module:font/fontsize~FontSizeConfig#options plugin configuration}.\n\t\t\t *\n\t\t\t * @error font-size-invalid-use-of-named-presets\n\t\t\t * @param {Array.<String>} presets Invalid values.\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'font-size-invalid-use-of-named-presets',\n\t\t\t\tnull, { presets }\n\t\t\t);\n\t\t}\n\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: FONT_SIZE,\n\t\t\tview: ( attributeValue, { writer } ) => {\n\t\t\t\tif ( !attributeValue ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\treturn writer.createAttributeElement( 'span', { style: 'font-size:' + attributeValue }, { priority: 7 } );\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_SIZE,\n\t\t\t\tvalue: viewElement => viewElement.getStyle( 'font-size' )\n\t\t\t},\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\t'font-size': /.*/\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Adds support for legacy `<font size=\"..\">` formatting.\n\t *\n\t * @private\n\t */\n\t_prepareCompatibilityConverter() {\n\t\tconst editor = this.editor;\n\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'font',\n\t\t\t\tattributes: {\n\t\t\t\t\t// Documentation mentions sizes from 1 to 7. To handle old content we support all values\n\t\t\t\t\t// up to 999 but clamp it to the valid range. Why 999? It should cover accidental values\n\t\t\t\t\t// similar to percentage, e.g. 100%, 200% which could be the usual mistake for font size.\n\t\t\t\t\t'size': /^[+-]?\\d{1,3}$/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_SIZE,\n\t\t\t\tvalue: viewElement => {\n\t\t\t\t\tconst value = viewElement.getAttribute( 'size' );\n\t\t\t\t\tconst isRelative = value[ 0 ] === '-' || value[ 0 ] === '+';\n\n\t\t\t\t\tlet size = parseInt( value, 10 );\n\n\t\t\t\t\tif ( isRelative ) {\n\t\t\t\t\t\t// Add relative size (which can be negative) to the default size = 3.\n\t\t\t\t\t\tsize = 3 + size;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst maxSize = styleFontSize.length - 1;\n\t\t\t\t\tconst clampedSize = Math.min( Math.max( size, 0 ), maxSize );\n\n\t\t\t\t\treturn styleFontSize[ clampedSize ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontsize/fontsizeui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui';\nimport { Collection } from 'ckeditor5/src/utils';\n\nimport { normalizeOptions } from './utils';\nimport { FONT_SIZE } from '../utils';\n\nimport fontSizeIcon from '../../theme/icons/font-size.svg';\nimport '../../theme/fontsize.css';\n\n/**\n * The font size UI plugin. It introduces the `'fontSize'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontSizeUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontSizeUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\tconst options = this._getLocalizedOptions();\n\n\t\tconst command = editor.commands.get( FONT_SIZE );\n\n\t\t// Register UI component.\n\t\teditor.ui.componentFactory.add( FONT_SIZE, locale => {\n\t\t\tconst dropdownView = createDropdown( locale );\n\t\t\taddListToDropdown( dropdownView, _prepareListOptions( options, command ) );\n\n\t\t\t// Create dropdown model.\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\tlabel: t( 'Font Size' ),\n\t\t\t\ticon: fontSizeIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tdropdownView.extendTemplate( {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: [\n\t\t\t\t\t\t'ck-font-size-dropdown'\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).to( command );\n\n\t\t\t// Execute command when an item from the dropdown is selected.\n\t\t\tthis.listenTo( dropdownView, 'execute', evt => {\n\t\t\t\teditor.execute( evt.source.commandName, { value: evt.source.commandParam } );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\t}\n\n\t/**\n\t * Returns options as defined in `config.fontSize.options` but processed to account for\n\t * editor localization, i.e. to display {@link module:font/fontsize~FontSizeOption}\n\t * in the correct language.\n\t *\n\t * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t}\n\t * when the user configuration is defined because the editor does not exist yet.\n\t *\n\t * @private\n\t * @returns {Array.<module:font/fontsize~FontSizeOption>}.\n\t */\n\t_getLocalizedOptions() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\tconst localizedTitles = {\n\t\t\tDefault: t( 'Default' ),\n\t\t\tTiny: t( 'Tiny' ),\n\t\t\tSmall: t( 'Small' ),\n\t\t\tBig: t( 'Big' ),\n\t\t\tHuge: t( 'Huge' )\n\t\t};\n\n\t\tconst options = normalizeOptions( editor.config.get( FONT_SIZE ).options );\n\n\t\treturn options.map( option => {\n\t\t\tconst title = localizedTitles[ option.title ];\n\n\t\t\tif ( title && title != option.title ) {\n\t\t\t\t// Clone the option to avoid altering the original `namedPresets` from `./utils.js`.\n\t\t\t\toption = Object.assign( {}, option, { title } );\n\t\t\t}\n\n\t\t\treturn option;\n\t\t} );\n\t}\n}\n\n// Prepares FontSize dropdown items.\n// @private\n// @param {Array.<module:font/fontsize~FontSizeOption>} options\n// @param {module:font/fontsize/fontsizecommand~FontSizeCommand} command\nfunction _prepareListOptions( options, command ) {\n\tconst itemDefinitions = new Collection();\n\n\tfor ( const option of options ) {\n\t\tconst def = {\n\t\t\ttype: 'button',\n\t\t\tmodel: new Model( {\n\t\t\t\tcommandName: FONT_SIZE,\n\t\t\t\tcommandParam: option.model,\n\t\t\t\tlabel: option.title,\n\t\t\t\tclass: 'ck-fontsize-option',\n\t\t\t\twithText: true\n\t\t\t} )\n\t\t};\n\n\t\tif ( option.view && option.view.styles ) {\n\t\t\tdef.model.set( 'labelStyle', `font-size:${ option.view.styles[ 'font-size' ] }` );\n\t\t}\n\n\t\tif ( option.view && option.view.classes ) {\n\t\t\tdef.model.set( 'class', `${ def.model.class } ${ option.view.classes }` );\n\t\t}\n\n\t\tdef.model.bind( 'isOn' ).to( command, 'value', value => value === option.model );\n\n\t\t// Add the option to the collection.\n\t\titemDefinitions.add( def );\n\t}\n\n\treturn itemDefinitions;\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M9.816 11.5 7.038 4.785 4.261 11.5h5.555zm.62 1.5H3.641l-1.666 4.028H.312l5.789-14h1.875l5.789 14h-1.663L10.436 13zm7.55 2.279.779-.779.707.707-2.265 2.265-2.193-2.265.707-.707.765.765V4.825c0-.042 0-.083.002-.123l-.77.77-.707-.707L17.207 2.5l2.265 2.265-.707.707-.782-.782c.002.043.003.089.003.135v10.454z\\\"/></svg>\";","/**\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 font/fontsize\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport FontSizeEditing from './fontsize/fontsizeediting';\nimport FontSizeUI from './fontsize/fontsizeui';\n\n/**\n * The font size plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentation\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:font/fontsize/fontsizeediting~FontSizeEditing} and\n * {@link module:font/fontsize/fontsizeui~FontSizeUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontSize extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontSizeEditing, FontSizeUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontSize';\n\t}\n}\n\n/**\n * The font size option descriptor.\n *\n * @typedef {Object} module:font/fontsize~FontSizeOption\n *\n * @property {String} title The user-readable title of the option.\n * @property {String} model The attribute's unique value in the model.\n * @property {module:engine/view/elementdefinition~ElementDefinition} view View element configuration.\n * @property {Array.<module:engine/view/elementdefinition~ElementDefinition>} [upcastAlso] An array with all matched elements that\n * the view-to-model conversion should also accept.\n */\n\n/**\n * The configuration of the font size feature.\n * It is introduced by the {@link module:font/fontsize/fontsizeediting~FontSizeEditing} feature.\n *\n * Read more in {@link module:font/fontsize~FontSizeConfig}.\n *\n * @member {module:font/fontsize~FontSizeConfig} module:core/editor/editorconfig~EditorConfig#fontSize\n */\n\n/**\n * The configuration of the font size feature.\n * This option is used by the {@link module:font/fontsize/fontsizeediting~FontSizeEditing} feature.\n *\n * \t\tClassicEditor\n * \t\t\t.create( {\n * \t\t\t\tfontSize: ... // Font size feature configuration.\n *\t\t\t} )\n * \t\t\t.then( ... )\n * \t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface module:font/fontsize~FontSizeConfig\n */\n\n/**\n * Available font size options. Expressed as predefined presets, numerical \"pixel\" values\n * or the {@link module:font/fontsize~FontSizeOption}.\n *\n * The default value is:\n *\n *\t\tconst fontSizeConfig = {\n *\t\t\toptions: [\n *\t\t\t\t'tiny',\n * \t\t\t\t'small',\n * \t\t\t\t'default',\n * \t\t\t\t'big',\n * \t\t\t\t'huge'\n *\t\t\t]\n *\t\t};\n *\n * It defines 4 sizes: **tiny**, **small**, **big**, and **huge**. These values will be rendered as `<span>` elements in the view.\n * The **default** defines a text without the `fontSize` attribute.\n *\n * Each `<span>` has the the `class` attribute set to the corresponding size name. For instance, this is what the **small** size looks\n * like in the view:\n *\n * \t\t<span class=\"text-small\">...</span>\n *\n * As an alternative, the font size might be defined using numerical values (either as a `Number` or as a `String`):\n *\n * \t\tconst fontSizeConfig = {\n * \t\t\toptions: [ 9, 10, 11, 12, 13, 14, 15 ]\n * \t\t};\n *\n * Also, you can define a label in the dropdown for numerical values:\n *\n *\t\tconst fontSizeConfig = {\n *\t\t\toptions: [\n *\t\t\t\t{\n * \t\t\t\t \ttitle: 'Small',\n * \t\t\t\t \tmodel: '8px\n * \t\t\t\t},\n * \t\t\t\t'default',\n * \t\t\t\t{\n * \t\t\t\t \ttitle: 'Big',\n * \t\t\t\t \tmodel: '14px\n * \t\t\t\t}\n *\t\t\t]\n *\t\t};\n *\n * Font size can be applied using the command API. To do that, use the `'fontSize'` command and pass the desired font size as a `value`.\n * For example, the following code will apply the `fontSize` attribute with the **tiny** value to the current selection:\n *\n *\t\teditor.execute( 'fontSize', { value: 'tiny' } );\n *\n * Executing the `fontSize` command without value will remove the `fontSize` attribute from the current selection.\n *\n * @member {Array.<String|Number|module:font/fontsize~FontSizeOption>} module:font/fontsize~FontSizeConfig#options\n */\n\n/**\n * By default the plugin removes any `font-size` value that does not match the plugin's configuration. It means that if you paste content\n * with font sizes that the editor does not understand, the `font-size` attribute will be removed and the content will be displayed\n * with the default size.\n *\n * You can preserve pasted font size values by switching the `supportAllValues` option to `true`:\n *\n *\t\tconst fontSizeConfig = {\n *\t\t\toptions: [ 9, 10, 11, 12, 'default', 14, 15 ],\n *\t\t\tsupportAllValues: true\n *\t\t};\n *\n * **Note:** This option can only be used with numerical values as font size options.\n *\n * With this configuration font sizes not specified in the editor configuration will not be removed when pasting the content.\n *\n * @member {Boolean} module:font/fontsize~FontSizeConfig#supportAllValues\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 font/fontcolor/fontcolorcommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_COLOR } from '../utils';\n\n/**\n * The font color command. It is used by {@link module:font/fontcolor/fontcolorediting~FontColorEditing}\n * to apply the font color.\n *\n *\t\teditor.execute( 'fontColor', { value: 'rgb(250, 20, 20)' } );\n *\n * **Note**: Executing the command with the `null` value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontColorCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_COLOR );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontcolor/fontcolorediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport FontColorCommand from './fontcolorcommand';\nimport { FONT_COLOR, renderDowncastElement, renderUpcastAttribute } from '../utils';\n\n/**\n * The font color editing feature.\n *\n * It introduces the {@link module:font/fontcolor/fontcolorcommand~FontColorCommand command} and\n * the `fontColor` attribute in the {@link module:engine/model/model~Model model} which renders\n * in the {@link module:engine/view/view view} as a `<span>` element (`<span style=\"color: ...\">`),\n * depending on the {@link module:font/fontcolor~FontColorConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontColorEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontColorEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( FONT_COLOR, {\n\t\t\tcolors: [\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n\t\t\t\t\tlabel: 'Black'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n\t\t\t\t\tlabel: 'Dim grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n\t\t\t\t\tlabel: 'Grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n\t\t\t\t\tlabel: 'Light grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n\t\t\t\t\tlabel: 'White',\n\t\t\t\t\thasBorder: true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n\t\t\t\t\tlabel: 'Red'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n\t\t\t\t\tlabel: 'Orange'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n\t\t\t\t\tlabel: 'Yellow'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n\t\t\t\t\tlabel: 'Green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n\t\t\t\t\tlabel: 'Aquamarine'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n\t\t\t\t\tlabel: 'Turquoise'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n\t\t\t\t\tlabel: 'Blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n\t\t\t\t\tlabel: 'Purple'\n\t\t\t\t}\n\t\t\t],\n\t\t\tcolumns: 5\n\t\t} );\n\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\t'color': /[\\s\\S]+/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_COLOR,\n\t\t\t\tvalue: renderUpcastAttribute( 'color' )\n\t\t\t}\n\t\t} );\n\n\t\t// Support legacy `<font color=\"..\">` formatting.\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'font',\n\t\t\t\tattributes: {\n\t\t\t\t\t'color': /^#?\\w+$/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_COLOR,\n\t\t\t\tvalue: viewElement => viewElement.getAttribute( 'color' )\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: FONT_COLOR,\n\t\t\tview: renderDowncastElement( 'color' )\n\t\t} );\n\n\t\teditor.commands.add( FONT_COLOR, new FontColorCommand( editor ) );\n\n\t\t// Allow the font color attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_COLOR } );\n\n\t\teditor.model.schema.setAttributeProperties( FONT_COLOR, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/ui/colorui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { createDropdown, normalizeColorOptions, getLocalizedColorOptions } from 'ckeditor5/src/ui';\n\nimport { addColorTableToDropdown } from '../utils';\n\n/**\n * The color UI plugin which isolates the common logic responsible for displaying dropdowns with color grids.\n *\n * It is used to create the `'fontBackgroundColor'` and `'fontColor'` dropdowns, each hosting\n * a {@link module:font/ui/colortableview~ColorTableView}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ColorUI extends Plugin {\n\t/**\n\t * Creates a plugin which introduces a dropdown with a preconfigured {@link module:font/ui/colortableview~ColorTableView}.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor\n\t * @param {Object} config The configuration object.\n\t * @param {String} config.commandName The name of the command which will be executed when a color tile is clicked.\n\t * @param {String} config.componentName The name of the dropdown in the {@link module:ui/componentfactory~ComponentFactory}\n\t * and the configuration scope name in `editor.config`.\n\t * @param {String} config.icon The SVG icon used by the dropdown.\n\t * @param {String} config.dropdownLabel The label used by the dropdown.\n\t */\n\tconstructor( editor, { commandName, icon, componentName, dropdownLabel } ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The name of the command which will be executed when a color tile is clicked.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.commandName = commandName;\n\n\t\t/**\n\t\t * The name of this component in the {@link module:ui/componentfactory~ComponentFactory}.\n\t\t * Also the configuration scope name in `editor.config`.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.componentName = componentName;\n\n\t\t/**\n\t\t * The SVG icon used by the dropdown.\n\t\t * @type {String}\n\t\t */\n\t\tthis.icon = icon;\n\n\t\t/**\n\t\t * The label used by the dropdown.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.dropdownLabel = dropdownLabel;\n\n\t\t/**\n\t\t * The number of columns in the color grid.\n\t\t *\n\t\t * @type {Number}\n\t\t */\n\t\tthis.columns = editor.config.get( `${ this.componentName }.columns` );\n\n\t\t/**\n\t\t * Keeps a reference to {@link module:font/ui/colortableview~ColorTableView}.\n\t\t *\n\t\t * @member {module:font/ui/colortableview~ColorTableView}\n\t\t */\n\t\tthis.colorTableView = undefined;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst t = locale.t;\n\t\tconst command = editor.commands.get( this.commandName );\n\t\tconst colorsConfig = normalizeColorOptions( editor.config.get( this.componentName ).colors );\n\t\tconst localizedColors = getLocalizedColorOptions( locale, colorsConfig );\n\t\tconst documentColorsCount = editor.config.get( `${ this.componentName }.documentColors` );\n\n\t\t// Register the UI component.\n\t\teditor.ui.componentFactory.add( this.componentName, locale => {\n\t\t\tconst dropdownView = createDropdown( locale );\n\t\t\tthis.colorTableView = addColorTableToDropdown( {\n\t\t\t\tdropdownView,\n\t\t\t\tcolors: localizedColors.map( option => ( {\n\t\t\t\t\tlabel: option.label,\n\t\t\t\t\tcolor: option.model,\n\t\t\t\t\toptions: {\n\t\t\t\t\t\thasBorder: option.hasBorder\n\t\t\t\t\t}\n\t\t\t\t} ) ),\n\t\t\t\tcolumns: this.columns,\n\t\t\t\tremoveButtonLabel: t( 'Remove color' ),\n\t\t\t\tdocumentColorsLabel: documentColorsCount !== 0 ? t( 'Document colors' ) : undefined,\n\t\t\t\tdocumentColorsCount: documentColorsCount === undefined ? this.columns : documentColorsCount\n\t\t\t} );\n\n\t\t\tthis.colorTableView.bind( 'selectedColor' ).to( command, 'value' );\n\n\t\t\tdropdownView.buttonView.set( {\n\t\t\t\tlabel: this.dropdownLabel,\n\t\t\t\ticon: this.icon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tdropdownView.extendTemplate( {\n\t\t\t\tattributes: {\n\t\t\t\t\tclass: 'ck-color-ui-dropdown'\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tdropdownView.bind( 'isEnabled' ).to( command );\n\n\t\t\tdropdownView.on( 'execute', ( evt, data ) => {\n\t\t\t\teditor.execute( this.commandName, data );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\tdropdownView.on( 'change:isOpen', ( evt, name, isVisible ) => {\n\t\t\t\t// Grids rendering is deferred (#6192).\n\t\t\t\tdropdownView.colorTableView.appendGrids();\n\n\t\t\t\tif ( isVisible ) {\n\t\t\t\t\tif ( documentColorsCount !== 0 ) {\n\t\t\t\t\t\tthis.colorTableView.updateDocumentColors( editor.model, this.componentName );\n\t\t\t\t\t}\n\t\t\t\t\tthis.colorTableView.updateSelectedColors();\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontcolor/fontcolorui\n */\n\nimport ColorUI from '../ui/colorui';\nimport { FONT_COLOR } from '../utils';\nimport fontColorIcon from '../../theme/icons/font-color.svg';\n\n/**\n * The font color UI plugin. It introduces the `'fontColor'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontColorUI extends ColorUI {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tconst t = editor.locale.t;\n\n\t\tsuper( editor, {\n\t\t\tcommandName: FONT_COLOR,\n\t\t\tcomponentName: FONT_COLOR,\n\t\t\ticon: fontColorIcon,\n\t\t\tdropdownLabel: t( 'Font Color' )\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontColorUI';\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M12.4 10.3 10 4.5l-2.4 5.8h4.8zm.5 1.2H7.1L5.7 15H4.2l5-12h1.6l5 12h-1.5L13 11.5zm3.1 7H4a1 1 0 0 1 0-2h12a1 1 0 0 1 0 2z\\\"/></svg>\";","/**\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 font/fontcolor\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport FontColorEditing from './fontcolor/fontcolorediting';\nimport FontColorUI from './fontcolor/fontcolorui';\n\n/**\n * The font color plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentation\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:font/fontcolor/fontcolorediting~FontColorEditing} and\n * {@link module:font/fontcolor/fontcolorui~FontColorUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontColor extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontColorEditing, FontColorUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontColor';\n\t}\n}\n\n/**\n * The configuration of the font color feature.\n * It is introduced by the {@link module:font/fontcolor/fontcolorediting~FontColorEditing} feature.\n *\n * Read more in {@link module:font/fontcolor~FontColorConfig}.\n *\n * @member {module:font/fontcolor~FontColorConfig} module:core/editor/editorconfig~EditorConfig#fontColor\n */\n\n/**\n * The configuration of the font color feature.\n * This option is used by the {@link module:font/fontcolor/fontcolorediting~FontColorEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n *\t\t\t\tfontColor: ... // Font color feature configuration.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface module:font/fontcolor~FontColorConfig\n */\n\n/**\n * Available font colors defined as an array of strings or objects.\n *\n * The default value registers the following colors:\n *\n *\t\tconst fontColorConfig = {\n *\t\t\tcolors: [\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n *\t\t\t\t\tlabel: 'Black'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n *\t\t\t\t\tlabel: 'Dim grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\t\tlabel: 'Grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\t\tlabel: 'Light grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\t\tlabel: 'White',\n *\t\t\t\t\thasBorder: true\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Red'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Orange'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Yellow'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Aquamarine'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Turquoise'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Purple'\n *\t\t\t\t}\n *\t\t\t]\n *\t\t};\n *\n * **Note**: The colors are displayed in the `'fontColor'` dropdown.\n *\n * @member {Array.<String|Object>} module:font/fontcolor~FontColorConfig#colors\n */\n\n/**\n * Represents the number of columns in the font color dropdown.\n *\n * The default value is:\n *\n *\t\tconst fontColorConfig = {\n *\t\t\tcolumns: 5\n *\t\t}\n *\n * @member {Number} module:font/fontcolor~FontColorConfig#columns\n */\n\n/**\n * Determines the maximum number of available document colors.\n * Setting it to `0` will disable the document colors feature.\n *\n * By default it equals to the {@link module:font/fontcolor~FontColorConfig#columns} value.\n *\n * Examples:\n *\n * \t// 1) Neither document colors nor columns are defined in the configuration.\n * \t// Document colors will equal 5,\n * \t// because the value will be inherited from columns,\n * \t// which has a predefined value of 5.\n * \tconst fontColorConfig = {}\n *\n * \t// 2) Document colors will equal 8, because the value will be inherited from columns.\n * \tconst fontColorConfig = {\n * \t\tcolumns: 8\n * \t}\n *\n * \t// 3) Document colors will equal 24, because it has its own value defined.\n * \tconst fontColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 24\n * \t}\n *\n * \t// 4) The document colors feature will be disabled.\n * \tconst fontColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 0\n * \t}\n *\n * @member {Number} module:font/fontcolor~FontColorConfig#documentColors\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 font/fontbackgroundcolor/fontbackgroundcolorcommand\n */\n\nimport FontCommand from '../fontcommand';\nimport { FONT_BACKGROUND_COLOR } from '../utils';\n\n/**\n * The font background color command. It is used by\n * {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing}\n * to apply the font background color.\n *\n *\t\teditor.execute( 'fontBackgroundColor', { value: 'rgb(250, 20, 20)' } );\n *\n * **Note**: Executing the command with the `null` value removes the attribute from the model.\n *\n * @extends module:font/fontcommand~FontCommand\n */\nexport default class FontBackgroundColorCommand extends FontCommand {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor, FONT_BACKGROUND_COLOR );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontbackgroundcolor/fontbackgroundcolorediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { addBackgroundRules } from 'ckeditor5/src/engine';\n\nimport FontBackgroundColorCommand from './fontbackgroundcolorcommand';\nimport { FONT_BACKGROUND_COLOR, renderDowncastElement, renderUpcastAttribute } from '../utils';\n\n/**\n * The font background color editing feature.\n *\n * It introduces the {@link module:font/fontbackgroundcolor/fontbackgroundcolorcommand~FontBackgroundColorCommand command} and\n * the `fontBackgroundColor` attribute in the {@link module:engine/model/model~Model model} which renders\n * in the {@link module:engine/view/view view} as a `<span>` element (`<span style=\"background-color: ...\">`),\n * depending on the {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig configuration}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontBackgroundColorEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontBackgroundColorEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( FONT_BACKGROUND_COLOR, {\n\t\t\tcolors: [\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n\t\t\t\t\tlabel: 'Black'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n\t\t\t\t\tlabel: 'Dim grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n\t\t\t\t\tlabel: 'Grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n\t\t\t\t\tlabel: 'Light grey'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n\t\t\t\t\tlabel: 'White',\n\t\t\t\t\thasBorder: true\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n\t\t\t\t\tlabel: 'Red'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n\t\t\t\t\tlabel: 'Orange'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n\t\t\t\t\tlabel: 'Yellow'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n\t\t\t\t\tlabel: 'Green'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n\t\t\t\t\tlabel: 'Aquamarine'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n\t\t\t\t\tlabel: 'Turquoise'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n\t\t\t\t\tlabel: 'Light blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n\t\t\t\t\tlabel: 'Blue'\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n\t\t\t\t\tlabel: 'Purple'\n\t\t\t\t}\n\t\t\t],\n\t\t\tcolumns: 5\n\t\t} );\n\n\t\teditor.data.addStyleProcessorRules( addBackgroundRules );\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tstyles: {\n\t\t\t\t\t'background-color': /[\\s\\S]+/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: FONT_BACKGROUND_COLOR,\n\t\t\t\tvalue: renderUpcastAttribute( 'background-color' )\n\t\t\t}\n\t\t} );\n\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: FONT_BACKGROUND_COLOR,\n\t\t\tview: renderDowncastElement( 'background-color' )\n\t\t} );\n\n\t\teditor.commands.add( FONT_BACKGROUND_COLOR, new FontBackgroundColorCommand( editor ) );\n\n\t\t// Allow the font backgroundColor attribute on text nodes.\n\t\teditor.model.schema.extend( '$text', { allowAttributes: FONT_BACKGROUND_COLOR } );\n\n\t\teditor.model.schema.setAttributeProperties( FONT_BACKGROUND_COLOR, {\n\t\t\tisFormatting: true,\n\t\t\tcopyOnEnter: true\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module font/fontbackgroundcolor/fontbackgroundcolorui\n */\n\nimport ColorUI from '../ui/colorui';\nimport { FONT_BACKGROUND_COLOR } from '../utils';\nimport fontBackgroundColorIcon from '../../theme/icons/font-background.svg';\n\n/**\n * The font background color UI plugin. It introduces the `'fontBackgroundColor'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontBackgroundColorUI extends ColorUI {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tconst t = editor.locale.t;\n\n\t\tsuper( editor, {\n\t\t\tcommandName: FONT_BACKGROUND_COLOR,\n\t\t\tcomponentName: FONT_BACKGROUND_COLOR,\n\t\t\ticon: fontBackgroundColorIcon,\n\t\t\tdropdownLabel: t( 'Font Background Color' )\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontBackgroundColorUI';\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M4 2h12a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zm8.38 9.262H7.62L10 5.506l2.38 5.756zm.532 1.285L14.34 16h1.426L10.804 4H9.196L4.234 16H5.66l1.428-3.453h5.824z\\\"/></svg>\";","/**\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 font/fontbackgroundcolor\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport FontBackgroundColorEditing from './fontbackgroundcolor/fontbackgroundcolorediting';\nimport FontBackgroundColorUI from './fontbackgroundcolor/fontbackgroundcolorui';\n\n/**\n * The font background color plugin.\n *\n * For a detailed overview, check the {@glink features/font font feature} documentation\n * and the {@glink api/font package page}.\n *\n * This is a \"glue\" plugin which loads\n * the {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing} and\n * {@link module:font/fontbackgroundcolor/fontbackgroundcolorui~FontBackgroundColorUI} features in the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class FontBackgroundColor extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontBackgroundColorEditing, FontBackgroundColorUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'FontBackgroundColor';\n\t}\n}\n\n/**\n * The configuration of the font background color feature.\n * It is introduced by the {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing} feature.\n *\n * Read more in {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig}.\n *\n * @member {module:font/fontbackgroundcolor~FontBackgroundColorConfig} module:core/editor/editorconfig~EditorConfig#fontBackgroundColor\n */\n\n/**\n * The configuration of the font background color feature.\n * This option is used by the {@link module:font/fontbackgroundcolor/fontbackgroundcolorediting~FontBackgroundColorEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n *\t\t\t\tfontBackgroundColor: ... // Font background color feature configuration.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface module:font/fontbackgroundcolor~FontBackgroundColorConfig\n */\n\n/**\n * Available font background colors defined as an array of strings or objects.\n *\n * The default value registers the following colors:\n *\n *\t\tconst fontBackgroundColorConfig = {\n *\t\t\tcolors: [\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 0%)',\n *\t\t\t\t\tlabel: 'Black'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 30%)',\n *\t\t\t\t\tlabel: 'Dim grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\t\tlabel: 'Grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\t\tlabel: 'Light grey'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\t\tlabel: 'White',\n *\t\t\t\t\thasBorder: true\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(0, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Red'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(30, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Orange'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(60, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Yellow'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(90, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Green'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(150, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Aquamarine'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(180, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Turquoise'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(210, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Light blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(240, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Blue'\n *\t\t\t\t},\n *\t\t\t\t{\n *\t\t\t\t\tcolor: 'hsl(270, 75%, 60%)',\n *\t\t\t\t\tlabel: 'Purple'\n *\t\t\t\t}\n *\t\t\t]\n *\t\t};\n *\n * **Note**: The colors are displayed in the `'fontBackgroundColor'` dropdown.\n *\n * @member {Array.<String|Object>} module:font/fontbackgroundcolor~FontBackgroundColorConfig#colors\n */\n\n/**\n * Represents the number of columns in the font background color dropdown.\n *\n * The default value is:\n *\n *\t\tconst fontBackgroundColorConfig = {\n *\t\t\tcolumns: 5\n *\t\t}\n *\n * @member {Number} module:font/fontbackgroundcolor~FontBackgroundColorConfig#columns\n */\n\n/**\n * Determines the maximum number of available document colors.\n * Setting it to `0` will disable the document colors feature.\n *\n * By default it equals to the {@link module:font/fontbackgroundcolor~FontBackgroundColorConfig#columns} value.\n *\n * Examples:\n *\n * \t// 1) Neither document colors nor columns are defined in the configuration.\n * \t// Document colors will equal 5,\n * \t// because the value will be inherited from columns,\n * \t// which has a predefined value of 5.\n * \tconst fontBackgroundColorConfig = {}\n *\n * \t// 2) Document colors will equal 8, because the value will be inherited from columns.\n * \tconst fontBackgroundColorConfig = {\n * \t\tcolumns: 8\n * \t}\n *\n * \t// 3) Document colors will equal 24, because it has its own value defined.\n * \tconst fontBackgroundColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 24\n * \t}\n *\n * \t// 4) The document colors feature will be disabled.\n * \tconst fontBackgroundColorConfig = {\n * \t\tcolumns: 8,\n * \t\tdocumentColors: 0\n * \t}\n *\n * @member {Number} module:font/fontbackgroundcolor~FontBackgroundColorConfig#documentColors\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 code-block/utils\n */\n\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * Returns code block languages as defined in `config.codeBlock.languages` but processed:\n *\n * * To consider the editor localization, i.e. to display {@link module:code-block/codeblock~CodeBlockLanguageDefinition}\n * in the correct language. There is no way to use {@link module:utils/locale~Locale#t} when the user\n * configuration is defined because the editor does not exist yet.\n * * To make sure each definition has a CSS class associated with it even if not specified\n * in the original configuration.\n *\n * @param {module:core/editor/editor~Editor} editor\n * @returns {Array.<module:code-block/codeblock~CodeBlockLanguageDefinition>}.\n */\nexport function getNormalizedAndLocalizedLanguageDefinitions( editor ) {\n\tconst t = editor.t;\n\tconst languageDefs = editor.config.get( 'codeBlock.languages' );\n\n\tfor ( const def of languageDefs ) {\n\t\tif ( def.label === 'Plain text' ) {\n\t\t\tdef.label = t( 'Plain text' );\n\t\t}\n\n\t\tif ( def.class === undefined ) {\n\t\t\tdef.class = `language-${ def.language }`;\n\t\t}\n\t}\n\n\treturn languageDefs;\n}\n\n/**\n * Returns an object associating certain language definition properties with others. For instance:\n *\n * For:\n *\n *\t\tconst definitions = {\n *\t\t\t{ language: 'php', class: 'language-php', label: 'PHP' },\n *\t\t\t{ language: 'javascript', class: 'js', label: 'JavaScript' },\n *\t\t};\n *\n *\t\tgetPropertyAssociation( definitions, 'class', 'language' );\n *\n * returns:\n *\n *\t\t{\n *\t\t\t'language-php': 'php'\n *\t\t\t'js': 'javascript'\n *\t\t}\n *\n * and\n *\n *\t\tgetPropertyAssociation( definitions, 'language', 'label' );\n *\n * returns:\n *\n *\t\t{\n *\t\t\t'php': 'PHP'\n *\t\t\t'javascript': 'JavaScript'\n *\t\t}\n *\n * @param {Array.<module:code-block/codeblock~CodeBlockLanguageDefinition>}\n * @param {String} key\n * @param {String} value\n * @param {Object.<String,String>}\n */\nexport function getPropertyAssociation( languageDefs, key, value ) {\n\tconst association = {};\n\n\tfor ( const def of languageDefs ) {\n\t\tif ( key === 'class' ) {\n\t\t\t// Only the first class is considered.\n\t\t\tassociation[ def[ key ].split( ' ' ).shift() ] = def[ value ];\n\t\t} else {\n\t\t\tassociation[ def[ key ] ] = def[ value ];\n\t\t}\n\t}\n\n\treturn association;\n}\n\n/**\n * For a given model text node, it returns white spaces that precede other characters in that node.\n * This corresponds to the indentation part of the code block line.\n *\n * @param {module:engine/model/text~Text} codeLineNodes\n * @returns {String}\n */\nexport function getLeadingWhiteSpaces( textNode ) {\n\treturn textNode.data.match( /^(\\s*)/ )[ 0 ];\n}\n\n/**\n * For plain text containing the code (a snippet), it returns a document fragment containing\n * view text nodes separated by `<br>` elements (in place of new line characters \"\\n\"), for instance:\n *\n * Input:\n *\n *\t\t\"foo()\\n\n *\t\tbar()\"\n *\n * Output:\n *\n *\t\t<DocumentFragment>\n *\t\t\t\"foo()\"\n *\t\t\t<br/>\n *\t\t\t\"bar()\"\n *\t\t</DocumentFragment>\n *\n * @param {module:engine/view/upcastwriter~UpcastWriter} writer\n * @param {String} text The raw code text to be converted.\n * @returns {module:engine/view/documentfragment~DocumentFragment}\n */\nexport function rawSnippetTextToViewDocumentFragment( writer, text ) {\n\tconst fragment = writer.createDocumentFragment();\n\tconst textLines = text.split( '\\n' );\n\n\tconst nodes = textLines.reduce( ( nodes, line, lineIndex ) => {\n\t\tnodes.push( line );\n\n\t\tif ( lineIndex < textLines.length - 1 ) {\n\t\t\tnodes.push( writer.createElement( 'br' ) );\n\t\t}\n\n\t\treturn nodes;\n\t}, [] );\n\n\twriter.appendChild( nodes, fragment );\n\n\treturn fragment;\n}\n\n/**\n * Returns an array of all model positions within the selection that represent code block lines.\n *\n * If the selection is collapsed, it returns the exact selection anchor position:\n *\n *\t\t<codeBlock>[]foo</codeBlock> -> <codeBlock>^foo</codeBlock>\n *\t\t<codeBlock>foo[]bar</codeBlock> -> <codeBlock>foo^bar</codeBlock>\n *\n * Otherwise, it returns positions **before** each text node belonging to all code blocks contained by the selection:\n *\n *\t\t<codeBlock> <codeBlock>\n *\t\t foo[bar ^foobar\n *\t\t <softBreak></softBreak> -> <softBreak></softBreak>\n *\t\t baz]qux ^bazqux\n *\t\t</codeBlock> </codeBlock>\n *\n * It also works across other noncode blocks:\n *\n *\t\t<codeBlock> <codeBlock>\n *\t\t foo[bar ^foobar\n *\t\t</codeBlock> </codeBlock>\n *\t\t<paragraph>text</paragraph> -> <paragraph>text</paragraph>\n *\t\t<codeBlock> <codeBlock>\n *\t\t baz]qux ^bazqux\n *\t\t</codeBlock> </codeBlock>\n *\n * **Note:** The positions are in reverse order so they do not get outdated when iterating over them and\n * the writer inserts or removes elements at the same time.\n *\n * **Note:** The position is located after the leading white spaces in the text node.\n *\n * @param {module:engine/model/model~Model} model\n * @returns {Array.<module:engine/model/position~Position>}\n */\nexport function getIndentOutdentPositions( model ) {\n\tconst selection = model.document.selection;\n\tconst positions = [];\n\n\t// When the selection is collapsed, there's only one position we can indent or outdent.\n\tif ( selection.isCollapsed ) {\n\t\tpositions.push( selection.anchor );\n\t}\n\n\t// When the selection is NOT collapsed, collect all positions starting before text nodes\n\t// (code lines) in any <codeBlock> within the selection.\n\telse {\n\t\t// Walk backward so positions we are about to collect here do not get outdated when\n\t\t// inserting or deleting using the writer.\n\t\tconst walker = selection.getFirstRange().getWalker( {\n\t\t\tignoreElementEnd: true,\n\t\t\tdirection: 'backward'\n\t\t} );\n\n\t\tfor ( const { item } of walker ) {\n\t\t\tif ( item.is( '$textProxy' ) && item.parent.is( 'element', 'codeBlock' ) ) {\n\t\t\t\tconst leadingWhiteSpaces = getLeadingWhiteSpaces( item.textNode );\n\t\t\t\tconst { parent, startOffset } = item.textNode;\n\n\t\t\t\t// Make sure the position is after all leading whitespaces in the text node.\n\t\t\t\tconst position = model.createPositionAt( parent, startOffset + leadingWhiteSpaces.length );\n\n\t\t\t\tpositions.push( position );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn positions;\n}\n\n/**\n * Checks if any of the blocks within the model selection is a code block.\n *\n * @param {module:engine/model/selection~Selection} selection\n * @returns {Boolean}\n */\nexport function isModelSelectionInCodeBlock( selection ) {\n\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\treturn firstBlock && firstBlock.is( 'element', 'codeBlock' );\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 code-block/codeblockcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\nimport { getNormalizedAndLocalizedLanguageDefinitions } from './utils';\n\n/**\n * The code block command plugin.\n *\n * @extends module:core/command~Command\n */\nexport default class CodeBlockCommand extends Command {\n\t/**\n\t * Whether the selection starts in a code block.\n\t *\n\t * @observable\n\t * @readonly\n\t * @member {Boolean} #value\n\t */\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.value = this._getValue();\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command. When the command {@link #value is on}, all topmost code blocks within\n\t * the selection will be removed. If it is off, all selected blocks will be flattened and\n\t * wrapped by a code block.\n\t *\n\t * @fires execute\n\t * @param {Object} [options] Command options.\n\t * @param {Boolean} [options.forceValue] If set, it will force the command behavior. If `true`, the command will apply a code block,\n\t * otherwise the command will remove the code block. If not set, the command will act basing on its current value.\n\t */\n\texecute( options = {} ) {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst normalizedLanguagesDefs = getNormalizedAndLocalizedLanguageDefinitions( editor );\n\t\tconst firstLanguageInConfig = normalizedLanguagesDefs[ 0 ];\n\n\t\tconst blocks = Array.from( selection.getSelectedBlocks() );\n\t\tconst value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;\n\t\tconst language = options.language || firstLanguageInConfig.language;\n\n\t\tmodel.change( writer => {\n\t\t\tif ( value ) {\n\t\t\t\tthis._applyCodeBlock( writer, blocks, language );\n\t\t\t} else {\n\t\t\t\tthis._removeCodeBlock( writer, blocks );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks the command's {@link #value}.\n\t *\n\t * @private\n\t * @returns {Boolean} The current value.\n\t */\n\t_getValue() {\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\t\tconst isCodeBlock = !!( firstBlock && firstBlock.is( 'element', 'codeBlock' ) );\n\n\t\treturn isCodeBlock ? firstBlock.getAttribute( 'language' ) : false;\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\tif ( this.value ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst selection = this.editor.model.document.selection;\n\t\tconst schema = this.editor.model.schema;\n\n\t\tconst firstBlock = first( selection.getSelectedBlocks() );\n\n\t\tif ( !firstBlock ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn canBeCodeBlock( schema, firstBlock );\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t * @param {String} [language]\n\t */\n\t_applyCodeBlock( writer, blocks, language ) {\n\t\tconst schema = this.editor.model.schema;\n\t\tconst allowedBlocks = blocks.filter( block => canBeCodeBlock( schema, block ) );\n\n\t\tfor ( const block of allowedBlocks ) {\n\t\t\twriter.rename( block, 'codeBlock' );\n\t\t\twriter.setAttribute( 'language', language, block );\n\t\t\tschema.removeDisallowedAttributes( [ block ], writer );\n\t\t}\n\n\t\tallowedBlocks.reverse().forEach( ( currentBlock, i ) => {\n\t\t\tconst nextBlock = allowedBlocks[ i + 1 ];\n\n\t\t\tif ( currentBlock.previousSibling === nextBlock ) {\n\t\t\t\twriter.appendElement( 'softBreak', nextBlock );\n\t\t\t\twriter.merge( writer.createPositionBefore( currentBlock ) );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @private\n\t * @param {module:engine/model/writer~Writer} writer\n\t * @param {Array.<module:engine/model/element~Element>} blocks\n\t */\n\t_removeCodeBlock( writer, blocks ) {\n\t\tconst codeBlocks = blocks.filter( block => block.is( 'element', 'codeBlock' ) );\n\n\t\tfor ( const block of codeBlocks ) {\n\t\t\tconst range = writer.createRangeOn( block );\n\n\t\t\tfor ( const item of Array.from( range.getItems() ).reverse() ) {\n\t\t\t\tif ( item.is( 'element', 'softBreak' ) && item.parent.is( 'element', 'codeBlock' ) ) {\n\t\t\t\t\tconst { position } = writer.split( writer.createPositionBefore( item ) );\n\n\t\t\t\t\twriter.rename( position.nodeAfter, 'paragraph' );\n\t\t\t\t\twriter.removeAttribute( 'language', position.nodeAfter );\n\t\t\t\t\twriter.remove( item );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twriter.rename( block, 'paragraph' );\n\t\t\twriter.removeAttribute( 'language', block );\n\t\t}\n\t}\n}\n\nfunction canBeCodeBlock( schema, element ) {\n\tif ( element.is( 'rootElement' ) || schema.isLimit( element ) ) {\n\t\treturn false;\n\t}\n\n\treturn schema.checkChild( element.parent, 'codeBlock' );\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 code-block/indentcodeblockcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport {\n\tgetIndentOutdentPositions,\n\tisModelSelectionInCodeBlock\n} from './utils';\n\n/**\n * The code block indentation increase command plugin.\n *\n * @extends module:core/command~Command\n */\nexport default class IndentCodeBlockCommand extends Command {\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A sequence of characters added to the line when the command is executed.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._indentSequence = editor.config.get( 'codeBlock.indentSequence' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command. When the command {@link #isEnabled is enabled}, the indentation of the\n\t * code lines in the selection will be increased.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tmodel.change( writer => {\n\t\t\tconst positions = getIndentOutdentPositions( model );\n\n\t\t\t// Indent all positions, for instance assuming the indent sequence is 4x space (\" \"):\n\t\t\t//\n\t\t\t//\t\t<codeBlock>^foo</codeBlock> -> <codeBlock> foo</codeBlock>\n\t\t\t//\n\t\t\t//\t\t<codeBlock>foo^bar</codeBlock> -> <codeBlock>foo bar</codeBlock>\n\t\t\t//\n\t\t\t// Also, when there is more than one position:\n\t\t\t//\n\t\t\t//\t\t<codeBlock>\n\t\t\t//\t\t\t^foobar\n\t\t\t//\t\t\t<softBreak></softBreak>\n\t\t\t//\t\t\t^bazqux\n\t\t\t//\t\t</codeBlock>\n\t\t\t//\n\t\t\t//\t\t->\n\t\t\t//\n\t\t\t//\t\t<codeBlock>\n\t\t\t//\t\t\t foobar\n\t\t\t//\t\t\t<softBreak></softBreak>\n\t\t\t//\t\t\t bazqux\n\t\t\t//\t\t</codeBlock>\n\t\t\t//\n\t\t\tfor ( const position of positions ) {\n\t\t\t\twriter.insertText( this._indentSequence, position );\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\tif ( !this._indentSequence ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Indent (forward) command is always enabled when there's any code block in the selection\n\t\t// because you can always indent code lines.\n\t\treturn isModelSelectionInCodeBlock( this.editor.model.document.selection );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module code-block/outdentcodeblockcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\n\nimport {\n\tgetLeadingWhiteSpaces,\n\tgetIndentOutdentPositions,\n\tisModelSelectionInCodeBlock\n} from './utils';\n\n/**\n * The code block indentation decrease command plugin.\n *\n * @extends module:core/command~Command\n */\nexport default class OutdentCodeBlockCommand extends Command {\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * A sequence of characters removed from the line when the command is executed.\n\t\t *\n\t\t * @readonly\n\t\t * @private\n\t\t * @member {String}\n\t\t */\n\t\tthis._indentSequence = editor.config.get( 'codeBlock.indentSequence' );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._checkEnabled();\n\t}\n\n\t/**\n\t * Executes the command. When the command {@link #isEnabled is enabled}, the indentation of the\n\t * code lines in the selection will be decreased.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tmodel.change( writer => {\n\t\t\tconst positions = getIndentOutdentPositions( model );\n\n\t\t\t// Outdent all positions, for instance assuming the indent sequence is 4x space (\" \"):\n\t\t\t//\n\t\t\t//\t\t<codeBlock>^foo</codeBlock> -> <codeBlock>foo</codeBlock>\n\t\t\t//\n\t\t\t//\t\t<codeBlock> ^bar</codeBlock> -> <codeBlock>bar</codeBlock>\n\t\t\t//\n\t\t\t// Also, when there is more than one position:\n\t\t\t//\n\t\t\t//\t\t<codeBlock>\n\t\t\t//\t\t\t ^foobar\n\t\t\t//\t\t\t<softBreak></softBreak>\n\t\t\t//\t\t\t ^bazqux\n\t\t\t//\t\t</codeBlock>\n\t\t\t//\n\t\t\t//\t\t->\n\t\t\t//\n\t\t\t//\t\t<codeBlock>\n\t\t\t//\t\t\tfoobar\n\t\t\t//\t\t\t<softBreak></softBreak>\n\t\t\t//\t\t\tbazqux\n\t\t\t//\t\t</codeBlock>\n\t\t\tfor ( const position of positions ) {\n\t\t\t\tconst range = getLastOutdentableSequenceRange( this.editor.model, position, this._indentSequence );\n\n\t\t\t\tif ( range ) {\n\t\t\t\t\twriter.remove( range );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Checks whether the command can be enabled in the current context.\n\t *\n\t * @private\n\t * @returns {Boolean} Whether the command should be enabled.\n\t */\n\t_checkEnabled() {\n\t\tif ( !this._indentSequence ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst model = this.editor.model;\n\n\t\tif ( !isModelSelectionInCodeBlock( model.document.selection ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Outdent command can execute only when there is an indent character sequence\n\t\t// in some of the lines.\n\t\treturn getIndentOutdentPositions( model ).some( position => {\n\t\t\treturn getLastOutdentableSequenceRange( model, position, this._indentSequence );\n\t\t} );\n\t}\n}\n\n// For a position coming from `getIndentOutdentPositions()`, it returns the range representing\n// the last occurrence of the indent sequence among the leading whitespaces of the code line the\n// position represents.\n//\n// For instance, assuming the indent sequence is 4x space (\" \"):\n//\n//\t\t<codeBlock>foo^</codeBlock> -> null\n//\t\t<codeBlock>foo^<softBreak></softBreak>bar</codeBlock> -> null\n//\t\t<codeBlock> ^foo</codeBlock> -> null\n//\t\t<codeBlock> ^foo</codeBlock> -> <codeBlock> [ ]foo</codeBlock>\n//\t\t<codeBlock> ^foo bar</codeBlock> -> <codeBlock>[ ]foo bar</codeBlock>\n//\n// @param {<module:engine/model/model~Model>} model\n// @param {<module:engine/model/position~Position>} position\n// @param {String} sequence\n// @returns {<module:engine/model/range~Range>|null}\nfunction getLastOutdentableSequenceRange( model, position, sequence ) {\n\t// Positions start before each text node (code line). Get the node corresponding to the position.\n\tconst nodeAtPosition = getCodeLineTextNodeAtPosition( position );\n\n\tif ( !nodeAtPosition ) {\n\t\treturn null;\n\t}\n\n\tconst leadingWhiteSpaces = getLeadingWhiteSpaces( nodeAtPosition );\n\tconst lastIndexOfSequence = leadingWhiteSpaces.lastIndexOf( sequence );\n\n\t// For instance, assuming the indent sequence is 4x space (\" \"):\n\t//\n\t//\t\t<codeBlock> \t^foo</codeBlock> -> null\n\t//\n\tif ( lastIndexOfSequence + sequence.length !== leadingWhiteSpaces.length ) {\n\t\treturn null;\n\t}\n\n\t// For instance, assuming the indent sequence is 4x space (\" \"):\n\t//\n\t//\t\t<codeBlock> ^foo</codeBlock> -> null\n\t//\n\tif ( lastIndexOfSequence === -1 ) {\n\t\treturn null;\n\t}\n\n\tconst { parent, startOffset } = nodeAtPosition;\n\n\t// Create a range that contains the **last** indent sequence among the leading whitespaces\n\t// of the line.\n\t//\n\t// For instance, assuming the indent sequence is 4x space (\" \"):\n\t//\n\t//\t\t<codeBlock> ^foo</codeBlock> -> <codeBlock> [ ]foo</codeBlock>\n\t//\n\treturn model.createRange(\n\t\tmodel.createPositionAt( parent, startOffset + lastIndexOfSequence ),\n\t\tmodel.createPositionAt( parent, startOffset + lastIndexOfSequence + sequence.length )\n\t);\n}\n\nfunction getCodeLineTextNodeAtPosition( position ) {\n\t// Positions start before each text node (code line). Get the node corresponding to the position.\n\tlet nodeAtPosition = position.parent.getChild( position.index );\n\n\t// <codeBlock>foo^</codeBlock>\n\t// <codeBlock>foo^<softBreak></softBreak>bar</codeBlock>\n\tif ( !nodeAtPosition || nodeAtPosition.is( 'element', 'softBreak' ) ) {\n\t\tnodeAtPosition = position.nodeBefore;\n\t}\n\n\t// <codeBlock>^</codeBlock>\n\t// <codeBlock>foo^<softBreak></softBreak>bar</codeBlock>\n\tif ( !nodeAtPosition || nodeAtPosition.is( 'element', 'softBreak' ) ) {\n\t\treturn null;\n\t}\n\n\treturn nodeAtPosition;\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 code-block/converters\n */\n\nimport { getPropertyAssociation } from './utils';\n\n/**\n * A model-to-view (both editing and data) converter for the `codeBlock` element.\n *\n * Sample input:\n *\n *\t\t<codeBlock language=\"javascript\">foo();<softBreak></softBreak>bar();</codeBlock>\n *\n * Sample output (editing):\n *\n *\t\t<pre data-language=\"JavaScript\"><code class=\"language-javascript\">foo();<br />bar();</code></pre>\n *\n * Sample output (data, see {@link module:code-block/converters~modelToDataViewSoftBreakInsertion}):\n *\n *\t\t<pre><code class=\"language-javascript\">foo();\\nbar();</code></pre>\n *\n * @param {module:engine/model/model~Model} model\n * @param {Array.<module:code-block/codeblock~CodeBlockLanguageDefinition>} languageDefs The normalized language\n * configuration passed to the feature.\n * @param {Boolean} [useLabels=false] When `true`, the `<pre>` element will get a `data-language` attribute with a\n * humanreadable label of the language. Used only in the editing.\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelToViewCodeBlockInsertion( model, languageDefs, useLabels = false ) {\n\t// Language CSS classes:\n\t//\n\t//\t\t{\n\t//\t\t\tphp: 'language-php',\n\t//\t\t\tpython: 'language-python',\n\t//\t\t\tjavascript: 'js',\n\t//\t\t\t...\n\t//\t\t}\n\tconst languagesToClasses = getPropertyAssociation( languageDefs, 'language', 'class' );\n\n\t// Language labels:\n\t//\n\t//\t\t{\n\t//\t\t\tphp: 'PHP',\n\t//\t\t\tpython: 'Python',\n\t//\t\t\tjavascript: 'JavaScript',\n\t//\t\t\t...\n\t//\t\t}\n\tconst languagesToLabels = getPropertyAssociation( languageDefs, 'language', 'label' );\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst { writer, mapper, consumable } = conversionApi;\n\n\t\tif ( !consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst codeBlockLanguage = data.item.getAttribute( 'language' );\n\t\tconst targetViewPosition = mapper.toViewPosition( model.createPositionBefore( data.item ) );\n\t\tconst preAttributes = {};\n\n\t\t// Attributes added only in the editing view.\n\t\tif ( useLabels ) {\n\t\t\tpreAttributes[ 'data-language' ] = languagesToLabels[ codeBlockLanguage ];\n\t\t\tpreAttributes.spellcheck = 'false';\n\t\t}\n\n\t\tconst pre = writer.createContainerElement( 'pre', preAttributes );\n\t\tconst code = writer.createContainerElement( 'code', {\n\t\t\tclass: languagesToClasses[ codeBlockLanguage ] || null\n\t\t} );\n\n\t\twriter.insert( writer.createPositionAt( pre, 0 ), code );\n\t\twriter.insert( targetViewPosition, pre );\n\t\tmapper.bindElements( data.item, code );\n\t};\n}\n\n/**\n * A model-to-data view converter for the new line (`softBreak`) separator.\n *\n * Sample input:\n *\n *\t\t<codeBlock ...>foo();<softBreak></softBreak>bar();</codeBlock>\n *\n * Sample output:\n *\n *\t\t<pre><code ...>foo();\\nbar();</code></pre>\n *\n * @param {module:engine/model/model~Model} model\n * @returns {Function} Returns a conversion callback.\n */\nexport function modelToDataViewSoftBreakInsertion( model ) {\n\treturn ( evt, data, conversionApi ) => {\n\t\tif ( data.item.parent.name !== 'codeBlock' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { writer, mapper, consumable } = conversionApi;\n\n\t\tif ( !consumable.consume( data.item, 'insert' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst position = mapper.toViewPosition( model.createPositionBefore( data.item ) );\n\n\t\twriter.insert( position, writer.createText( '\\n' ) );\n\t};\n}\n\n/**\n * A view-to-model converter for `<pre>` with the `<code>` HTML.\n *\n * Sample input:\n *\n *\t\t<pre><code class=\"language-javascript\">foo();bar();</code></pre>\n *\n * Sample output:\n *\n *\t\t<codeBlock language=\"javascript\">foo();bar();</codeBlock>\n *\n * @param {module:engine/view/view~View} editingView\n * @param {Array.<module:code-block/codeblock~CodeBlockLanguageDefinition>} languageDefs The normalized language\n * configuration passed to the feature.\n * @returns {Function} Returns a conversion callback.\n */\nexport function dataViewToModelCodeBlockInsertion( editingView, languageDefs ) {\n\t// Language names associated with CSS classes:\n\t//\n\t//\t\t{\n\t//\t\t\t'language-php': 'php',\n\t//\t\t\t'language-python': 'python',\n\t//\t\t\tjs: 'javascript',\n\t//\t\t\t...\n\t//\t\t}\n\tconst classesToLanguages = getPropertyAssociation( languageDefs, 'class', 'language' );\n\tconst defaultLanguageName = languageDefs[ 0 ].language;\n\n\treturn ( evt, data, conversionApi ) => {\n\t\tconst viewCodeElement = data.viewItem;\n\t\tconst viewPreElement = viewCodeElement.parent;\n\n\t\tif ( !viewPreElement || !viewPreElement.is( 'element', 'pre' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// In case of nested code blocks we don't want to convert to another code block.\n\t\tif ( data.modelCursor.findAncestor( 'codeBlock' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { consumable, writer } = conversionApi;\n\n\t\tif ( !consumable.test( viewCodeElement, { name: true } ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst codeBlock = writer.createElement( 'codeBlock' );\n\t\tconst viewChildClasses = [ ...viewCodeElement.getClassNames() ];\n\n\t\t// As we're to associate each class with a model language, a lack of class (empty class) can be\n\t\t// also associated with a language if the language definition was configured so. Pushing an empty\n\t\t// string to make sure the association will work.\n\t\tif ( !viewChildClasses.length ) {\n\t\t\tviewChildClasses.push( '' );\n\t\t}\n\n\t\t// Figure out if any of the <code> element's class names is a valid programming\n\t\t// language class. If so, use it on the model element (becomes the language of the entire block).\n\t\tfor ( const className of viewChildClasses ) {\n\t\t\tconst language = classesToLanguages[ className ];\n\n\t\t\tif ( language ) {\n\t\t\t\twriter.setAttribute( 'language', language, codeBlock );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If no language value was set, use the default language from the config.\n\t\tif ( !codeBlock.hasAttribute( 'language' ) ) {\n\t\t\twriter.setAttribute( 'language', defaultLanguageName, codeBlock );\n\t\t}\n\n\t\tconversionApi.convertChildren( viewCodeElement, codeBlock );\n\n\t\t// Let's try to insert code block.\n\t\tif ( !conversionApi.safeInsert( codeBlock, data.modelCursor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconsumable.consume( viewCodeElement, { name: true } );\n\n\t\tconversionApi.updateConversionResult( codeBlock, data );\n\t};\n}\n\n/**\n * A view-to-model converter for new line characters in `<pre>`.\n *\n * Sample input:\n *\n *\t\t<pre><code class=\"language-javascript\">foo();\\nbar();</code></pre>\n *\n * Sample output:\n *\n *\t\t<codeBlock language=\"javascript\">foo();<softBreak></softBreak>bar();</codeBlock>\n *\n * @returns {Function} Returns a conversion callback.\n */\nexport function dataViewToModelTextNewlinesInsertion() {\n\treturn ( evt, data, { consumable, writer } ) => {\n\t\tlet position = data.modelCursor;\n\n\t\t// When node is already converted then do nothing.\n\t\tif ( !consumable.test( data.viewItem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// When not inside `codeBlock` then do nothing.\n\t\tif ( !position.findAncestor( 'codeBlock' ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconsumable.consume( data.viewItem );\n\n\t\tconst text = data.viewItem.data;\n\t\tconst textLines = text.split( '\\n' ).map( data => writer.createText( data ) );\n\t\tconst lastLine = textLines[ textLines.length - 1 ];\n\n\t\tfor ( const node of textLines ) {\n\t\t\twriter.insert( node, position );\n\t\t\tposition = position.getShiftedBy( node.offsetSize );\n\n\t\t\tif ( node !== lastLine ) {\n\t\t\t\tconst softBreak = writer.createElement( 'softBreak' );\n\n\t\t\t\twriter.insert( softBreak, position );\n\t\t\t\tposition = writer.createPositionAfter( softBreak );\n\t\t\t}\n\t\t}\n\n\t\tdata.modelRange = writer.createRange(\n\t\t\tdata.modelCursor,\n\t\t\tposition\n\t\t);\n\t\tdata.modelCursor = position;\n\t};\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module code-block/codeblockediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ShiftEnter } from 'ckeditor5/src/enter';\nimport { UpcastWriter } from 'ckeditor5/src/engine';\n\nimport CodeBlockCommand from './codeblockcommand';\nimport IndentCodeBlockCommand from './indentcodeblockcommand';\nimport OutdentCodeBlockCommand from './outdentcodeblockcommand';\nimport {\n\tgetNormalizedAndLocalizedLanguageDefinitions,\n\tgetLeadingWhiteSpaces,\n\trawSnippetTextToViewDocumentFragment\n} from './utils';\nimport {\n\tmodelToViewCodeBlockInsertion,\n\tmodelToDataViewSoftBreakInsertion,\n\tdataViewToModelCodeBlockInsertion,\n\tdataViewToModelTextNewlinesInsertion\n} from './converters';\n\nconst DEFAULT_ELEMENT = 'paragraph';\n\n/**\n * The editing part of the code block feature.\n *\n * Introduces the `'codeBlock'` command and the `'codeBlock'` model element.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CodeBlockEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CodeBlockEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ShiftEnter ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'codeBlock', {\n\t\t\tlanguages: [\n\t\t\t\t{ language: 'plaintext', label: 'Plain text' },\n\t\t\t\t{ language: 'c', label: 'C' },\n\t\t\t\t{ language: 'cs', label: 'C#' },\n\t\t\t\t{ language: 'cpp', label: 'C++' },\n\t\t\t\t{ language: 'css', label: 'CSS' },\n\t\t\t\t{ language: 'diff', label: 'Diff' },\n\t\t\t\t{ language: 'html', label: 'HTML' },\n\t\t\t\t{ language: 'java', label: 'Java' },\n\t\t\t\t{ language: 'javascript', label: 'JavaScript' },\n\t\t\t\t{ language: 'php', label: 'PHP' },\n\t\t\t\t{ language: 'python', label: 'Python' },\n\t\t\t\t{ language: 'ruby', label: 'Ruby' },\n\t\t\t\t{ language: 'typescript', label: 'TypeScript' },\n\t\t\t\t{ language: 'xml', label: 'XML' }\n\t\t\t],\n\n\t\t\t// A single tab.\n\t\t\tindentSequence: '\\t'\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst model = editor.model;\n\t\tconst view = editor.editing.view;\n\n\t\tconst normalizedLanguagesDefs = getNormalizedAndLocalizedLanguageDefinitions( editor );\n\n\t\t// The main command.\n\t\teditor.commands.add( 'codeBlock', new CodeBlockCommand( editor ) );\n\n\t\t// Commands that change the indentation.\n\t\teditor.commands.add( 'indentCodeBlock', new IndentCodeBlockCommand( editor ) );\n\t\teditor.commands.add( 'outdentCodeBlock', new OutdentCodeBlockCommand( editor ) );\n\n\t\tconst getCommandExecuter = commandName => {\n\t\t\treturn ( data, cancel ) => {\n\t\t\t\tconst command = this.editor.commands.get( commandName );\n\n\t\t\t\tif ( command.isEnabled ) {\n\t\t\t\t\tthis.editor.execute( commandName );\n\t\t\t\t\tcancel();\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\n\t\teditor.keystrokes.set( 'Tab', getCommandExecuter( 'indentCodeBlock' ) );\n\t\teditor.keystrokes.set( 'Shift+Tab', getCommandExecuter( 'outdentCodeBlock' ) );\n\n\t\tschema.register( 'codeBlock', {\n\t\t\tallowWhere: '$block',\n\t\t\tisBlock: true,\n\t\t\tallowAttributes: [ 'language' ]\n\t\t} );\n\n\t\tschema.extend( '$text', {\n\t\t\tallowIn: 'codeBlock'\n\t\t} );\n\n\t\t// Disallow all attributes on $text inside `codeBlock`.\n\t\tschema.addAttributeCheck( context => {\n\t\t\tif ( context.endsWith( 'codeBlock $text' ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} );\n\n\t\t// Conversion.\n\t\teditor.editing.downcastDispatcher.on( 'insert:codeBlock', modelToViewCodeBlockInsertion( model, normalizedLanguagesDefs, true ) );\n\t\teditor.data.downcastDispatcher.on( 'insert:codeBlock', modelToViewCodeBlockInsertion( model, normalizedLanguagesDefs ) );\n\t\teditor.data.downcastDispatcher.on( 'insert:softBreak', modelToDataViewSoftBreakInsertion( model ), { priority: 'high' } );\n\n\t\teditor.data.upcastDispatcher.on( 'element:code', dataViewToModelCodeBlockInsertion( view, normalizedLanguagesDefs ) );\n\t\teditor.data.upcastDispatcher.on( 'text', dataViewToModelTextNewlinesInsertion() );\n\n\t\t// Intercept the clipboard input (paste) when the selection is anchored in the code block and force the clipboard\n\t\t// data to be pasted as a single plain text. Otherwise, the code lines will split the code block and\n\t\t// \"spill out\" as separate paragraphs.\n\t\tthis.listenTo( editor.editing.view.document, 'clipboardInput', ( evt, data ) => {\n\t\t\tlet insertionRange = model.createRange( model.document.selection.anchor );\n\n\t\t\t// Use target ranges in case this is a drop.\n\t\t\tif ( data.targetRanges ) {\n\t\t\t\tinsertionRange = editor.editing.mapper.toModelRange( data.targetRanges[ 0 ] );\n\t\t\t}\n\n\t\t\tif ( !insertionRange.start.parent.is( 'element', 'codeBlock' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst text = data.dataTransfer.getData( 'text/plain' );\n\t\t\tconst writer = new UpcastWriter( editor.editing.view.document );\n\n\t\t\t// Pass the view fragment to the default clipboardInput handler.\n\t\t\tdata.content = rawSnippetTextToViewDocumentFragment( writer, text );\n\t\t} );\n\n\t\t// Make sure multiline selection is always wrapped in a code block when `getSelectedContent()`\n\t\t// is used (e.g. clipboard copy). Otherwise, only the raw text will be copied to the clipboard and,\n\t\t// upon next paste, this bare text will not be inserted as a code block, which is not the best UX.\n\t\t// Similarly, when the selection in a single line, the selected content should be an inline code\n\t\t// so it can be pasted later on and retain it's preformatted nature.\n\t\tthis.listenTo( model, 'getSelectedContent', ( evt, [ selection ] ) => {\n\t\t\tconst anchor = selection.anchor;\n\n\t\t\tif ( selection.isCollapsed || !anchor.parent.is( 'element', 'codeBlock' ) || !anchor.hasSameParentAs( selection.focus ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmodel.change( writer => {\n\t\t\t\tconst docFragment = evt.return;\n\n\t\t\t\t// fo[o<softBreak></softBreak>b]ar -> <codeBlock language=\"...\">[o<softBreak></softBreak>b]<codeBlock>\n\t\t\t\tif ( docFragment.childCount > 1 || selection.containsEntireContent( anchor.parent ) ) {\n\t\t\t\t\tconst codeBlock = writer.createElement( 'codeBlock', anchor.parent.getAttributes() );\n\t\t\t\t\twriter.append( docFragment, codeBlock );\n\n\t\t\t\t\tconst newDocumentFragment = writer.createDocumentFragment();\n\t\t\t\t\twriter.append( codeBlock, newDocumentFragment );\n\n\t\t\t\t\tevt.return = newDocumentFragment;\n\t\t\t\t}\n\n\t\t\t\t// \"f[oo]\" -> <$text code=\"true\">oo</text>\n\t\t\t\telse {\n\t\t\t\t\tconst textNode = docFragment.getChild( 0 );\n\n\t\t\t\t\tif ( schema.checkAttribute( textNode, 'code' ) ) {\n\t\t\t\t\t\twriter.setAttribute( 'code', true, textNode );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst commands = editor.commands;\n\t\tconst indent = commands.get( 'indent' );\n\t\tconst outdent = commands.get( 'outdent' );\n\n\t\tif ( indent ) {\n\t\t\tindent.registerChildCommand( commands.get( 'indentCodeBlock' ) );\n\t\t}\n\n\t\tif ( outdent ) {\n\t\t\toutdent.registerChildCommand( commands.get( 'outdentCodeBlock' ) );\n\t\t}\n\n\t\t// Customize the response to the <kbd>Enter</kbd> and <kbd>Shift</kbd>+<kbd>Enter</kbd>\n\t\t// key press when the selection is in the code block. Upon enter key press we can either\n\t\t// leave the block if it's \"two enters\" in a row or create a new code block line, preserving\n\t\t// previous line's indentation.\n\t\tthis.listenTo( editor.editing.view.document, 'enter', ( evt, data ) => {\n\t\t\tconst positionParent = editor.model.document.selection.getLastPosition().parent;\n\n\t\t\tif ( !positionParent.is( 'element', 'codeBlock' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !leaveBlockStartOnEnter( editor, data.isSoft ) && !leaveBlockEndOnEnter( editor, data.isSoft ) ) {\n\t\t\t\tbreakLineOnEnter( editor );\n\t\t\t}\n\n\t\t\tdata.preventDefault();\n\t\t\tevt.stop();\n\t\t}, { context: 'pre' } );\n\t}\n}\n\n// Normally, when the Enter (or Shift+Enter) key is pressed, a soft line break is to be added to the\n// code block. Let's try to follow the indentation of the previous line when possible, for instance:\n//\n//\t\t// Before pressing enter (or shift enter)\n//\t\t<codeBlock>\n//\t\t\" foo()\"[] // Indent of 4 spaces.\n//\t\t</codeBlock>\n//\n//\t\t// After pressing:\n//\t\t<codeBlock>\n//\t\t\" foo()\" // Indent of 4 spaces.\n//\t\t<softBreak></softBreak> // A new soft break created by pressing enter.\n//\t\t\" \"[] // Retain the indent of 4 spaces.\n//\t\t</codeBlock>\n//\n// @param {module:core/editor/editor~Editor} editor\nfunction breakLineOnEnter( editor ) {\n\tconst model = editor.model;\n\tconst modelDoc = model.document;\n\tconst lastSelectionPosition = modelDoc.selection.getLastPosition();\n\tconst node = lastSelectionPosition.nodeBefore || lastSelectionPosition.textNode;\n\tlet leadingWhiteSpaces;\n\n\t// Figure out the indentation (white space chars) at the beginning of the line.\n\tif ( node && node.is( '$text' ) ) {\n\t\tleadingWhiteSpaces = getLeadingWhiteSpaces( node );\n\t}\n\n\t// Keeping everything in a change block for a single undo step.\n\teditor.model.change( writer => {\n\t\teditor.execute( 'shiftEnter' );\n\n\t\t// If the line before being broken in two had some indentation, let's retain it\n\t\t// in the new line.\n\t\tif ( leadingWhiteSpaces ) {\n\t\t\twriter.insertText( leadingWhiteSpaces, modelDoc.selection.anchor );\n\t\t}\n\t} );\n}\n\n// Leave the code block when Enter (but NOT Shift+Enter) has been pressed twice at the beginning\n// of the code block:\n//\n//\t\t// Before:\n//\t\t<codeBlock>[]<softBreak></softBreak>foo</codeBlock>\n//\n//\t\t// After pressing:\n//\t\t<paragraph>[]</paragraph><codeBlock>foo</codeBlock>\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {Boolean} isSoftEnter When `true`, enter was pressed along with <kbd>Shift</kbd>.\n// @returns {Boolean} `true` when selection left the block. `false` if stayed.\nfunction leaveBlockStartOnEnter( editor, isSoftEnter ) {\n\tconst model = editor.model;\n\tconst modelDoc = model.document;\n\tconst view = editor.editing.view;\n\tconst lastSelectionPosition = modelDoc.selection.getLastPosition();\n\tconst nodeAfter = lastSelectionPosition.nodeAfter;\n\n\tif ( isSoftEnter || !modelDoc.selection.isCollapsed || !lastSelectionPosition.isAtStart ) {\n\t\treturn false;\n\t}\n\n\tif ( !nodeAfter || !nodeAfter.is( 'element', 'softBreak' ) ) {\n\t\treturn false;\n\t}\n\n\t// We're doing everything in a single change block to have a single undo step.\n\teditor.model.change( writer => {\n\t\t// \"Clone\" the <codeBlock> in the standard way.\n\t\teditor.execute( 'enter' );\n\n\t\t// The cloned block exists now before the original code block.\n\t\tconst newBlock = modelDoc.selection.anchor.parent.previousSibling;\n\n\t\t// Make the cloned <codeBlock> a regular <paragraph> (with clean attributes, so no language).\n\t\twriter.rename( newBlock, DEFAULT_ELEMENT );\n\t\twriter.setSelection( newBlock, 'in' );\n\t\teditor.model.schema.removeDisallowedAttributes( [ newBlock ], writer );\n\n\t\t// Remove the <softBreak> that originally followed the selection position.\n\t\twriter.remove( nodeAfter );\n\t} );\n\n\t// Eye candy.\n\tview.scrollToTheSelection();\n\n\treturn true;\n}\n\n// Leave the code block when Enter (but NOT Shift+Enter) has been pressed twice at the end\n// of the code block:\n//\n//\t\t// Before:\n//\t\t<codeBlock>foo[]</codeBlock>\n//\n//\t\t// After first press:\n//\t\t<codeBlock>foo<softBreak></softBreak>[]</codeBlock>\n//\n//\t\t// After second press:\n//\t\t<codeBlock>foo</codeBlock><paragraph>[]</paragraph>\n//\n// @param {module:core/editor/editor~Editor} editor\n// @param {Boolean} isSoftEnter When `true`, enter was pressed along with <kbd>Shift</kbd>.\n// @returns {Boolean} `true` when selection left the block. `false` if stayed.\nfunction leaveBlockEndOnEnter( editor, isSoftEnter ) {\n\tconst model = editor.model;\n\tconst modelDoc = model.document;\n\tconst view = editor.editing.view;\n\tconst lastSelectionPosition = modelDoc.selection.getLastPosition();\n\tconst nodeBefore = lastSelectionPosition.nodeBefore;\n\n\tlet emptyLineRangeToRemoveOnEnter;\n\n\tif ( isSoftEnter || !modelDoc.selection.isCollapsed || !lastSelectionPosition.isAtEnd || !nodeBefore ) {\n\t\treturn false;\n\t}\n\n\t// When the position is directly preceded by a soft break\n\t//\n\t//\t\t<codeBlock>foo<softBreak></softBreak>[]</codeBlock>\n\t//\n\t// it creates the following range that will be cleaned up before leaving:\n\t//\n\t//\t\t<codeBlock>foo[<softBreak></softBreak>]</codeBlock>\n\t//\n\tif ( nodeBefore.is( 'element', 'softBreak' ) ) {\n\t\temptyLineRangeToRemoveOnEnter = model.createRangeOn( nodeBefore );\n\t}\n\n\t// When there's some text before the position made purely of whitespace characters\n\t//\n\t//\t\t<codeBlock>foo<softBreak></softBreak> []</codeBlock>\n\t//\n\t// but NOT when it's the first one of the kind\n\t//\n\t//\t\t<codeBlock> []</codeBlock>\n\t//\n\t// it creates the following range to clean up before leaving:\n\t//\n\t//\t\t<codeBlock>foo[<softBreak></softBreak> ]</codeBlock>\n\t//\n\telse if (\n\t\tnodeBefore.is( '$text' ) &&\n\t\t!nodeBefore.data.match( /\\S/ ) &&\n\t\tnodeBefore.previousSibling &&\n\t\tnodeBefore.previousSibling.is( 'element', 'softBreak' )\n\t) {\n\t\temptyLineRangeToRemoveOnEnter = model.createRange(\n\t\t\tmodel.createPositionBefore( nodeBefore.previousSibling ), model.createPositionAfter( nodeBefore )\n\t\t);\n\t}\n\n\t// Not leaving the block in the following cases:\n\t//\n\t//\t\t<codeBlock> []</codeBlock>\n\t//\t\t<codeBlock> a []</codeBlock>\n\t//\t\t<codeBlock>foo<softBreak></softBreak>bar[]</codeBlock>\n\t//\t\t<codeBlock>foo<softBreak></softBreak> a []</codeBlock>\n\t//\n\telse {\n\t\treturn false;\n\t}\n\n\t// We're doing everything in a single change block to have a single undo step.\n\teditor.model.change( writer => {\n\t\t// Remove the last <softBreak> and all white space characters that followed it.\n\t\twriter.remove( emptyLineRangeToRemoveOnEnter );\n\n\t\t// \"Clone\" the <codeBlock> in the standard way.\n\t\teditor.execute( 'enter' );\n\n\t\tconst newBlock = modelDoc.selection.anchor.parent;\n\n\t\t// Make the cloned <codeBlock> a regular <paragraph> (with clean attributes, so no language).\n\t\twriter.rename( newBlock, DEFAULT_ELEMENT );\n\t\teditor.model.schema.removeDisallowedAttributes( [ newBlock ], writer );\n\t} );\n\n\t// Eye candy.\n\tview.scrollToTheSelection();\n\n\treturn true;\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 code-block/codeblockui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Collection } from 'ckeditor5/src/utils';\nimport { Model, SplitButtonView, createDropdown, addListToDropdown } from 'ckeditor5/src/ui';\n\nimport { getNormalizedAndLocalizedLanguageDefinitions } from './utils';\n\nimport codeBlockIcon from '../theme/icons/codeblock.svg';\nimport '../theme/codeblock.css';\n\n/**\n * The code block UI plugin.\n *\n * Introduces the `'codeBlock'` dropdown.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CodeBlockUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CodeBlockUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst componentFactory = editor.ui.componentFactory;\n\t\tconst normalizedLanguageDefs = getNormalizedAndLocalizedLanguageDefinitions( editor );\n\t\tconst defaultLanguageDefinition = normalizedLanguageDefs[ 0 ];\n\n\t\tcomponentFactory.add( 'codeBlock', locale => {\n\t\t\tconst command = editor.commands.get( 'codeBlock' );\n\t\t\tconst dropdownView = createDropdown( locale, SplitButtonView );\n\t\t\tconst splitButtonView = dropdownView.buttonView;\n\n\t\t\tsplitButtonView.set( {\n\t\t\t\tlabel: t( 'Insert code block' ),\n\t\t\t\ttooltip: true,\n\t\t\t\ticon: codeBlockIcon,\n\t\t\t\tisToggleable: true\n\t\t\t} );\n\n\t\t\tsplitButtonView.bind( 'isOn' ).to( command, 'value', value => !!value );\n\n\t\t\tsplitButtonView.on( 'execute', () => {\n\t\t\t\teditor.execute( 'codeBlock', {\n\t\t\t\t\tlanguage: defaultLanguageDefinition.language\n\t\t\t\t} );\n\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\tdropdownView.on( 'execute', evt => {\n\t\t\t\teditor.execute( 'codeBlock', {\n\t\t\t\t\tlanguage: evt.source._codeBlockLanguage,\n\t\t\t\t\tforceValue: true\n\t\t\t\t} );\n\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\tdropdownView.class = 'ck-code-block-dropdown';\n\t\t\tdropdownView.bind( 'isEnabled' ).to( command );\n\n\t\t\taddListToDropdown( dropdownView, this._getLanguageListItemDefinitions( normalizedLanguageDefs ) );\n\n\t\t\treturn dropdownView;\n\t\t} );\n\t}\n\n\t/**\n\t * A helper returning a collection of the `codeBlock` dropdown items representing languages\n\t * available for the user to choose from.\n\t *\n\t * @private\n\t * @param {Array.<module:code-block/codeblock~CodeBlockLanguageDefinition>} normalizedLanguageDefs\n\t * @returns {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>}\n\t */\n\t_getLanguageListItemDefinitions( normalizedLanguageDefs ) {\n\t\tconst editor = this.editor;\n\t\tconst command = editor.commands.get( 'codeBlock' );\n\t\tconst itemDefinitions = new Collection();\n\n\t\tfor ( const languageDef of normalizedLanguageDefs ) {\n\t\t\tconst definition = {\n\t\t\t\ttype: 'button',\n\t\t\t\tmodel: new Model( {\n\t\t\t\t\t_codeBlockLanguage: languageDef.language,\n\t\t\t\t\tlabel: languageDef.label,\n\t\t\t\t\twithText: true\n\t\t\t\t} )\n\t\t\t};\n\n\t\t\tdefinition.model.bind( 'isOn' ).to( command, 'value', value => {\n\t\t\t\treturn value === definition.model._codeBlockLanguage;\n\t\t\t} );\n\n\t\t\titemDefinitions.add( definition );\n\t\t}\n\n\t\treturn itemDefinitions;\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M12.87 12.61a.75.75 0 0 1-.089.976l-.085.07-3.154 2.254 3.412 2.414a.75.75 0 0 1 .237.95l-.057.095a.75.75 0 0 1-.95.237l-.096-.058-4.272-3.022-.003-1.223 4.01-2.867a.75.75 0 0 1 1.047.174zm2.795-.231.095.057 4.011 2.867-.003 1.223-4.272 3.022-.095.058a.75.75 0 0 1-.88-.151l-.07-.086-.058-.095a.75.75 0 0 1 .15-.88l.087-.07 3.412-2.414-3.154-2.253-.085-.071a.75.75 0 0 1 .862-1.207zM16 0a2 2 0 0 1 2 2v9.354l-.663-.492-.837-.001V2a.5.5 0 0 0-.5-.5H2a.5.5 0 0 0-.5.5v15a.5.5 0 0 0 .5.5h3.118L7.156 19H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h14zM5.009 15l.003 1H3v-1h2.009zm2.188-2-1.471 1H5v-1h2.197zM10 11v.095L8.668 12H7v-1h3zm4-2v1H7V9h7zm0-2v1H7V7h7zm-4-2v1H5V5h5zM6 3v1H3V3h3z\\\"/></svg>\";","/**\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 mention/mentioncommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { CKEditorError, toMap } from 'ckeditor5/src/utils';\n\nimport { _addMentionAttributes } from './mentionediting';\n\n/**\n * The mention command.\n *\n * The command is registered by {@link module:mention/mentionediting~MentionEditing} as `'mention'`.\n *\n * To insert a mention onto a range, execute the command and specify a mention object with a range to replace:\n *\n *\t\tconst focus = editor.model.document.selection.focus;\n *\n *\t\t// It will replace one character before the selection focus with the '#1234' text\n *\t\t// with the mention attribute filled with passed attributes.\n *\t\teditor.execute( 'mention', {\n *\t\t\tmarker: '#',\n *\t\t\tmention: {\n *\t\t\t\tid: '#1234',\n *\t\t\t\tname: 'Foo',\n *\t\t\t\ttitle: 'Big Foo'\n *\t\t\t},\n *\t\t\trange: model.createRange( focus, focus.getShiftedBy( -1 ) )\n *\t\t} );\n *\n *\t\t// It will replace one character before the selection focus with the 'The \"Big Foo\"' text\n *\t\t// with the mention attribute filled with passed attributes.\n *\t\teditor.execute( 'mention', {\n *\t\t\tmarker: '#',\n *\t\t\tmention: {\n *\t\t\t\tid: '#1234',\n *\t\t\t\tname: 'Foo',\n *\t\t\t\ttitle: 'Big Foo'\n *\t\t\t},\n *\t\t\ttext: 'The \"Big Foo\"',\n *\t\t\trange: model.createRange( focus, focus.getShiftedBy( -1 ) )\n *\t\t} );\n *\n * @extends module:core/command~Command\n */\nexport default class MentionCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst doc = model.document;\n\n\t\tthis.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'mention' );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @param {Object} [options] Options for the executed command.\n\t * @param {Object|String} options.mention The mention object to insert. When a string is passed, it will be used to create a plain\n\t * object with the name attribute that equals the passed string.\n\t * @param {String} options.marker The marker character (e.g. `'@'`).\n\t * @param {String} [options.text] The text of the inserted mention. Defaults to the full mention string composed from `marker` and\n\t * `mention` string or `mention.id` if an object is passed.\n\t * @param {String} [options.range] The range to replace. Note that the replaced range might be shorter than the inserted text with the\n\t * mention attribute.\n\t * @fires execute\n\t */\n\texecute( options ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\t\tconst selection = document.selection;\n\n\t\tconst mentionData = typeof options.mention == 'string' ? { id: options.mention } : options.mention;\n\t\tconst mentionID = mentionData.id;\n\n\t\tconst range = options.range || selection.getFirstRange();\n\n\t\tconst mentionText = options.text || mentionID;\n\n\t\tconst mention = _addMentionAttributes( { _text: mentionText, id: mentionID }, mentionData );\n\n\t\tif ( options.marker.length != 1 ) {\n\t\t\t/**\n\t\t\t * The marker must be a single character.\n\t\t\t *\n\t\t\t * Correct markers: `'@'`, `'#'`.\n\t\t\t *\n\t\t\t * Incorrect markers: `'$$'`, `'[@'`.\n\t\t\t *\n\t\t\t * See {@link module:mention/mention~MentionConfig}.\n\t\t\t *\n\t\t\t * @error mentioncommand-incorrect-marker\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'mentioncommand-incorrect-marker',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tif ( mentionID.charAt( 0 ) != options.marker ) {\n\t\t\t/**\n\t\t\t * The feed item ID must start with the marker character.\n\t\t\t *\n\t\t\t * Correct mention feed setting:\n\t\t\t *\n\t\t\t *\t\tmentions: [\n\t\t\t *\t\t\t{\n\t\t\t *\t\t\t\tmarker: '@',\n\t\t\t *\t\t\t\tfeed: [ '@Ann', '@Barney', ... ]\n\t\t\t *\t\t\t}\n\t\t\t *\t\t]\n\t\t\t *\n\t\t\t * Incorrect mention feed setting:\n\t\t\t *\n\t\t\t *\t\tmentions: [\n\t\t\t *\t\t\t{\n\t\t\t *\t\t\t\tmarker: '@',\n\t\t\t *\t\t\t\tfeed: [ 'Ann', 'Barney', ... ]\n\t\t\t *\t\t\t}\n\t\t\t *\t\t]\n\t\t\t *\n\t\t\t * See {@link module:mention/mention~MentionConfig}.\n\t\t\t *\n\t\t\t * @error mentioncommand-incorrect-id\n\t\t\t */\n\t\t\tthrow new CKEditorError(\n\t\t\t\t'mentioncommand-incorrect-id',\n\t\t\t\tthis\n\t\t\t);\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\tconst currentAttributes = toMap( selection.getAttributes() );\n\t\t\tconst attributesWithMention = new Map( currentAttributes.entries() );\n\n\t\t\tattributesWithMention.set( 'mention', mention );\n\n\t\t\t// Replace a range with the text with a mention.\n\t\t\tmodel.insertContent( writer.createText( mentionText, attributesWithMention ), range );\n\t\t\tmodel.insertContent( writer.createText( ' ', currentAttributes ), range.start.getShiftedBy( mentionText.length ) );\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/mentionediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { uid } from 'ckeditor5/src/utils';\n\nimport MentionCommand from './mentioncommand';\n\n/**\n * The mention editing feature.\n *\n * It introduces the {@link module:mention/mentioncommand~MentionCommand command} and the `mention`\n * attribute in the {@link module:engine/model/model~Model model} which renders in the {@link module:engine/view/view view}\n * as a `<span class=\"mention\" data-mention=\"@mention\">`.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MentionEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MentionEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\t\tconst doc = model.document;\n\n\t\t// Allow the mention attribute on all text nodes.\n\t\tmodel.schema.extend( '$text', { allowAttributes: 'mention' } );\n\n\t\t// Upcast conversion.\n\t\teditor.conversion.for( 'upcast' ).elementToAttribute( {\n\t\t\tview: {\n\t\t\t\tname: 'span',\n\t\t\t\tkey: 'data-mention',\n\t\t\t\tclasses: 'mention'\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: 'mention',\n\t\t\t\tvalue: viewElement => _toMentionAttribute( viewElement )\n\t\t\t}\n\t\t} );\n\n\t\t// Downcast conversion.\n\t\teditor.conversion.for( 'downcast' ).attributeToElement( {\n\t\t\tmodel: 'mention',\n\t\t\tview: createViewMentionElement\n\t\t} );\n\t\teditor.conversion.for( 'downcast' ).add( preventPartialMentionDowncast );\n\n\t\tdoc.registerPostFixer( writer => removePartialMentionPostFixer( writer, doc, model.schema ) );\n\t\tdoc.registerPostFixer( writer => extendAttributeOnMentionPostFixer( writer, doc ) );\n\t\tdoc.registerPostFixer( writer => selectionMentionAttributePostFixer( writer, doc ) );\n\n\t\teditor.commands.add( 'mention', new MentionCommand( editor ) );\n\t}\n}\n\nexport function _addMentionAttributes( baseMentionData, data ) {\n\treturn Object.assign( { uid: uid() }, baseMentionData, data || {} );\n}\n\n/**\n * Creates a mention attribute value from the provided view element and optional data.\n *\n * This function is exposed as\n * {@link module:mention/mention~Mention#toMentionAttribute `editor.plugins.get( 'Mention' ).toMentionAttribute()`}.\n *\n * @protected\n * @param {module:engine/view/element~Element} viewElementOrMention\n * @param {String|Object} [data] Mention data to be extended.\n * @returns {module:mention/mention~MentionAttribute}\n */\nexport function _toMentionAttribute( viewElementOrMention, data ) {\n\tconst dataMention = viewElementOrMention.getAttribute( 'data-mention' );\n\n\tconst textNode = viewElementOrMention.getChild( 0 );\n\n\t// Do not convert empty mentions.\n\tif ( !textNode ) {\n\t\treturn;\n\t}\n\n\tconst baseMentionData = {\n\t\tid: dataMention,\n\t\t_text: textNode.data\n\t};\n\n\treturn _addMentionAttributes( baseMentionData, data );\n}\n\n// A converter that blocks partial mention from being converted.\n//\n// This converter is registered with 'highest' priority in order to consume mention attribute before it is converted by\n// any other converters. This converter only consumes partial mention - those whose `_text` attribute is not equal to text with mention\n// attribute. This may happen when copying part of mention text.\n//\n// @param {module:engine/conversion/dwoncastdispatcher~DowncastDispatcher}\nfunction preventPartialMentionDowncast( dispatcher ) {\n\tdispatcher.on( 'attribute:mention', ( evt, data, conversionApi ) => {\n\t\tconst mention = data.attributeNewValue;\n\n\t\tif ( !data.item.is( '$textProxy' ) || !mention ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst start = data.range.start;\n\t\tconst textNode = start.textNode || start.nodeAfter;\n\n\t\tif ( textNode.data != mention._text ) {\n\t\t\t// Consume item to prevent partial mention conversion.\n\t\t\tconversionApi.consumable.consume( data.item, evt.name );\n\t\t}\n\t}, { priority: 'highest' } );\n}\n\n// Creates a mention element from the mention data.\n//\n// @param {Object} mention\n// @param {module:engine/conversion/downcastdispatcher~DowncastConversionApi} conversionApi\n// @returns {module:engine/view/attributeelement~AttributeElement}\nfunction createViewMentionElement( mention, { writer } ) {\n\tif ( !mention ) {\n\t\treturn;\n\t}\n\n\tconst attributes = {\n\t\tclass: 'mention',\n\t\t'data-mention': mention.id\n\t};\n\n\tconst options = {\n\t\tid: mention.uid,\n\t\tpriority: 20\n\t};\n\n\treturn writer.createAttributeElement( 'span', attributes, options );\n}\n\n// Model post-fixer that disallows typing with selection when the selection is placed after the text node with the mention attribute or\n// before a text node with mention attribute.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/document~Document} doc\n// @returns {Boolean} Returns `true` if the selection was fixed.\nfunction selectionMentionAttributePostFixer( writer, doc ) {\n\tconst selection = doc.selection;\n\tconst focus = selection.focus;\n\n\tif ( selection.isCollapsed && selection.hasAttribute( 'mention' ) && shouldNotTypeWithMentionAt( focus ) ) {\n\t\twriter.removeSelectionAttribute( 'mention' );\n\n\t\treturn true;\n\t}\n}\n\n// Helper function to detect if mention attribute should be removed from selection.\n// This check makes only sense if the selection has mention attribute.\n//\n// The mention attribute should be removed from a selection when selection focus is placed:\n// a) after a text node\n// b) the position is at parents start - the selection will set attributes from node after.\nfunction shouldNotTypeWithMentionAt( position ) {\n\tconst isAtStart = position.isAtStart;\n\tconst isAfterAMention = position.nodeBefore && position.nodeBefore.is( '$text' );\n\n\treturn isAfterAMention || isAtStart;\n}\n\n// Model post-fixer that removes the mention attribute from the modified text node.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/document~Document} doc\n// @returns {Boolean} Returns `true` if the selection was fixed.\nfunction removePartialMentionPostFixer( writer, doc, schema ) {\n\tconst changes = doc.differ.getChanges();\n\n\tlet wasChanged = false;\n\n\tfor ( const change of changes ) {\n\t\t// Checks the text node on the current position.\n\t\tconst position = change.position;\n\n\t\tif ( change.name == '$text' ) {\n\t\t\tconst nodeAfterInsertedTextNode = position.textNode && position.textNode.nextSibling;\n\n\t\t\t// Checks the text node where the change occurred.\n\t\t\twasChanged = checkAndFix( position.textNode, writer ) || wasChanged;\n\n\t\t\t// Occurs on paste inside a text node with mention.\n\t\t\twasChanged = checkAndFix( nodeAfterInsertedTextNode, writer ) || wasChanged;\n\t\t\twasChanged = checkAndFix( position.nodeBefore, writer ) || wasChanged;\n\t\t\twasChanged = checkAndFix( position.nodeAfter, writer ) || wasChanged;\n\t\t}\n\n\t\t// Checks text nodes in inserted elements (might occur when splitting a paragraph or pasting content inside text with mention).\n\t\tif ( change.name != '$text' && change.type == 'insert' ) {\n\t\t\tconst insertedNode = position.nodeAfter;\n\n\t\t\tfor ( const item of writer.createRangeIn( insertedNode ).getItems() ) {\n\t\t\t\twasChanged = checkAndFix( item, writer ) || wasChanged;\n\t\t\t}\n\t\t}\n\n\t\t// Inserted inline elements might break mention.\n\t\tif ( change.type == 'insert' && schema.isInline( change.name ) ) {\n\t\t\tconst nodeAfterInserted = position.nodeAfter && position.nodeAfter.nextSibling;\n\n\t\t\twasChanged = checkAndFix( position.nodeBefore, writer ) || wasChanged;\n\t\t\twasChanged = checkAndFix( nodeAfterInserted, writer ) || wasChanged;\n\t\t}\n\t}\n\n\treturn wasChanged;\n}\n\n// This post-fixer will extend the attribute applied on the part of the mention so the whole text node of the mention will have\n// the added attribute.\n//\n// @param {module:engine/model/writer~Writer} writer\n// @param {module:engine/model/document~Document} doc\n// @returns {Boolean} Returns `true` if the selection was fixed.\nfunction extendAttributeOnMentionPostFixer( writer, doc ) {\n\tconst changes = doc.differ.getChanges();\n\n\tlet wasChanged = false;\n\n\tfor ( const change of changes ) {\n\t\tif ( change.type === 'attribute' && change.attributeKey != 'mention' ) {\n\t\t\t// Checks the node on the left side of the range...\n\t\t\tconst nodeBefore = change.range.start.nodeBefore;\n\t\t\t// ... and on the right side of the range.\n\t\t\tconst nodeAfter = change.range.end.nodeAfter;\n\n\t\t\tfor ( const node of [ nodeBefore, nodeAfter ] ) {\n\t\t\t\tif ( isBrokenMentionNode( node ) && node.getAttribute( change.attributeKey ) != change.attributeNewValue ) {\n\t\t\t\t\twriter.setAttribute( change.attributeKey, change.attributeNewValue, node );\n\n\t\t\t\t\twasChanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn wasChanged;\n}\n\n// Checks if a node has a correct mention attribute if present.\n// Returns `true` if the node is text and has a mention attribute whose text does not match the expected mention text.\n//\n// @param {module:engine/model/node~Node} node The node to check.\n// @returns {Boolean}\nfunction isBrokenMentionNode( node ) {\n\tif ( !node || !( node.is( '$text' ) || node.is( '$textProxy' ) ) || !node.hasAttribute( 'mention' ) ) {\n\t\treturn false;\n\t}\n\n\tconst text = node.data;\n\tconst mention = node.getAttribute( 'mention' );\n\n\tconst expectedText = mention._text;\n\n\treturn text != expectedText;\n}\n\n// Fixes a mention on a text node if it needs a fix.\n//\n// @param {module:engine/model/text~Text} textNode\n// @param {module:engine/model/writer~Writer} writer\n// @returns {Boolean}\nfunction checkAndFix( textNode, writer ) {\n\tif ( isBrokenMentionNode( textNode ) ) {\n\t\twriter.removeAttribute( 'mention', textNode );\n\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/ui/mentionsview\n */\n\nimport { ListView } from 'ckeditor5/src/ui';\nimport { Rect } from 'ckeditor5/src/utils';\n\nimport '../../theme/mentionui.css';\n\n/**\n * The mention ui view.\n *\n * @extends module:ui/list/listview~ListView\n */\nexport default class MentionsView extends ListView {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( locale ) {\n\t\tsuper( locale );\n\n\t\tthis.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck-mentions'\n\t\t\t\t],\n\n\t\t\t\ttabindex: '-1'\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * {@link #select Selects} the first item.\n\t */\n\tselectFirst() {\n\t\tthis.select( 0 );\n\t}\n\n\t/**\n\t * Selects next item to the currently {@link #select selected}.\n\t *\n\t * If the last item is already selected, it will select the first item.\n\t */\n\tselectNext() {\n\t\tconst item = this.selected;\n\t\tconst index = this.items.getIndex( item );\n\n\t\tthis.select( index + 1 );\n\t}\n\n\t/**\n\t * Selects previous item to the currently {@link #select selected}.\n\t *\n\t * If the first item is already selected, it will select the last item.\n\t */\n\tselectPrevious() {\n\t\tconst item = this.selected;\n\t\tconst index = this.items.getIndex( item );\n\n\t\tthis.select( index - 1 );\n\t}\n\n\t/**\n\t * Marks item at a given index as selected.\n\t *\n\t * Handles selection cycling when passed index is out of bounds:\n\t * - if the index is lower than 0, it will select the last item,\n\t * - if the index is higher than the last item index, it will select the first item.\n\t *\n\t * @param {Number} index Index of an item to be marked as selected.\n\t */\n\tselect( index ) {\n\t\tlet indexToGet = 0;\n\n\t\tif ( index > 0 && index < this.items.length ) {\n\t\t\tindexToGet = index;\n\t\t} else if ( index < 0 ) {\n\t\t\tindexToGet = this.items.length - 1;\n\t\t}\n\n\t\tconst item = this.items.get( indexToGet );\n\n\t\t// Return early if item is already selected.\n\t\tif ( this.selected === item ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove highlight of previously selected item.\n\t\tif ( this.selected ) {\n\t\t\tthis.selected.removeHighlight();\n\t\t}\n\n\t\titem.highlight();\n\t\tthis.selected = item;\n\n\t\t// Scroll the mentions view to the selected element.\n\t\tif ( !this._isItemVisibleInScrolledArea( item ) ) {\n\t\t\tthis.element.scrollTop = item.element.offsetTop;\n\t\t}\n\t}\n\n\t/**\n\t * Triggers the `execute` event on the {@link #select selected} item.\n\t */\n\texecuteSelected() {\n\t\tthis.selected.fire( 'execute' );\n\t}\n\n\t// Checks if an item is visible in the scrollable area.\n\t//\n\t// The item is considered visible when:\n\t// - its top boundary is inside the scrollable rect\n\t// - its bottom boundary is inside the scrollable rect (the whole item must be visible)\n\t_isItemVisibleInScrolledArea( item ) {\n\t\treturn new Rect( this.element ).contains( new Rect( item.element ) );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/ui/domwrapperview\n */\n\nimport { View } from 'ckeditor5/src/ui';\n\n/**\n * This class wraps DOM element as a CKEditor5 UI View.\n *\n * It allows to render any DOM element and use it in mentions list.\n *\n * @extends {module:ui/view~View}\n */\nexport default class DomWrapperView extends View {\n\t/**\n\t * Creates an instance of {@link module:mention/ui/domwrapperview~DomWrapperView} class.\n\t *\n\t * Also see {@link #render}.\n\t *\n\t * @param {module:utils/locale~Locale} [locale] The localization services instance.\n\t * @param {Element} domElement\n\t */\n\tconstructor( locale, domElement ) {\n\t\tsuper( locale );\n\n\t\t// Disable template rendering on this view.\n\t\tthis.template = false;\n\n\t\t/**\n\t\t * The DOM element for which wrapper was created.\n\t\t *\n\t\t * @type {Element}\n\t\t */\n\t\tthis.domElement = domElement;\n\n\t\t// Render dom wrapper as a button.\n\t\tthis.domElement.classList.add( 'ck-button' );\n\n\t\t/**\n\t\t * Controls whether the dom wrapper view is \"on\". This is in line with {@link module:ui/button/button~Button#isOn} property.\n\t\t *\n\t\t * @observable\n\t\t * @default true\n\t\t * @member {Boolean} #isOn\n\t\t */\n\t\tthis.set( 'isOn', false );\n\n\t\t// Handle isOn state as in buttons.\n\t\tthis.on( 'change:isOn', ( evt, name, isOn ) => {\n\t\t\tif ( isOn ) {\n\t\t\t\tthis.domElement.classList.add( 'ck-on' );\n\t\t\t\tthis.domElement.classList.remove( 'ck-off' );\n\t\t\t} else {\n\t\t\t\tthis.domElement.classList.add( 'ck-off' );\n\t\t\t\tthis.domElement.classList.remove( 'ck-on' );\n\t\t\t}\n\t\t} );\n\n\t\t// Pass click event as execute event.\n\t\tthis.listenTo( this.domElement, 'click', () => {\n\t\t\tthis.fire( 'execute' );\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trender() {\n\t\tsuper.render();\n\n\t\tthis.element = this.domElement;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/ui/mentionlistitemview\n */\n\nimport { ListItemView } from 'ckeditor5/src/ui';\n\nexport default class MentionListItemView extends ListItemView {\n\thighlight() {\n\t\tconst child = this.children.first;\n\n\t\tchild.isOn = true;\n\t}\n\n\tremoveHighlight() {\n\t\tconst child = this.children.first;\n\n\t\tchild.isOn = false;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/mentionui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView, ContextualBalloon, clickOutsideHandler } from 'ckeditor5/src/ui';\nimport { Collection, keyCodes, env, Rect, CKEditorError, logWarning } from 'ckeditor5/src/utils';\nimport { TextWatcher } from 'ckeditor5/src/typing';\n\nimport { debounce } from 'lodash-es';\n\nimport MentionsView from './ui/mentionsview';\nimport DomWrapperView from './ui/domwrapperview';\nimport MentionListItemView from './ui/mentionlistitemview';\n\nconst VERTICAL_SPACING = 3;\n\n// The key codes that mention UI handles when it is open.\nconst handledKeyCodes = [\n\tkeyCodes.arrowup,\n\tkeyCodes.arrowdown,\n\tkeyCodes.enter,\n\tkeyCodes.tab,\n\tkeyCodes.esc\n];\n\n/**\n * The mention UI feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class MentionUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'MentionUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The mention view.\n\t\t *\n\t\t * @type {module:mention/ui/mentionsview~MentionsView}\n\t\t * @private\n\t\t */\n\t\tthis._mentionsView = this._createMentionView();\n\n\t\t/**\n\t\t * Stores mention feeds configurations.\n\t\t *\n\t\t * @type {Map<String, Object>}\n\t\t * @private\n\t\t */\n\t\tthis._mentionsConfigurations = new Map();\n\n\t\t/**\n\t\t * Debounced feed requester. It uses `lodash#debounce` method to delay function call.\n\t\t *\n\t\t * @private\n\t\t * @param {String} marker\n\t\t * @param {String} feedText\n\t\t * @method\n\t\t */\n\t\tthis._requestFeedDebounced = debounce( this._requestFeed, 100 );\n\n\t\teditor.config.define( 'mention', { feeds: [] } );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t/**\n\t\t * The contextual balloon plugin instance.\n\t\t *\n\t\t * @private\n\t\t * @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}\n\t\t */\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\t// Key listener that handles navigation in mention view.\n\t\teditor.editing.view.document.on( 'keydown', ( evt, data ) => {\n\t\t\tif ( isHandledKey( data.keyCode ) && this._isUIVisible ) {\n\t\t\t\t// do it before preventing default since space should be inserted\n\t\t\t\tif (data.keyCode == keyCodes.space) {\n\t\t\t\t\tthis._hideUIAndRemoveMarker();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tdata.preventDefault();\n\t\t\t\tevt.stop(); // Required for Enter key overriding.\n\n\t\t\t\tif ( data.keyCode == keyCodes.arrowdown ) {\n\t\t\t\t\tthis._mentionsView.selectNext();\n\t\t\t\t}\n\n\t\t\t\tif ( data.keyCode == keyCodes.arrowup ) {\n\t\t\t\t\tthis._mentionsView.selectPrevious();\n\t\t\t\t}\n\n\t\t\t\tif ( data.keyCode == keyCodes.enter || data.keyCode == keyCodes.tab ) {\n\t\t\t\t\tthis._mentionsView.executeSelected();\n\t\t\t\t}\n\n\t\t\t\tif ( data.keyCode == keyCodes.esc ) {\n\t\t\t\t\tthis._hideUIAndRemoveMarker();\n\t\t\t\t}\n\t\t\t}\n\t\t}, { priority: 'highest' } ); // Required to override the Enter key.\n\n\t\t// Close the dropdown upon clicking outside of the plugin UI.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this._mentionsView,\n\t\t\tactivator: () => this._isUIVisible,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideUIAndRemoveMarker()\n\t\t} );\n\n\t\tconst feeds = editor.config.get( 'mention.feeds' );\n\n\t\tfor ( const mentionDescription of feeds ) {\n\t\t\tconst feed = mentionDescription.feed;\n\n\t\t\tconst marker = mentionDescription.marker;\n\n\t\t\tif ( !isValidMentionMarker( marker ) ) {\n\t\t\t\t/**\n\t\t\t\t * The marker must be a single character.\n\t\t\t\t *\n\t\t\t\t * Correct markers: `'@'`, `'#'`.\n\t\t\t\t *\n\t\t\t\t * Incorrect markers: `'$$'`, `'[@'`.\n\t\t\t\t *\n\t\t\t\t * See {@link module:mention/mention~MentionConfig}.\n\t\t\t\t *\n\t\t\t\t * @error mentionconfig-incorrect-marker\n\t\t\t\t * @param {String} marker Configured marker\n\t\t\t\t */\n\t\t\t\tthrow new CKEditorError( 'mentionconfig-incorrect-marker', null, { marker } );\n\t\t\t}\n\n\t\t\tconst minimumCharacters = mentionDescription.minimumCharacters || 0;\n\t\t\tconst feedCallback = typeof feed == 'function' ? feed.bind( this.editor ) : createFeedCallback( feed );\n\t\t\tconst watcher = this._setupTextWatcherForFeed( marker, minimumCharacters );\n\t\t\tconst itemRenderer = mentionDescription.itemRenderer;\n\n\t\t\tconst definition = { watcher, marker, feedCallback, itemRenderer };\n\n\t\t\tthis._mentionsConfigurations.set( marker, definition );\n\t\t}\n\n\t\tthis.on( 'requestFeed:response', ( evt, data ) => this._handleFeedResponse( data ) );\n\t\tthis.on( 'requestFeed:error', () => this._hideUIAndRemoveMarker() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\t// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).\n\t\tthis._mentionsView.destroy();\n\t}\n\n\t/**\n\t * Returns true when {@link #_mentionsView} is in the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon} and it is\n\t * currently visible.\n\t *\n\t * @readonly\n\t * @protected\n\t * @type {Boolean}\n\t */\n\tget _isUIVisible() {\n\t\treturn this._balloon.visibleView === this._mentionsView;\n\t}\n\n\t/**\n\t * Creates the {@link #_mentionsView}.\n\t *\n\t * @private\n\t * @returns {module:mention/ui/mentionsview~MentionsView}\n\t */\n\t_createMentionView() {\n\t\tconst locale = this.editor.locale;\n\n\t\tconst mentionsView = new MentionsView( locale );\n\n\t\tthis._items = new Collection();\n\n\t\tmentionsView.items.bindTo( this._items ).using( data => {\n\t\t\tconst { item, marker } = data;\n\n\t\t\tconst listItemView = new MentionListItemView( locale );\n\n\t\t\tconst view = this._renderItem( item, marker );\n\t\t\tview.delegate( 'execute' ).to( listItemView );\n\n\t\t\tlistItemView.children.add( view );\n\t\t\tlistItemView.item = item;\n\t\t\tlistItemView.marker = marker;\n\n\t\t\tlistItemView.on( 'execute', () => {\n\t\t\t\tmentionsView.fire( 'execute', {\n\t\t\t\t\titem,\n\t\t\t\t\tmarker\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\treturn listItemView;\n\t\t} );\n\n\t\tmentionsView.on( 'execute', ( evt, data ) => {\n\t\t\tconst editor = this.editor;\n\t\t\tconst model = editor.model;\n\n\t\t\tconst item = data.item;\n\t\t\tconst marker = data.marker;\n\n\t\t\tconst mentionMarker = editor.model.markers.get( 'mention' );\n\n\t\t\t// Create a range on matched text.\n\t\t\tconst end = model.createPositionAt( model.document.selection.focus );\n\t\t\tconst start = model.createPositionAt( mentionMarker.getStart() );\n\t\t\tconst range = model.createRange( start, end );\n\n\t\t\tthis._hideUIAndRemoveMarker();\n\n\t\t\teditor.execute( 'mention', {\n\t\t\t\tmention: item,\n\t\t\t\ttext: item.text,\n\t\t\t\tmarker,\n\t\t\t\trange\n\t\t\t} );\n\n\t\t\teditor.editing.view.focus();\n\t\t} );\n\n\t\treturn mentionsView;\n\t}\n\n\t/**\n\t * Returns item renderer for the marker.\n\t *\n\t * @private\n\t * @param {String} marker\n\t * @returns {Function|null}\n\t */\n\t_getItemRenderer( marker ) {\n\t\tconst { itemRenderer } = this._mentionsConfigurations.get( marker );\n\n\t\treturn itemRenderer;\n\t}\n\n\t/**\n\t * Requests a feed from a configured callbacks.\n\t *\n\t * @private\n\t * @fires module:mention/mentionui~MentionUI#event:requestFeed:response\n\t * @fires module:mention/mentionui~MentionUI#event:requestFeed:discarded\n\t * @fires module:mention/mentionui~MentionUI#event:requestFeed:error\n\t * @param {String} marker\n\t * @param {String} feedText\n\t */\n\t_requestFeed( marker, feedText ) {\n\t\t// Store the last requested feed - it is used to discard any out-of order requests.\n\t\tthis._lastRequested = feedText;\n\n\t\tconst { feedCallback } = this._mentionsConfigurations.get( marker );\n\t\tconst feedResponse = feedCallback( feedText );\n\n\t\tconst isAsynchronous = feedResponse instanceof Promise;\n\n\t\t// For synchronous feeds (e.g. callbacks, arrays) fire the response event immediately.\n\t\tif ( !isAsynchronous ) {\n\t\t\t/**\n\t\t\t * Fired whenever requested feed has a response.\n\t\t\t *\n\t\t\t * @event requestFeed:response\n\t\t\t * @param {Object} data Event data.\n\t\t\t * @param {Array.<module:mention/mention~MentionFeedItem>} data.feed Autocomplete items.\n\t\t\t * @param {String} data.marker The character which triggers autocompletion for mention.\n\t\t\t * @param {String} data.feedText The text for which feed items were requested.\n\t\t\t */\n\t\t\tthis.fire( 'requestFeed:response', { feed: feedResponse, marker, feedText } );\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle the asynchronous responses.\n\t\tfeedResponse\n\t\t\t.then( response => {\n\t\t\t\t// Check the feed text of this response with the last requested one so either:\n\t\t\t\tif ( this._lastRequested == feedText ) {\n\t\t\t\t\t// It is the same and fire the response event.\n\t\t\t\t\tthis.fire( 'requestFeed:response', { feed: response, marker, feedText } );\n\t\t\t\t} else {\n\t\t\t\t\t// It is different - most probably out-of-order one, so fire the discarded event.\n\t\t\t\t\t/**\n\t\t\t\t\t * Fired whenever the requested feed was discarded. This happens when the response was delayed and\n\t\t\t\t\t * other feed was already requested.\n\t\t\t\t\t *\n\t\t\t\t\t * @event requestFeed:discarded\n\t\t\t\t\t * @param {Object} data Event data.\n\t\t\t\t\t * @param {Array.<module:mention/mention~MentionFeedItem>} data.feed Autocomplete items.\n\t\t\t\t\t * @param {String} data.marker The character which triggers autocompletion for mention.\n\t\t\t\t\t * @param {String} data.feedText The text for which feed items were requested.\n\t\t\t\t\t */\n\t\t\t\t\tthis.fire( 'requestFeed:discarded', { feed: response, marker, feedText } );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.catch( error => {\n\t\t\t\t/**\n\t\t\t\t * Fired whenever the requested {@link module:mention/mention~MentionFeed#feed} promise fails with error.\n\t\t\t\t *\n\t\t\t\t * @event requestFeed:error\n\t\t\t\t * @param {Object} data Event data.\n\t\t\t\t * @param {Error} data.error The error that was caught.\n\t\t\t\t */\n\t\t\t\tthis.fire( 'requestFeed:error', { error } );\n\n\t\t\t\t/**\n\t\t\t\t * The callback used for obtaining mention autocomplete feed thrown and error and the mention UI was hidden or\n\t\t\t\t * not displayed at all.\n\t\t\t\t *\n\t\t\t\t * @error mention-feed-callback-error\n\t\t\t\t * @param {String} marker Configured marker for which error occurred.\n\t\t\t\t */\n\t\t\t\tlogWarning( 'mention-feed-callback-error', { marker } );\n\t\t\t} );\n\t}\n\n\t/**\n\t * Registers a text watcher for the marker.\n\t *\n\t * @private\n\t * @param {String} marker\n\t * @param {Number} minimumCharacters\n\t * @returns {module:typing/textwatcher~TextWatcher}\n\t */\n\t_setupTextWatcherForFeed( marker, minimumCharacters ) {\n\t\tconst editor = this.editor;\n\n\t\tconst watcher = new TextWatcher( editor.model, createTestCallback( marker, minimumCharacters ) );\n\n\t\t// use \"matched:data\" instead of just \"matched\" so that mention is not triggered on mere click\n\t\twatcher.on( 'matched:data', ( evt, data ) => {\n\t\t\tconst selection = editor.model.document.selection;\n\t\t\tconst focus = selection.focus;\n\n\t\t\tif ( hasExistingMention( focus ) ) {\n\t\t\t\tthis._hideUIAndRemoveMarker();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst feedText = requestFeedText( marker, data.text );\n\t\t\tconst matchedTextLength = marker.length + feedText.length;\n\n\t\t\t// Create a marker range.\n\t\t\tconst start = focus.getShiftedBy( -matchedTextLength );\n\t\t\tconst end = focus.getShiftedBy( -feedText.length );\n\n\t\t\tconst markerRange = editor.model.createRange( start, end );\n\n\t\t\tif ( checkIfStillInCompletionMode( editor ) ) {\n\t\t\t\tconst mentionMarker = editor.model.markers.get( 'mention' );\n\n\t\t\t\t// Update the marker - user might've moved the selection to other mention trigger.\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.updateMarker( mentionMarker, { range: markerRange } );\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\teditor.model.change( writer => {\n\t\t\t\t\twriter.addMarker( 'mention', { range: markerRange, usingOperation: false, affectsData: false } );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tthis._requestFeedDebounced( marker, feedText );\n\t\t} );\n\n\t\twatcher.on( 'unmatched', () => {\n\t\t\tthis._hideUIAndRemoveMarker();\n\t\t} );\n\n\t\tconst mentionCommand = editor.commands.get( 'mention' );\n\t\twatcher.bind( 'isEnabled' ).to( mentionCommand );\n\n\t\treturn watcher;\n\t}\n\n\t/**\n\t * Handles the feed response event data.\n\t *\n\t * @param data\n\t * @private\n\t */\n\t_handleFeedResponse( data ) {\n\t\tconst { feed, marker } = data;\n\n\t\t// If the marker is not in the document happens when the selection had changed and the 'mention' marker was removed.\n\t\tif ( !checkIfStillInCompletionMode( this.editor ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Reset the view.\n\t\tthis._items.clear();\n\n\t\tfor ( const feedItem of feed ) {\n\t\t\tconst item = typeof feedItem != 'object' ? { id: feedItem, text: feedItem } : feedItem;\n\n\t\t\tthis._items.add( { item, marker } );\n\t\t}\n\n\t\tconst mentionMarker = this.editor.model.markers.get( 'mention' );\n\n\t\tif ( this._items.length ) {\n\t\t\tthis._showOrUpdateUI( mentionMarker );\n\t\t} else {\n\t\t\t// Do not show empty mention UI.\n\t\t\tthis._hideUIAndRemoveMarker();\n\t\t}\n\t}\n\n\t/**\n\t * Shows the mentions balloon. If the panel is already visible, it will reposition it.\n\t *\n\t * @private\n\t */\n\t_showOrUpdateUI( markerMarker ) {\n\t\tif ( this._isUIVisible ) {\n\t\t\t// Update balloon position as the mention list view may change its size.\n\t\t\tthis._balloon.updatePosition( this._getBalloonPanelPositionData( markerMarker, this._mentionsView.position ) );\n\t\t} else {\n\t\t\tthis._balloon.add( {\n\t\t\t\tview: this._mentionsView,\n\t\t\t\tposition: this._getBalloonPanelPositionData( markerMarker, this._mentionsView.position ),\n\t\t\t\twithArrow: false,\n\t\t\t\tsingleViewMode: true\n\t\t\t} );\n\t\t}\n\n\t\tthis._mentionsView.position = this._balloon.view.position;\n\t\tthis._mentionsView.selectFirst();\n\t}\n\n\t/**\n\t * Hides the mentions balloon and removes the 'mention' marker from the markers collection.\n\t *\n\t * @private\n\t */\n\t_hideUIAndRemoveMarker() {\n\t\t// Remove the mention view from balloon before removing marker - it is used by balloon position target().\n\t\tif ( this._balloon.hasView( this._mentionsView ) ) {\n\t\t\tthis._balloon.remove( this._mentionsView );\n\t\t}\n\n\t\tif ( checkIfStillInCompletionMode( this.editor ) ) {\n\t\t\tthis.editor.model.change( writer => writer.removeMarker( 'mention' ) );\n\t\t}\n\n\t\t// Make the last matched position on panel view undefined so the #_getBalloonPanelPositionData() method will return all positions\n\t\t// on the next call.\n\t\tthis._mentionsView.position = undefined;\n\t}\n\n\t/**\n\t * Renders a single item in the autocomplete list.\n\t *\n\t * @private\n\t * @param {module:mention/mention~MentionFeedItem} item\n\t * @param {String} marker\n\t * @returns {module:ui/button/buttonview~ButtonView|module:mention/ui/domwrapperview~DomWrapperView}\n\t */\n\t_renderItem( item, marker ) {\n\t\tconst editor = this.editor;\n\n\t\tlet view;\n\t\tlet label = item.id;\n\n\t\tconst renderer = this._getItemRenderer( marker );\n\n\t\tif ( renderer ) {\n\t\t\tconst renderResult = renderer( item );\n\n\t\t\tif ( typeof renderResult != 'string' ) {\n\t\t\t\tview = new DomWrapperView( editor.locale, renderResult );\n\t\t\t} else {\n\t\t\t\tlabel = renderResult;\n\t\t\t}\n\t\t}\n\n\t\tif ( !view ) {\n\t\t\tconst buttonView = new ButtonView( editor.locale );\n\n\t\t\tbuttonView.label = label;\n\t\t\tbuttonView.withText = true;\n\n\t\t\tview = buttonView;\n\t\t}\n\n\t\treturn view;\n\t}\n\n\t/**\n\t * Creates a position options object used to position the balloon panel.\n\t *\n\t * @param {module:engine/model/markercollection~Marker} mentionMarker\n\t * @param {String|undefined} preferredPosition The name of the last matched position name.\n\t * @returns {module:utils/dom/position~Options}\n\t * @private\n\t */\n\t_getBalloonPanelPositionData( mentionMarker, preferredPosition ) {\n\t\tconst editor = this.editor;\n\t\tconst editing = editor.editing;\n\t\tconst domConverter = editing.view.domConverter;\n\t\tconst mapper = editing.mapper;\n\n\t\treturn {\n\t\t\ttarget: () => {\n\t\t\t\tlet modelRange = mentionMarker.getRange();\n\n\t\t\t\t// Target the UI to the model selection range - the marker has been removed so probably the UI will not be shown anyway.\n\t\t\t\t// The logic is used by ContextualBalloon to display another panel in the same place.\n\t\t\t\tif ( modelRange.start.root.rootName == '$graveyard' ) {\n\t\t\t\t\tmodelRange = editor.model.document.selection.getFirstRange();\n\t\t\t\t}\n\n\t\t\t\tconst viewRange = mapper.toViewRange( modelRange );\n\t\t\t\tconst rangeRects = Rect.getDomRangeRects( domConverter.viewRangeToDom( viewRange ) );\n\n\t\t\t\treturn rangeRects.pop();\n\t\t\t},\n\t\t\tlimiter: () => {\n\t\t\t\tconst view = this.editor.editing.view;\n\t\t\t\tconst viewDocument = view.document;\n\t\t\t\tconst editableElement = viewDocument.selection.editableElement;\n\n\t\t\t\tif ( editableElement ) {\n\t\t\t\t\treturn view.domConverter.mapViewToDom( editableElement.root );\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\tpositions: getBalloonPanelPositions( preferredPosition )\n\t\t};\n\t}\n}\n\n// Returns the balloon positions data callbacks.\n//\n// @param {String} preferredPosition\n// @returns {Array.<module:utils/dom/position~Position>}\nfunction getBalloonPanelPositions( preferredPosition ) {\n\tconst positions = {\n\t\t// Positions the panel to the southeast of the caret rectangle.\n\t\t'caret_se': targetRect => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.bottom + VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right,\n\t\t\t\tname: 'caret_se'\n\t\t\t};\n\t\t},\n\n\t\t// Positions the panel to the northeast of the caret rectangle.\n\t\t'caret_ne': ( targetRect, balloonRect ) => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.top - balloonRect.height - VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right,\n\t\t\t\tname: 'caret_ne'\n\t\t\t};\n\t\t},\n\n\t\t// Positions the panel to the southwest of the caret rectangle.\n\t\t'caret_sw': ( targetRect, balloonRect ) => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.bottom + VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right - balloonRect.width,\n\t\t\t\tname: 'caret_sw'\n\t\t\t};\n\t\t},\n\n\t\t// Positions the panel to the northwest of the caret rect.\n\t\t'caret_nw': ( targetRect, balloonRect ) => {\n\t\t\treturn {\n\t\t\t\ttop: targetRect.top - balloonRect.height - VERTICAL_SPACING,\n\t\t\t\tleft: targetRect.right - balloonRect.width,\n\t\t\t\tname: 'caret_nw'\n\t\t\t};\n\t\t}\n\t};\n\n\t// Returns only the last position if it was matched to prevent the panel from jumping after the first match.\n\tif ( Object.prototype.hasOwnProperty.call( positions, preferredPosition ) ) {\n\t\treturn [\n\t\t\tpositions[ preferredPosition ]\n\t\t];\n\t}\n\n\t// By default return all position callbacks.\n\treturn [\n\t\tpositions.caret_se,\n\t\tpositions.caret_sw,\n\t\tpositions.caret_ne,\n\t\tpositions.caret_nw\n\t];\n}\n\n// Creates a RegExp pattern for the marker.\n//\n// Function has to be exported to achieve 100% code coverage.\n//\n// @param {String} marker\n// @param {Number} minimumCharacters\n// @returns {RegExp}\n// trilium change: '=' will end the mention but also accepts it as the beginning (support for autocompleting attribute name and relation value)\nexport function createRegExp( marker, minimumCharacters ) {\n\tconst numberOfCharacters = minimumCharacters == 0 ? '*' : `{${ minimumCharacters },}`;\n\n\tconst openAfterCharacters = env.features.isRegExpUnicodePropertySupported ? '\\\\p{Ps}\\\\p{Pi}\"\\'' : '\\\\(\\\\[{\"\\'';\n\tconst mentionCharacters = '^\\\\s='\n\n\t// The pattern consists of 3 groups:\n\t// - 0 (non-capturing): Opening sequence - start of the line, space or an opening punctuation character like \"(\" or \"\\\"\",\n\t// - 1: The marker character,\n\t// - 2: Mention input (taking the minimal length into consideration to trigger the UI),\n\t//\n\t// The pattern matches up to the caret (end of string switch - $).\n\t// (0: opening sequence )(1: marker )(2: typed mention )$\n\tconst pattern = `(?:^|[= ${ openAfterCharacters }])([${ marker }])([${ mentionCharacters }]${ numberOfCharacters })$`;\n\n\treturn new RegExp( pattern, 'u' );\n}\n\n// Creates a test callback for the marker to be used in the text watcher instance.\n//\n// @param {String} marker\n// @param {Number} minimumCharacters\n// @returns {Function}\nfunction createTestCallback( marker, minimumCharacters ) {\n\tconst regExp = createRegExp( marker, minimumCharacters );\n\n\treturn text => regExp.test( text );\n}\n\n// Creates a text matcher from the marker.\n//\n// @param {String} marker\n// @returns {Function}\nfunction requestFeedText( marker, text ) {\n\tconst regExp = createRegExp( marker, 0 );\n\n\tconst match = text.match( regExp );\n\n\treturn match[ 2 ];\n}\n\n// The default feed callback.\nfunction createFeedCallback( feedItems ) {\n\treturn feedText => {\n\t\tconst filteredItems = feedItems\n\t\t// Make the default mention feed case-insensitive.\n\t\t\t.filter( item => {\n\t\t\t\t// Item might be defined as object.\n\t\t\t\tconst itemId = typeof item == 'string' ? item : String( item.id );\n\n\t\t\t\t// The default feed is case insensitive.\n\t\t\t\treturn itemId.toLowerCase().includes( feedText.toLowerCase() );\n\t\t\t} )\n\t\t\t// Do not return more than 10 items.\n\t\t\t.slice( 0, 10 );\n\n\t\treturn filteredItems;\n\t};\n}\n\n// Checks if a given key code is handled by the mention UI.\n//\n// @param {Number}\n// @returns {Boolean}\nfunction isHandledKey( keyCode ) {\n\treturn handledKeyCodes.includes( keyCode );\n}\n\n// Checks if position in inside or right after a text with a mention.\n//\n// @param {module:engine/model/position~Position} position.\n// @returns {Boolean}\nfunction hasExistingMention( position ) {\n\t// The text watcher listens only to changed range in selection - so the selection attributes are not yet available\n\t// and you cannot use selection.hasAttribute( 'mention' ) just yet.\n\t// See https://github.com/ckeditor/ckeditor5-engine/issues/1723.\n\tconst hasMention = position.textNode && position.textNode.hasAttribute( 'mention' );\n\n\tconst nodeBefore = position.nodeBefore;\n\n\treturn hasMention || nodeBefore && nodeBefore.is( '$text' ) && nodeBefore.hasAttribute( 'mention' );\n}\n\n// Checks if string is a valid mention marker.\n//\n// @param {String} marker\n// @returns {Boolean}\nfunction isValidMentionMarker( marker ) {\n\treturn marker && marker.length == 1;\n}\n\n// Checks the mention plugins is in completion mode (e.g. when typing is after a valid mention string like @foo).\n//\n// @returns {Boolean}\nfunction checkIfStillInCompletionMode( editor ) {\n\treturn editor.model.markers.has( 'mention' );\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 indent/indentediting\n */\n\nimport { Plugin, MultiCommand } from 'ckeditor5/src/core';\n\n/**\n * The indent editing feature.\n *\n * This plugin registers the `'indent'` and `'outdent'` commands.\n *\n * **Note**: In order for the commands to work, at least one of the compatible features is required. Read more in the\n * {@link module:indent/indent~Indent indent feature} API documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class IndentEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'IndentEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.commands.add( 'indent', new MultiCommand( editor ) );\n\t\teditor.commands.add( 'outdent', new MultiCommand( editor ) );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM2.75 16.5h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 1 0 0 1.5zM1.632 6.95 5.02 9.358a.4.4 0 0 1-.013.661l-3.39 2.207A.4.4 0 0 1 1 11.892V7.275a.4.4 0 0 1 .632-.326z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 3.75c0 .414.336.75.75.75h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 0 0-.75.75zm5 6c0 .414.336.75.75.75h9.5a.75.75 0 1 0 0-1.5h-9.5a.75.75 0 0 0-.75.75zM2.75 16.5h14.5a.75.75 0 1 0 0-1.5H2.75a.75.75 0 1 0 0 1.5zm1.618-9.55L.98 9.358a.4.4 0 0 0 .013.661l3.39 2.207A.4.4 0 0 0 5 11.892V7.275a.4.4 0 0 0-.632-.326z\\\"/></svg>\";","/**\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 indent/indentui\n */\nimport { ButtonView } from 'ckeditor5/src/ui';\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport indentIcon from '../theme/icons/indent.svg';\nimport outdentIcon from '../theme/icons/outdent.svg';\n\n/**\n * The indent UI feature.\n *\n * This plugin registers the `'indent'` and `'outdent'` buttons.\n *\n * **Note**: In order for the commands to work, at least one of the compatible features is required. Read more in\n * the {@link module:indent/indent~Indent indent feature} API documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class IndentUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'IndentUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst t = editor.t;\n\n\t\tconst localizedIndentIcon = locale.uiLanguageDirection == 'ltr' ? indentIcon : outdentIcon;\n\t\tconst localizedOutdentIcon = locale.uiLanguageDirection == 'ltr' ? outdentIcon : indentIcon;\n\n\t\tthis._defineButton( 'indent', t( 'Increase indent' ), localizedIndentIcon );\n\t\tthis._defineButton( 'outdent', t( 'Decrease indent' ), localizedOutdentIcon );\n\t}\n\n\t/**\n\t * Defines a UI button.\n\t *\n\t * @param {String} commandName\n\t * @param {String} label\n\t * @param {String} icon\n\t * @private\n\t */\n\t_defineButton( commandName, label, icon ) {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( commandName, locale => {\n\t\t\tconst command = editor.commands.get( commandName );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel,\n\t\t\t\ticon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( commandName );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module indent/indentblockcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * The indent block command.\n *\n * The command is registered by the {@link module:indent/indentblock~IndentBlock} as `'indentBlock'` for indenting blocks and\n * `'outdentBlock'` for outdenting blocks.\n *\n * To increase block indentation at the current selection, execute the command:\n *\n *\t\teditor.execute( 'indentBlock' );\n *\n * To decrease block indentation at the current selection, execute the command:\n *\n *\t\teditor.execute( 'outdentBlock' );\n *\n * @extends module:core/command~Command\n */\nexport default class IndentBlockCommand extends Command {\n\t/**\n\t * Creates an instance of the command.\n\t *\n\t * @param {module:core/editor/editor~Editor} editor The editor instance.\n\t * @param {module:indent/indentblockcommand~IndentBehavior} indentBehavior\n\t */\n\tconstructor( editor, indentBehavior ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The command's indentation behavior.\n\t\t *\n\t\t * @type {module:indent/indentblockcommand~IndentBehavior}\n\t\t * @private\n\t\t */\n\t\tthis._indentBehavior = indentBehavior;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\t// Check whether any of the position's ancestors is a list item.\n\t\tconst editor = this.editor;\n\t\tconst model = editor.model;\n\n\t\tconst block = first( model.document.selection.getSelectedBlocks() );\n\n\t\tif ( !block || !model.schema.checkAttribute( block, 'blockIndent' ) ) {\n\t\t\tthis.isEnabled = false;\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis.isEnabled = this._indentBehavior.checkEnabled( block.getAttribute( 'blockIndent' ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\n\t\tconst blocksToChange = getBlocksToChange( model );\n\n\t\tmodel.change( writer => {\n\t\t\tfor ( const block of blocksToChange ) {\n\t\t\t\tconst currentIndent = block.getAttribute( 'blockIndent' );\n\n\t\t\t\tconst nextIndent = this._indentBehavior.getNextIndent( currentIndent );\n\n\t\t\t\tif ( nextIndent ) {\n\t\t\t\t\twriter.setAttribute( 'blockIndent', nextIndent, block );\n\t\t\t\t} else {\n\t\t\t\t\twriter.removeAttribute( 'blockIndent', block );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Returns blocks from selection that should have blockIndent selection set.\n//\n// @param {module:engine/model/model~model} model A model.\nfunction getBlocksToChange( model ) {\n\tconst selection = model.document.selection;\n\tconst schema = model.schema;\n\tconst blocksInSelection = Array.from( selection.getSelectedBlocks() );\n\n\treturn blocksInSelection.filter( block => schema.checkAttribute( block, 'blockIndent' ) );\n}\n\n/**\n * Provides indentation behavior to {@link module:indent/indentblockcommand~IndentBlockCommand}.\n *\n * @interface module:indent/indentblockcommand~IndentBehavior\n */\n\n/**\n * Checks if the command should be enabled.\n *\n * @method #checkEnabled\n * @param {String} indentAttributeValue The current indent attribute value.\n * @returns {Boolean}\n */\n\n/**\n * Returns a new indent attribute value based on the current indent. This method returns `undefined` when the indentation should be removed.\n *\n * @method #getNextIndent\n * @param {String} indentAttributeValue The current indent attribute value.\n * @returns {String|undefined}\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 indent/indentcommandbehavior/indentusingoffset\n */\n\n/**\n * The block indentation behavior that uses offsets to set indentation.\n *\n * @implements module:indent/indentblockcommand~IndentBehavior\n */\nexport default class IndentUsingOffset {\n\t/**\n\t * Creates an instance of the indentation behavior.\n\t *\n\t * @param {Object} config\n\t * @param {String} config.direction The direction of indentation.\n\t * @param {Number} config.offset The offset of the next indentation step.\n\t * @param {String} config.unit Indentation unit.\n\t */\n\tconstructor( config ) {\n\t\t/**\n\t\t * The direction of indentation.\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis.isForward = config.direction === 'forward';\n\n\t\t/**\n\t\t * The offset of the next indentation step.\n\t\t *\n\t\t * @type {Number}\n\t\t */\n\t\tthis.offset = config.offset;\n\n\t\t/**\n\t\t * Indentation unit.\n\t\t *\n\t\t * @type {String}\n\t\t */\n\t\tthis.unit = config.unit;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tcheckEnabled( indentAttributeValue ) {\n\t\tconst currentOffset = parseFloat( indentAttributeValue || 0 );\n\n\t\t// The command is always enabled for forward indentation.\n\t\treturn this.isForward || currentOffset > 0;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tgetNextIndent( indentAttributeValue ) {\n\t\tconst currentOffset = parseFloat( indentAttributeValue || 0 );\n\t\tconst isSameUnit = !indentAttributeValue || indentAttributeValue.endsWith( this.unit );\n\n\t\tif ( !isSameUnit ) {\n\t\t\treturn this.isForward ? this.offset + this.unit : undefined;\n\t\t}\n\n\t\tconst nextOffset = this.isForward ? this.offset : -this.offset;\n\n\t\tconst offsetToSet = currentOffset + nextOffset;\n\n\t\treturn offsetToSet > 0 ? offsetToSet + this.unit : undefined;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module indent/indentcommandbehavior/indentusingclasses\n */\n\n/**\n * The block indentation behavior that uses classes to set indentation.\n *\n * @implements module:indent/indentblockcommand~IndentBehavior\n */\nexport default class IndentUsingClasses {\n\t/**\n\t * Creates an instance of the indentation behavior.\n\t *\n\t * @param {Object} config\n\t * @param {String} config.direction The direction of indentation.\n\t * @param {Array.<String>} config.classes A list of classes used for indentation.\n\t */\n\tconstructor( config ) {\n\t\t/**\n\t\t * The direction of indentation.\n\t\t *\n\t\t * @type {Boolean}\n\t\t */\n\t\tthis.isForward = config.direction === 'forward';\n\n\t\t/**\n\t\t * A list of classes used for indentation.\n\t\t *\n\t\t * @type {Array.<String>}\n\t\t */\n\t\tthis.classes = config.classes;\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tcheckEnabled( indentAttributeValue ) {\n\t\tconst currentIndex = this.classes.indexOf( indentAttributeValue );\n\n\t\tif ( this.isForward ) {\n\t\t\treturn currentIndex < this.classes.length - 1;\n\t\t} else {\n\t\t\treturn currentIndex >= 0;\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tgetNextIndent( indentAttributeValue ) {\n\t\tconst currentIndex = this.classes.indexOf( indentAttributeValue );\n\t\tconst indexStep = this.isForward ? 1 : -1;\n\n\t\treturn this.classes[ currentIndex + indexStep ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module indent/indentblock\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { addMarginRules } from 'ckeditor5/src/engine';\n\nimport IndentBlockCommand from './indentblockcommand';\nimport IndentUsingOffset from './indentcommandbehavior/indentusingoffset';\nimport IndentUsingClasses from './indentcommandbehavior/indentusingclasses';\n\nconst DEFAULT_ELEMENTS = [ 'paragraph', 'heading1', 'heading2', 'heading3', 'heading4', 'heading5', 'heading6' ];\n\n/**\n * The block indentation feature.\n *\n * It registers the `'indentBlock'` and `'outdentBlock'` commands.\n *\n * If the plugin {@link module:indent/indent~Indent} is defined, it also attaches the `'indentBlock'` and `'outdentBlock'` commands to\n * the `'indent'` and `'outdent'` commands.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class IndentBlock extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\teditor.config.define( 'indentBlock', {\n\t\t\toffset: 40,\n\t\t\tunit: 'px'\n\t\t} );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'IndentBlock';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst configuration = editor.config.get( 'indentBlock' );\n\n\t\tconst useOffsetConfig = !configuration.classes || !configuration.classes.length;\n\n\t\tconst indentConfig = Object.assign( { direction: 'forward' }, configuration );\n\t\tconst outdentConfig = Object.assign( { direction: 'backward' }, configuration );\n\n\t\tif ( useOffsetConfig ) {\n\t\t\teditor.data.addStyleProcessorRules( addMarginRules );\n\t\t\tthis._setupConversionUsingOffset( editor.conversion );\n\n\t\t\teditor.commands.add( 'indentBlock', new IndentBlockCommand( editor, new IndentUsingOffset( indentConfig ) ) );\n\t\t\teditor.commands.add( 'outdentBlock', new IndentBlockCommand( editor, new IndentUsingOffset( outdentConfig ) ) );\n\t\t} else {\n\t\t\tthis._setupConversionUsingClasses( configuration.classes );\n\t\t\teditor.commands.add( 'indentBlock', new IndentBlockCommand( editor, new IndentUsingClasses( indentConfig ) ) );\n\t\t\teditor.commands.add( 'outdentBlock', new IndentBlockCommand( editor, new IndentUsingClasses( outdentConfig ) ) );\n\t\t}\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\n\t\tconst indentCommand = editor.commands.get( 'indent' );\n\t\tconst outdentCommand = editor.commands.get( 'outdent' );\n\n\t\t// Enable block indentation to heading configuration options. If it is not defined enable in paragraph and default headings.\n\t\tconst options = editor.config.get( 'heading.options' );\n\t\tconst configuredElements = options && options.map( option => option.model );\n\t\tconst knownElements = configuredElements || DEFAULT_ELEMENTS;\n\n\t\tknownElements.forEach( elementName => {\n\t\t\tif ( schema.isRegistered( elementName ) ) {\n\t\t\t\tschema.extend( elementName, { allowAttributes: 'blockIndent' } );\n\t\t\t}\n\t\t} );\n\n\t\tschema.setAttributeProperties( 'blockIndent', { isFormatting: true } );\n\n\t\tindentCommand.registerChildCommand( editor.commands.get( 'indentBlock' ) );\n\t\toutdentCommand.registerChildCommand( editor.commands.get( 'outdentBlock' ) );\n\t}\n\n\t/**\n\t * Setups conversion for using offset indents.\n\t *\n\t * @private\n\t */\n\t_setupConversionUsingOffset() {\n\t\tconst conversion = this.editor.conversion;\n\t\tconst locale = this.editor.locale;\n\t\tconst marginProperty = locale.contentLanguageDirection === 'rtl' ? 'margin-right' : 'margin-left';\n\n\t\tconversion.for( 'upcast' ).attributeToAttribute( {\n\t\t\tview: {\n\t\t\t\tstyles: {\n\t\t\t\t\t[ marginProperty ]: /[\\s\\S]+/\n\t\t\t\t}\n\t\t\t},\n\t\t\tmodel: {\n\t\t\t\tkey: 'blockIndent',\n\t\t\t\tvalue: viewElement => viewElement.getStyle( marginProperty )\n\t\t\t}\n\t\t} );\n\n\t\tconversion.for( 'downcast' ).attributeToAttribute( {\n\t\t\tmodel: 'blockIndent',\n\t\t\tview: modelAttributeValue => {\n\t\t\t\treturn {\n\t\t\t\t\tkey: 'style',\n\t\t\t\t\tvalue: {\n\t\t\t\t\t\t[ marginProperty ]: modelAttributeValue\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Setups conversion for using classes.\n\t *\n\t * @param {Array.<String>} classes\n\t * @private\n\t */\n\t_setupConversionUsingClasses( classes ) {\n\t\tconst definition = {\n\t\t\tmodel: {\n\t\t\t\tkey: 'blockIndent',\n\t\t\t\tvalues: []\n\t\t\t},\n\t\t\tview: {}\n\t\t};\n\n\t\tfor ( const className of classes ) {\n\t\t\tdefinition.model.values.push( className );\n\t\t\tdefinition.view[ className ] = {\n\t\t\t\tkey: 'class',\n\t\t\t\tvalue: [ className ]\n\t\t\t};\n\t\t}\n\n\t\tthis.editor.conversion.attributeToAttribute( definition );\n\t}\n}\n\n/**\n * The configuration of the {@link module:indent/indentblock~IndentBlock block indentation feature}.\n *\n * Read more in {@link module:indent/indentblock~IndentBlockConfig}.\n *\n * @member {module:indent/indentblock~IndentBlockConfig} module:core/editor/editorconfig~EditorConfig#indentBlock\n */\n\n/**\n * The configuration of the block indentation feature.\n *\n * If no {@link module:indent/indentblock~IndentBlockConfig#classes} are set, the block indentation feature will use\n * {@link module:indent/indentblock~IndentBlockConfig#offset} and {@link module:indent/indentblock~IndentBlockConfig#unit} to\n * create indentation steps.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tindentBlock: {\n *\t\t\t\t\toffset: 2,\n *\t\t\t\t\tunit: 'em'\n * \t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * Alternatively, the block indentation feature may set one of defined {@link module:indent/indentblock~IndentBlockConfig#classes} as\n * indentation steps:\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tindentBlock: {\n *\t\t\t\t\tclasses: [\n *\t\t\t\t\t\t'indent-a', // The first step - smallest indentation.\n *\t\t\t\t\t\t'indent-b',\n *\t\t\t\t\t\t'indent-c',\n *\t\t\t\t\t\t'indent-d',\n *\t\t\t\t\t\t'indent-e' // The last step - biggest indentation.\n *\t\t\t\t\t]\n * \t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * In the example above only 5 indentation steps will be available.\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface IndentBlockConfig\n */\n\n/**\n * The size of indentation {@link module:indent/indentblock~IndentBlockConfig#unit units} for each indentation step.\n *\n * @default 40\n * @member {Number} module:indent/indentblock~IndentBlockConfig#offset\n */\n\n/**\n * The unit used for indentation {@link module:indent/indentblock~IndentBlockConfig#offset}.\n *\n * @default 'px'\n * @member {String} module:indent/indentblock~IndentBlockConfig#unit\n */\n\n/**\n * An optional list of classes to use for indenting the editor content. If not set or set to an empty array, no classes will be used.\n * The {@link module:indent/indentblock~IndentBlockConfig#unit `indentBlock.unit`} and\n * {@link module:indent/indentblock~IndentBlockConfig#offset `indentBlock.offset`} properties will be used instead.\n *\n * @default undefined\n * @member {Array.<String>|undefined} module:indent/indentblock~IndentBlockConfig#classes\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 select-all/selectallcommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\n/**\n * The select all command.\n *\n * It is used by the {@link module:select-all/selectallediting~SelectAllEditing select all editing feature} to handle\n * the <kbd>Ctrl/⌘</kbd>+<kbd>A</kbd> keystroke.\n *\n * Executing this command changes the {@glink framework/guides/architecture/editing-engine#model model}\n * selection so it contains the entire content of the editable root of the editor the selection is\n * {@link module:engine/model/selection~Selection#anchor anchored} in.\n *\n * If the selection was anchored in a {@glink framework/guides/tutorials/implementing-a-block-widget nested editable}\n * (e.g. a caption of an image), the new selection will contain its entire content. Successive executions of this command\n * will expand the selection to encompass more and more content up to the entire editable root of the editor.\n *\n * @extends module:core/command~Command\n */\nexport default class SelectAllCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tlet scopeElement = model.schema.getLimitElement( selection );\n\n\t\t// If an entire scope is selected, or the selection's ancestor is not a scope yet,\n\t\t// browse through ancestors to find the enclosing parent scope.\n\t\tif ( selection.containsEntireContent( scopeElement ) || !isSelectAllScope( model.schema, scopeElement ) ) {\n\t\t\tdo {\n\t\t\t\tscopeElement = scopeElement.parent;\n\n\t\t\t\t// Do nothing, if the entire `root` is already selected.\n\t\t\t\tif ( !scopeElement ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} while ( !isSelectAllScope( model.schema, scopeElement ) );\n\t\t}\n\n\t\tmodel.change( writer => {\n\t\t\twriter.setSelection( scopeElement, 'in' );\n\t\t} );\n\t}\n}\n\n// Checks whether the element is a valid select-all scope.\n// Returns true, if the element is a {@link module:engine/model/schema~Schema#isLimit limit},\n// and can contain any text or paragraph.\n//\n// @param {module:engine/model/schema~Schema} schema The schema to check against.\n// @param {module:engine/model/element~Element} element\n// @return {Boolean}\nfunction isSelectAllScope( schema, element ) {\n\treturn schema.isLimit( element ) && ( schema.checkChild( element, '$text' ) || schema.checkChild( element, 'paragraph' ) );\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 select-all/selectallediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { getCode, parseKeystroke } from '@ckeditor/ckeditor5-utils/src/keyboard';\nimport SelectAllCommand from './selectallcommand';\n\nconst SELECT_ALL_KEYSTROKE = parseKeystroke( 'Ctrl+A' );\n\n/**\n * The select all editing feature.\n *\n * It registers the `'selectAll'` {@link module:select-all/selectallcommand~SelectAllCommand command}\n * and the <kbd>Ctrl/⌘</kbd>+<kbd>A</kbd> keystroke listener which executes it.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SelectAllEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SelectAllEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst view = editor.editing.view;\n\t\tconst viewDocument = view.document;\n\n\t\teditor.commands.add( 'selectAll', new SelectAllCommand( editor ) );\n\n\t\tthis.listenTo( viewDocument, 'keydown', ( eventInfo, domEventData ) => {\n\t\t\tif ( getCode( domEventData ) === SELECT_ALL_KEYSTROKE ) {\n\t\t\t\teditor.execute( 'selectAll' );\n\t\t\t\tdomEventData.preventDefault();\n\t\t\t}\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module select-all/selectallui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport selectAllIcon from '../theme/icons/select-all.svg';\n\n/**\n * The select all UI feature.\n *\n * It registers the `'selectAll'` UI button in the editor's\n * {@link module:ui/componentfactory~ComponentFactory component factory}. When clicked, the button\n * executes the {@link module:select-all/selectallcommand~SelectAllCommand select all command}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SelectAllUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SelectAllUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( 'selectAll', locale => {\n\t\t\tconst command = editor.commands.get( 'selectAll' );\n\t\t\tconst view = new ButtonView( locale );\n\t\t\tconst t = locale.t;\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Select all' ),\n\t\t\t\ticon: selectAllIcon,\n\t\t\t\tkeystroke: 'Ctrl+A',\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute the command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( 'selectAll' );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 20 20\\\"><path d=\\\"M.75 15.5a.75.75 0 0 1 .75.75V18l.008.09A.5.5 0 0 0 2 18.5h1.75a.75.75 0 1 1 0 1.5H1.5l-.144-.007a1.5 1.5 0 0 1-1.35-1.349L0 18.5v-2.25a.75.75 0 0 1 .75-.75zm18.5 0a.75.75 0 0 1 .75.75v2.25l-.007.144a1.5 1.5 0 0 1-1.349 1.35L18.5 20h-2.25a.75.75 0 1 1 0-1.5H18a.5.5 0 0 0 .492-.41L18.5 18v-1.75a.75.75 0 0 1 .75-.75zm-10.45 3c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2v-1.1c0-.11.09-.2.2-.2h1.6zm.45-5.5a.75.75 0 1 1 0 1.5h-8.5a.75.75 0 1 1 0-1.5h8.5zM1.3 11c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2v-1.6c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5H4.75a.75.75 0 1 1 0-1.5h10.5zM1.3 7c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2H.2a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm18.5 0c.11 0 .2.09.2.2v1.6a.2.2 0 0 1-.2.2h-1.1a.2.2 0 0 1-.2-.2V7.2c0-.11.09-.2.2-.2h1.1zm-4.55-2a.75.75 0 1 1 0 1.5h-2.5a.75.75 0 1 1 0-1.5h2.5zm-5 0a.75.75 0 1 1 0 1.5h-5.5a.75.75 0 0 1 0-1.5h5.5zm-6.5-5a.75.75 0 0 1 0 1.5H2a.5.5 0 0 0-.492.41L1.5 2v1.75a.75.75 0 0 1-1.5 0V1.5l.007-.144A1.5 1.5 0 0 1 1.356.006L1.5 0h2.25zM18.5 0l.144.007a1.5 1.5 0 0 1 1.35 1.349L20 1.5v2.25a.75.75 0 1 1-1.5 0V2l-.008-.09A.5.5 0 0 0 18 1.5h-1.75a.75.75 0 1 1 0-1.5h2.25zM8.8 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2H7.2a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6zm4 0c.11 0 .2.09.2.2v1.1a.2.2 0 0 1-.2.2h-1.6a.2.2 0 0 1-.2-.2V.2c0-.11.09-.2.2-.2h1.6z\\\"/></svg>\";","/**\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 select-all/selectall\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport SelectAllEditing from './selectallediting';\nimport SelectAllUI from './selectallui';\n\n/**\n * The select all feature.\n *\n * This is a \"glue\" plugin which loads the {@link module:select-all/selectallediting~SelectAllEditing select all editing feature}\n * and the {@link module:select-all/selectallui~SelectAllUI select all UI feature}.\n *\n * Please refer to the documentation of individual features to learn more.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class SelectAll extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ SelectAllEditing, SelectAllUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'SelectAll';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module horizontal-line/horizontallinecommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { findOptimalInsertionPosition, checkSelectionOnObject } from 'ckeditor5/src/widget';\n\n/**\n * The horizontal line command.\n *\n * The command is registered by {@link module:horizontal-line/horizontallineediting~HorizontalLineEditing} as `'horizontalLine'`.\n *\n * To insert a horizontal line at the current selection, execute the command:\n *\n *\t\teditor.execute( 'horizontalLine' );\n *\n * @extends module:core/command~Command\n */\nexport default class HorizontalLineCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = isHorizontalLineAllowed( this.editor.model );\n\t}\n\n\t/**\n\t * Executes the command.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\n\t\tmodel.change( writer => {\n\t\t\tconst horizontalElement = writer.createElement( 'horizontalLine' );\n\n\t\t\tmodel.insertContent( horizontalElement );\n\n\t\t\tlet nextElement = horizontalElement.nextSibling;\n\n\t\t\t// Check whether an element next to the inserted horizontal line is defined and can contain a text.\n\t\t\tconst canSetSelection = nextElement && model.schema.checkChild( nextElement, '$text' );\n\n\t\t\t// If the element is missing, but a paragraph could be inserted next to the horizontal line, let's add it.\n\t\t\tif ( !canSetSelection && model.schema.checkChild( horizontalElement.parent, 'paragraph' ) ) {\n\t\t\t\tnextElement = writer.createElement( 'paragraph' );\n\n\t\t\t\tmodel.insertContent( nextElement, writer.createPositionAfter( horizontalElement ) );\n\t\t\t}\n\n\t\t\t// Put the selection inside the element, at the beginning.\n\t\t\tif ( nextElement ) {\n\t\t\t\twriter.setSelection( nextElement, 0 );\n\t\t\t}\n\t\t} );\n\t}\n}\n\n// Checks if the `horizontalLine` element can be inserted at the current model selection.\n//\n// @param {module:engine/model/model~Model} model\n// @returns {Boolean}\nfunction isHorizontalLineAllowed( model ) {\n\tconst schema = model.schema;\n\tconst selection = model.document.selection;\n\n\treturn isHorizontalLineAllowedInParent( selection, schema, model ) &&\n\t\t!checkSelectionOnObject( selection, schema );\n}\n\n// Checks if a horizontal line is allowed by the schema in the optimal insertion parent.\n//\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// @param {module:engine/model/schema~Schema} schema\n// @param {module:engine/model/model~Model} model Model instance.\n// @returns {Boolean}\nfunction isHorizontalLineAllowedInParent( selection, schema, model ) {\n\tconst parent = getInsertHorizontalLineParent( selection, model );\n\n\treturn schema.checkChild( parent, 'horizontalLine' );\n}\n\n// Returns a node that will be used to insert a horizontal line with `model.insertContent` to check if the horizontal line can be\n// placed there.\n//\n// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection\n// @param {module:engine/model/model~Model} model Model instance.\n// @returns {module:engine/model/element~Element}\nfunction getInsertHorizontalLineParent( selection, model ) {\n\tconst insertAt = findOptimalInsertionPosition( selection, model );\n\n\tconst parent = insertAt.parent;\n\n\tif ( parent.isEmpty && !parent.is( 'element', '$root' ) ) {\n\t\treturn parent.parent;\n\t}\n\n\treturn parent;\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 horizontal-line/horizontallineediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { toWidget } from 'ckeditor5/src/widget';\n\nimport HorizontalLineCommand from './horizontallinecommand';\n\nimport '../theme/horizontalline.css';\n\n/**\n * The horizontal line editing feature.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HorizontalLineEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HorizontalLineEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst schema = editor.model.schema;\n\t\tconst t = editor.t;\n\t\tconst conversion = editor.conversion;\n\n\t\tschema.register( 'horizontalLine', {\n\t\t\tisObject: true,\n\t\t\tallowWhere: '$block'\n\t\t} );\n\n\t\tconversion.for( 'dataDowncast' ).elementToElement( {\n\t\t\tmodel: 'horizontalLine',\n\t\t\tview: ( modelElement, { writer } ) => {\n\t\t\t\treturn writer.createEmptyElement( 'hr' );\n\t\t\t}\n\t\t} );\n\n\t\tconversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'horizontalLine',\n\t\t\tview: ( modelElement, { writer } ) => {\n\t\t\t\tconst label = t( 'Horizontal line' );\n\t\t\t\tconst viewWrapper = writer.createContainerElement( 'div' );\n\t\t\t\tconst viewHrElement = writer.createEmptyElement( 'hr' );\n\n\t\t\t\twriter.addClass( 'ck-horizontal-line', viewWrapper );\n\t\t\t\twriter.setCustomProperty( 'hr', true, viewWrapper );\n\n\t\t\t\twriter.insert( writer.createPositionAt( viewWrapper, 0 ), viewHrElement );\n\n\t\t\t\treturn toHorizontalLineWidget( viewWrapper, writer, label );\n\t\t\t}\n\t\t} );\n\n\t\tconversion.for( 'upcast' ).elementToElement( { view: 'hr', model: 'horizontalLine' } );\n\n\t\teditor.commands.add( 'horizontalLine', new HorizontalLineCommand( editor ) );\n\t}\n}\n\n// Converts a given {@link module:engine/view/element~Element} to a horizontal line widget:\n// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to\n// recognize the horizontal line widget element.\n// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.\n//\n// @param {module:engine/view/element~Element} viewElement\n// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.\n// @param {String} label The element's label.\n// @returns {module:engine/view/element~Element}\nfunction toHorizontalLineWidget( viewElement, writer, label ) {\n\twriter.setCustomProperty( 'horizontalLine', true, viewElement );\n\n\treturn toWidget( viewElement, writer, { label } );\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 horizontal-line/horizontallineui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport horizontalLineIcon from '../theme/icons/horizontalline.svg';\n\n/**\n * The horizontal line UI plugin.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HorizontalLineUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HorizontalLineUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// Add the `horizontalLine` button to feature components.\n\t\teditor.ui.componentFactory.add( 'horizontalLine', locale => {\n\t\t\tconst command = editor.commands.get( 'horizontalLine' );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Horizontal line' ),\n\t\t\t\ticon: horizontalLineIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isEnabled' ).to( command, 'isEnabled' );\n\n\t\t\t// Execute the command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( 'horizontalLine' );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M2 9h16v2H2z\\\"/></svg>\";","/**\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 undo/basecommand\n */\n\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport { transformSets } from '@ckeditor/ckeditor5-engine/src/model/operation/transform';\n\n/**\n * Base class for undo feature commands: {@link module:undo/undocommand~UndoCommand} and {@link module:undo/redocommand~RedoCommand}.\n *\n * @protected\n * @extends module:core/command~Command\n */\nexport default class BaseCommand extends Command {\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * Stack of items stored by the command. These are pairs of:\n\t\t *\n\t\t * * {@link module:engine/model/batch~Batch batch} saved by the command,\n\t\t * * {@link module:engine/model/selection~Selection selection} state at the moment of saving the batch.\n\t\t *\n\t\t * @protected\n\t\t * @member {Array} #_stack\n\t\t */\n\t\tthis._stack = [];\n\n\t\t/**\n\t\t * Stores all batches that were created by this command.\n\t\t *\n\t\t * @protected\n\t\t * @member {WeakSet.<module:engine/model/batch~Batch>} #_createdBatches\n\t\t */\n\t\tthis._createdBatches = new WeakSet();\n\n\t\t// Refresh state, so the command is inactive right after initialization.\n\t\tthis.refresh();\n\n\t\tthis.listenTo( editor.data, 'set', () => this.clearStack() );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tthis.isEnabled = this._stack.length > 0;\n\t}\n\n\t/**\n\t * Stores a batch in the command, together with the selection state of the {@link module:engine/model/document~Document document}\n\t * created by the editor which this command is registered to.\n\t *\n\t * @param {module:engine/model/batch~Batch} batch The batch to add.\n\t */\n\taddBatch( batch ) {\n\t\tconst docSelection = this.editor.model.document.selection;\n\n\t\tconst selection = {\n\t\t\tranges: docSelection.hasOwnRange ? Array.from( docSelection.getRanges() ) : [],\n\t\t\tisBackward: docSelection.isBackward\n\t\t};\n\n\t\tthis._stack.push( { batch, selection } );\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Removes all items from the stack.\n\t */\n\tclearStack() {\n\t\tthis._stack = [];\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Restores the {@link module:engine/model/document~Document#selection document selection} state after a batch was undone.\n\t *\n\t * @protected\n\t * @param {Array.<module:engine/model/range~Range>} ranges Ranges to be restored.\n\t * @param {Boolean} isBackward A flag describing whether the restored range was selected forward or backward.\n\t * @param {Array.<module:engine/model/operation/operation~Operation>} operations Operations which has been applied\n\t * since selection has been stored.\n\t */\n\t_restoreSelection( ranges, isBackward, operations ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\t// This will keep the transformed selection ranges.\n\t\tconst selectionRanges = [];\n\n\t\t// Transform all ranges from the restored selection.\n\t\tconst transformedRangeGroups = ranges.map( range => range.getTransformedByOperations( operations ) );\n\t\tconst allRanges = transformedRangeGroups.flat();\n\n\t\tfor ( const rangeGroup of transformedRangeGroups ) {\n\t\t\t// While transforming there could appear ranges that are contained by other ranges, we shall ignore them.\n\t\t\tconst transformed = rangeGroup\n\t\t\t\t.filter( range => range.root != document.graveyard )\n\t\t\t\t.filter( range => !isRangeContainedByAnyOtherRange( range, allRanges ) );\n\n\t\t\t// All the transformed ranges ended up in graveyard.\n\t\t\tif ( !transformed.length ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// After the range got transformed, we have an array of ranges. Some of those\n\t\t\t// ranges may be \"touching\" -- they can be next to each other and could be merged.\n\t\t\tnormalizeRanges( transformed );\n\n\t\t\t// For each `range` from `ranges`, we take only one transformed range.\n\t\t\t// This is because we want to prevent situation where single-range selection\n\t\t\t// got transformed to multi-range selection.\n\t\t\tselectionRanges.push( transformed[ 0 ] );\n\t\t}\n\n\t\t// @if CK_DEBUG_ENGINE // console.log( `Restored selection by undo: ${ selectionRanges.join( ', ' ) }` );\n\n\t\t// `selectionRanges` may be empty if all ranges ended up in graveyard. If that is the case, do not restore selection.\n\t\tif ( selectionRanges.length ) {\n\t\t\tmodel.change( writer => {\n\t\t\t\twriter.setSelection( selectionRanges, { backward: isBackward } );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Undoes a batch by reversing that batch, transforming reversed batch and finally applying it.\n\t * This is a helper method for {@link #execute}.\n\t *\n\t * @protected\n\t * @param {module:engine/model/batch~Batch} batchToUndo The batch to be undone.\n\t * @param {module:engine/model/batch~Batch} undoingBatch The batch that will contain undoing changes.\n\t */\n\t_undo( batchToUndo, undoingBatch ) {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\t// All changes done by the command execution will be saved as one batch.\n\t\tthis._createdBatches.add( undoingBatch );\n\n\t\tconst operationsToUndo = batchToUndo.operations.slice().filter( operation => operation.isDocumentOperation );\n\t\toperationsToUndo.reverse();\n\n\t\t// We will process each operation from `batchToUndo`, in reverse order. If there were operations A, B and C in undone batch,\n\t\t// we need to revert them in reverse order, so first C' (reversed C), then B', then A'.\n\t\tfor ( const operationToUndo of operationsToUndo ) {\n\t\t\tconst nextBaseVersion = operationToUndo.baseVersion + 1;\n\t\t\tconst historyOperations = Array.from( document.history.getOperations( nextBaseVersion ) );\n\n\t\t\tconst transformedSets = transformSets(\n\t\t\t\t[ operationToUndo.getReversed() ],\n\t\t\t\thistoryOperations,\n\t\t\t\t{\n\t\t\t\t\tuseRelations: true,\n\t\t\t\t\tdocument: this.editor.model.document,\n\t\t\t\t\tpadWithNoOps: false,\n\t\t\t\t\tforceWeakRemove: true\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tconst reversedOperations = transformedSets.operationsA;\n\n\t\t\t// After reversed operation has been transformed by all history operations, apply it.\n\t\t\tfor ( const operation of reversedOperations ) {\n\t\t\t\t// Before applying, add the operation to the `undoingBatch`.\n\t\t\t\tundoingBatch.addOperation( operation );\n\t\t\t\tmodel.applyOperation( operation );\n\n\t\t\t\tdocument.history.setOperationAsUndone( operationToUndo, operation );\n\t\t\t}\n\t\t}\n\t}\n}\n\n// Normalizes list of ranges by joining intersecting or \"touching\" ranges.\n//\n// @param {Array.<module:engine/model/range~Range>} ranges\n//\nfunction normalizeRanges( ranges ) {\n\tranges.sort( ( a, b ) => a.start.isBefore( b.start ) ? -1 : 1 );\n\n\tfor ( let i = 1; i < ranges.length; i++ ) {\n\t\tconst previousRange = ranges[ i - 1 ];\n\t\tconst joinedRange = previousRange.getJoined( ranges[ i ], true );\n\n\t\tif ( joinedRange ) {\n\t\t\t// Replace the ranges on the list with the new joined range.\n\t\t\ti--;\n\t\t\tranges.splice( i, 2, joinedRange );\n\t\t}\n\t}\n}\n\nfunction isRangeContainedByAnyOtherRange( range, ranges ) {\n\treturn ranges.some( otherRange => otherRange !== range && otherRange.containsRange( range, true ) );\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 undo/undocommand\n */\n\nimport BaseCommand from './basecommand';\n\n/**\n * The undo command stores {@link module:engine/model/batch~Batch batches} applied to the\n * {@link module:engine/model/document~Document document} and is able to undo a batch by reversing it and transforming by\n * batches from {@link module:engine/model/document~Document#history history} that happened after the reversed batch.\n *\n * The undo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.\n *\n * @extends module:undo/basecommand~BaseCommand\n */\nexport default class UndoCommand extends BaseCommand {\n\t/**\n\t * Executes the command. This method reverts a {@link module:engine/model/batch~Batch batch} added to the command's stack, transforms\n\t * and applies the reverted version on the {@link module:engine/model/document~Document document} and removes the batch from the stack.\n\t * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.\n\t *\n\t * @fires execute\n\t * @fires revert\n\t * @param {module:engine/model/batch~Batch} [batch] A batch that should be undone. If not set, the last added batch will be undone.\n\t */\n\texecute( batch = null ) {\n\t\t// If batch is not given, set `batchIndex` to the last index in command stack.\n\t\tconst batchIndex = batch ? this._stack.findIndex( a => a.batch == batch ) : this._stack.length - 1;\n\n\t\tconst item = this._stack.splice( batchIndex, 1 )[ 0 ];\n\t\tconst undoingBatch = this.editor.model.createBatch( 'transparent' );\n\n\t\t// All changes has to be done in one `enqueueChange` callback so other listeners will not\n\t\t// step between consecutive operations, or won't do changes to the document before selection is properly restored.\n\t\tthis.editor.model.enqueueChange( undoingBatch, () => {\n\t\t\tthis._undo( item.batch, undoingBatch );\n\n\t\t\tconst operations = this.editor.model.document.history.getOperations( item.batch.baseVersion );\n\t\t\tthis._restoreSelection( item.selection.ranges, item.selection.isBackward, operations );\n\n\t\t\tthis.fire( 'revert', item.batch, undoingBatch );\n\t\t} );\n\n\t\tthis.refresh();\n\t}\n}\n\n/**\n * Fired when execution of the command reverts some batch.\n *\n * @event revert\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 undo/redocommand\n */\n\nimport BaseCommand from './basecommand';\n\n/**\n * The redo command stores {@link module:engine/model/batch~Batch batches} that were used to undo a batch by\n * {@link module:undo/undocommand~UndoCommand}. It is able to redo a previously undone batch by reversing the undoing\n * batches created by `UndoCommand`. The reversed batch is transformed by all the batches from\n * {@link module:engine/model/document~Document#history history} that happened after the reversed undo batch.\n *\n * The redo command also takes care of restoring the {@link module:engine/model/document~Document#selection document selection}.\n *\n * @extends module:undo/basecommand~BaseCommand\n */\nexport default class RedoCommand extends BaseCommand {\n\t/**\n\t * Executes the command. This method reverts the last {@link module:engine/model/batch~Batch batch} added to\n\t * the command's stack, applies the reverted and transformed version on the\n\t * {@link module:engine/model/document~Document document} and removes the batch from the stack.\n\t * Then, it restores the {@link module:engine/model/document~Document#selection document selection}.\n\t *\n\t * @fires execute\n\t */\n\texecute() {\n\t\tconst item = this._stack.pop();\n\t\tconst redoingBatch = this.editor.model.createBatch( 'transparent' );\n\n\t\t// All changes have to be done in one `enqueueChange` callback so other listeners will not step between consecutive\n\t\t// operations, or won't do changes to the document before selection is properly restored.\n\t\tthis.editor.model.enqueueChange( redoingBatch, () => {\n\t\t\tconst lastOperation = item.batch.operations[ item.batch.operations.length - 1 ];\n\t\t\tconst nextBaseVersion = lastOperation.baseVersion + 1;\n\t\t\tconst operations = this.editor.model.document.history.getOperations( nextBaseVersion );\n\n\t\t\tthis._restoreSelection( item.selection.ranges, item.selection.isBackward, operations );\n\t\t\tthis._undo( item.batch, redoingBatch );\n\t\t} );\n\n\t\tthis.refresh();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/undoediting\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport UndoCommand from './undocommand';\nimport RedoCommand from './redocommand';\n\n/**\n * The undo engine feature.\n *\n * It introduces the `'undo'` and `'redo'` commands to the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UndoEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'UndoEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\t/**\n\t\t * The command that manages undo {@link module:engine/model/batch~Batch batches} stack (history).\n\t\t * Created and registered during the {@link #init feature initialization}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:undo/undocommand~UndoCommand} #_undoCommand\n\t\t */\n\n\t\t/**\n\t\t * The command that manages redo {@link module:engine/model/batch~Batch batches} stack (history).\n\t\t * Created and registered during the {@link #init feature initialization}.\n\t\t *\n\t\t * @private\n\t\t * @member {module:undo/undocommand~UndoCommand} #_redoCommand\n\t\t */\n\n\t\t/**\n\t\t * Keeps track of which batches were registered in undo.\n\t\t *\n\t\t * @private\n\t\t * @member {WeakSet.<module:engine/model/batch~Batch>}\n\t\t */\n\t\tthis._batchRegistry = new WeakSet();\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\t// Create commands.\n\t\tthis._undoCommand = new UndoCommand( editor );\n\t\tthis._redoCommand = new RedoCommand( editor );\n\n\t\t// Register command to the editor.\n\t\teditor.commands.add( 'undo', this._undoCommand );\n\t\teditor.commands.add( 'redo', this._redoCommand );\n\n\t\tthis.listenTo( editor.model, 'applyOperation', ( evt, args ) => {\n\t\t\tconst operation = args[ 0 ];\n\n\t\t\t// Do not register batch if the operation is not a document operation.\n\t\t\t// This prevents from creating empty undo steps, where all operations where non-document operations.\n\t\t\t// Non-document operations creates and alters content in detached tree fragments (for example, document fragments).\n\t\t\t// Most of time this is preparing data before it is inserted into actual tree (for example during copy & paste).\n\t\t\t// Such operations should not be reversed.\n\t\t\tif ( !operation.isDocumentOperation ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst batch = operation.batch;\n\n\t\t\tconst isRedoBatch = this._redoCommand._createdBatches.has( batch );\n\t\t\tconst isUndoBatch = this._undoCommand._createdBatches.has( batch );\n\t\t\tconst isRegisteredBatch = this._batchRegistry.has( batch );\n\n\t\t\t// If changes are not a part of a batch or this is not a new batch, omit those changes.\n\t\t\tif ( isRegisteredBatch || ( batch.type == 'transparent' && !isRedoBatch && !isUndoBatch ) ) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tif ( isRedoBatch ) {\n\t\t\t\t\t// If this batch comes from `redoCommand`, add it to `undoCommand` stack.\n\t\t\t\t\tthis._undoCommand.addBatch( batch );\n\t\t\t\t} else if ( !isUndoBatch ) {\n\t\t\t\t\t// A default batch - these are new changes in the document, not introduced by undo feature.\n\t\t\t\t\t// Add them to `undoCommand` stack and clear `redoCommand` stack.\n\t\t\t\t\tthis._undoCommand.addBatch( batch );\n\t\t\t\t\tthis._redoCommand.clearStack();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add the batch to the registry so it will not be processed again.\n\t\t\tthis._batchRegistry.add( batch );\n\t\t}, { priority: 'highest' } );\n\n\t\tthis.listenTo( this._undoCommand, 'revert', ( evt, undoneBatch, undoingBatch ) => {\n\t\t\tthis._redoCommand.addBatch( undoingBatch );\n\t\t} );\n\n\t\teditor.keystrokes.set( 'CTRL+Z', 'undo' );\n\t\teditor.keystrokes.set( 'CTRL+Y', 'redo' );\n\t\teditor.keystrokes.set( 'CTRL+SHIFT+Z', 'redo' );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m5.042 9.367 2.189 1.837a.75.75 0 0 1-.965 1.149l-3.788-3.18a.747.747 0 0 1-.21-.284.75.75 0 0 1 .17-.945L6.23 4.762a.75.75 0 1 1 .964 1.15L4.863 7.866h8.917A.75.75 0 0 1 14 7.9a4 4 0 1 1-1.477 7.718l.344-1.489a2.5 2.5 0 1 0 1.094-4.73l.008-.032H5.042z\\\"/></svg>\";","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"m14.958 9.367-2.189 1.837a.75.75 0 0 0 .965 1.149l3.788-3.18a.747.747 0 0 0 .21-.284.75.75 0 0 0-.17-.945L13.77 4.762a.75.75 0 1 0-.964 1.15l2.331 1.955H6.22A.75.75 0 0 0 6 7.9a4 4 0 1 0 1.477 7.718l-.344-1.489A2.5 2.5 0 1 1 6.039 9.4l-.008-.032h8.927z\\\"/></svg>\";","/**\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 undo/undoui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nimport undoIcon from '../theme/icons/undo.svg';\nimport redoIcon from '../theme/icons/redo.svg';\n\n/**\n * The undo UI feature. It introduces the `'undo'` and `'redo'` buttons to the editor.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class UndoUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'UndoUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst locale = editor.locale;\n\t\tconst t = editor.t;\n\n\t\tconst localizedUndoIcon = locale.uiLanguageDirection == 'ltr' ? undoIcon : redoIcon;\n\t\tconst localizedRedoIcon = locale.uiLanguageDirection == 'ltr' ? redoIcon : undoIcon;\n\n\t\tthis._addButton( 'undo', t( 'Undo' ), 'CTRL+Z', localizedUndoIcon );\n\t\tthis._addButton( 'redo', t( 'Redo' ), 'CTRL+Y', localizedRedoIcon );\n\t}\n\n\t/**\n\t * Creates a button for the specified command.\n\t *\n\t * @private\n\t * @param {String} name Command name.\n\t * @param {String} label Button label.\n\t * @param {String} keystroke Command keystroke.\n\t * @param {String} Icon Source of the icon.\n\t */\n\t_addButton( name, label, keystroke, Icon ) {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( name, locale => {\n\t\t\tconst command = editor.commands.get( name );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel,\n\t\t\t\ticon: Icon,\n\t\t\t\tkeystroke,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isEnabled' ).to( command, 'isEnabled' );\n\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( name );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module undo/undo\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport UndoEditing from './undoediting';\nimport UndoUI from './undoui';\n\n/**\n * The undo feature.\n *\n * This is a \"glue\" plugin which loads the {@link module:undo/undoediting~UndoEditing undo editing feature}\n * and {@link module:undo/undoui~UndoUI undo UI feature}.\n *\n * Below is the explanation of the undo mechanism working together with {@link module:engine/model/history~History History}:\n *\n * Whenever a {@link module:engine/model/operation/operation~Operation operation} is applied to the\n * {@link module:engine/model/document~Document document}, it is saved to `History` as is.\n * The {@link module:engine/model/batch~Batch batch} that owns that operation is also saved, in\n * {@link module:undo/undocommand~UndoCommand}, together with the selection that was present in the document before the\n * operation was applied. A batch is saved instead of the operation because changes are undone batch-by-batch, not operation-by-operation\n * and a batch is seen as one undo step.\n *\n * After some changes happen to the document, the `History` and `UndoCommand` stack can be represented as follows:\n *\n *\t\t History Undo stack\n *\t\t============== ==================================\n *\t\t[operation A1] [batch A]\n *\t\t[operation B1] [batch B]\n *\t\t[operation B2] [batch C]\n *\t\t[operation C1]\n *\t\t[operation C2]\n *\t\t[operation B3]\n *\t\t[operation C3]\n *\n * Where operations starting with the same letter are from same batch.\n *\n * Undoing a batch means that a set of operations which will reverse the effects of that batch needs to be generated.\n * For example, if a batch added several letters, undoing the batch should remove them. It is important to apply undoing\n * operations in the reversed order, so if a batch has operation `X`, `Y`, `Z`, reversed operations `Zr`, `Yr` and `Xr`\n * need to be applied. Otherwise reversed operation `Xr` would operate on a wrong document state, because operation `X`\n * does not know that operations `Y` and `Z` happened.\n *\n * After operations from an undone batch got {@link module:engine/model/operation/operation~Operation#getReversed reversed},\n * one needs to make sure if they are ready to be applied. In the scenario above, operation `C3` is the last operation and `C3r`\n * bases on up-to-date document state, so it can be applied to the document.\n *\n *\t\t History Undo stack\n *\t\t================= ==================================\n *\t\t[ operation A1 ] [ batch A ]\n *\t\t[ operation B1 ] [ batch B ]\n *\t\t[ operation B2 ] [ processing undoing batch C ]\n *\t\t[ operation C1 ]\n *\t\t[ operation C2 ]\n *\t\t[ operation B3 ]\n *\t\t[ operation C3 ]\n *\t\t[ operation C3r ]\n *\n * Next is operation `C2`, reversed to `C2r`. `C2r` bases on `C2`, so it bases on the wrong document state. It needs to be\n * transformed by operations from history that happened after it, so it \"knows\" about them. Let us assume that `C2' = C2r * B3 * C3 * C3r`,\n * where `*` means \"transformed by\". Rest of operations from that batch are processed in the same fashion.\n *\n *\t\t History Undo stack Redo stack\n *\t\t================= ================================== ==================================\n *\t\t[ operation A1 ] [ batch A ] [ batch Cr ]\n *\t\t[ operation B1 ] [ batch B ]\n *\t\t[ operation B2 ]\n *\t\t[ operation C1 ]\n *\t\t[ operation C2 ]\n *\t\t[ operation B3 ]\n *\t\t[ operation C3 ]\n *\t\t[ operation C3r ]\n *\t\t[ operation C2' ]\n *\t\t[ operation C1' ]\n *\n * Selective undo works on the same basis, however, instead of undoing the last batch in the undo stack, any batch can be undone.\n * The same algorithm applies: operations from a batch (i.e. `A1`) are reversed and then transformed by operations stored in history.\n *\n * Redo also is very similar to undo. It has its own stack that is filled with undoing (reversed batches). Operations from\n * batch that is re-done are reversed-back, transformed in proper order and applied to the document.\n *\n *\t\t History Undo stack Redo stack\n *\t\t================= ================================== ==================================\n *\t\t[ operation A1 ] [ batch A ]\n *\t\t[ operation B1 ] [ batch B ]\n *\t\t[ operation B2 ] [ batch Crr ]\n *\t\t[ operation C1 ]\n *\t\t[ operation C2 ]\n *\t\t[ operation B3 ]\n *\t\t[ operation C3 ]\n *\t\t[ operation C3r ]\n *\t\t[ operation C2' ]\n *\t\t[ operation C1' ]\n *\t\t[ operation C1'r]\n *\t\t[ operation C2'r]\n *\t\t[ operation C3rr]\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Undo extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ UndoEditing, UndoUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Undo';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module remove-format/removeformatui\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ButtonView } from 'ckeditor5/src/ui';\n\nimport removeFormatIcon from '../theme/icons/remove-format.svg';\n\nconst REMOVE_FORMAT = 'removeFormat';\n\n/**\n * The remove format UI plugin. It registers the `'removeFormat'` button which can be\n * used in the toolbar.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class RemoveFormatUI extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'RemoveFormatUI';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\teditor.ui.componentFactory.add( REMOVE_FORMAT, locale => {\n\t\t\tconst command = editor.commands.get( REMOVE_FORMAT );\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: t( 'Remove Format' ),\n\t\t\t\ticon: removeFormatIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\tview.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute the command.\n\t\t\tthis.listenTo( view, 'execute', () => {\n\t\t\t\teditor.execute( REMOVE_FORMAT );\n\t\t\t\teditor.editing.view.focus();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M8.69 14.915c.053.052.173.083.36.093a.366.366 0 0 1 .345.485l-.003.01a.738.738 0 0 1-.697.497h-2.67a.374.374 0 0 1-.353-.496l.013-.038a.681.681 0 0 1 .644-.458c.197-.012.325-.043.386-.093a.28.28 0 0 0 .072-.11L9.592 4.5H6.269c-.359-.017-.609.013-.75.09-.142.078-.289.265-.442.563-.192.29-.516.464-.864.464H4.17a.43.43 0 0 1-.407-.569L4.46 3h13.08l-.62 2.043a.81.81 0 0 1-.775.574h-.114a.486.486 0 0 1-.486-.486c.001-.284-.054-.464-.167-.54-.112-.076-.367-.106-.766-.091h-3.28l-2.68 10.257c-.006.074.007.127.038.158zM3 17h8a.5.5 0 1 1 0 1H3a.5.5 0 1 1 0-1zm11.299 1.17a.75.75 0 1 1-1.06-1.06l1.414-1.415-1.415-1.414a.75.75 0 0 1 1.06-1.06l1.415 1.414 1.414-1.415a.75.75 0 1 1 1.06 1.06l-1.413 1.415 1.414 1.415a.75.75 0 0 1-1.06 1.06l-1.415-1.414-1.414 1.414z\\\"/></svg>\";","/**\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 remove-format/removeformatcommand\n */\n\nimport { Command } from 'ckeditor5/src/core';\nimport { first } from 'ckeditor5/src/utils';\n\n/**\n * The remove format command.\n *\n * It is used by the {@link module:remove-format/removeformat~RemoveFormat remove format feature}\n * to clear the formatting in the selection.\n *\n *\t\teditor.execute( 'removeFormat' );\n *\n * @extends module:core/command~Command\n */\nexport default class RemoveFormatCommand extends Command {\n\t/**\n\t * @inheritDoc\n\t */\n\trefresh() {\n\t\tconst model = this.editor.model;\n\n\t\tthis.isEnabled = !!first( this._getFormattingItems( model.document.selection, model.schema ) );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\texecute() {\n\t\tconst model = this.editor.model;\n\t\tconst schema = model.schema;\n\n\t\tmodel.change( writer => {\n\t\t\tfor ( const item of this._getFormattingItems( model.document.selection, schema ) ) {\n\t\t\t\tif ( item.is( 'selection' ) ) {\n\t\t\t\t\tfor ( const attributeName of this._getFormattingAttributes( item, schema ) ) {\n\t\t\t\t\t\twriter.removeSelectionAttribute( attributeName );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Workaround for items with multiple removable attributes. See\n\t\t\t\t\t// https://github.com/ckeditor/ckeditor5-remove-format/pull/1#pullrequestreview-220515609\n\t\t\t\t\tconst itemRange = writer.createRangeOn( item );\n\n\t\t\t\t\tfor ( const attributeName of this._getFormattingAttributes( item, schema ) ) {\n\t\t\t\t\t\twriter.removeAttribute( attributeName, itemRange );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * Returns an iterable of items in a selection (including the selection itself) that have formatting model\n\t * attributes to be removed by the feature.\n\t *\n\t * @protected\n\t * @param {module:engine/model/documentselection~DocumentSelection} selection\n\t * @param {module:engine/model/schema~Schema} schema The schema describing the item.\n\t * @returns {Iterable.<module:engine/model/item~Item>|Iterable.<module:engine/model/documentselection~DocumentSelection>}\n\t */\n\t* _getFormattingItems( selection, schema ) {\n\t\tconst itemHasRemovableFormatting = item => {\n\t\t\treturn !!first( this._getFormattingAttributes( item, schema ) );\n\t\t};\n\n\t\t// Check formatting on selected items that are not blocks.\n\t\tfor ( const curRange of selection.getRanges() ) {\n\t\t\tfor ( const item of curRange.getItems() ) {\n\t\t\t\tif ( !schema.isBlock( item ) && itemHasRemovableFormatting( item ) ) {\n\t\t\t\t\tyield item;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check formatting from selected blocks.\n\t\tfor ( const block of selection.getSelectedBlocks() ) {\n\t\t\tif ( itemHasRemovableFormatting( block ) ) {\n\t\t\t\tyield block;\n\t\t\t}\n\t\t}\n\n\t\t// Finally the selection might be formatted as well, so make sure to check it.\n\t\tif ( itemHasRemovableFormatting( selection ) ) {\n\t\t\tyield selection;\n\t\t}\n\t}\n\n\t/**\n\t * Returns an iterable of formatting attributes of a given model item.\n\t *\n\t * **Note:** Formatting items have the `isFormatting` property set to `true`.\n\t *\n\t * @protected\n\t * @param {module:engine/model/item~Item|module:engine/model/documentselection~DocumentSelection} item\n\t * @param {module:engine/model/schema~Schema} schema The schema describing the item.\n\t * @returns {Iterable.<String>} The names of formatting attributes found in a given item.\n\t */\n\t* _getFormattingAttributes( item, schema ) {\n\t\tfor ( const [ attributeName ] of item.getAttributes() ) {\n\t\t\tconst attributeProperties = schema.getAttributeProperties( attributeName );\n\n\t\t\tif ( attributeProperties && attributeProperties.isFormatting ) {\n\t\t\t\tyield attributeName;\n\t\t\t}\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module remove-format/removeformatediting\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport RemoveFormatCommand from './removeformatcommand';\n\n/**\n * The remove format editing plugin.\n *\n * It registers the {@link module:remove-format/removeformatcommand~RemoveFormatCommand removeFormat} command.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class RemoveFormatEditing extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'RemoveFormatEditing';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.commands.add( 'removeFormat', new RemoveFormatCommand( editor ) );\n\t}\n}\n","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nexport default class MentionCustomization extends Plugin {\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\t// override standard mention command (see https://github.com/ckeditor/ckeditor5/issues/6470)\n\t\teditor.commands.add('mention', new CustomMentionCommand(editor));\n\t}\n}\n\nclass CustomMentionCommand extends Command {\n\texecute(options) {\n\t\tconst {model} = this.editor;\n\t\tconst {document} = model;\n\t\tconst {selection} = document;\n\t\tconst {mention} = options;\n\n\t\tconst range = options.range || selection.getFirstRange();\n\n\t\tif (mention.id.startsWith('#') || mention.id.startsWith('~')) {\n\t\t\tmodel.change(writer => {\n\t\t\t\t// Replace a range with the text with a mention.\n\t\t\t\tmodel.insertContent( writer.createText( mention.id, {} ), range );\n\t\t\t});\n\t\t}\n\t\telse if (mention.action === 'create-note') {\n\t\t\tconst editorEl = this.editor.editing.view.getDomRoot();\n\t\t\tconst component = glob.getComponentByEl(editorEl);\n\n\t\t\tcomponent.createNoteForReferenceLink(mention.noteTitle).then(notePath => {\n\t\t\t\tthis.insertReference(range, notePath);\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\tthis.insertReference(range, options.mention.notePath);\n\t\t}\n\t}\n\n\tinsertReference(range, notePath) {\n\t\tconst {model} = this.editor;\n\n\t\tmodel.change(writer => {\n\t\t\t// override the selection or at least the beginning @ character\n\t\t\tmodel.insertContent(writer.createText('', {}), range);\n\n\t\t\tthis.editor.execute('referenceLink', {notePath: notePath});\n\t\t});\n\t}\n}\n","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';\n\nexport default class UploadimagePlugin extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FileRepository ];\n\t}\n\n\tstatic get pluginName() {\n\t\treturn 'UploadimagePlugin';\n\t}\n\n\tinit() {\n\t\tthis.editor.plugins.get('FileRepository').createUploadAdapter = loader => new Adapter(loader);\n\t}\n}\n\nclass Adapter {\n\t/**\n\t * Creates a new adapter instance.\n\t *\n\t * @param {module:upload/filerepository~FileLoader} loader\n\t */\n\tconstructor(loader) {\n\t\t/**\n\t\t * FileLoader instance to use during the upload.\n\t\t *\n\t\t * @member {module:upload/filerepository~FileLoader} #loader\n\t\t */\n\t\tthis.loader = loader;\n\t}\n\n\t/**\n\t * Starts the upload process.\n\t *\n\t * @see module:upload/filerepository~Adapter#upload\n\t * @returns {Promise}\n\t */\n\tupload() {\n\t\treturn this.loader.file\n\t\t\t.then( file => new Promise( ( resolve, reject ) => {\n\t\t\t\tthis._initRequest().then(() => {\n\t\t\t\t\tthis._initListeners( resolve, reject, file );\n\t\t\t\t\tthis._sendRequest( file );\n\t\t\t\t});\n\t\t\t} ) );\n\t}\n\n\t/**\n\t * Aborts the upload process.\n\t *\n\t * @see module:upload/filerepository~Adapter#abort\n\t * @returns {Promise}\n\t */\n\tabort() {\n\t\tif (this.xhr) {\n\t\t\tthis.xhr.abort();\n\t\t}\n\t}\n\n\t/**\n\t * Initializes the XMLHttpRequest object.\n\t *\n\t * @private\n\t */\n\t_initRequest() {\n\t\treturn glob.getHeaders().then(headers => {\n\t\t\tconst xhr = this.xhr = new XMLHttpRequest();\n\n\t\t\tconst {noteId} = glob.getActiveTabNote();\n\n\t\t\t// this must be relative path\n\t\t\tconst url = \"api/images?noteId=\" + noteId;\n\n\t\t\txhr.open('POST', url, true);\n\t\t\txhr.responseType = 'json';\n\n\t\t\tfor (const headerName in headers) {\n\t\t\t\txhr.setRequestHeader(headerName, headers[headerName]);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Initializes XMLHttpRequest listeners.\n\t *\n\t * @private\n\t * @param {Function} resolve Callback function to be called when the request is successful.\n\t * @param {Function} reject Callback function to be called when the request cannot be completed.\n\t */\n\tasync _initListeners(resolve, reject) {\n\t\tconst xhr = this.xhr;\n\t\tconst loader = this.loader;\n\t\tconst file = await loader.file;\n\t\tconst genericError = 'Cannot upload file:' + ` ${file.name}.`;\n\n\t\txhr.addEventListener('error', () => reject(genericError));\n\t\txhr.addEventListener('abort', () => reject());\n\t\txhr.addEventListener('load', () => {\n\t\t\tconst response = xhr.response;\n\n\t\t\tif (!response || !response.uploaded) {\n\t\t\t\treturn reject(response && response.error && response.error.message ? response.error.message : genericError);\n\t\t\t}\n\n\t\t\tresolve({\n\t\t\t\tdefault: response.url\n\t\t\t});\n\t\t});\n\n\t\t// Upload progress when it's supported.\n\t\t/* istanbul ignore else */\n\t\tif (xhr.upload) {\n\t\t\txhr.upload.addEventListener('progress', evt => {\n\t\t\t\tif (evt.lengthComputable) {\n\t\t\t\t\tloader.uploadTotal = evt.total;\n\t\t\t\t\tloader.uploaded = evt.loaded;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Prepares the data and sends the request.\n\t *\n\t * @private\n\t */\n\tasync _sendRequest() {\n\t\t// Prepare form data.\n\t\tconst data = new FormData();\n\t\tdata.append('upload', await this.loader.file);\n\n\t\t// Send request.\n\t\tthis.xhr.send(data);\n\t}\n}\n","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport {toWidget} from '@ckeditor/ckeditor5-widget/src/utils';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\nimport Command from '@ckeditor/ckeditor5-core/src/command';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport noteIcon from './icons/note.svg';\n\nexport default class IncludeNote extends Plugin {\n\tstatic get requires() {\n\t\treturn [ IncludeNoteEditing, IncludeNoteUI ];\n\t}\n}\n\nclass IncludeNoteUI extends Plugin {\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\t// The \"includeNote\" button must be registered among the UI components of the editor\n\t\t// to be displayed in the toolbar.\n\t\teditor.ui.componentFactory.add( 'includeNote', locale => {\n\t\t\t// The state of the button will be bound to the widget command.\n\t\t\tconst command = editor.commands.get( 'insertIncludeNote' );\n\n\t\t\t// The button will be an instance of ButtonView.\n\t\t\tconst buttonView = new ButtonView( locale );\n\n\t\t\tbuttonView.set( {\n\t\t\t\t// The t() function helps localize the editor. All strings enclosed in t() can be\n\t\t\t\t// translated and change when the language of the editor changes.\n\t\t\t\tlabel: t( 'Include note' ),\n\t\t\t\ticon: noteIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\t// Bind the state of the button to the command.\n\t\t\tbuttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );\n\n\t\t\t// Execute the command when the button is clicked (executed).\n\t\t\tthis.listenTo( buttonView, 'execute', () => editor.execute( 'insertIncludeNote' ) );\n\n\t\t\treturn buttonView;\n\t\t} );\n\t}\n}\n\nclass IncludeNoteEditing extends Plugin {\n\tstatic get requires() {\n\t\treturn [ Widget ];\n\t}\n\n\tinit() {\n\t\tthis._defineSchema();\n\t\tthis._defineConverters();\n\n\t\tthis.editor.commands.add( 'insertIncludeNote', new InsertIncludeNoteCommand( this.editor ) );\n\t}\n\n\t_defineSchema() {\n\t\tconst schema = this.editor.model.schema;\n\n\t\tschema.register( 'includeNote', {\n\t\t\t// Behaves like a self-contained object (e.g. an image).\n\t\t\tisObject: true,\n\n\t\t\tallowAttributes: [ 'noteId', 'boxSize' ],\n\n\t\t\t// Allow in places where other blocks are allowed (e.g. directly in the root).\n\t\t\tallowWhere: '$block'\n\t\t} );\n\t}\n\n\t_defineConverters() {\n\t\tconst editor = this.editor;\n\t\tconst conversion = editor.conversion;\n\n\t\t// <includeNote> converters\n\t\tconversion.for( 'upcast' ).elementToElement( {\n\t\t\tmodel: ( viewElement, { writer: modelWriter } ) => {\n\n\t\t\t\treturn modelWriter.createElement( 'includeNote', {\n\t\t\t\t\tnoteId: viewElement.getAttribute( 'data-note-id' ),\n\t\t\t\t\tboxSize: viewElement.getAttribute( 'data-box-size' ),\n\t\t\t\t} );\n\t\t\t},\n\t\t\tview: {\n\t\t\t\tname: 'section',\n\t\t\t\tclasses: 'include-note'\n\t\t\t}\n\t\t} );\n\t\tconversion.for( 'dataDowncast' ).elementToElement( {\n\t\t\tmodel: 'includeNote',\n\t\t\tview: ( modelElement, { writer: viewWriter } ) => {\n\t\t\t\t// it would make sense here to downcast to <iframe>, with this even HTML export can support note inclusion\n\t\t\t\treturn viewWriter.createContainerElement( 'section', {\n\t\t\t\t\tclass: 'include-note',\n\t\t\t\t\t'data-note-id': modelElement.getAttribute( 'noteId' ),\n\t\t\t\t\t'data-box-size': modelElement.getAttribute( 'boxSize' ),\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t\tconversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'includeNote',\n\t\t\tview: ( modelElement, { writer: viewWriter } ) => {\n\n\t\t\t\tconst noteId = modelElement.getAttribute( 'noteId' );\n\t\t\t\tconst boxSize = modelElement.getAttribute( 'boxSize' );\n\n\t\t\t\tconst section = viewWriter.createContainerElement( 'section', {\n\t\t\t\t\tclass: 'include-note box-size-' + boxSize,\n\t\t\t\t\t'data-note-id': noteId,\n\t\t\t\t\t'data-box-size': boxSize\n\t\t\t\t} );\n\n\t\t\t\tconst includedNoteWrapper = viewWriter.createUIElement( 'div', {\n\t\t\t\t\tclass: 'include-note-wrapper'\n\t\t\t\t}, function( domDocument ) {\n\t\t\t\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t\t\t\tconst editorEl = editor.editing.view.getDomRoot();\n\t\t\t\t\tconst component = glob.getComponentByEl( editorEl );\n\n\t\t\t\t\tcomponent.loadIncludedNote( noteId, $( domElement ) );\n\n\t\t\t\t\tpreventCKEditorHandling( domElement, editor );\n\n\t\t\t\t\treturn domElement;\n\t\t\t\t} );\n\n\t\t\t\tviewWriter.insert( viewWriter.createPositionAt( section, 0 ), includedNoteWrapper );\n\n\t\t\t\treturn toWidget( section, viewWriter, { label: 'include note widget' } );\n\t\t\t}\n\t\t} );\n\t}\n}\n\nclass InsertIncludeNoteCommand extends Command {\n\texecute() {\n\t\tconst editorEl = this.editor.editing.view.getDomRoot();\n\t\tconst component = glob.getComponentByEl(editorEl);\n\n\t\tcomponent.triggerCommand('addIncludeNoteToText');\n\t}\n\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst allowedIn = model.schema.findAllowedParent( selection.getFirstPosition(), 'includeNote' );\n\n\t\tthis.isEnabled = allowedIn !== null;\n\t}\n}\n\n/**\n * Hack coming from https://github.com/ckeditor/ckeditor5/issues/4465\n * Source issue: https://github.com/zadam/trilium/issues/1117\n */\nfunction preventCKEditorHandling( domElement, editor ) {\n\t// Prevent the editor from listening on below events in order to stop rendering selection.\n\n\t// commenting out click events to allow link click handler to still work\n\t//domElement.addEventListener( 'click', stopEventPropagationAndHackRendererFocus, { capture: true } );\n\tdomElement.addEventListener( 'mousedown', stopEventPropagationAndHackRendererFocus, { capture: true } );\n\tdomElement.addEventListener( 'focus', stopEventPropagationAndHackRendererFocus, { capture: true } );\n\n\t// Prevents TAB handling or other editor keys listeners which might be executed on editors selection.\n\tdomElement.addEventListener( 'keydown', stopEventPropagationAndHackRendererFocus, { capture: true } );\n\n\tfunction stopEventPropagationAndHackRendererFocus( evt ) {\n\t\tevt.stopPropagation();\n\t\t// This prevents rendering changed view selection thus preventing to changing DOM selection while inside a widget.\n\t\teditor.editing.view._renderer.isFocused = false;\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"24\\\" height=\\\"24\\\" viewBox=\\\"0 0 24 24\\\"><path d=\\\"M19,3H5C3.897,3,3,3.897,3,5v14c0,1.103,0.897,2,2,2h8c0.131,0,0.26-0.026,0.381-0.076s0.232-0.123,0.326-0.217l7-7 c0.086-0.086,0.147-0.187,0.196-0.293c0.014-0.03,0.022-0.061,0.033-0.093c0.028-0.084,0.046-0.17,0.051-0.259 C20.989,13.041,21,13.021,21,13V5C21,3.897,20.103,3,19,3z M5,5h14v7h-6c-0.553,0-1,0.448-1,1v6H5V5z M14,17.586V14h3.586 L14,17.586z\\\"/></svg>\";","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { toWidget, viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget/src/utils';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\nimport Command from '@ckeditor/ckeditor5-core/src/command';\n\nexport default class ReferenceLink extends Plugin {\n\tstatic get requires() {\n\t\treturn [ ReferenceLinkEditing ];\n\t}\n}\n\nclass ReferenceLinkCommand extends Command {\n\texecute( { notePath } ) {\n\t\tif (!notePath || !notePath.trim()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\n\t\tconst noteId = notePath.split('/').pop();\n\n\t\t// make sure the referenced note is in cache before adding reference element\n\t\tglob.treeCache.getNote(noteId, true).then(() => {\n\t\t\teditor.model.change(writer => {\n\t\t\t\tconst placeholder = writer.createElement('reference', {notePath: notePath});\n\n\t\t\t\t// ... and insert it into the document.\n\t\t\t\teditor.model.insertContent(placeholder);\n\n\t\t\t\t// Put the selection on the inserted element.\n\t\t\t\twriter.setSelection(placeholder, 'after');\n\t\t\t});\n\t\t});\n\t}\n\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\n\t\tthis.isEnabled = model.schema.checkChild(selection.focus.parent, 'reference');\n\t}\n}\n\nclass ReferenceLinkEditing extends Plugin {\n\tstatic get requires() {\n\t\treturn [ Widget ];\n\t}\n\n\tinit() {\n\t\tthis._defineSchema();\n\t\tthis._defineConverters();\n\n\t\tthis.editor.commands.add( 'referenceLink', new ReferenceLinkCommand( this.editor ) );\n\n\t\tthis.editor.editing.mapper.on(\n\t\t\t'viewToModelPosition',\n\t\t\tviewToModelPositionOutsideModelElement( this.editor.model,\n\t\t\t\t\tviewElement => viewElement.hasClass( 'reference-link' ) )\n\t\t);\n\t}\n\n\t_defineSchema() {\n\t\tconst schema = this.editor.model.schema;\n\n\t\tschema.register( 'reference', {\n\t\t\t// Allow wherever text is allowed:\n\t\t\tallowWhere: '$text',\n\n\t\t\tisInline: true,\n\n\t\t\t// The inline widget is self-contained so it cannot be split by the caret and it can be selected:\n\t\t\tisObject: true,\n\n\t\t\tallowAttributes: [ 'notePath' ]\n\t\t} );\n\t}\n\n\t_defineConverters() {\n\t\tconst editor = this.editor;\n\t\tconst conversion = editor.conversion;\n\n\t\tconversion.for( 'upcast' ).elementToElement( {\n\t\t\tview: {\n\t\t\t\tname: 'a',\n\t\t\t\tclasses: [ 'reference-link' ]\n\t\t\t},\n\t\t\tmodel: ( viewElement, { writer: modelWriter } ) => {\n\t\t\t\tlet notePath = viewElement.getAttribute('data-note-path');\n\n\t\t\t\tif (!notePath) {\n\t\t\t\t\tnotePath = viewElement.getAttribute('href');\n\t\t\t\t}\n\n\t\t\t\treturn modelWriter.createElement( 'reference', { notePath: notePath } );\n\t\t\t}\n\t\t} );\n\n\t\tconversion.for( 'editingDowncast' ).elementToElement( {\n\t\t\tmodel: 'reference',\n\t\t\tview: ( modelItem, { writer: viewWriter } ) => {\n\t\t\t\tlet notePath = modelItem.getAttribute( 'notePath' );\n\n\t\t\t\tif (!notePath) {\n\t\t\t\t\tnotePath = modelItem.getAttribute( 'href' );\n\t\t\t\t}\n\n\t\t\t\tconst referenceLinkView = viewWriter.createContainerElement( 'a', {\n\t\t\t\t\thref: 'javascript:',\n\t\t\t\t\tclass: 'reference-link',\n\t\t\t\t\t'data-note-path': notePath\n\t\t\t\t} );\n\n\t\t\t\tconst noteTitleView = viewWriter.createUIElement('span', {}, function( domDocument ) {\n\t\t\t\t\tconst domElement = this.toDomElement( domDocument );\n\t\t\t\t\tconst noteId = notePath.split('/').pop();\n\n\t\t\t\t\tconst editorEl = editor.editing.view.getDomRoot();\n\t\t\t\t\tconst component = glob.getComponentByEl(editorEl);\n\n\t\t\t\t\tcomponent.loadReferenceLinkTitle(noteId, $(domElement));\n\n\t\t\t\t\treturn domElement;\n\t\t\t\t});\n\n\t\t\t\tviewWriter.insert( viewWriter.createPositionAt( referenceLinkView, 0 ), noteTitleView );\n\n\t\t\t\t// Enable widget handling on a reference element inside the editing view.\n\t\t\t\treturn toWidget( referenceLinkView, viewWriter );\n\t\t\t}\n\t\t} );\n\n\t\tconversion.for( 'dataDowncast' ).elementToElement( {\n\t\t\tmodel: 'reference',\n\t\t\tview: ( modelItem, { writer: viewWriter } ) => {\n\t\t\t\tlet notePath = modelItem.getAttribute( 'notePath' );\n\n\t\t\t\tif (!notePath) {\n\t\t\t\t\tnotePath = modelItem.getAttribute( 'href' );\n\t\t\t\t}\n\n\t\t\t\tconst referenceLinkView = viewWriter.createContainerElement( 'a', {\n\t\t\t\t\thref: '#' + notePath,\n\t\t\t\t\tclass: 'reference-link',\n\t\t\t\t\t'data-note-path': notePath\n\t\t\t\t} );\n\n\t\t\t\tconst noteId = notePath.split('/').pop();\n\t\t\t\t// needs to be sync\n\t\t\t\tconst note = glob.treeCache.getNoteFromCache(noteId);\n\n\t\t\t\tif (note) {\n\t\t\t\t\tconst innerText = viewWriter.createText(note.title);\n\t\t\t\t\tviewWriter.insert(viewWriter.createPositionAt(referenceLinkView, 0), innerText);\n\t\t\t\t}\n\n\t\t\t\treturn referenceLinkView;\n\t\t\t}\n\t\t} );\n\t}\n}\n","import global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';\n\nexport function getSelectedMathModelWidget( selection ) {\n\tconst selectedElement = selection.getSelectedElement();\n\n\tif ( selectedElement && ( selectedElement.is( 'element', 'mathtex-inline' ) || selectedElement.is( 'element', 'mathtex-display' ) ) ) {\n\t\treturn selectedElement;\n\t}\n\n\treturn null;\n}\n\n// Simple MathJax 3 version check\nexport function isMathJaxVersion3( version ) {\n\treturn version && typeof version === 'string' && version.split( '.' ).length === 3 && version.split( '.' )[ 0 ] === '3';\n}\n\n// Check if equation has delimiters.\nexport function hasDelimiters( text ) {\n\treturn text.match( /^(\\\\\\[.*?\\\\\\]|\\\\\\(.*?\\\\\\))$/ );\n}\n\n// Find delimiters count\nexport function delimitersCounts( text ) {\n\treturn text.match( /(\\\\\\[|\\\\\\]|\\\\\\(|\\\\\\))/g ).length;\n}\n\n// Extract delimiters and figure display mode for the model\nexport function extractDelimiters( equation ) {\n\tequation = equation.trim();\n\n\t// Remove delimiters (e.g. \\( \\) or \\[ \\])\n\tconst hasInlineDelimiters = equation.includes( '\\\\(' ) && equation.includes( '\\\\)' );\n\tconst hasDisplayDelimiters = equation.includes( '\\\\[' ) && equation.includes( '\\\\]' );\n\tif ( hasInlineDelimiters || hasDisplayDelimiters ) {\n\t\tequation = equation.substring( 2, equation.length - 2 ).trim();\n\t}\n\n\treturn {\n\t\tequation,\n\t\tdisplay: hasDisplayDelimiters\n\t};\n}\n\nexport async function renderEquation(\n\tequation, element, engine = 'katex', lazyLoad, display = false, preview = false, previewUid, previewClassName = []\n) {\n\tif ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) {\n\t\tif ( isMathJaxVersion3( MathJax.version ) ) {\n\t\t\tselectRenderMode( element, preview, previewUid, previewClassName, el => {\n\t\t\t\trenderMathJax3( equation, el, display, () => {\n\t\t\t\t\tif ( preview ) {\n\t\t\t\t\t\tmoveAndScaleElement( element, el );\n\t\t\t\t\t\tel.style.visibility = 'visible';\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\t} else {\n\t\t\tselectRenderMode( element, preview, previewUid, previewClassName, el => {\n\t\t\t\t// Fixme: MathJax typesetting cause occasionally math processing error without asynchronous call\n\t\t\t\tglobal.window.setTimeout( () => {\n\t\t\t\t\trenderMathJax2( equation, el, display );\n\n\t\t\t\t\t// Move and scale after rendering\n\t\t\t\t\tif ( preview ) {\n\t\t\t\t\t\t// eslint-disable-next-line\n\t\t\t\t\t\tMathJax.Hub.Queue( () => {\n\t\t\t\t\t\t\tmoveAndScaleElement( element, el );\n\t\t\t\t\t\t\tel.style.visibility = 'visible';\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\t\t}\n\t} else if ( engine === 'katex' && typeof katex !== 'undefined' ) {\n\t\tselectRenderMode( element, preview, previewUid, previewClassName, el => {\n\t\t\tkatex.render( equation, el, {\n\t\t\t\tthrowOnError: false,\n\t\t\t\tdisplayMode: display\n\t\t\t} );\n\t\t\tif ( preview ) {\n\t\t\t\tmoveAndScaleElement( element, el );\n\t\t\t\tel.style.visibility = 'visible';\n\t\t\t}\n\t\t} );\n\t} else if ( typeof engine === 'function' ) {\n\t\tengine( equation, element, display );\n\t} else {\n\t\tif ( typeof lazyLoad !== 'undefined' ) {\n\t\t\ttry {\n\t\t\t\tif ( !global.window.CKEDITOR_MATH_LAZY_LOAD ) {\n\t\t\t\t\tglobal.window.CKEDITOR_MATH_LAZY_LOAD = lazyLoad();\n\t\t\t\t}\n\t\t\t\telement.innerHTML = equation;\n\t\t\t\tawait global.window.CKEDITOR_MATH_LAZY_LOAD;\n\t\t\t\trenderEquation( equation, element, engine, undefined, display, preview, previewUid, previewClassName );\n\t\t\t}\n\t\t\tcatch ( err ) {\n\t\t\t\telement.innerHTML = equation;\n\t\t\t\tconsole.error( `math-tex-typesetting-lazy-load-failed: Lazy load failed: ${ err }` );\n\t\t\t}\n\t\t} else {\n\t\t\telement.innerHTML = equation;\n\t\t\tconsole.warn( `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${ engine }) for tex.` );\n\t\t}\n\t}\n}\n\nexport function getBalloonPositionData( editor ) {\n\tconst view = editor.editing.view;\n\tconst defaultPositions = BalloonPanelView.defaultPositions;\n\n\tconst selectedElement = view.document.selection.getSelectedElement();\n\tif ( selectedElement ) {\n\t\treturn {\n\t\t\ttarget: view.domConverter.viewToDom( selectedElement ),\n\t\t\tpositions: [\n\t\t\t\tdefaultPositions.southArrowNorth,\n\t\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\t\tdefaultPositions.southArrowNorthEast\n\t\t\t]\n\t\t};\n\t}\n\telse {\n\t\tconst viewDocument = view.document;\n\t\treturn {\n\t\t\ttarget: view.domConverter.viewRangeToDom( viewDocument.selection.getFirstRange() ),\n\t\t\tpositions: [\n\t\t\t\tdefaultPositions.southArrowNorth,\n\t\t\t\tdefaultPositions.southArrowNorthWest,\n\t\t\t\tdefaultPositions.southArrowNorthEast\n\t\t\t]\n\t\t};\n\t}\n}\n\nfunction selectRenderMode( element, preview, previewUid, previewClassName, cb ) {\n\tif ( preview ) {\n\t\tcreatePreviewElement( element, previewUid, previewClassName, previewEl => {\n\t\t\tcb( previewEl );\n\t\t} );\n\t} else {\n\t\tcb( element );\n\t}\n}\n\nfunction renderMathJax3( equation, element, display, cb ) {\n\tlet promiseFunction = undefined;\n\tif ( typeof MathJax.tex2chtmlPromise !== 'undefined' ) {\n\t\tpromiseFunction = MathJax.tex2chtmlPromise;\n\t} else if ( typeof MathJax.tex2svgPromise !== 'undefined' ) {\n\t\tpromiseFunction = MathJax.tex2svgPromise;\n\t}\n\n\tif ( typeof promiseFunction !== 'undefined' ) {\n\t\tpromiseFunction( equation, { display } ).then( node => {\n\t\t\tif ( element.firstChild ) {\n\t\t\t\telement.removeChild( element.firstChild );\n\t\t\t}\n\t\t\telement.appendChild( node );\n\t\t\tcb();\n\t\t} );\n\t}\n}\n\nfunction renderMathJax2( equation, element, display ) {\n\tif ( display ) {\n\t\telement.innerHTML = '\\\\[' + equation + '\\\\]';\n\t} else {\n\t\telement.innerHTML = '\\\\(' + equation + '\\\\)';\n\t}\n\t// eslint-disable-next-line\n\tMathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] );\n}\n\nfunction createPreviewElement( element, previewUid, previewClassName, render ) {\n\tconst previewEl = getPreviewElement( element, previewUid, previewClassName );\n\trender( previewEl );\n}\n\nfunction getPreviewElement( element, previewUid, previewClassName ) {\n\tlet previewEl = global.document.getElementById( previewUid );\n\t// Create if not found\n\tif ( !previewEl ) {\n\t\tpreviewEl = global.document.createElement( 'div' );\n\t\tpreviewEl.setAttribute( 'id', previewUid );\n\t\tpreviewEl.classList.add( ...previewClassName );\n\t\tpreviewEl.style.visibility = 'hidden';\n\t\tglobal.document.body.appendChild( previewEl );\n\n\t\tlet ticking = false;\n\n\t\tconst renderTransformation = () => {\n\t\t\tif ( !ticking ) {\n\t\t\t\tglobal.window.requestAnimationFrame( () => {\n\t\t\t\t\tmoveElement( element, previewEl );\n\t\t\t\t\tticking = false;\n\t\t\t\t} );\n\n\t\t\t\tticking = true;\n\t\t\t}\n\t\t};\n\n\t\t// Create scroll listener for following\n\t\tglobal.window.addEventListener( 'resize', renderTransformation );\n\t\tglobal.window.addEventListener( 'scroll', renderTransformation );\n\t}\n\treturn previewEl;\n}\n\nfunction moveAndScaleElement( parent, child ) {\n\t// Move to right place\n\tmoveElement( parent, child );\n\n\t// Scale parent element same as preview\n\tconst domRect = child.getBoundingClientRect();\n\tparent.style.width = domRect.width + 'px';\n\tparent.style.height = domRect.height + 'px';\n}\n\nfunction moveElement( parent, child ) {\n\tconst domRect = parent.getBoundingClientRect();\n\tconst left = global.window.scrollX + domRect.left;\n\tconst top = global.window.scrollY + domRect.top;\n\tchild.style.position = 'absolute';\n\tchild.style.left = left + 'px';\n\tchild.style.top = top + 'px';\n\tchild.style.zIndex = 'var(--ck-z-modal)';\n\tchild.style.pointerEvents = 'none';\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 ui/labeledinput/labeledinputview\n */\n\nimport View from '../view';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport LabelView from '../label/labelview';\nimport '../../theme/components/labeledinput/labeledinput.css';\n\n/**\n * The labeled input view class.\n *\n * @extends module:ui/view~View\n */\nexport default class LabeledInputView extends View {\n\t/**\n\t * Creates an instance of the labeled input view class.\n\t *\n\t * @param {module:utils/locale~Locale} locale The locale instance.\n\t * @param {Function} InputView Constructor of the input view.\n\t */\n\tconstructor( locale, InputView ) {\n\t\tsuper( locale );\n\n\t\tconst inputUid = `ck-input-${ uid() }`;\n\t\tconst statusUid = `ck-status-${ uid() }`;\n\n\t\t/**\n\t\t * The text of the label.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #label\n\t\t */\n\t\tthis.set( 'label' );\n\n\t\t/**\n\t\t * The value of the input.\n\t\t *\n\t\t * @observable\n\t\t * @member {String} #value\n\t\t */\n\t\tthis.set( 'value' );\n\n\t\t/**\n\t\t * Controls whether the component is in read-only mode.\n\t\t *\n\t\t * @observable\n\t\t * @member {Boolean} #isReadOnly\n\t\t */\n\t\tthis.set( 'isReadOnly', false );\n\n\t\t/**\n\t\t * The validation error text. When set, it will be displayed\n\t\t * next to the {@link #inputView} as a typical validation error message.\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** Setting this property to anything but `null` will automatically\n\t\t * make the {@link module:ui/inputtext/inputtextview~InputTextView#hasError `hasError`}\n\t\t * of the {@link #inputView} `true`.\n\t\t *\n\t\t * **Note:** Typing in the {@link #inputView} which fires the\n\t\t * {@link module:ui/inputtext/inputtextview~InputTextView#event:input `input` event}\n\t\t * resets this property back to `null`, indicating that the input field can be revalidated.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #errorText\n\t\t */\n\t\tthis.set( 'errorText', null );\n\n\t\t/**\n\t\t * The additional information text displayed next to the {@link #inputView} which can\n\t\t * be used to inform the user about the purpose of the input, provide help or hints.\n\t\t *\n\t\t * Set it to `null` to hide the message.\n\t\t *\n\t\t * **Note:** This text will be displayed in the same place as {@link #errorText} but the\n\t\t * latter always takes precedence: if the {@link #errorText} is set, it replaces\n\t\t * {@link #errorText} for as long as the value of the input is invalid.\n\t\t *\n\t\t * @observable\n\t\t * @member {String|null} #infoText\n\t\t */\n\t\tthis.set( 'infoText', null );\n\n\t\t/**\n\t\t * The label view.\n\t\t *\n\t\t * @member {module:ui/label/labelview~LabelView} #labelView\n\t\t */\n\t\tthis.labelView = this._createLabelView( inputUid );\n\n\t\t/**\n\t\t * The input view.\n\t\t *\n\t\t * @member {module:ui/inputtext/inputtextview~InputTextView} #inputView\n\t\t */\n\t\tthis.inputView = this._createInputView( InputView, inputUid, statusUid );\n\n\t\t/**\n\t\t * The status view for the {@link #inputView}. It displays {@link #errorText} and\n\t\t * {@link #infoText}.\n\t\t *\n\t\t * @member {module:ui/view~View} #statusView\n\t\t */\n\t\tthis.statusView = this._createStatusView( statusUid );\n\n\t\t/**\n\t\t * The combined status text made of {@link #errorText} and {@link #infoText}.\n\t\t * Note that when present, {@link #errorText} always takes precedence in the\n\t\t * status.\n\t\t *\n\t\t * @see #errorText\n\t\t * @see #infoText\n\t\t * @see #statusView\n\t\t * @private\n\t\t * @observable\n\t\t * @member {String|null} #_statusText\n\t\t */\n\t\tthis.bind( '_statusText' ).to(\n\t\t\tthis, 'errorText',\n\t\t\tthis, 'infoText',\n\t\t\t( errorText, infoText ) => errorText || infoText\n\t\t);\n\n\t\tconst bind = this.bindTemplate;\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-input',\n\t\t\t\t\tbind.if( 'isReadOnly', 'ck-disabled' )\n\t\t\t\t]\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\tthis.labelView,\n\t\t\t\tthis.inputView,\n\t\t\t\tthis.statusView\n\t\t\t]\n\t\t} );\n\t}\n\n\t/**\n\t * Creates label view class instance and bind with view.\n\t *\n\t * @private\n\t * @param {String} id Unique id to set as labelView#for attribute.\n\t * @returns {module:ui/label/labelview~LabelView}\n\t */\n\t_createLabelView( id ) {\n\t\tconst labelView = new LabelView( this.locale );\n\n\t\tlabelView.for = id;\n\t\tlabelView.bind( 'text' ).to( this, 'label' );\n\n\t\treturn labelView;\n\t}\n\n\t/**\n\t * Creates input view class instance and bind with view.\n\t *\n\t * @private\n\t * @param {Function} InputView Input view constructor.\n\t * @param {String} inputUid Unique id to set as inputView#id attribute.\n\t * @param {String} statusUid Unique id of the status for the input's `aria-describedby` attribute.\n\t * @returns {module:ui/inputtext/inputtextview~InputTextView}\n\t */\n\t_createInputView( InputView, inputUid, statusUid ) {\n\t\tconst inputView = new InputView( this.locale, statusUid );\n\n\t\tinputView.id = inputUid;\n\t\tinputView.ariaDescribedById = statusUid;\n\t\tinputView.bind( 'value' ).to( this );\n\t\tinputView.bind( 'isReadOnly' ).to( this );\n\t\tinputView.bind( 'hasError' ).to( this, 'errorText', value => !!value );\n\n\t\tinputView.on( 'input', () => {\n\t\t\t// UX: Make the error text disappear and disable the error indicator as the user\n\t\t\t// starts fixing the errors.\n\t\t\tthis.errorText = null;\n\t\t} );\n\n\t\treturn inputView;\n\t}\n\n\t/**\n\t * Creates the status view instance. It displays {@link #errorText} and {@link #infoText}\n\t * next to the {@link #inputView}. See {@link #_statusText}.\n\t *\n\t * @private\n\t * @param {String} statusUid Unique id of the status, shared with the input's `aria-describedby` attribute.\n\t * @returns {module:ui/view~View}\n\t */\n\t_createStatusView( statusUid ) {\n\t\tconst statusView = new View( this.locale );\n\t\tconst bind = this.bindTemplate;\n\n\t\tstatusView.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-labeled-input__status',\n\t\t\t\t\tbind.if( 'errorText', 'ck-labeled-input__status_error' ),\n\t\t\t\t\tbind.if( '_statusText', 'ck-hidden', value => !value )\n\t\t\t\t],\n\t\t\t\tid: statusUid,\n\t\t\t\trole: bind.if( 'errorText', 'alert' )\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttext: bind.to( '_statusText' )\n\t\t\t\t}\n\t\t\t]\n\t\t} );\n\n\t\treturn statusView;\n\t}\n\n\t/**\n\t * Moves the focus to the input and selects the value.\n\t */\n\tselect() {\n\t\tthis.inputView.select();\n\t}\n\n\t/**\n\t * Focuses the input.\n\t */\n\tfocus() {\n\t\tthis.inputView.focus();\n\t}\n}\n","import View from '@ckeditor/ckeditor5-ui/src/view';\n\nimport { renderEquation } from '../utils';\n\nexport default class MathView extends View {\n\tconstructor( engine, lazyLoad, locale, previewUid, previewClassName ) {\n\t\tsuper( locale );\n\n\t\tthis.engine = engine;\n\t\tthis.lazyLoad = lazyLoad;\n\t\tthis.previewUid = previewUid;\n\t\tthis.previewClassName = previewClassName;\n\n\t\tthis.set( 'value', '' );\n\t\tthis.set( 'display', false );\n\n\t\tthis.on( 'change', () => {\n\t\t\tif ( this.isRendered ) {\n\t\t\t\tthis.updateMath();\n\t\t\t}\n\t\t} );\n\n\t\tthis.setTemplate( {\n\t\t\ttag: 'div',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-math-preview'\n\t\t\t\t]\n\t\t\t}\n\t\t} );\n\t}\n\n\tupdateMath() {\n\t\trenderEquation( this.value, this.element, this.engine, this.lazyLoad, this.display, true, this.previewUid, this.previewClassName );\n\t}\n\n\trender() {\n\t\tsuper.render();\n\t\tthis.updateMath();\n\t}\n}\n","import View from '@ckeditor/ckeditor5-ui/src/view';\nimport ViewCollection from '@ckeditor/ckeditor5-ui/src/viewcollection';\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport LabeledInputView from '@ckeditor/ckeditor5-ui/src/labeledinput/labeledinputview';\nimport InputTextView from '@ckeditor/ckeditor5-ui/src/inputtext/inputtextview';\nimport LabelView from '@ckeditor/ckeditor5-ui/src/label/labelview';\n\nimport KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';\nimport FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';\nimport FocusCycler from '@ckeditor/ckeditor5-ui/src/focuscycler';\n\nimport checkIcon from '@ckeditor/ckeditor5-core/theme/icons/check.svg';\nimport cancelIcon from '@ckeditor/ckeditor5-core/theme/icons/cancel.svg';\n\nimport submitHandler from '@ckeditor/ckeditor5-ui/src/bindings/submithandler';\n\nimport { extractDelimiters, hasDelimiters } from '../utils';\n\nimport MathView from './mathview';\n\nimport '../../theme/mathform.css';\n\nexport default class MainFormView extends View {\n\tconstructor( locale, engine, lazyLoad, previewEnabled, previewUid, previewClassName, popupClassName ) {\n\t\tsuper( locale );\n\n\t\tconst t = locale.t;\n\n\t\t// Create key event & focus trackers\n\t\tthis._createKeyAndFocusTrackers();\n\n\t\t// Equation input\n\t\tthis.mathInputView = this._createMathInput();\n\n\t\t// Display button\n\t\tthis.displayButtonView = this._createDisplayButton();\n\n\t\t// Submit button\n\t\tthis.saveButtonView = this._createButton( t( 'Save' ), checkIcon, 'ck-button-save', null );\n\t\tthis.saveButtonView.type = 'submit';\n\n\t\t// Cancel button\n\t\tthis.cancelButtonView = this._createButton( t( 'Cancel' ), cancelIcon, 'ck-button-cancel', 'cancel' );\n\n\t\tthis.previewEnabled = previewEnabled;\n\n\t\tlet children = [];\n\t\tif ( this.previewEnabled ) {\n\t\t\t// Preview label\n\t\t\tthis.previewLabel = new LabelView( locale );\n\t\t\tthis.previewLabel.text = t( 'Equation preview' );\n\n\t\t\t// Math element\n\t\t\tthis.mathView = new MathView( engine, lazyLoad, locale, previewUid, previewClassName );\n\t\t\tthis.mathView.bind( 'display' ).to( this.displayButtonView, 'isOn' );\n\n\t\t\tchildren = [\n\t\t\t\tthis.mathInputView,\n\t\t\t\tthis.displayButtonView,\n\t\t\t\tthis.previewLabel,\n\t\t\t\tthis.mathView\n\t\t\t];\n\t\t} else {\n\t\t\tchildren = [\n\t\t\t\tthis.mathInputView,\n\t\t\t\tthis.displayButtonView\n\t\t\t];\n\t\t}\n\n\t\t// Add UI elements to template\n\t\tthis.setTemplate( {\n\t\t\ttag: 'form',\n\t\t\tattributes: {\n\t\t\t\tclass: [\n\t\t\t\t\t'ck',\n\t\t\t\t\t'ck-math-form',\n\t\t\t\t\t...popupClassName\n\t\t\t\t],\n\t\t\t\ttabindex: '-1',\n\t\t\t\tspellcheck: 'false'\n\t\t\t},\n\t\t\tchildren: [\n\t\t\t\t{\n\t\t\t\t\ttag: 'div',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\tclass: [\n\t\t\t\t\t\t\t'ck-math-view'\n\t\t\t\t\t\t]\n\t\t\t\t\t},\n\t\t\t\t\tchildren\n\t\t\t\t},\n\t\t\t\tthis.saveButtonView,\n\t\t\t\tthis.cancelButtonView\n\t\t\t]\n\t\t} );\n\t}\n\n\trender() {\n\t\tsuper.render();\n\n\t\t// Prevent default form submit event & trigger custom 'submit'\n\t\tsubmitHandler( {\n\t\t\tview: this\n\t\t} );\n\n\t\t// Register form elements to focusable elements\n\t\tconst childViews = [\n\t\t\tthis.mathInputView,\n\t\t\tthis.displayButtonView,\n\t\t\tthis.saveButtonView,\n\t\t\tthis.cancelButtonView\n\t\t];\n\n\t\tchildViews.forEach( v => {\n\t\t\tthis._focusables.add( v );\n\t\t\tthis.focusTracker.add( v.element );\n\t\t} );\n\n\t\t// Listen to keypresses inside form element\n\t\tthis.keystrokes.listenTo( this.element );\n\t}\n\n\tfocus() {\n\t\tthis._focusCycler.focusFirst();\n\t}\n\n\tget equation() {\n\t\treturn this.mathInputView.inputView.element.value;\n\t}\n\n\tset equation( equation ) {\n\t\tthis.mathInputView.inputView.element.value = equation;\n\t\tif ( this.previewEnabled ) {\n\t\t\tthis.mathView.value = equation;\n\t\t}\n\t}\n\n\t_createKeyAndFocusTrackers() {\n\t\tthis.focusTracker = new FocusTracker();\n\t\tthis.keystrokes = new KeystrokeHandler();\n\t\tthis._focusables = new ViewCollection();\n\n\t\tthis._focusCycler = new FocusCycler( {\n\t\t\tfocusables: this._focusables,\n\t\t\tfocusTracker: this.focusTracker,\n\t\t\tkeystrokeHandler: this.keystrokes,\n\t\t\tactions: {\n\t\t\t\tfocusPrevious: 'shift + tab',\n\t\t\t\tfocusNext: 'tab'\n\t\t\t}\n\t\t} );\n\t}\n\n\t_createMathInput() {\n\t\tconst t = this.locale.t;\n\n\t\t// Create equation input\n\t\tconst mathInput = new LabeledInputView( this.locale, InputTextView );\n\t\tconst inputView = mathInput.inputView;\n\t\tmathInput.infoText = t( 'Insert equation in TeX format.' );\n\t\tinputView.on( 'input', () => {\n\t\t\tif ( this.previewEnabled ) {\n\t\t\t\tconst equationInput = inputView.element.value.trim();\n\n\t\t\t\t// If input has delimiters\n\t\t\t\tif ( hasDelimiters( equationInput ) ) {\n\t\t\t\t\t// Get equation without delimiters\n\t\t\t\t\tconst params = extractDelimiters( equationInput );\n\n\t\t\t\t\t// Remove delimiters from input field\n\t\t\t\t\tinputView.element.value = params.equation;\n\n\t\t\t\t\t// update display button and preview\n\t\t\t\t\tthis.displayButtonView.isOn = params.display;\n\t\t\t\t\tif ( this.previewEnabled ) {\n\t\t\t\t\t\t// Update preview view\n\t\t\t\t\t\tthis.mathView.value = params.equation;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.mathView.value = equationInput;\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\treturn mathInput;\n\t}\n\n\t_createButton( label, icon, className, eventName ) {\n\t\tconst button = new ButtonView( this.locale );\n\n\t\tbutton.set( {\n\t\t\tlabel,\n\t\t\ticon,\n\t\t\ttooltip: true\n\t\t} );\n\n\t\tbutton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: className\n\t\t\t}\n\t\t} );\n\n\t\tif ( eventName ) {\n\t\t\tbutton.delegate( 'execute' ).to( this, eventName );\n\t\t}\n\n\t\treturn button;\n\t}\n\n\t_createDisplayButton() {\n\t\tconst t = this.locale.t;\n\n\t\tconst switchButton = new ButtonView( this.locale );\n\n\t\tswitchButton.set( {\n\t\t\tlabel: t( 'Display mode' ),\n\t\t\twithText: true\n\t\t} );\n\n\t\tswitchButton.extendTemplate( {\n\t\t\tattributes: {\n\t\t\t\tclass: 'ck-button-display-toggle'\n\t\t\t}\n\t\t} );\n\n\t\tswitchButton.on( 'execute', () => {\n\t\t\t// Toggle state\n\t\t\tswitchButton.isOn = !switchButton.isOn;\n\n\t\t\tif ( this.previewEnabled ) {\n\t\t\t\t// Update preview view\n\t\t\t\tthis.mathView.display = switchButton.isOn;\n\t\t\t}\n\t\t} );\n\n\t\treturn switchButton;\n\t}\n}\n","import Command from '@ckeditor/ckeditor5-core/src/command';\n\nimport { getSelectedMathModelWidget } from './utils';\n\nexport default class MathCommand extends Command {\n\texecute( equation, display, outputType, forceOutputType ) {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst selectedElement = selection.getSelectedElement();\n\n\t\tmodel.change( writer => {\n\t\t\tlet mathtex;\n\t\t\tif ( selectedElement && ( selectedElement.is( 'element', 'mathtex-inline' ) ||\n\t\t\t\t\tselectedElement.is( 'element', 'mathtex-display' ) ) ) {\n\t\t\t\t// Update selected element\n\t\t\t\tconst typeAttr = selectedElement.getAttribute( 'type' );\n\n\t\t\t\t// Use already set type if found and is not forced\n\t\t\t\tconst type = forceOutputType ? outputType : typeAttr || outputType;\n\n\t\t\t\tmathtex = writer.createElement( display ? 'mathtex-display' : 'mathtex-inline', { equation, type, display } );\n\t\t\t} else {\n\t\t\t\t// Create new model element\n\t\t\t\tmathtex = writer.createElement( display ? 'mathtex-display' : 'mathtex-inline', { equation, type: outputType, display } );\n\t\t\t}\n\t\t\tmodel.insertContent( mathtex );\n\t\t} );\n\t}\n\n\trefresh() {\n\t\tconst model = this.editor.model;\n\t\tconst selection = model.document.selection;\n\t\tconst selectedElement = selection.getSelectedElement();\n\n\t\tthis.isEnabled = selectedElement === null || ( selectedElement.is( 'element', 'mathtex-inline' ) ||\n\t\t\t\tselectedElement.is( 'element', 'mathtex-display' ) );\n\n\t\tconst selectedEquation = getSelectedMathModelWidget( selection );\n\t\tthis.value = selectedEquation ? selectedEquation.getAttribute( 'equation' ) : null;\n\t\tthis.display = selectedEquation ? selectedEquation.getAttribute( 'display' ) : null;\n\t}\n}\n","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport { toWidget, viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget/src/utils';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\n\nimport MathCommand from './mathcommand';\n\nimport { renderEquation, extractDelimiters } from './utils';\n\nexport default class MathEditing extends Plugin {\n\tstatic get requires() {\n\t\treturn [ Widget ];\n\t}\n\n\tstatic get pluginName() {\n\t\treturn 'MathEditing';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\teditor.commands.add( 'math', new MathCommand( editor ) );\n\n\t\tthis._defineSchema();\n\t\tthis._defineConverters();\n\n\t\teditor.editing.mapper.on(\n\t\t\t'viewToModelPosition',\n\t\t\tviewToModelPositionOutsideModelElement( editor.model, viewElement => viewElement.hasClass( 'math' ) )\n\t\t);\n\t\teditor.config.define( 'math', {\n\t\t\tengine: 'mathjax',\n\t\t\toutputType: 'script',\n\t\t\tforceOutputType: false,\n\t\t\tenablePreview: true,\n\t\t\tpreviewClassName: [],\n\t\t\tpopupClassName: []\n\t\t} );\n\t}\n\n\t_defineSchema() {\n\t\tconst schema = this.editor.model.schema;\n\t\tschema.register( 'mathtex-inline', {\n\t\t\tallowWhere: '$text',\n\t\t\tisInline: true,\n\t\t\tisObject: true,\n\t\t\tallowAttributes: [ 'equation', 'type', 'display' ]\n\t\t} );\n\n\t\tschema.register( 'mathtex-display', {\n\t\t\tallowWhere: '$block',\n\t\t\tisInline: false,\n\t\t\tisObject: true,\n\t\t\tallowAttributes: [ 'equation', 'type', 'display' ]\n\t\t} );\n\t}\n\n\t_defineConverters() {\n\t\tconst conversion = this.editor.conversion;\n\t\tconst mathConfig = this.editor.config.get( 'math' );\n\n\t\t// View -> Model\n\t\tconversion.for( 'upcast' )\n\t\t\t// MathJax inline way (e.g. <script type=\"math/tex\">\\sqrt{\\frac{a}{b}}</script>)\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'script',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\ttype: 'math/tex'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: ( viewElement, { writer } ) => {\n\t\t\t\t\tconst equation = viewElement.getChild( 0 ).data.trim();\n\t\t\t\t\treturn writer.createElement( 'mathtex-inline', {\n\t\t\t\t\t\tequation,\n\t\t\t\t\t\ttype: mathConfig.forceOutputType ? mathConfig.outputType : 'script',\n\t\t\t\t\t\tdisplay: false\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t// MathJax display way (e.g. <script type=\"math/tex; mode=display\">\\sqrt{\\frac{a}{b}}</script>)\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'script',\n\t\t\t\t\tattributes: {\n\t\t\t\t\t\ttype: 'math/tex; mode=display'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tmodel: ( viewElement, { writer } ) => {\n\t\t\t\t\tconst equation = viewElement.getChild( 0 ).data.trim();\n\t\t\t\t\treturn writer.createElement( 'mathtex-display', {\n\t\t\t\t\t\tequation,\n\t\t\t\t\t\ttype: mathConfig.forceOutputType ? mathConfig.outputType : 'script',\n\t\t\t\t\t\tdisplay: true\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t// CKEditor 4 way (e.g. <span class=\"math-tex\">\\( \\sqrt{\\frac{a}{b}} \\)</span>)\n\t\t\t.elementToElement( {\n\t\t\t\tview: {\n\t\t\t\t\tname: 'span',\n\t\t\t\t\tclasses: [ 'math-tex' ]\n\t\t\t\t},\n\t\t\t\tmodel: ( viewElement, { writer } ) => {\n\t\t\t\t\tconst equation = viewElement.getChild( 0 ).data.trim();\n\n\t\t\t\t\tconst params = Object.assign( extractDelimiters( equation ), {\n\t\t\t\t\t\ttype: mathConfig.forceOutputType ? mathConfig.outputType : 'span'\n\t\t\t\t\t} );\n\n\t\t\t\t\treturn writer.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Model -> View (element)\n\t\tconversion.for( 'editingDowncast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'mathtex-inline',\n\t\t\t\tview: ( modelItem, { writer } ) => {\n\t\t\t\t\tconst widgetElement = createMathtexEditingView( modelItem, writer );\n\t\t\t\t\treturn toWidget( widgetElement, writer, 'span' );\n\t\t\t\t}\n\t\t\t} ).elementToElement( {\n\t\t\t\tmodel: 'mathtex-display',\n\t\t\t\tview: ( modelItem, { writer } ) => {\n\t\t\t\t\tconst widgetElement = createMathtexEditingView( modelItem, writer );\n\t\t\t\t\treturn toWidget( widgetElement, writer, 'div' );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t// Model -> Data\n\t\tconversion.for( 'dataDowncast' )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'mathtex-inline',\n\t\t\t\tview: createMathtexView\n\t\t\t} )\n\t\t\t.elementToElement( {\n\t\t\t\tmodel: 'mathtex-display',\n\t\t\t\tview: createMathtexView\n\t\t\t} );\n\n\t\t// Create view for editor\n\t\tfunction createMathtexEditingView( modelItem, writer ) {\n\t\t\tconst equation = modelItem.getAttribute( 'equation' );\n\t\t\tconst display = modelItem.getAttribute( 'display' );\n\n\t\t\tconst styles = 'user-select: none; ' + ( display ? '' : 'display: inline-block;' );\n\t\t\tconst classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' );\n\n\t\t\tconst mathtexView = writer.createContainerElement( display ? 'div' : 'span', {\n\t\t\t\tstyle: styles,\n\t\t\t\tclass: classes\n\t\t\t} );\n\n\t\t\tconst uiElement = writer.createUIElement( 'div', null, function( domDocument ) {\n\t\t\t\tconst domElement = this.toDomElement( domDocument );\n\n\t\t\t\trenderEquation( equation, domElement, mathConfig.engine, mathConfig.lazyLoad, display, false );\n\n\t\t\t\treturn domElement;\n\t\t\t} );\n\n\t\t\twriter.insert( writer.createPositionAt( mathtexView, 0 ), uiElement );\n\n\t\t\treturn mathtexView;\n\t\t}\n\n\t\t// Create view for data\n\t\tfunction createMathtexView( modelItem, { writer } ) {\n\t\t\tconst equation = modelItem.getAttribute( 'equation' );\n\t\t\tconst type = modelItem.getAttribute( 'type' );\n\t\t\tconst display = modelItem.getAttribute( 'display' );\n\n\t\t\tif ( type === 'span' ) {\n\t\t\t\tconst mathtexView = writer.createContainerElement( 'span', {\n\t\t\t\t\tclass: 'math-tex'\n\t\t\t\t} );\n\n\t\t\t\tif ( display ) {\n\t\t\t\t\twriter.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\\\[' + equation + '\\\\]' ) );\n\t\t\t\t} else {\n\t\t\t\t\twriter.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\\\(' + equation + '\\\\)' ) );\n\t\t\t\t}\n\n\t\t\t\treturn mathtexView;\n\t\t\t} else {\n\t\t\t\tconst mathtexView = writer.createContainerElement( 'script', {\n\t\t\t\t\ttype: display ? 'math/tex; mode=display' : 'math/tex'\n\t\t\t\t} );\n\n\t\t\t\twriter.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( equation ) );\n\n\t\t\t\treturn mathtexView;\n\t\t\t}\n\t\t}\n\t}\n}\n","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ClickObserver from '@ckeditor/ckeditor5-engine/src/view/observer/clickobserver';\nimport ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';\nimport clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';\nimport uid from '@ckeditor/ckeditor5-utils/src/uid';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\nimport { getBalloonPositionData } from './utils';\n\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport MainFormView from './ui/mainformview';\n\n// Need math commands from there\nimport MathEditing from './mathediting';\n\nimport mathIcon from '../theme/icons/math.svg';\n\nconst mathKeystroke = 'Ctrl+M';\n\nexport default class MathUI extends Plugin {\n\tstatic get requires() {\n\t\treturn [ ContextualBalloon, MathEditing ];\n\t}\n\n\tstatic get pluginName() {\n\t\treturn 'MathUI';\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\teditor.editing.view.addObserver( ClickObserver );\n\n\t\tthis._previewUid = `math-preview-${ uid() }`;\n\n\t\tthis.formView = this._createFormView();\n\n\t\tthis._balloon = editor.plugins.get( ContextualBalloon );\n\n\t\tthis._createToolbarMathButton();\n\n\t\tthis._enableUserBalloonInteractions();\n\t}\n\n\tdestroy() {\n\t\tsuper.destroy();\n\n\t\tthis.formView.destroy();\n\n\t\t// Destroy preview element\n\t\tconst previewEl = global.document.getElementById( this._previewUid );\n\t\tif ( previewEl ) {\n\t\t\tpreviewEl.parentNode.removeChild( previewEl );\n\t\t}\n\t}\n\n\t_showUI() {\n\t\tconst editor = this.editor;\n\t\tconst mathCommand = editor.commands.get( 'math' );\n\n\t\tif ( !mathCommand.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._addFormView();\n\n\t\tthis._balloon.showStack( 'main' );\n\t}\n\n\t_createFormView() {\n\t\tconst editor = this.editor;\n\t\tconst mathCommand = editor.commands.get( 'math' );\n\n\t\tconst mathConfig = editor.config.get( 'math' );\n\n\t\tconst formView = new MainFormView(\n\t\t\teditor.locale,\n\t\t\tmathConfig.engine,\n\t\t\tmathConfig.lazyLoad,\n\t\t\tmathConfig.enablePreview,\n\t\t\tthis._previewUid,\n\t\t\tmathConfig.previewClassName,\n\t\t\tmathConfig.popupClassName\n\t\t);\n\n\t\tformView.mathInputView.bind( 'value' ).to( mathCommand, 'value' );\n\t\tformView.displayButtonView.bind( 'isOn' ).to( mathCommand, 'display' );\n\n\t\t// Form elements should be read-only when corresponding commands are disabled.\n\t\tformView.mathInputView.bind( 'isReadOnly' ).to( mathCommand, 'isEnabled', value => !value );\n\t\tformView.saveButtonView.bind( 'isEnabled' ).to( mathCommand );\n\t\tformView.displayButtonView.bind( 'isEnabled' ).to( mathCommand );\n\n\t\t// Listen to submit button click\n\t\tthis.listenTo( formView, 'submit', () => {\n\t\t\teditor.execute( 'math', formView.equation, formView.displayButtonView.isOn, mathConfig.outputType, mathConfig.forceOutputType );\n\t\t\tthis._closeFormView();\n\t\t} );\n\n\t\t// Listen to cancel button click\n\t\tthis.listenTo( formView, 'cancel', () => {\n\t\t\tthis._closeFormView();\n\t\t} );\n\n\t\t// Close plugin ui, if esc is pressed (while ui is focused)\n\t\tformView.keystrokes.set( 'esc', ( data, cancel ) => {\n\t\t\tthis._closeFormView();\n\t\t\tcancel();\n\t\t} );\n\n\t\treturn formView;\n\t}\n\n\t_addFormView() {\n\t\tif ( this._isFormInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\t\tconst mathCommand = editor.commands.get( 'math' );\n\n\t\tthis._balloon.add( {\n\t\t\tview: this.formView,\n\t\t\tposition: getBalloonPositionData( editor )\n\t\t} );\n\n\t\tif ( this._balloon.visibleView === this.formView ) {\n\t\t\tthis.formView.mathInputView.select();\n\t\t}\n\n\t\t// Show preview element\n\t\tconst previewEl = global.document.getElementById( this._previewUid );\n\t\tif ( previewEl && this.formView.previewEnabled ) {\n\t\t\t// Force refresh preview\n\t\t\tthis.formView.mathView.updateMath();\n\t\t}\n\n\t\tthis.formView.equation = mathCommand.value || '';\n\t\tthis.formView.displayButtonView.isOn = mathCommand.display || false;\n\t}\n\n\t_hideUI() {\n\t\tif ( !this._isFormInPanel ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst editor = this.editor;\n\n\t\tthis.stopListening( editor.ui, 'update' );\n\t\tthis.stopListening( this._balloon, 'change:visibleView' );\n\n\t\teditor.editing.view.focus();\n\n\t\t// Remove form first because it's on top of the stack.\n\t\tthis._removeFormView();\n\t}\n\n\t_closeFormView() {\n\t\tconst mathCommand = this.editor.commands.get( 'math' );\n\t\tif ( mathCommand.value !== undefined ) {\n\t\t\tthis._removeFormView();\n\t\t} else {\n\t\t\tthis._hideUI();\n\t\t}\n\t}\n\n\t_removeFormView() {\n\t\tif ( this._isFormInPanel ) {\n\t\t\tthis.formView.saveButtonView.focus();\n\n\t\t\tthis._balloon.remove( this.formView );\n\n\t\t\t// Hide preview element\n\t\t\tconst previewEl = global.document.getElementById( this._previewUid );\n\t\t\tif ( previewEl ) {\n\t\t\t\tpreviewEl.style.visibility = 'hidden';\n\t\t\t}\n\n\t\t\tthis.editor.editing.view.focus();\n\t\t}\n\t}\n\n\t_createToolbarMathButton() {\n\t\tconst editor = this.editor;\n\t\tconst mathCommand = editor.commands.get( 'math' );\n\t\tconst t = editor.t;\n\n\t\t// Handle the `Ctrl+M` keystroke and show the panel.\n\t\teditor.keystrokes.set( mathKeystroke, ( keyEvtData, cancel ) => {\n\t\t\t// Prevent focusing the search bar in FF and opening new tab in Edge. #153, #154.\n\t\t\tcancel();\n\n\t\t\tif ( mathCommand.isEnabled ) {\n\t\t\t\tthis._showUI();\n\t\t\t}\n\t\t} );\n\n\t\tthis.editor.ui.componentFactory.add( 'math', locale => {\n\t\t\tconst button = new ButtonView( locale );\n\n\t\t\tbutton.isEnabled = true;\n\t\t\tbutton.label = t( 'Insert math' );\n\t\t\tbutton.icon = mathIcon;\n\t\t\tbutton.keystroke = mathKeystroke;\n\t\t\tbutton.tooltip = true;\n\t\t\tbutton.isToggleable = true;\n\n\t\t\tbutton.bind( 'isEnabled' ).to( mathCommand, 'isEnabled' );\n\n\t\t\tthis.listenTo( button, 'execute', () => this._showUI() );\n\n\t\t\treturn button;\n\t\t} );\n\t}\n\n\t_enableUserBalloonInteractions() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = this.editor.editing.view.document;\n\t\tthis.listenTo( viewDocument, 'click', () => {\n\t\t\tconst mathCommand = editor.commands.get( 'math' );\n\t\t\tif ( mathCommand.value ) {\n\t\t\t\tif ( mathCommand.isEnabled ) {\n\t\t\t\t\tthis._showUI();\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Close the panel on the Esc key press when the editable has focus and the balloon is visible.\n\t\teditor.keystrokes.set( 'Esc', ( data, cancel ) => {\n\t\t\tif ( this._isUIVisible ) {\n\t\t\t\tthis._hideUI();\n\t\t\t\tcancel();\n\t\t\t}\n\t\t} );\n\n\t\t// Close on click outside of balloon panel element.\n\t\tclickOutsideHandler( {\n\t\t\temitter: this.formView,\n\t\t\tactivator: () => this._isFormInPanel,\n\t\t\tcontextElements: [ this._balloon.view.element ],\n\t\t\tcallback: () => this._hideUI()\n\t\t} );\n\t}\n\n\tget _isUIVisible() {\n\t\tconst visibleView = this._balloon.visibleView;\n\n\t\treturn visibleView == this.formView;\n\t}\n\n\tget _isFormInPanel() {\n\t\treturn this._balloon.hasView( this.formView );\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" viewBox=\\\"0 0 15.44 10.78\\\" height=\\\"40.74\\\" width=\\\"58.35\\\"><path d=\\\"M8.15 0c-.06 0-.1.02-.11.03a.12.12 0 0 0-.02.01 6.81 6.81 0 0 0-2.32 4.9v.9a6.82 6.82 0 0 0 2.32 4.9.12.12 0 0 0 .02 0c.02.02.06.04.11.04.07 0 .12-.03.16-.07a.22.22 0 0 0 0-.32.12.12 0 0 0-.02-.02A4.4 4.4 0 0 1 7 8.44a7.62 7.62 0 0 1-.5-2.6v-.9c0-.82.19-1.76.5-2.6A4.4 4.4 0 0 1 8.3.42.12.12 0 0 0 8.3.39a.22.22 0 0 0 .08-.16.22.22 0 0 0-.07-.16.22.22 0 0 0-.16-.07zm4.83 0a.22.22 0 0 0-.16.07.22.22 0 0 0-.07.16c0 .08.05.13.08.16a.12.12 0 0 0 .01.02c.52.39.98 1.1 1.3 1.94.3.83.49 1.77.49 2.6v.88c0 .83-.18 1.78-.5 2.6a4.4 4.4 0 0 1-1.29 1.95.22.22 0 0 0-.01.33c.03.04.08.07.15.07.05 0 .09-.02.12-.03a.12.12 0 0 0 .02-.01 6.82 6.82 0 0 0 2.32-4.9v-.9a6.81 6.81 0 0 0-2.32-4.9.12.12 0 0 0-.02 0c-.03-.02-.06-.04-.12-.04zm-8.5.46c-.4 0-1.13.23-1.46 1.32-.06.2-.11.45-.33 1.58h-.64c-.1 0-.19-.01-.28.03a.25.25 0 0 0-.12.12.38.38 0 0 0-.03.17c0 .04 0 .1.04.14.03.04.07.07.11.08.09.03.16.02.26.02h.56l-.77 4.04c-.1.51-.19 1-.32 1.36-.06.18-.14.32-.22.4-.08.1-.16.13-.26.13-.03 0-.1 0-.2-.03.11-.05.2-.13.26-.2a.7.7 0 0 0 .13-.4.48.48 0 0 0-.16-.38.53.53 0 0 0-.35-.12c-.34 0-.7.3-.7.76 0 .27.14.5.34.64s.44.2.68.2c.33 0 .61-.17.83-.4.21-.21.37-.48.47-.69.18-.35.32-.84.43-1.25a14.17 14.17 0 0 0 .18-.8l.61-3.26h.81c.1 0 .2.01.3-.03.04-.03.09-.07.11-.13.02-.05.03-.1.03-.17 0-.05-.01-.1-.05-.14a.23.23 0 0 0-.11-.07c-.08-.03-.16-.02-.25-.02h-.73l.2-1.07a26.3 26.3 0 0 1 .24-1.07c.08-.17.22-.3.39-.3l.21.05a.7.7 0 0 0-.25.2.7.7 0 0 0-.13.4c0 .15.06.28.16.37.1.08.22.12.35.12.34 0 .7-.3.7-.76 0-.28-.15-.5-.35-.64-.2-.14-.45-.2-.7-.2zm5.4 2.78c-.6 0-1.06.37-1.36.76-.16.2-.27.4-.35.57-.07.18-.12.3-.12.42 0 .1.08.18.14.2.06.03.1.02.1.02.06 0 .12 0 .18-.04.05-.05.07-.1.08-.17v.02c.35-1.09 1-1.3 1.3-1.3.09 0 .2.01.29.09.09.07.17.2.17.5 0 .27-.18 1-.57 2.48a1.8 1.8 0 0 1-.37.75.7.7 0 0 1-.52.26c-.04 0-.13 0-.22-.03a.68.68 0 0 0 .3-.56.47.47 0 0 0-.18-.39.55.55 0 0 0-.32-.1c-.4 0-.7.33-.7.74 0 .28.16.5.38.63.21.13.48.18.73.18.39 0 .69-.2.89-.41.09-.1.15-.19.2-.27.2.36.59.68 1.16.68.6 0 1.05-.37 1.35-.76.15-.2.27-.4.34-.57.08-.18.12-.3.12-.42a.24.24 0 0 0-.11-.2c-.06-.03-.12-.02-.13-.02a.26.26 0 0 0-.18.06c-.05.05-.06.1-.07.14-.34 1.1-1.02 1.3-1.3 1.3-.17 0-.27-.06-.35-.17a.72.72 0 0 1-.11-.4c0-.22.06-.45.18-.91l.36-1.45c.03-.14.1-.44.25-.7.15-.25.36-.46.68-.46.03 0 .12 0 .22.03a.7.7 0 0 0-.32.56c0 .11.04.23.13.33.08.1.22.16.4.16.14 0 .3-.06.44-.18a.73.73 0 0 0 .24-.55c0-.32-.2-.54-.42-.66a1.52 1.52 0 0 0-.68-.16c-.34 0-.62.16-.82.34a1.8 1.8 0 0 0-.3.35 1.32 1.32 0 0 0-.5-.54 1.37 1.37 0 0 0-.63-.15z\\\" style=\\\"line-height:1.25;-inkscape-font-specification:'Latin Modern Math'\\\" font-weight=\\\"400\\\" font-size=\\\"10.58\\\" font-family=\\\"Latin Modern Math\\\" letter-spacing=\\\"-1.06\\\" word-spacing=\\\"0\\\"/></svg>\\n\";","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard';\nimport Undo from '@ckeditor/ckeditor5-undo/src/undo';\nimport LiveRange from '@ckeditor/ckeditor5-engine/src/model/liverange';\nimport LivePosition from '@ckeditor/ckeditor5-engine/src/model/liveposition';\nimport global from '@ckeditor/ckeditor5-utils/src/dom/global';\n\nimport { extractDelimiters, hasDelimiters, delimitersCounts } from './utils';\n\nexport default class AutoMath extends Plugin {\n\tstatic get requires() {\n\t\treturn [ Clipboard, Undo ];\n\t}\n\n\tstatic get pluginName() {\n\t\treturn 'AutoMath';\n\t}\n\n\tconstructor( editor ) {\n\t\tsuper( editor );\n\n\t\tthis._timeoutId = null;\n\n\t\tthis._positionToInsert = null;\n\t}\n\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst modelDocument = editor.model.document;\n\n\t\tthis.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => {\n\t\t\tconst firstRange = modelDocument.selection.getFirstRange();\n\n\t\t\tconst leftLivePosition = LivePosition.fromPosition( firstRange.start );\n\t\t\tleftLivePosition.stickiness = 'toPrevious';\n\n\t\t\tconst rightLivePosition = LivePosition.fromPosition( firstRange.end );\n\t\t\trightLivePosition.stickiness = 'toNext';\n\n\t\t\tmodelDocument.once( 'change:data', () => {\n\t\t\t\tthis._mathBetweenPositions( leftLivePosition, rightLivePosition );\n\n\t\t\t\tleftLivePosition.detach();\n\t\t\t\trightLivePosition.detach();\n\t\t\t}, { priority: 'high' } );\n\t\t} );\n\n\t\teditor.commands.get( 'undo' ).on( 'execute', () => {\n\t\t\tif ( this._timeoutId ) {\n\t\t\t\tglobal.window.clearTimeout( this._timeoutId );\n\t\t\t\tthis._positionToInsert.detach();\n\n\t\t\t\tthis._timeoutId = null;\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t}\n\t\t}, { priority: 'high' } );\n\t}\n\n\t_mathBetweenPositions( leftPosition, rightPosition ) {\n\t\tconst editor = this.editor;\n\n\t\tconst mathConfig = this.editor.config.get( 'math' );\n\n\t\tconst equationRange = new LiveRange( leftPosition, rightPosition );\n\t\tconst walker = equationRange.getWalker( { ignoreElementEnd: true } );\n\n\t\tlet text = '';\n\n\t\t// Get equation text\n\t\tfor ( const node of walker ) {\n\t\t\tif ( node.item.is( '$textProxy' ) ) {\n\t\t\t\ttext += node.item.data;\n\t\t\t}\n\t\t}\n\n\t\ttext = text.trim();\n\n\t\t// Skip if don't have delimiters\n\t\tif ( !hasDelimiters( text ) || delimitersCounts( text ) !== 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst mathCommand = editor.commands.get( 'math' );\n\n\t\t// Do not anything if math element cannot be inserted at the current position\n\t\tif ( !mathCommand.isEnabled ) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._positionToInsert = LivePosition.fromPosition( leftPosition );\n\n\t\t// With timeout user can undo conversation if want use plain text\n\t\tthis._timeoutId = global.window.setTimeout( () => {\n\t\t\teditor.model.change( writer => {\n\t\t\t\tthis._timeoutId = null;\n\n\t\t\t\twriter.remove( equationRange );\n\n\t\t\t\tlet insertPosition;\n\n\t\t\t\t// Check if position where the math element should be inserted is still valid.\n\t\t\t\tif ( this._positionToInsert.root.rootName !== '$graveyard' ) {\n\t\t\t\t\tinsertPosition = this._positionToInsert;\n\t\t\t\t}\n\n\t\t\t\teditor.model.change( innerWriter => {\n\t\t\t\t\tconst params = Object.assign( extractDelimiters( text ), {\n\t\t\t\t\t\ttype: mathConfig.outputType\n\t\t\t\t\t} );\n\t\t\t\t\tconst mathElement = innerWriter.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params );\n\n\t\t\t\t\teditor.model.insertContent( mathElement, insertPosition );\n\n\t\t\t\t\tinnerWriter.setSelection( mathElement, 'on' );\n\t\t\t\t} );\n\n\t\t\t\tthis._positionToInsert.detach();\n\t\t\t\tthis._positionToInsert = null;\n\t\t\t} );\n\t\t}, 100 );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n// The editor creator to use.\nimport BalloonEditorBase from '@ckeditor/ckeditor5-editor-balloon/src/ballooneditor';\n\nimport UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';\nimport Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';\nimport Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';\nimport Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';\nimport Superscript from '@ckeditor/ckeditor5-basic-styles/src/superscript';\nimport Subscript from '@ckeditor/ckeditor5-basic-styles/src/subscript';\nimport Underline from '@ckeditor/ckeditor5-basic-styles/src/underline';\nimport Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough';\nimport Code from '@ckeditor/ckeditor5-basic-styles/src/code';\nimport BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';\nimport Heading from '@ckeditor/ckeditor5-heading/src/heading';\nimport Image from '@ckeditor/ckeditor5-image/src/image';\nimport ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';\nimport ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';\nimport ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';\nimport ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';\nimport ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';\nimport Link from '@ckeditor/ckeditor5-link/src/link';\nimport AutoLink from '@ckeditor/ckeditor5-link/src/autolink';\nimport List from '@ckeditor/ckeditor5-list/src/list';\nimport ListStyle from '@ckeditor/ckeditor5-list/src/liststyle';\nimport TodoList from '@ckeditor/ckeditor5-list/src/todolist';\nimport Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';\nimport PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';\nimport Table from '@ckeditor/ckeditor5-table/src/table';\nimport TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';\nimport TableProperties from '@ckeditor/ckeditor5-table/src/tableproperties';\nimport TableCellProperties from '@ckeditor/ckeditor5-table/src/tablecellproperties';\nimport BlockToolbar from '@ckeditor/ckeditor5-ui/src/toolbar/block/blocktoolbar';\nimport HeadingButtonsUI from '@ckeditor/ckeditor5-heading/src/headingbuttonsui';\nimport ParagraphButtonUI from '@ckeditor/ckeditor5-paragraph/src/paragraphbuttonui';\nimport TextTransformation from '@ckeditor/ckeditor5-typing/src/texttransformation';\nimport Font from '@ckeditor/ckeditor5-font/src/font';\nimport FontColor from '@ckeditor/ckeditor5-font/src/fontcolor';\nimport FontBackgroundColor from '@ckeditor/ckeditor5-font/src/fontbackgroundcolor';\nimport CodeBlock from '@ckeditor/ckeditor5-code-block/src/codeblock';\nimport Mention from '@ckeditor/ckeditor5-mention/src/mention';\nimport Indent from '@ckeditor/ckeditor5-indent/src/indent';\nimport IndentBlock from '@ckeditor/ckeditor5-indent/src/indentblock';\nimport SelectAll from '@ckeditor/ckeditor5-select-all/src/selectall';\nimport HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline';\nimport Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard.js';\nimport Enter from '@ckeditor/ckeditor5-enter/src/enter.js';\nimport ShiftEnter from '@ckeditor/ckeditor5-enter/src/shiftenter.js';\nimport Typing from '@ckeditor/ckeditor5-typing/src/typing.js';\nimport Undo from '@ckeditor/ckeditor5-undo/src/undo.js';\nimport RemoveFormat from '@ckeditor/ckeditor5-remove-format/src/removeformat';\nimport MentionCustomization from './mention_customization.js';\nimport UploadimagePlugin from './uploadimage';\nimport InternalLinkPlugin from './internallink';\nimport MarkdownImportPlugin from './markdownimport';\nimport CuttonotePlugin from './cuttonote';\nimport IncludeNote from './includenote';\nimport ReferenceLink from './referencelink';\nimport indentBlockShortcutPlugin from './indent_block_shortcut.js';\nimport removeFormatLinksPlugin from './remove_format_links.js';\nimport Mathematics from 'ckeditor5-math/src/math';\n\nexport default class BalloonEditor extends BalloonEditorBase {}\n\n// Plugins to include in the build.\nBalloonEditor.builtinPlugins = [\n\tClipboard, Enter, SelectAll, ShiftEnter, Typing, Undo, // essentials package expanded to allow selectively disable Enter and ShiftEnter\n\tUploadAdapter,\n\tAutoformat,\n\tBold,\n\tItalic,\n\tUnderline,\n\tStrikethrough,\n\tCode,\n\tSuperscript,\n\tSubscript,\n\tBlockQuote,\n\tHeading,\n\tImage,\n\tImageCaption,\n\tImageStyle,\n\tImageToolbar,\n\tImageUpload,\n\tImageResize,\n\tLink,\n\tAutoLink,\n\tList,\n\tListStyle,\n\tTodoList,\n\tParagraph,\n\tPasteFromOffice,\n\tTable,\n\tTableToolbar,\n\tTableProperties,\n\tTableCellProperties,\n\tIndent,\n\tIndentBlock,\n\tBlockToolbar,\n\tParagraphButtonUI,\n\tHeadingButtonsUI,\n\tUploadimagePlugin,\n\tInternalLinkPlugin,\n\tMarkdownImportPlugin,\n\tCuttonotePlugin,\n\tTextTransformation,\n\tFont,\n\tFontColor,\n\tFontBackgroundColor,\n\tCodeBlock,\n\tSelectAll,\n\tHorizontalLine,\n\tRemoveFormat,\n\tMention,\n\tMentionCustomization,\n\tIncludeNote,\n\tReferenceLink,\n\tindentBlockShortcutPlugin,\n\tremoveFormatLinksPlugin,\n\tMathematics\n];\n\n// Editor configuration.\nBalloonEditor.defaultConfig = {\n\ttoolbar: {\n\t\titems: [\n\t\t\t'fontSize',\n\t\t\t'bold',\n\t\t\t'italic',\n\t\t\t'underline',\n\t\t\t'strikethrough',\n\t\t\t'superscript',\n\t\t\t'subscript',\n\t\t\t'fontColor',\n\t\t\t'fontBackgroundColor',\n\t\t\t'code',\n\t\t\t'link',\n\t\t\t'removeFormat',\n\t\t\t'internallink',\n\t\t\t'cuttonote'\n\t\t]\n\t},\n\timage: {\n\t\tstyles: [\n\t\t\t'alignLeft',\n\t\t\t'alignCenter',\n\t\t\t'alignRight',\n\t\t\t'full', // full and side are for BC since the old images have been created with these styles\n\t\t\t'side'\n\t\t],\n\t\tresizeOptions: [\n\t\t\t{\n\t\t\t\tname: 'imageResize:original',\n\t\t\t\tvalue: null,\n\t\t\t\ticon: 'original'\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'imageResize:25',\n\t\t\t\tvalue: '25',\n\t\t\t\ticon: 'small'\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'imageResize:50',\n\t\t\t\tvalue: '50',\n\t\t\t\ticon: 'medium'\n\t\t\t}\n\t\t],\n\t\ttoolbar: [\n\t\t\t'imageStyle:alignLeft',\n\t\t\t'imageStyle:alignCenter',\n\t\t\t'imageStyle:alignRight',\n\t\t\t'|',\n\t\t\t'imageResize:25',\n\t\t\t'imageResize:50',\n\t\t\t'imageResize:original'\n\t\t]\n\t},\n\theading: {\n\t\toptions: [\n\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n\t\t\t// heading1 is not used since that should be a note's title\n\t\t\t{ model: 'heading2', view: 'h2', title: 'Heading 2', class: 'ck-heading_heading2' },\n\t\t\t{ model: 'heading3', view: 'h3', title: 'Heading 3', class: 'ck-heading_heading3' },\n\t\t\t{ model: 'heading4', view: 'h4', title: 'Heading 4', class: 'ck-heading_heading4' },\n\t\t\t{ model: 'heading5', view: 'h5', title: 'Heading 5', class: 'ck-heading_heading5' },\n\t\t\t{ model: 'heading6', view: 'h6', title: 'Heading 6', class: 'ck-heading_heading6' }\n\t\t]\n\t},\n\tblockToolbar: [\n\t\t'heading',\n\t\t'|',\n\t\t'bulletedList', 'numberedList', 'todoList',\n\t\t'|',\n\t\t'blockQuote', 'codeBlock', 'insertTable', 'includeNote', 'math',\n\t\t'|',\n\t\t'outdent', 'indent', 'horizontalLine',\n\t\t'|',\n\t\t'imageUpload',\n\t\t'markdownImport'\n\t],\n\ttable: {\n\t\tcontentToolbar: [\n\t\t\t'tableColumn',\n\t\t\t'tableRow',\n\t\t\t'mergeTableCells',\n\t\t\t'tableProperties',\n\t\t\t'tableCellProperties'\n\t\t]\n\t},\n\tlink: {\n\t\tdefaultProtocol: 'https://'\n\t},\n\t// This value must be kept in sync with the language defined in webpack.config.js.\n\tlanguage: 'en'\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 typing/typing\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Input from './input';\nimport Delete from './delete';\n\n/**\n * The typing feature. It handles typing.\n *\n * This is a \"glue\" plugin which loads the {@link module:typing/input~Input} and {@link module:typing/delete~Delete}\n * plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Typing extends Plugin {\n\tstatic get requires() {\n\t\treturn [ Input, Delete ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Typing';\n\t}\n}\n\n/**\n * The configuration of the typing features. Used by the features from the `@ckeditor/ckeditor5-typing` package.\n *\n * Read more in {@link module:typing/typing~TypingConfig}.\n *\n * @member {module:typing/typing~TypingConfig} module:core/editor/editorconfig~EditorConfig#typing\n */\n\n/**\n * The configuration of the typing features. Used by the typing features in `@ckeditor/ckeditor5-typing` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\ttyping: ... // Typing feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface TypingConfig\n */\n\n/**\n * The granularity of undo/redo for typing and deleting. The value `20` means (more or less) that a new undo step\n * is created every 20 characters are inserted or deleted.\n *\n * @member {Number} [module:typing/typing~TypingConfig#undoStep=20]\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 basic-styles/bold\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport BoldEditing from './bold/boldediting';\nimport BoldUI from './bold/boldui';\n\n/**\n * The bold feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/bold/boldediting~BoldEditing bold editing feature}\n * and {@link module:basic-styles/bold/boldui~BoldUI bold UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Bold extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ BoldEditing, BoldUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Bold';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/italic\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ItalicEditing from './italic/italicediting';\nimport ItalicUI from './italic/italicui';\n\n/**\n * The italic feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/italic/italicediting~ItalicEditing} and\n * {@link module:basic-styles/italic/italicui~ItalicUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Italic extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ItalicEditing, ItalicUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Italic';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/underline\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport UnderlineEditing from './underline/underlineediting';\nimport UnderlineUI from './underline/underlineui';\n\n/**\n * The underline feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/underline/underlineediting~UnderlineEditing} and\n * {@link module:basic-styles/underline/underlineui~UnderlineUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Underline extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ UnderlineEditing, UnderlineUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Underline';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/strikethrough\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport StrikethroughEditing from './strikethrough/strikethroughediting';\nimport StrikethroughUI from './strikethrough/strikethroughui';\n\n/**\n * The strikethrough feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/strikethrough/strikethroughediting~StrikethroughEditing} and\n * {@link module:basic-styles/strikethrough/strikethroughui~StrikethroughUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Strikethrough extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ StrikethroughEditing, StrikethroughUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Strikethrough';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/code\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport CodeEditing from './code/codeediting';\nimport CodeUI from './code/codeui';\n\nimport '../theme/code.css';\n\n/**\n * The code feature.\n *\n * For a detailed overview check the {@glink features/basic-styles Basic styles feature documentation}\n * and the {@glink api/basic-styles package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:basic-styles/code/codeediting~CodeEditing code editing feature}\n * and {@link module:basic-styles/code/codeui~CodeUI code UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Code extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ CodeEditing, CodeUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Code';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/superscript\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport SuperscriptEditing from './superscript/superscriptediting';\nimport SuperscriptUI from './superscript/superscriptui';\n\n/**\n * The superscript feature.\n *\n * It loads the {@link module:basic-styles/superscript/superscriptediting~SuperscriptEditing} and\n * {@link module:basic-styles/superscript/superscriptui~SuperscriptUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Superscript extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ SuperscriptEditing, SuperscriptUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Superscript';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module basic-styles/subscript\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport SubscriptEditing from './subscript/subscriptediting';\nimport SubscriptUI from './subscript/subscriptui';\n\n/**\n * The subscript feature.\n *\n * It loads the {@link module:basic-styles/subscript/subscriptediting~SubscriptEditing} and\n * {@link module:basic-styles/subscript/subscriptui~SubscriptUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Subscript extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ SubscriptEditing, SubscriptUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Subscript';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module block-quote/blockquote\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport BlockQuoteEditing from './blockquoteediting';\nimport BlockQuoteUI from './blockquoteui';\n\n/**\n * The block quote plugin.\n *\n * For more information about this feature check the {@glink api/block-quote package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:block-quote/blockquoteediting~BlockQuoteEditing block quote editing feature}\n * and {@link module:block-quote/blockquoteui~BlockQuoteUI block quote UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class BlockQuote extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ BlockQuoteEditing, BlockQuoteUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'BlockQuote';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module heading/heading\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport HeadingEditing from './headingediting';\nimport HeadingUI from './headingui';\n\nimport '../theme/heading.css';\n\n/**\n * The headings feature.\n *\n * For a detailed overview, check the {@glink features/headings Headings feature documentation}\n * and the {@glink api/heading package page}.\n *\n * This is a \"glue\" plugin which loads the {@link module:heading/headingediting~HeadingEditing heading editing feature}\n * and {@link module:heading/headingui~HeadingUI heading UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Heading extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ HeadingEditing, HeadingUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Heading';\n\t}\n}\n\n/**\n * The configuration of the heading feature. Introduced by the {@link module:heading/headingediting~HeadingEditing} feature.\n *\n * Read more in {@link module:heading/heading~HeadingConfig}.\n *\n * @member {module:heading/heading~HeadingConfig} module:core/editor/editorconfig~EditorConfig#heading\n */\n\n/**\n * The configuration of the heading feature.\n * The option is used by the {@link module:heading/headingediting~HeadingEditing} feature.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n * \t\t\t\theading: ... // Heading feature config.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface HeadingConfig\n */\n\n/**\n * The available heading options.\n *\n * The default value is:\n *\n *\t\tconst headingConfig = {\n *\t\t\toptions: [\n *\t\t\t\t{ model: 'paragraph', title: 'Paragraph', class: 'ck-heading_paragraph' },\n *\t\t\t\t{ model: 'heading1', view: 'h2', title: 'Heading 1', class: 'ck-heading_heading1' },\n *\t\t\t\t{ model: 'heading2', view: 'h3', title: 'Heading 2', class: 'ck-heading_heading2' },\n *\t\t\t\t{ model: 'heading3', view: 'h4', title: 'Heading 3', class: 'ck-heading_heading3' }\n *\t\t\t]\n *\t\t};\n *\n * It defines 3 levels of headings. In the editor model they will use `heading1`, `heading2`, and `heading3` elements.\n * Their respective view elements (so the elements output by the editor) will be: `h2`, `h3`, and `h4`. This means that\n * if you choose \"Heading 1\" in the headings dropdown the editor will turn the current block to `<heading1>` in the model\n * which will result in rendering (and outputting to data) the `<h2>` element.\n *\n * The `title` and `class` properties will be used by the `headings` dropdown to render available options.\n * Usually, the first option in the headings dropdown is the \"Paragraph\" option, hence it's also defined on the list.\n * However, you don't need to define its view representation because it's handled by\n * the {@link module:paragraph/paragraph~Paragraph} feature (which is required by\n * the {@link module:heading/headingediting~HeadingEditing} feature).\n *\n * You can **read more** about configuring heading levels and **see more examples** in\n * the {@glink features/headings Headings} guide.\n *\n * Note: In the model you should always start from `heading1`, regardless of how the headings are represented in the view.\n * That's assumption is used by features like {@link module:autoformat/autoformat~Autoformat} to know which element\n * they should use when applying the first level heading.\n *\n * The defined headings are also available as values passed to the `'heading'` command under their model names.\n * For example, the below code will apply `<heading1>` to the current selection:\n *\n *\t\teditor.execute( 'heading', { value: 'heading1' } );\n *\n * @member {Array.<module:heading/heading~HeadingOption>} module:heading/heading~HeadingConfig#options\n */\n\n/**\n * Heading option descriptor.\n *\n * @typedef {Object} module:heading/heading~HeadingOption\n * @property {String} model Name of the model element to convert.\n * @property {module:engine/view/elementdefinition~ElementDefinition} view Definition of a view element to convert from/to.\n * @property {String} title The user-readable title of the option.\n * @property {String} class The class which will be added to the dropdown item representing this option.\n * @property {String} [icon] Icon used by {@link module:heading/headingbuttonsui~HeadingButtonsUI}. It can be omitted when using\n * the default configuration.\n * @extends module:engine/conversion/conversion~ConverterDefinition\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 image/image\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Widget } from 'ckeditor5/src/widget';\n\nimport ImageEditing from './image/imageediting';\nimport ImageTextAlternative from './imagetextalternative';\nimport { isImageWidget } from './image/utils';\n\nimport '../theme/image.css';\n\n/**\n * The image plugin.\n *\n * For a detailed overview, check the {@glink features/image image feature} documentation.\n *\n * This is a \"glue\" plugin which loads the following plugins:\n *\n * * {@link module:image/image/imageediting~ImageEditing},\n * * {@link module:image/imagetextalternative~ImageTextAlternative}.\n *\n * Usually, it is used in conjuction with other plugins from this package. See the {@glink api/image package page}\n * for more information.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Image extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageEditing, Widget, ImageTextAlternative ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Image';\n\t}\n\n\t/**\n\t * Checks if a given view element is an image widget.\n\t *\n\t * @param {module:engine/view/element~Element} viewElement\n\t * @returns {Boolean}\n\t */\n\tisImageWidget( viewElement ) {\n\t\treturn isImageWidget( viewElement );\n\t}\n}\n\n/**\n * The configuration of the image features. Used by the image features in the `@ckeditor/ckeditor5-image` package.\n *\n * Read more in {@link module:image/image~ImageConfig}.\n *\n * @member {module:image/image~ImageConfig} module:core/editor/editorconfig~EditorConfig#image\n */\n\n/**\n * The configuration of the image features. Used by the image features in the `@ckeditor/ckeditor5-image` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\timage: ... // Image feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface ImageConfig\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 image/imagecaption\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ImageCaptionEditing from './imagecaption/imagecaptionediting';\n\nimport '../theme/imagecaption.css';\n\n/**\n * The image caption plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-captions image caption} documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageCaption extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageCaptionEditing ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageCaption';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module image/imagestyle\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ImageStyleEditing from './imagestyle/imagestyleediting';\nimport ImageStyleUI from './imagestyle/imagestyleui';\n\n/**\n * The image style plugin.\n *\n * For a detailed overview, check the {@glink features/image#image-styles image styles} documentation.\n *\n * This is a \"glue\" plugin which loads the {@link module:image/imagestyle/imagestyleediting~ImageStyleEditing}\n * and {@link module:image/imagestyle/imagestyleui~ImageStyleUI} plugins.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageStyle extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageStyleEditing, ImageStyleUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageStyle';\n\t}\n}\n\n/**\n * Available image styles.\n *\n * The default value is:\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [ 'full', 'side' ]\n *\t\t};\n *\n * which configures two default styles:\n *\n * * the \"full\" style which does not apply any class, e.g. for images styled to span 100% width of the content,\n * * the \"side\" style with the `.image-style-side` CSS class.\n *\n * See {@link module:image/imagestyle/utils~defaultStyles} to learn more about default\n * styles provided by the image feature.\n *\n * The {@link module:image/imagestyle/utils~defaultStyles default styles} can be customized,\n * e.g. to change the icon, title or CSS class of the style. The feature also provides several\n * {@link module:image/imagestyle/utils~defaultIcons default icons} to choose from.\n *\n *\t\timport customIcon from 'custom-icon.svg';\n *\n *\t\t// ...\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [\n *\t\t\t\t// This will only customize the icon of the \"full\" style.\n *\t\t\t\t// Note: 'right' is one of default icons provided by the feature.\n *\t\t\t\t{ name: 'full', icon: 'right' },\n *\n *\t\t\t\t// This will customize the icon, title and CSS class of the default \"side\" style.\n *\t\t\t\t{ name: 'side', icon: customIcon, title: 'My side style', className: 'custom-side-image' }\n *\t\t\t]\n *\t\t};\n *\n * If none of the default styles is good enough, it is possible to define independent custom styles, too:\n *\n *\t\timport { icons } from 'ckeditor5/src/core';\n *\n *\t\tconst fullSizeIcon = icons.objectCenter';\n *\t\tconst sideIcon = icons.objectRight';\n *\n *\t\t// ...\n *\n *\t\tconst imageConfig = {\n *\t\t\tstyles: [\n *\t\t\t\t// A completely custom full size style with no class, used as a default.\n *\t\t\t\t{ name: 'fullSize', title: 'Full size', icon: fullSizeIcon, isDefault: true },\n *\n *\t\t\t\t{ name: 'side', title: 'To the side', icon: sideIcon, className: 'side-image' }\n *\t\t\t]\n *\t\t};\n *\n * Note: Setting `title` to one of {@link module:image/imagestyle/imagestyleui~ImageStyleUI#localizedDefaultStylesTitles}\n * will automatically translate it to the language of the editor.\n *\n * Read more about styling images in the {@glink features/image#image-styles Image styles guide}.\n *\n * The feature creates commands based on defined styles, so you can change the style of a selected image by executing\n * the following command:\n *\n *\t\teditor.execute( 'imageStyle' { value: 'side' } );\n *\n * The feature also creates buttons that execute the commands. So, assuming that you use the\n * default image styles setting, you can {@link module:image/image~ImageConfig#toolbar configure the image toolbar}\n * (or any other toolbar) to contain these options:\n *\n *\t\tconst imageConfig = {\n *\t\t\ttoolbar: [ 'imageStyle:full', 'imageStyle:side' ]\n *\t\t};\n *\n * @member {Array.<module:image/imagestyle/imagestyleediting~ImageStyleFormat>} module:image/image~ImageConfig#styles\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 image/imagetoolbar\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { WidgetToolbarRepository } from 'ckeditor5/src/widget';\n\nimport { getSelectedImageWidget } from './image/utils';\n\n/**\n * The image toolbar plugin. It creates and manages the image toolbar (the toolbar displayed when an image is selected).\n *\n * For a detailed overview, check the {@glink features/image#image-contextual-toolbar image contextual toolbar} documentation.\n *\n * Instances of toolbar components (e.g. buttons) are created using the editor's\n * {@link module:ui/componentfactory~ComponentFactory component factory}\n * based on the {@link module:image/image~ImageConfig#toolbar `image.toolbar` configuration option}.\n *\n * The toolbar uses the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetToolbarRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n\n\t\twidgetToolbarRepository.register( 'image', {\n\t\t\tariaLabel: t( 'Image toolbar' ),\n\t\t\titems: editor.config.get( 'image.toolbar' ) || [],\n\t\t\tgetRelatedElement: getSelectedImageWidget\n\t\t} );\n\t}\n}\n\n/**\n * Items to be placed in the image toolbar.\n * This option is used by the {@link module:image/imagetoolbar~ImageToolbar} feature.\n *\n * Assuming that you use the following features:\n *\n * * {@link module:image/imagestyle~ImageStyle} (with a default configuration),\n * * {@link module:image/imagetextalternative~ImageTextAlternative},\n *\n * three toolbar items will be available in {@link module:ui/componentfactory~ComponentFactory}:\n * `'imageStyle:full'`, `'imageStyle:side'`, and `'imageTextAlternative'` so you can configure the toolbar like this:\n *\n *\t\tconst imageConfig = {\n *\t\t\ttoolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:image/image~ImageConfig#toolbar\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 image/imageupload\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ImageUploadUI from './imageupload/imageuploadui';\nimport ImageUploadProgress from './imageupload/imageuploadprogress';\nimport ImageUploadEditing from './imageupload/imageuploadediting';\n\n/**\n * The image upload plugin.\n *\n * For a detailed overview, check the {@glink features/image-upload/image-upload image upload feature} documentation.\n *\n * This plugin does not do anything directly, but it loads a set of specific plugins to enable image uploading:\n *\n * * {@link module:image/imageupload/imageuploadediting~ImageUploadEditing},\n * * {@link module:image/imageupload/imageuploadui~ImageUploadUI},\n * * {@link module:image/imageupload/imageuploadprogress~ImageUploadProgress}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageUpload extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageUpload';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageUploadEditing, ImageUploadUI, ImageUploadProgress ];\n\t}\n}\n\n/**\n * The image upload configuration.\n *\n * @member {module:image/imageupload~ImageUploadConfig} module:image/image~ImageConfig#upload\n */\n\n/**\n * The configuration of the image upload feature. Used by the image upload feature in the `@ckeditor/ckeditor5-image` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\timage: {\n * \t\t\t\t\tupload: ... // Image upload feature options.\n * \t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface module:image/imageupload~ImageUploadConfig\n */\n\n/**\n * The list of accepted image types.\n *\n * The accepted types of images can be customized to allow only certain types of images:\n *\n *\t\t// Allow only JPEG and PNG images:\n *\t\tconst imageUploadConfig = {\n *\t\t\ttypes: [ 'png', 'jpeg' ]\n *\t\t};\n *\n * The type string should match [one of the sub-types](https://www.iana.org/assignments/media-types/media-types.xhtml#image)\n * of the image MIME type. For example, for the `image/jpeg` MIME type, add `'jpeg'` to your image upload configuration.\n *\n * **Note:** This setting only restricts some image types to be selected and uploaded through the CKEditor UI and commands. Image type\n * recognition and filtering should also be implemented on the server which accepts image uploads.\n *\n * @member {Array.<String>} module:image/imageupload~ImageUploadConfig#types\n * @default [ 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff' ]\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 image/imageresize\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ImageResizeButtons from './imageresize/imageresizebuttons';\nimport ImageResizeEditing from './imageresize/imageresizeediting';\nimport ImageResizeHandles from './imageresize/imageresizehandles';\n\nimport '../theme/imageresize.css';\n\n/**\n * The image resize plugin.\n *\n * It adds a possibility to resize each image using handles.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ImageResize extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ImageResizeEditing, ImageResizeHandles, ImageResizeButtons ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ImageResize';\n\t}\n}\n\n/**\n * The available options are `'px'` or `'%'`.\n *\n * Determines the size unit applied to the resized image.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\timage: {\n *\t\t\t\t\tresizeUnit: 'px'\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n *\n * This option is used by the {@link module:image/imageresize~ImageResize} feature.\n *\n * @default '%'\n * @member {String} module:image/image~ImageConfig#resizeUnit\n */\n\n/**\n * The image resize options.\n *\n * Each option should have at least these two properties:\n *\n * * name: The name of the UI component registered in the global\n * {@link module:core/editor/editorui~EditorUI#componentFactory component factory} of the editor,\n * representing the button a user can click to change the size of an image,\n * * value: An actual image width applied when a user clicks the mentioned button\n * ({@link module:image/imageresize/resizeimagecommand~ResizeImageCommand} gets executed).\n * The value property is combined with the {@link module:image/image~ImageConfig#resizeUnit `config.image.resizeUnit`} (`%` by default).\n * For instance: `value: '50'` and `resizeUnit: '%'` will render as `'50%'` in the UI.\n *\n * **Resetting the image size**\n *\n * If you want to set an option that will reset image to its original size, you need to pass a `null` value\n * to one of the options. The `:original` token is not mandatory, you can call it anything you wish, but it must reflect\n * in the standalone buttons configuration for the image toolbar.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\timage: {\n *\t\t\t\t\tresizeUnit: \"%\",\n *\t\t\t\t\tresizeOptions: [ {\n *\t\t\t\t\t\tname: 'resizeImage:original',\n *\t\t\t\t\t\tvalue: null\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:50',\n *\t\t\t\t\t\tvalue: '50'\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:75',\n *\t\t\t\t\t\tvalue: '75'\n *\t\t\t\t\t} ]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * **Resizing images using a dropdown**\n *\n * With resize options defined, you can decide whether you want to display them as a dropdown or as standalone buttons.\n * For the dropdown, you need to pass only the `resizeImage` token to the\n{@link module:image/image~ImageConfig#toolbar `config.image.toolbar`}. The dropdown contains all defined options by default:\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\timage: {\n *\t\t\t\t\tresizeUnit: \"%\",\n *\t\t\t\t\tresizeOptions: [ {\n *\t\t\t\t\t\tname: 'resizeImage:original',\n *\t\t\t\t\t\tvalue: null\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:50',\n *\t\t\t\t\t\tvalue: '50'\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:75',\n *\t\t\t\t\t\tvalue: '75'\n *\t\t\t\t\t} ],\n *\t\t\t\t\ttoolbar: [ 'resizeImage', ... ],\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * **Resizing images using individual buttons**\n *\n * If you want to have separate buttons for {@link module:image/imageresize/imageresizebuttons~ImageResizeOption each option},\n * pass their names to the {@link module:image/image~ImageConfig#toolbar `config.image.toolbar`} instead. Please keep in mind\n * that this time **you must define the additional\n * {@link module:image/imageresize/imageresizebuttons~ImageResizeOption `icon` property}**:\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\timage: {\n *\t\t\t\t\tresizeUnit: \"%\",\n *\t\t\t\t\tresizeOptions: [ {\n *\t\t\t\t\t\tname: 'resizeImage:original',\n *\t\t\t\t\t\tvalue: null,\n *\t\t\t\t\t\ticon: 'original'\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:25',\n *\t\t\t\t\t\tvalue: '25',\n *\t\t\t\t\t\ticon: 'small'\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:50',\n *\t\t\t\t\t\tvalue: '50',\n *\t\t\t\t\t\ticon: 'medium'\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:75',\n *\t\t\t\t\t\tvalue: '75',\n *\t\t\t\t\t\ticon: 'large'\n *\t\t\t\t\t} ],\n *\t\t\t\t\ttoolbar: [ 'resizeImage:25', 'resizeImage:50', 'resizeImage:75', 'resizeImage:original', ... ],\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * **Customizing resize button labels**\n *\n * You can set your own label for each resize button. To do that, add the `label` property like in the example below.\n *\n * * When using the **dropdown**, the labels are displayed on the list of all options when you open the dropdown.\n * * When using **standalone buttons**, the labels will are displayed as tooltips when a user hovers over the button.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\timage: {\n *\t\t\t\t\tresizeUnit: \"%\",\n *\t\t\t\t\tresizeOptions: [ {\n *\t\t\t\t\t\tname: 'resizeImage:original',\n *\t\t\t\t\t\tvalue: null,\n *\t\t\t\t\t\tlabel: 'Original size'\n *\t\t\t\t\t\t// Note: add the \"icon\" property if you're configuring a standalone button.\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:50',\n *\t\t\t\t\t\tvalue: '50',\n *\t\t\t\t\t\tlabel: 'Medium size'\n *\t\t\t\t\t\t// Note: add the \"icon\" property if you're configuring a standalone button.\n *\t\t\t\t\t},\n *\t\t\t\t\t{\n *\t\t\t\t\t\tname: 'resizeImage:75',\n *\t\t\t\t\t\tvalue: '75',\n *\t\t\t\t\t\tlabel: 'Large size'\n *\t\t\t\t\t\t// Note: add the \"icon\" property if you're configuring a standalone button.\n *\t\t\t\t\t} ]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * **Default value**\n *\n * The following configuration is used by default:\n *\n *\t\tresizeOptions = [\n *\t\t\t{\n *\t\t\t\tname: 'resizeImage:original',\n *\t\t\t\tvalue: null,\n *\t\t\t\ticon: 'original'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tname: 'resizeImage:25',\n *\t\t\t\tvalue: '25',\n *\t\t\t\ticon: 'small'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tname: 'resizeImage:50',\n *\t\t\t\tvalue: '50',\n *\t\t\t\ticon: 'medium'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tname: 'resizeImage:75',\n *\t\t\t\tvalue: '75',\n *\t\t\t\ticon: 'large'\n *\t\t\t}\n *\t\t];\n *\n * @member {Array.<module:image/imageresize/imageresizebuttons~ImageResizeOption>} module:image/image~ImageConfig#resizeOptions\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 link/link\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport LinkEditing from './linkediting';\nimport LinkUI from './linkui';\nimport AutoLink from './autolink';\n\n/**\n * The link plugin.\n *\n * This is a \"glue\" plugin that loads the {@link module:link/linkediting~LinkEditing link editing feature}\n * and {@link module:link/linkui~LinkUI link UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Link extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ LinkEditing, LinkUI, AutoLink ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Link';\n\t}\n}\n\n/**\n * The configuration of the {@link module:link/link~Link} feature.\n *\n * Read more in {@link module:link/link~LinkConfig}.\n *\n * @member {module:link/link~LinkConfig} module:core/editor/editorconfig~EditorConfig#link\n */\n\n/**\n * The configuration of the {@link module:link/link~Link link feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tlink: ... // Link feature configuration.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n * @interface LinkConfig\n */\n\n/**\n * When set, the editor will add the given protocol to the link when the user creates a link without one.\n * For example, when the user is creating a link and types `ckeditor.com` in the link form input, during link submission\n * the editor will automatically add the `http://` protocol, so the link will look as follows: `http://ckeditor.com`.\n *\n * The feature also provides email address auto-detection. When you submit `hello@example.com`,\n * the plugin will automatically change it to `mailto:hello@example.com`.\n *\n * \t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\tlink: {\n * \t\t\t\t\tdefaultProtocol: 'http://'\n * \t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * **NOTE:** If no configuration is provided, the editor will not auto-fix the links.\n *\n * @member {String} module:link/link~LinkConfig#defaultProtocol\n */\n\n/**\n * When set to `true`, the `target=\"blank\"` and `rel=\"noopener noreferrer\"` attributes are automatically added to all external links\n * in the editor. \"External links\" are all links in the editor content starting with `http`, `https`, or `//`.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tlink: {\n *\t\t\t\t\taddTargetToExternalLinks: true\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * Internally, this option activates a predefined {@link module:link/link~LinkConfig#decorators automatic link decorator}\n * that extends all external links with the `target` and `rel` attributes.\n *\n * **Note**: To control the `target` and `rel` attributes of specific links in the edited content, a dedicated\n * {@link module:link/link~LinkDecoratorManualDefinition manual} decorator must be defined in the\n * {@link module:link/link~LinkConfig#decorators `config.link.decorators`} array. In such scenario,\n * the `config.link.addTargetToExternalLinks` option should remain `undefined` or `false` to not interfere with the manual decorator.\n *\n * It is possible to add other {@link module:link/link~LinkDecoratorAutomaticDefinition automatic}\n * or {@link module:link/link~LinkDecoratorManualDefinition manual} link decorators when this option is active.\n *\n * More information about decorators can be found in the {@link module:link/link~LinkConfig#decorators decorators configuration}\n * reference.\n *\n * @default false\n * @member {Boolean} module:link/link~LinkConfig#addTargetToExternalLinks\n */\n\n/**\n * Decorators provide an easy way to configure and manage additional link attributes in the editor content. There are\n * two types of link decorators:\n *\n * * {@link module:link/link~LinkDecoratorAutomaticDefinition Automatic} &ndash; They match links against predefined rules and\n * manage their attributes based on the results.\n * * {@link module:link/link~LinkDecoratorManualDefinition Manual} &ndash; They allow users to control link attributes individually,\n * using the editor UI.\n *\n * Link decorators are defined as objects with key-value pairs, where the key is the name provided for a given decorator and the\n * value is the decorator definition.\n *\n * The name of the decorator also corresponds to the {@glink framework/guides/architecture/editing-engine#text-attributes text attribute}\n * in the model. For instance, the `isExternal` decorator below is represented as a `linkIsExternal` attribute in the model.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tlink: {\n *\t\t\t\t\tdecorators: {\n *\t\t\t\t\t\tisExternal: {\n *\t\t\t\t\t\t\tmode: 'automatic',\n *\t\t\t\t\t\t\tcallback: url => url.startsWith( 'http://' ),\n *\t\t\t\t\t\t\tattributes: {\n *\t\t\t\t\t\t\t\ttarget: '_blank',\n *\t\t\t\t\t\t\t\trel: 'noopener noreferrer'\n *\t\t\t\t\t\t\t}\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\tisDownloadable: {\n *\t\t\t\t\t\t\tmode: 'manual',\n *\t\t\t\t\t\t\tlabel: 'Downloadable',\n *\t\t\t\t\t\t\tattributes: {\n *\t\t\t\t\t\t\t\tdownload: 'file.png',\n *\t\t\t\t\t\t\t}\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t// ...\n *\t\t\t\t\t}\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * To learn more about the configuration syntax, check out the {@link module:link/link~LinkDecoratorAutomaticDefinition automatic}\n * and {@link module:link/link~LinkDecoratorManualDefinition manual} decorator option reference.\n *\n * **Warning:** Currently, link decorators work independently of one another and no conflict resolution mechanism exists.\n * For example, configuring the `target` attribute using both an automatic and a manual decorator at the same time could end up with\n * quirky results. The same applies if multiple manual or automatic decorators were defined for the same attribute.\n *\n * **Note**: Since the `target` attribute management for external links is a common use case, there is a predefined automatic decorator\n * dedicated for that purpose which can be enabled by turning a single option on. Check out the\n * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}\n * configuration description to learn more.\n *\n * See also the {@glink features/link#custom-link-attributes-decorators link feature guide} for more information.\n *\n * @member {Object.<String, module:link/link~LinkDecoratorDefinition>} module:link/link~LinkConfig#decorators\n */\n\n/**\n * A link decorator definition. Two types implement this defition:\n *\n * * {@link module:link/link~LinkDecoratorManualDefinition}\n * * {@link module:link/link~LinkDecoratorAutomaticDefinition}\n *\n * Refer to their document for more information about available options or to the\n * {@glink features/link#custom-link-attributes-decorators link feature guide} for general information.\n *\n * @interface LinkDecoratorDefinition\n */\n\n/**\n * Link decorator type.\n *\n * Check out the {@glink features/link#custom-link-attributes-decorators link feature guide} for more information.\n *\n * @member {'manual'|'automatic'} module:link/link~LinkDecoratorDefinition#mode\n */\n\n/**\n * Describes an automatic {@link module:link/link~LinkConfig#decorators link decorator}. This decorator type matches\n * all links in the editor content against a function that decides whether the link should receive a predefined set of attributes.\n *\n * It takes an object with key-value pairs of attributes and a callback function that must return a Boolean value based on the link's\n * `href` (URL). When the callback returns `true`, attributes are applied to the link.\n *\n * For example, to add the `target=\"_blank\"` attribute to all links in the editor starting with `http://`, the\n * configuration could look like this:\n *\n *\t\t{\n *\t\t\tmode: 'automatic',\n *\t\t\tcallback: url => url.startsWith( 'http://' ),\n *\t\t\tattributes: {\n *\t\t\t\ttarget: '_blank'\n *\t\t\t}\n *\t\t}\n *\n * **Note**: Since the `target` attribute management for external links is a common use case, there is a predefined automatic decorator\n * dedicated for that purpose that can be enabled by turning a single option on. Check out the\n * {@link module:link/link~LinkConfig#addTargetToExternalLinks `config.link.addTargetToExternalLinks`}\n * configuration description to learn more.\n *\n * @typedef {Object} module:link/link~LinkDecoratorAutomaticDefinition\n * @property {'automatic'} mode Link decorator type. It is `'automatic'` for all automatic decorators.\n * @property {Function} callback Takes a `url` as a parameter and returns `true` if the `attributes` should be applied to the link.\n * @property {Object} attributes Key-value pairs used as link attributes added to the output during the\n * {@glink framework/guides/architecture/editing-engine#conversion downcasting}.\n * Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.\n */\n\n/**\n * Describes a manual {@link module:link/link~LinkConfig#decorators link decorator}. This decorator type is represented in\n * the link feature's {@link module:link/linkui user interface} as a switch that the user can use to control the presence\n * of a predefined set of attributes.\n *\n * For instance, to allow the users to manually control the presence of the `target=\"_blank\"` and\n * `rel=\"noopener noreferrer\"` attributes on specific links, the decorator could look as follows:\n *\n *\t\t{\n *\t\t\tmode: 'manual',\n *\t\t\tlabel: 'Open in a new tab',\n *\t\t\tdefaultValue: true,\n *\t\t\tattributes: {\n *\t\t\t\ttarget: '_blank',\n *\t\t\t\trel: 'noopener noreferrer'\n *\t\t\t}\n *\t\t}\n *\n * @typedef {Object} module:link/link~LinkDecoratorManualDefinition\n * @property {'manual'} mode Link decorator type. It is `'manual'` for all manual decorators.\n * @property {String} label The label of the UI button that the user can use to control the presence of link attributes.\n * @property {Object} attributes Key-value pairs used as link attributes added to the output during the\n * {@glink framework/guides/architecture/editing-engine#conversion downcasting}.\n * Attributes should follow the {@link module:engine/view/elementdefinition~ElementDefinition} syntax.\n * @property {Boolean} [defaultValue] Controls whether the decorator is \"on\" by default.\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 list/list\n */\n\nimport ListEditing from './listediting';\nimport ListUI from './listui';\n\nimport { Plugin } from 'ckeditor5/src/core';\n\n/**\n * The list feature.\n *\n * This is a \"glue\" plugin that loads the {@link module:list/listediting~ListEditing list editing feature}\n * and {@link module:list/listui~ListUI list UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class List extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ListEditing, ListUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'List';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/liststyle\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport ListStyleEditing from './liststyleediting';\nimport ListStyleUI from './liststyleui';\n\n/**\n * The list style feature.\n *\n * This is a \"glue\" plugin that loads the {@link module:list/liststyleediting~ListStyleEditing list style editing feature}\n * and the {@link module:list/liststyleui~ListStyleUI list style UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ListStyle extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ListStyleEditing, ListStyleUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'ListStyle';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module list/todolist\n */\n\nimport TodoListEditing from './todolistediting';\nimport TodoListUI from './todolistui';\nimport { Plugin } from 'ckeditor5/src/core';\nimport '../theme/todolist.css';\n\n/**\n * The to-do list feature.\n *\n * This is a \"glue\" plugin that loads the {@link module:list/todolistediting~TodoListEditing to-do list editing feature}\n * and the {@link module:list/todolistui~TodoListUI to-do list UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TodoList extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TodoListEditing, TodoListUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TodoList';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paste-from-office/pastefromoffice\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { ClipboardPipeline } from 'ckeditor5/src/clipboard';\n\nimport GoogleDocsNormalizer from './normalizers/googledocsnormalizer';\nimport MSWordNormalizer from './normalizers/mswordnormalizer';\n\n/**\n * The Paste from Office plugin.\n *\n * This plugin handles content pasted from Office apps and transforms it (if necessary)\n * to a valid structure which can then be understood by the editor features.\n *\n * Transformation is made by a set of predefined {@link module:paste-from-office/normalizer~Normalizer normalizers}.\n * This plugin includes following normalizers:\n * * {@link module:paste-from-office/normalizers/mswordnormalizer~MSWordNormalizer Microsoft Word normalizer}\n * * {@link module:paste-from-office/normalizers/googledocsnormalizer~GoogleDocsNormalizer Google Docs normalizer}\n *\n * For more information about this feature check the {@glink api/paste-from-office package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class PasteFromOffice extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'PasteFromOffice';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ ClipboardPipeline ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst viewDocument = editor.editing.view.document;\n\t\tconst normalizers = [];\n\n\t\tnormalizers.push( new MSWordNormalizer( viewDocument ) );\n\t\tnormalizers.push( new GoogleDocsNormalizer( viewDocument ) );\n\n\t\teditor.plugins.get( 'ClipboardPipeline' ).on(\n\t\t\t'inputTransformation',\n\t\t\t( evt, data ) => {\n\t\t\t\tif ( data.isTransformedWithPasteFromOffice ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst htmlString = data.dataTransfer.getData( 'text/html' );\n\t\t\t\tconst activeNormalizer = normalizers.find( normalizer => normalizer.isActive( htmlString ) );\n\n\t\t\t\tif ( activeNormalizer ) {\n\t\t\t\t\tactiveNormalizer.execute( data );\n\n\t\t\t\t\tdata.isTransformedWithPasteFromOffice = true;\n\t\t\t\t}\n\t\t\t},\n\t\t\t{ priority: 'high' }\n\t\t);\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module table/table\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Widget } from 'ckeditor5/src/widget';\n\nimport TableEditing from './tableediting';\nimport TableUI from './tableui';\nimport TableSelection from './tableselection';\nimport TableClipboard from './tableclipboard';\nimport TableKeyboard from './tablekeyboard';\nimport TableMouse from './tablemouse';\n\nimport '../theme/table.css';\n\n/**\n * The table plugin.\n *\n * For a detailed overview, check the {@glink features/table Table feature documentation}.\n *\n * This is a \"glue\" plugin that loads the following table features:\n *\n * * {@link module:table/tableediting~TableEditing editing feature},\n * * {@link module:table/tableselection~TableSelection selection feature},\n * * {@link module:table/tablekeyboard~TableKeyboard keyboard navigation feature},\n * * {@link module:table/tablemouse~TableMouse mouse selection feature},\n * * {@link module:table/tableclipboard~TableClipboard clipboard feature},\n * * {@link module:table/tableui~TableUI UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Table extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableEditing, TableUI, TableSelection, TableMouse, TableKeyboard, TableClipboard, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Table';\n\t}\n}\n\n/**\n * The configuration of the table feature. Used by the table feature in the `@ckeditor/ckeditor5-table` package.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n * \t\t\t\ttable: ... // Table feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface TableConfig\n */\n\n/**\n * The configuration of the {@link module:table/table~Table} feature.\n *\n * Read more in {@link module:table/table~TableConfig}.\n *\n * @member {module:table/table~TableConfig} module:core/editor/editorconfig~EditorConfig#table\n */\n\n/**\n * An array of color definitions (either strings or objects).\n *\n *\t\tconst colors = [\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 60%)',\n *\t\t\t\tlabel: 'Grey'\n *\t\t\t},\n *\t\t\t'hsl(0, 0%, 80%)',\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\tlabel: 'Light grey'\n *\t\t\t},\n *\t\t\t{\n *\t\t\t\tcolor: 'hsl(0, 0%, 100%)',\n *\t\t\t\tlabel: 'White',\n *\t\t\t\thasBorder: true\n *\t\t\t},\n *\t\t\t'#FF0000'\n *\t\t]\n *\n * Usually used as a configuration parameter, for instance in\n * {@link module:table/table~TableConfig#tableProperties `config.table.tableProperties`}\n * or {@link module:table/table~TableConfig#tableCellProperties `config.table.tableCellProperties`}.\n *\n * @typedef {Array.<String|Object>} module:table/table~TableColorConfig\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 table/tabletoolbar\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { WidgetToolbarRepository } from 'ckeditor5/src/widget';\nimport { getSelectedTableWidget, getTableWidgetAncestor } from './utils/ui/widget';\n\n/**\n * The table toolbar class. It creates toolbars for the table feature and its content (for now only for the table cell content).\n *\n * The table toolbar shows up when a table widget is selected. Its components (e.g. buttons) are created based on the\n * {@link module:table/table~TableConfig#tableToolbar `table.tableToolbar` configuration option}.\n *\n * Table content toolbar shows up when the selection is inside the content of a table. It creates its component based on the\n * {@link module:table/table~TableConfig#contentToolbar `table.contentToolbar` configuration option}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableToolbar extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ WidgetToolbarRepository ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableToolbar';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tafterInit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\t\tconst widgetToolbarRepository = editor.plugins.get( WidgetToolbarRepository );\n\n\t\tconst tableContentToolbarItems = editor.config.get( 'table.contentToolbar' );\n\n\t\tconst tableToolbarItems = editor.config.get( 'table.tableToolbar' );\n\n\t\tif ( tableContentToolbarItems ) {\n\t\t\twidgetToolbarRepository.register( 'tableContent', {\n\t\t\t\tariaLabel: t( 'Table toolbar' ),\n\t\t\t\titems: tableContentToolbarItems,\n\t\t\t\tgetRelatedElement: getTableWidgetAncestor\n\t\t\t} );\n\t\t}\n\n\t\tif ( tableToolbarItems ) {\n\t\t\twidgetToolbarRepository.register( 'table', {\n\t\t\t\tariaLabel: t( 'Table toolbar' ),\n\t\t\t\titems: tableToolbarItems,\n\t\t\t\tgetRelatedElement: getSelectedTableWidget\n\t\t\t} );\n\t\t}\n\t}\n}\n\n/**\n * Items to be placed in the table content toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * Assuming that you use the {@link module:table/tableui~TableUI} feature, the following toolbar items will be available\n * in {@link module:ui/componentfactory~ComponentFactory}:\n *\n * * `'tableRow'`,\n * * `'tableColumn'`,\n * * `'mergeTableCells'`.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\tcontentToolbar: [ 'tableRow', 'tableColumn', 'mergeTableCells' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:table/table~TableConfig#contentToolbar\n */\n\n/**\n * Items to be placed in the table toolbar.\n * The {@link module:table/tabletoolbar~TableToolbar} plugin is required to make this toolbar work.\n *\n * You can thus configure the toolbar like this:\n *\n *\t\tconst tableConfig = {\n *\t\t\ttableToolbar: [ 'blockQuote' ]\n *\t\t};\n *\n * Of course, the same buttons can also be used in the\n * {@link module:core/editor/editorconfig~EditorConfig#toolbar main editor toolbar}.\n *\n * Read more about configuring the toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.\n *\n * @member {Array.<String>} module:table/table~TableConfig#tableToolbar\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 table/tableproperties\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport TablePropertiesEditing from './tableproperties/tablepropertiesediting';\nimport TablePropertiesUI from './tableproperties/tablepropertiesui';\n\n/**\n * The table properties feature. Enables support for setting properties of tables (size, border, background, etc.).\n *\n * Read more in the {@glink features/table#table-and-cell-styling-tools Table and cell styling tools} section.\n * See also the {@link module:table/tablecellproperties~TableCellProperties} plugin.\n *\n * This is a \"glue\" plugin that loads the\n * {@link module:table/tableproperties/tablepropertiesediting~TablePropertiesEditing table properties editing feature} and\n * the {@link module:table/tableproperties/tablepropertiesui~TablePropertiesUI table properties UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableProperties extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableProperties';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TablePropertiesEditing, TablePropertiesUI ];\n\t}\n}\n\n/**\n * The configuration of the table properties user interface (balloon). It allows to define:\n *\n * * The color palette for the table border color style field (`tableProperties.borderColors`),\n * * The color palette for the table background style field (`tableProperties.backgroundColors`).\n *\n *\t\tconst tableConfig = {\n *\t\t\ttableProperties: {\n *\t\t\t\tborderColors: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\t\t\tlabel: 'Light grey'\n *\t\t\t\t\t},\n *\t\t\t\t\t// ...\n *\t\t\t\t],\n *\t\t\t\tbackgroundColors: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\t\t\tlabel: 'Green'\n *\t\t\t\t\t},\n *\t\t\t\t\t// ...\n *\t\t\t\t]\n *\t\t\t}\n *\t\t};\n *\n * **Note**: The configurations do not impact the data loaded into the editor,\n * i.e. they do not limit or filter the colors in the data. They are used only in the user interface\n * allowing users to pick colors in a more convenient way.\n *\n * The default color palettes for the table background and the table border are the same\n * ({@link module:table/utils/ui/table-properties~defaultColors check out their content}).\n *\n * Both color palette configurations must follow the\n * {@link module:table/table~TableColorConfig table color configuration format}.\n *\n * Read more about configuring the table feature in {@link module:table/table~TableConfig}.\n *\n * @member {Object} module:table/table~TableConfig#tableProperties\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 table/tablecellproperties\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport TableCellPropertiesUI from './tablecellproperties/tablecellpropertiesui';\nimport TableCellPropertiesEditing from './tablecellproperties/tablecellpropertiesediting';\n\n/**\n * The table cell properties feature. Enables support for setting properties of table cells (size, border, background, etc.).\n *\n * Read more in the {@glink features/table#table-and-cell-styling-tools Table and cell styling tools} section.\n * See also the {@link module:table/tableproperties~TableProperties} plugin.\n *\n * This is a \"glue\" plugin that loads the\n * {@link module:table/tablecellproperties/tablecellpropertiesediting~TableCellPropertiesEditing table cell properties editing feature} and\n * the {@link module:table/tablecellproperties/tablecellpropertiesui~TableCellPropertiesUI table cell properties UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class TableCellProperties extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'TableCellProperties';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ TableCellPropertiesEditing, TableCellPropertiesUI ];\n\t}\n}\n\n/**\n * The configuration of the table cell properties user interface (balloon). It allows to define:\n *\n * * The color palette for the cell border color style field (`tableCellProperties.borderColors`),\n * * The color palette for the cell background style field (`tableCellProperties.backgroundColors`).\n *\n *\t\tconst tableConfig = {\n *\t\t\ttableCellProperties: {\n *\t\t\t\tborderColors: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tcolor: 'hsl(0, 0%, 90%)',\n *\t\t\t\t\t\tlabel: 'Light grey'\n *\t\t\t\t\t},\n *\t\t\t\t\t// ...\n *\t\t\t\t],\n *\t\t\t\tbackgroundColors: [\n *\t\t\t\t\t{\n *\t\t\t\t\t\tcolor: 'hsl(120, 75%, 60%)',\n *\t\t\t\t\t\tlabel: 'Green'\n *\t\t\t\t\t},\n *\t\t\t\t\t// ...\n *\t\t\t\t]\n *\t\t\t}\n *\t\t};\n *\n * **Note**: The configurations do not impact the data loaded into the editor,\n * i.e. they do not limit or filter the colors in the data. They are used only in the user interface\n * allowing users to pick colors in a more convenient way.\n *\n * The default color palettes for the cell background and the cell border are the same\n * ({@link module:table/utils/ui/table-properties~defaultColors check out their content}).\n *\n * Both color palette configurations must follow the\n * {@link module:table/table~TableColorConfig table color configuration format}.\n *\n * Read more about configuring the table feature in {@link module:table/table~TableConfig}.\n *\n * @member {Object} module:table/table~TableConfig#tableCellProperties\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 indent/indent\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport IndentEditing from './indentediting';\nimport IndentUI from './indentui';\n\n/**\n * The indent feature.\n *\n * This plugin acts as a single entry point plugin for other features that implement indentation of elements like lists or paragraphs.\n *\n * The compatible features are:\n *\n * * The {@link module:list/list~List} or {@link module:list/listediting~ListEditing} feature for list indentation.\n * * The {@link module:indent/indentblock~IndentBlock} feature for block indentation.\n *\n * This is a \"glue\" plugin that loads the following plugins:\n *\n * * The {@link module:indent/indentediting~IndentEditing indent editing feature}.\n * * The {@link module:indent/indentui~IndentUI indent UI feature}.\n *\n * The dependent plugins register the `'indent'` and `'outdent'` commands and introduce the `'indent'` and `'outdent'` buttons\n * that allow to increase or decrease text indentation of supported elements.\n *\n * **Note**: In order for the commands and buttons to work, at least one of compatible features is required.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Indent extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Indent';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ IndentEditing, IndentUI ];\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module paragraph/paragraphbuttonui\n */\n\nimport Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport icon from '../theme/icons/paragraph.svg';\n\n/**\n * This plugin defines the `'paragraph'` button. It can be used together with\n * {@link module:heading/headingbuttonsui~HeadingButtonsUI} to replace the standard heading dropdown.\n *\n * This plugin is not loaded automatically by the {@link module:paragraph/paragraph~Paragraph} plugin. It must\n * be added manually.\n *\n *\t\tClassicEditor\n *\t\t\t.create( {\n *\t\t\t\tplugins: [ ..., Heading, Paragraph, HeadingButtonsUI, ParagraphButtonUI ]\n *\t\t\t\ttoolbar: [ 'paragraph', 'heading1', 'heading2', 'heading3' ]\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class ParagraphButtonUI extends Plugin {\n\tinit() {\n\t\tconst editor = this.editor;\n\t\tconst t = editor.t;\n\n\t\teditor.ui.componentFactory.add( 'paragraph', locale => {\n\t\t\tconst view = new ButtonView( locale );\n\t\t\tconst command = editor.commands.get( 'paragraph' );\n\n\t\t\tview.label = t( 'Paragraph' );\n\t\t\tview.icon = icon;\n\t\t\tview.tooltip = true;\n\t\t\tview.isToggleable = true;\n\t\t\tview.bind( 'isEnabled' ).to( command );\n\t\t\tview.bind( 'isOn' ).to( command, 'value' );\n\n\t\t\tview.on( 'execute', () => {\n\t\t\t\teditor.execute( 'paragraph' );\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg viewBox=\\\"0 0 20 20\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\"><path d=\\\"M10.5 5.5H7v5h3.5a2.5 2.5 0 1 0 0-5zM5 3h6.5v.025a5 5 0 0 1 0 9.95V13H7v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1z\\\"/></svg>\";","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport internalLinkIcon from './icons/trilium.svg';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nexport default class InternalLinkPlugin extends Plugin {\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( 'internalLink', locale => {\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: 'Internal Trilium link (CTRL-L)',\n\t\t\t\ticon: internalLinkIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n // enable internal link only if the editor is not read only\n\t\t\tview.bind('isEnabled').to(editor, 'isReadOnly', isReadOnly => !isReadOnly);\n\n\t\t\tview.on( 'execute', () => {\n\t\t\t\tconst editorEl = editor.editing.view.getDomRoot();\n\t\t\t\tconst component = glob.getComponentByEl(editorEl);\n\n\t\t\t\tcomponent.triggerCommand('addLinkToText');\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\" standalone=\\\"no\\\"?>\\n<svg\\n xmlns:dc=\\\"http://purl.org/dc/elements/1.1/\\\"\\n xmlns:cc=\\\"http://creativecommons.org/ns#\\\"\\n xmlns:rdf=\\\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\\\"\\n xmlns:svg=\\\"http://www.w3.org/2000/svg\\\"\\n xmlns=\\\"http://www.w3.org/2000/svg\\\"\\n xmlns:sodipodi=\\\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\\\"\\n xmlns:inkscape=\\\"http://www.inkscape.org/namespaces/inkscape\\\"\\n version=\\\"1.1\\\"\\n x=\\\"0px\\\"\\n y=\\\"0px\\\"\\n viewBox=\\\"0 0 67.008179 71.908997\\\"\\n enable-background=\\\"new 0 0 100 100\\\"\\n xml:space=\\\"preserve\\\"\\n id=\\\"svg4\\\"\\n sodipodi:docname=\\\"trilium.svg\\\"\\n width=\\\"67.008179\\\"\\n height=\\\"71.908997\\\"\\n inkscape:version=\\\"0.92.3 (2405546, 2018-03-11)\\\"><metadata\\n id=\\\"metadata10\\\"><rdf:RDF><cc:Work\\n rdf:about=\\\"\\\"><dc:format>image/svg+xml</dc:format><dc:type\\n rdf:resource=\\\"http://purl.org/dc/dcmitype/StillImage\\\" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs\\n id=\\\"defs8\\\" /><sodipodi:namedview\\n pagecolor=\\\"#ffffff\\\"\\n bordercolor=\\\"#666666\\\"\\n borderopacity=\\\"1\\\"\\n objecttolerance=\\\"10\\\"\\n gridtolerance=\\\"10\\\"\\n guidetolerance=\\\"10\\\"\\n inkscape:pageopacity=\\\"0\\\"\\n inkscape:pageshadow=\\\"2\\\"\\n inkscape:window-width=\\\"1857\\\"\\n inkscape:window-height=\\\"1053\\\"\\n id=\\\"namedview6\\\"\\n showgrid=\\\"false\\\"\\n fit-margin-top=\\\"0\\\"\\n fit-margin-left=\\\"0\\\"\\n fit-margin-right=\\\"0\\\"\\n fit-margin-bottom=\\\"0\\\"\\n inkscape:zoom=\\\"2.36\\\"\\n inkscape:cx=\\\"33.504176\\\"\\n inkscape:cy=\\\"35.954\\\"\\n inkscape:window-x=\\\"63\\\"\\n inkscape:window-y=\\\"27\\\"\\n inkscape:window-maximized=\\\"1\\\"\\n inkscape:current-layer=\\\"svg4\\\" /><path\\n d=\\\"m 47.470176,30.998 c 0.008,-0.009 0.021,-0.021 0.027,-0.029 0.938,-1.156 -0.823,-13.453 -5.063,-20.125 -1.389,-2.186 -2.239,-3.423 -3.219,-4.719 -3.907,-5.166 -6,-6.125 -6,-6.125 0,0 -13.979,10.735 -13.562,30.27 -1.754,0.065 -11.2179997,7.528 -14.8259997,14.388 -1.206,2.291 -1.856,3.645 -2.493,5.141 -2.53899996,5.957 -2.32999996,8.25 -2.32999996,8.25 0,0 16.27099966,6.79 33.01399966,-3.294 0.007,0.021 0.013,0.046 0.02,0.063 0.537,1.389 12.08,5.979 19.976,5.621 2.587,-0.116 4.084,-0.238 5.696,-0.444 6.424,-0.818 8.298,-2.157 8.298,-2.157 0,0 -2.36,-17.487 -19.538,-26.84 z m -13.179,20.3 c 1.059,-1.183 4.648,-5.853 0.995,-11.315 -0.253,-0.377 -0.496,-0.236 -0.496,-0.236 0,0 0.063,10.822 -5.162,12.359 -5.225,1.537 -13.886,4.4 -20.4269997,0.455 -0.697,-0.42 1.2269997,-13 12.8469997,-19.377 0.546,1.599 2.836,6.854 9.292,6.409 0.453,-0.031 0.453,-0.313 0.453,-0.313 0,0 -9.422,-5.328 -8.156,-10.625 1.266,-5.297 3.089,-14.236 9.766,-17.948 0.714,-0.397 10.746,7.593 10.417,20.94 -1.606,-0.319 -7.377,-1.004 -10.226,4.864 -0.198,0.409 0.046,0.549 0.046,0.549 0,0 9.31,-5.521 13.275,-1.789 3.965,3.733 10.813,9.763 10.71,17.4 -0.01,0.817 -11.924,5.542 -23.334,-1.373 z M 19.117176,21.1 c 0,0 -0.991,3.241 -0.603,7.524 L 5.1211763,21.1 c 10e-4,0 6.2209997,-4.214 13.9959997,0 z M 4.6971763,21.985 18.041176,29.597 c -3.872,1.872 -6.142,4.388 -6.142,4.388 -7.6149997,-4.499 -7.2019997,-12 -7.2019997,-12 z M 55.791176,35.019 c 0,0 -2.321,-2.471 -6.23,-4.263 l 13.187,-7.881 c -10e-4,0 0.564,7.493 -6.957,12.144 z m 6.4,-12.951 -13.237,7.794 c 0.3,-4.291 -0.754,-7.511 -0.754,-7.511 7.687,-4.371 13.991,-0.283 13.991,-0.283 z m -36.611,37.665 c 0,0 3.309,-0.737 6.845,-3.185 l 0.056,15.361 c 0,10e-4 -6.733,-3.333 -6.901,-12.176 z m 7.88,12.11 0.044,-15.362 c 3.539,2.445 6.846,3.181 6.846,3.181 -0.16,8.844 -6.89,12.181 -6.89,12.181 z\\\"\\n id=\\\"path2\\\"\\n inkscape:connector-curvature=\\\"0\\\" /></svg>\";","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport markdownIcon from './icons/markdown-mark.svg';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\n\nexport default class MarkdownImportPlugin extends Plugin {\n\tinit() {\n\t\tconst editor = this.editor;\n\n\t\teditor.ui.componentFactory.add( 'markdownImport', locale => {\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: 'Markdown import from clipboard',\n\t\t\t\ticon: markdownIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\t// Callback executed once the image is clicked.\n\t\t\tview.on( 'execute', () => {\n\t\t\t\tglob.importMarkdownInline();\n\t\t\t} );\n\n\t\t\treturn view;\n\t\t} );\n\t}\n}\n","export default \"<svg xmlns=\\\"http://www.w3.org/2000/svg\\\" width=\\\"208\\\" height=\\\"128\\\" viewBox=\\\"0 0 208 128\\\"><rect width=\\\"198\\\" height=\\\"118\\\" x=\\\"5\\\" y=\\\"5\\\" ry=\\\"10\\\" stroke=\\\"#000\\\" stroke-width=\\\"10\\\" fill=\\\"none\\\"/><path d=\\\"M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39zm125 0l-30-33h20V30h20v35h20z\\\"/></svg>\";","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport scissorsIcon from './icons/scissors.svg';\nimport ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';\nimport HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';\n\nexport default class CutToNotePlugin extends Plugin {\n\tinit() {\n\t\tthis.htmlDataProcessor = new HtmlDataProcessor();\n\n\t\tthis.editor.ui.componentFactory.add( 'cutToNote', locale => {\n\t\t\tconst view = new ButtonView( locale );\n\n\t\t\tview.set( {\n\t\t\t\tlabel: 'Cut & paste selection to sub-note',\n\t\t\t\ticon: scissorsIcon,\n\t\t\t\ttooltip: true\n\t\t\t} );\n\n\t\t\t// Callback executed once the image is clicked.\n\t\t\tview.on('execute', () => {\n\t\t\t\tconst editorEl = this.editor.editing.view.getDomRoot();\n\t\t\t\tconst component = glob.getComponentByEl(editorEl);\n\n\t\t\t\tcomponent.triggerCommand('cutIntoNote');\n\t\t\t});\n\n\t\t\treturn view;\n\t\t} );\n\n\t\twindow.cutToNote = {\n\t\t\tgetSelectedHtml: () => this.getSelectedHtml(),\n\t\t\tremoveSelection: () => this.removeSelection()\n\t\t};\n\t}\n\n\tgetSelectedHtml() {\n\t\tconst model = this.editor.model;\n\t\tconst document = model.document;\n\n\t\tconst content = this.editor.data.toView(model.getSelectedContent(document.selection));\n\n\t\treturn this.htmlDataProcessor.toData(content);\n\t}\n\n\tasync removeSelection() {\n\t\tconst model = this.editor.model;\n\n\t\tmodel.deleteContent(model.document.selection);\n\n\t\tconst editorEl = this.editor.editing.view.getDomRoot();\n\t\tconst component = glob.getComponentByEl(editorEl);\n\n\t\tawait component.triggerCommand('saveNoteDetailNow');\n\t}\n}\n","export default \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->\\n<!DOCTYPE svg PUBLIC \\\"-//W3C//DTD SVG 1.1//EN\\\" \\\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\\\">\\n<svg version=\\\"1.1\\\" xmlns=\\\"http://www.w3.org/2000/svg\\\" xmlns:xlink=\\\"http://www.w3.org/1999/xlink\\\" x=\\\"0px\\\" y=\\\"0px\\\" viewBox=\\\"0 0 1000 1000\\\" enable-background=\\\"new 0 0 1000 1000\\\" xml:space=\\\"preserve\\\">\\n<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>\\n<g><g><path d=\\\"M853.9,754.9c-26-45.4-66.5-76.2-109.1-87.8c-33.7-9.2-68.7-6.4-98.9,10.7l-90-157.3C611.6,409.5,736.5,160.5,759,121.2C788,70.4,736,10,736,10L500,422.8L264,10c0,0-52,60.4-22.9,111.2c22.5,39.3,147.5,288.3,203.1,399.3l-89.9,157.3c-30.2-17.1-65.3-19.9-98.9-10.7c-42.7,11.6-83.1,42.3-109.1,87.8c-46.8,81.7-28.9,179.7,39.7,219c30.4,17.5,65.7,20.3,99.6,11.1c42.6-11.6,83.1-42.4,109.1-87.7c11.4-20,18.9-41,22.8-61.8v0c0-0.2,0-0.3,0.2-0.5c0.2-1.7,0.5-3.5,0.7-5.4c19.3-129.5,55.8-195.7,81.6-227.8c25.9,32.1,62.4,98.3,81.7,227.8c0.2,1.9,0.5,3.6,0.7,5.4c0.1,0.2,0.1,0.3,0.2,0.5v0c3.9,20.8,11.4,41.8,22.7,61.8c26,45.3,66.5,76.1,109.2,87.7c34,9.2,69.2,6.4,99.7-11.1C882.8,934.5,900.6,836.5,853.9,754.9z M327.9,858.9c-14.8,25.8-38.1,45.2-62.5,51.8c-10.8,3-26.7,4.7-41.3-3.6c-31.1-17.8-36.2-70.1-11.1-114c15-26,37.8-45,62.5-51.8c10.7-2.9,26.7-4.7,41.3,3.6C347.9,762.7,353,814.9,327.9,858.9z M775.9,907.1c-14.6,8.4-30.4,6.6-41.3,3.6c-24.4-6.6-47.7-26-62.5-51.8c-25.1-44-20-96.2,11.1-114c14.7-8.3,30.6-6.5,41.3-3.6C749.3,748,772.1,767,787,793C812.1,837,807.1,889.3,775.9,907.1z\\\"/><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g>\\n</svg>\";","/**\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 font/font\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport FontFamily from './fontfamily';\nimport FontSize from './fontsize';\nimport FontColor from './fontcolor';\nimport FontBackgroundColor from './fontbackgroundcolor';\n\n/**\n * A plugin that enables a set of text styling features:\n *\n * * {@link module:font/fontsize~FontSize},\n * * {@link module:font/fontfamily~FontFamily}.\n * * {@link module:font/fontcolor~FontColor},\n * * {@link module:font/fontbackgroundcolor~FontBackgroundColor}.\n *\n * For a detailed overview, check the {@glink features/font Font feature} documentation\n * and the {@glink api/font package page}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Font extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ FontFamily, FontSize, FontColor, FontBackgroundColor ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Font';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module code-block/codeblock\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport CodeBlockEditing from './codeblockediting';\nimport CodeBlockUI from './codeblockui';\n\n/**\n * The code block plugin.\n *\n * For more information about this feature check the {@glink api/code-block package page} and the\n * {@glink features/code-blocks code block feature guide}.\n *\n * This is a \"glue\" plugin that loads the {@link module:code-block/codeblockediting~CodeBlockEditing code block editing feature}\n * and the {@link module:code-block/codeblockui~CodeBlockUI code block UI feature}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class CodeBlock extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ CodeBlockEditing, CodeBlockUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'CodeBlock';\n\t}\n}\n\n/**\n * The configuration of the {@link module:code-block/codeblock~CodeBlock} feature.\n *\n * Read more in {@link module:code-block/codeblock~CodeBlockConfig}.\n *\n * @member {module:code-block/codeblock~CodeBlockConfig} module:core/editor/editorconfig~EditorConfig#codeBlock\n */\n\n/**\n * The configuration of the {@link module:code-block/codeblock~CodeBlock code block feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tcodeBlock: ... // The code block feature configuration.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface CodeBlockConfig\n */\n\n/**\n * The code block language descriptor. See {@link module:code-block/codeblock~CodeBlockConfig#languages} to learn more.\n *\n *\t\t{\n *\t\t\t language: 'javascript',\n *\t\t\t label: 'JavaScript'\n *\t\t}\n *\n * @typedef {Object} module:code-block/codeblock~CodeBlockLanguageDefinition\n * @property {String} language The name of the language that will be stored in the model attribute. Also, when `class`\n * is not specified, it will be used to create the CSS class associated with the language (prefixed by \"language-\").\n * @property {String} label The humanreadable label associated with the language and displayed in the UI.\n * @property {String} [class] The CSS class associated with the language. When not specified the `language`\n * property is used to create a class prefixed by \"language-\".\n */\n\n/**\n * The list of code languages available in the user interface to choose for a particular code block.\n *\n * The language of the code block is represented as a CSS class (by default prefixed by \"language-\") set on the\n * `<code>` element, both when editing and in the editor data. The CSS class associated with the language\n * can be used by thirdparty code syntax highlighters to detect and apply the correct highlighting.\n *\n * For instance, this language configuration:\n *\n *\t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcodeBlock: {\n *\t\t\t\t\tlanguages: [\n *\t\t\t\t\t\t// ...\n *\t\t\t\t\t\t{ language: 'javascript', label: 'JavaScript' },\n *\t\t\t\t\t\t// ...\n *\t\t\t\t\t]\n *\t\t\t\t}\n *\t\t} )\n *\t\t.then( ... )\n *\t\t.catch( ... );\n *\n * will result in the following structure of JavaScript code blocks in the editor editing and data:\n *\n *\t\t<pre><code class=\"language-javascript\">window.alert( 'Hello world!' )</code></pre>\n *\n * You can customize the CSS class by specifying an optional `class` property in the language definition.\n * You can set **multiple classes** but **only the first one** will be used as defining language class:\n *\n *\t\tClassicEditor\n *\t\t\t.create( document.querySelector( '#editor' ), {\n *\t\t\t\tcodeBlock: {\n *\t\t\t\t\tlanguages: [\n *\t\t\t\t\t\t// Do not render the CSS class for the plain text code blocks.\n *\t\t\t\t\t\t{ language: 'plaintext', label: 'Plain text', class: '' },\n *\n *\t\t\t\t\t\t// Use the \"php-code\" class for PHP code blocks.\n *\t\t\t\t\t\t{ language: 'php', label: 'PHP', class: 'php-code' },\n *\n *\t\t\t\t\t\t// Use the \"js\" class for JavaScript code blocks.\n *\t\t\t\t\t\t// Note that only the first (\"js\") class will determine the language of the block when loading data.\n *\t\t\t\t\t\t{ language: 'javascript', label: 'JavaScript', class: 'js javascript js-code' },\n *\n *\t\t\t\t\t\t// Python code blocks will have the default \"language-python\" CSS class.\n *\t\t\t\t\t\t{ language: 'python', label: 'Python' }\n *\t\t\t\t\t]\n *\t\t\t\t}\n *\t\t} )\n *\t\t.then( ... )\n *\t\t.catch( ... );\n *\n * The default value of the language configuration is as follows:\n *\n *\t\tlanguages: [\n *\t\t\t{ language: 'plaintext', label: 'Plain text' }, // The default language.\n *\t\t\t{ language: 'c', label: 'C' },\n *\t\t\t{ language: 'cs', label: 'C#' },\n *\t\t\t{ language: 'cpp', label: 'C++' },\n *\t\t\t{ language: 'css', label: 'CSS' },\n *\t\t\t{ language: 'diff', label: 'Diff' },\n *\t\t\t{ language: 'html', label: 'HTML' },\n *\t\t\t{ language: 'java', label: 'Java' },\n *\t\t\t{ language: 'javascript', label: 'JavaScript' },\n *\t\t\t{ language: 'php', label: 'PHP' },\n *\t\t\t{ language: 'python', label: 'Python' },\n *\t\t\t{ language: 'ruby', label: 'Ruby' },\n *\t\t\t{ language: 'typescript', label: 'TypeScript' },\n *\t\t\t{ language: 'xml', label: 'XML' }\n *\t\t]\n *\n * **Note**: The first language defined in the configuration is considered the default one. This means it will be\n * applied to code blocks loaded from the data that have no CSS `class` specified (or no matching `class` in the configuration).\n * It will also be used when creating new code blocks using the main UI button. By default it is \"Plain text\".\n *\n * @member {Array.<module:code-block/codeblock~CodeBlockLanguageDefinition>} module:code-block/codeblock~CodeBlockConfig#languages\n */\n\n/**\n * A sequence of characters inserted or removed from the code block lines when its indentation\n * is changed by the user, for instance, using <kbd>Tab</kbd> and <kbd>Shift</kbd>+<kbd>Tab</kbd> keys.\n *\n * The default value is a single tab character (\"\t\", `\\u0009` in Unicode).\n *\n * This configuration is used by `indentCodeBlock` and `outdentCodeBlock` commands (instances of\n * {@link module:code-block/indentcodeblockcommand~IndentCodeBlockCommand}).\n *\n * **Note**: Setting this configuration to `false` will disable the code block indentation commands\n * and associated keystrokes.\n *\n * @member {String} module:code-block/codeblock~CodeBlockConfig#indentSequence\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 horizontal-line/horizontalline\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\nimport { Widget } from 'ckeditor5/src/widget';\nimport HorizontalLineEditing from './horizontallineediting';\nimport HorizontalLineUI from './horizontallineui';\n\n/**\n * The horizontal line feature.\n *\n * It provides the possibility to insert a horizontal line into the rich-text editor.\n *\n * For a detailed overview, check the {@glink features/horizontal-line Horizontal line feature} documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class HorizontalLine extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ HorizontalLineEditing, HorizontalLineUI, Widget ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'HorizontalLine';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module remove-format/removeformat\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport RemoveFormatUI from './removeformatui';\nimport RemoveFormatEditing from './removeformatediting';\n\n/**\n * The remove format plugin.\n *\n * This is a \"glue\" plugin which loads the {@link module:remove-format/removeformatediting~RemoveFormatEditing}\n * and {@link module:remove-format/removeformatui~RemoveFormatUI} plugins.\n *\n * For a detailed overview, check out the {@glink features/remove-format remove format} feature documentation.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class RemoveFormat extends Plugin {\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ RemoveFormatEditing, RemoveFormatUI ];\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'RemoveFormat';\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license\n */\n\n/**\n * @module mention/mention\n */\n\nimport { Plugin } from 'ckeditor5/src/core';\n\nimport MentionEditing, { _toMentionAttribute } from './mentionediting';\nimport MentionUI from './mentionui';\n\nimport '../theme/mention.css';\n\n/**\n * The mention plugin.\n *\n * For a detailed overview, check the {@glink features/mentions Mention feature documentation}.\n *\n * @extends module:core/plugin~Plugin\n */\nexport default class Mention extends Plugin {\n\t/**\n\t * Creates a mention attribute value from the provided view element and optional data.\n\t *\n\t *\t\teditor.plugins.get( 'Mention' ).toMentionAttribute( viewElement, { userId: '1234' } );\n\t *\n\t *\t\t// For a view element: <span data-mention=\"@joe\">@John Doe</span>\n\t *\t\t// it will return:\n\t *\t\t// { id: '@joe', userId: '1234', uid: '7a7bc7...', _text: '@John Doe' }\n\t *\n\t * @param {module:engine/view/element~Element} viewElement\n\t * @param {String|Object} [data] Additional data to be stored in the mention attribute.\n\t * @returns {module:mention/mention~MentionAttribute}\n\t */\n\ttoMentionAttribute( viewElement, data ) {\n\t\treturn _toMentionAttribute( viewElement, data );\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get pluginName() {\n\t\treturn 'Mention';\n\t}\n\n\t/**\n\t * @inheritDoc\n\t */\n\tstatic get requires() {\n\t\treturn [ MentionEditing, MentionUI ];\n\t}\n}\n\n/**\n * The configuration of the {@link module:mention/mention~Mention} feature.\n *\n * Read more in {@link module:mention/mention~MentionConfig}.\n *\n * @member {module:mention/mention~MentionConfig} module:core/editor/editorconfig~EditorConfig#mention\n * @type {Array.<module/mention~MentionFeed>}\n */\n\n/**\n * The configuration of the mention feature.\n *\n * Read more about {@glink features/mentions#configuration configuring the mention feature}.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tmention: ... // Mention feature options.\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.\n *\n * @interface MentionConfig\n */\n\n/**\n * The list of mention feeds supported by the editor.\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tplugins: [ Mention, ... ],\n *\t\t\t\tmention: {\n *\t\t\t\t\tfeeds: [\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\tmarker: '@',\n *\t\t\t\t\t\t\tfeed: [ '@Barney', '@Lily', '@Marshall', '@Robin', '@Ted' ]\n *\t\t\t\t\t\t},\n *\t\t\t\t\t\t...\n * \t\t\t\t\t]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * You can provide many mention feeds but they must use different `marker`s.\n * For example, you can use `'@'` to autocomplete people and `'#'` to autocomplete tags.\n *\n * @member {Array.<module:mention/mention~MentionFeed>} module:mention/mention~MentionConfig#feeds\n */\n\n/**\n * The mention feed descriptor. Used in {@link module:mention/mention~MentionConfig `config.mention`}.\n *\n * See {@link module:mention/mention~MentionConfig} to learn more.\n *\n *\t\t// Static configuration.\n *\t\tconst mentionFeedPeople = {\n *\t\t\tmarker: '@',\n *\t\t\tfeed: [ '@Alice', '@Bob', ... ],\n *\t\t\tminimumCharacters: 2\n *\t\t};\n *\n *\t\t// Simple synchronous callback.\n *\t\tconst mentionFeedTags = {\n *\t\t\tmarker: '#',\n *\t\t\tfeed: searchString => {\n *\t\t\t\treturn tags\n *\t\t\t\t\t// Filter the tags list.\n *\t\t\t\t\t.filter( tag => {\n *\t\t\t\t\t\treturn tag.toLowerCase().includes( queryText.toLowerCase() );\n *\t\t\t\t\t} )\n *\t\t\t\t\t// Return 10 items max - needed for generic queries when the list may contain hundreds of elements.\n *\t\t\t\t\t.slice( 0, 10 );\n *\t\t\t}\n * \t\t};\n *\n *\t\tconst tags = [ 'wysiwyg', 'rte', 'rich-text-edior', 'collaboration', 'real-time', ... ];\n *\n *\t\t// Asynchronous callback.\n *\t\tconst mentionFeedPlaceholders = {\n *\t\t\tmarker: '$',\n *\t\t\tfeed: searchString => {\n *\t\t\t\treturn getMatchingPlaceholders( searchString );\n *\t\t\t}\n * \t\t};\n *\n *\t\tfunction getMatchingPlaceholders( searchString ) {\n *\t\t\treturn new Promise( resolve => {\n *\t\t\t\tdoSomeXHRQuery( result => {\n *\t\t\t\t\t// console.log( result );\n *\t\t\t\t\t// -> [ '$name', '$surname', '$postal', ... ]\n *\n *\t\t\t\t\tresolve( result );\n * \t\t\t\t} );\n *\t\t\t} );\n *\t\t}\n *\n * @typedef {Object} module:mention/mention~MentionFeed\n * @property {String} [marker] The character which triggers autocompletion for mention. It must be a single character.\n * @property {Array.<module:mention/mention~MentionFeedItem>|Function} feed Autocomplete items. Provide an array for\n * a static configuration (the mention feature will show matching items automatically) or a function which returns an array of\n * matching items (directly, or via a promise). If a function is passed, it is executed in the context of the editor instance.\n * @property {Number} [minimumCharacters=0] Specifies after how many characters the autocomplete panel should be shown.\n * @property {Function} [itemRenderer] A function that renders a {@link module:mention/mention~MentionFeedItem}\n * to the autocomplete panel.\n */\n\n/**\n * The mention feed item. It may be defined as a string or a plain object.\n *\n * When defining a feed item as a plain object, the `id` property is obligatory. Additional properties\n * can be used when customizing the mention feature bahavior\n * (see {@glink features/mentions#customizing-the-autocomplete-list \"Customizing the autocomplete list\"}\n * and {@glink features/mentions#customizing-the-output \"Customizing the output\"} sections).\n *\n *\t\tClassicEditor\n *\t\t\t.create( editorElement, {\n *\t\t\t\tplugins: [ Mention, ... ],\n *\t\t\t\tmention: {\n *\t\t\t\t\tfeeds: [\n *\t\t\t\t\t\t// Feed items as objects.\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\tmarker: '@',\n *\t\t\t\t\t\t\tfeed: [\n *\t\t\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t\t\tid: '@Barney',\n *\t\t\t\t\t\t\t\t\tfullName: 'Barney Bloom'\n *\t\t\t\t\t\t\t\t},\n *\t\t\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t\t\tid: '@Lily',\n *\t\t\t\t\t\t\t\t\tfullName: 'Lily Smith'\n *\t\t\t\t\t\t\t\t},\n *\t\t\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t\t\tid: '@Marshall',\n *\t\t\t\t\t\t\t\t\tfullName: 'Marshall McDonald'\n *\t\t\t\t\t\t\t\t},\n *\t\t\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t\t\tid: '@Robin',\n *\t\t\t\t\t\t\t\t\tfullName: 'Robin Hood'\n *\t\t\t\t\t\t\t\t},\n *\t\t\t\t\t\t\t\t{\n *\t\t\t\t\t\t\t\t\tid: '@Ted',\n *\t\t\t\t\t\t\t\t\tfullName: 'Ted Cruze'\n *\t\t\t\t\t\t\t\t},\n *\t\t\t\t\t\t\t\t// ...\n *\t\t\t\t\t\t\t]\n *\t\t\t\t\t\t},\n *\n *\t\t\t\t\t\t// Feed items as plain strings.\n *\t\t\t\t\t\t{\n *\t\t\t\t\t\t\tmarker: '#',\n *\t\t\t\t\t\t\tfeed: [ 'wysiwyg', 'rte', 'rich-text-edior', 'collaboration', 'real-time', ... ]\n *\t\t\t\t\t\t},\n * \t\t\t\t\t]\n *\t\t\t\t}\n *\t\t\t} )\n *\t\t\t.then( ... )\n *\t\t\t.catch( ... );\n *\n * @typedef {Object|String} module:mention/mention~MentionFeedItem\n * @property {String} id A unique ID of the mention. It must start with the marker character.\n * @property {String} [text] Text inserted into the editor when creating a mention.\n */\n\n/**\n * Represents a mention in the model.\n *\n * See {@link module:mention/mention~Mention#toMentionAttribute `Mention#toMentionAttribute()`}.\n *\n * @interface module:mention/mention~MentionAttribute\n * @property {String} id The ID of a mention. It identifies the mention item in the mention feed. There can be multiple mentions\n * in the document with the same ID (e.g. the same hashtag being mentioned).\n * @property {String} uid A unique ID of this mention instance. Should be passed as an `option.id` when using\n * {@link module:engine/view/downcastwriter~DowncastWriter#createAttributeElement writer.createAttributeElement()}.\n * @property {String} _text Helper property that stores the text of the inserted mention. Used for detecting a broken mention\n * in the editing area.\n */\n","/**\n * https://github.com/zadam/trilium/issues/978\n */\nexport default function indentBlockShortcutPlugin(editor) {\n\teditor.keystrokes.set( 'Tab', ( data, cancel ) => {\n\t\tconst command = editor.commands.get( 'indentBlock' );\n\n\t\tif ( command.isEnabled && !isInTable() ) {\n\t\t\tcommand.execute();\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\teditor.keystrokes.set( 'Shift+Tab', ( data, cancel ) => {\n\t\tconst command = editor.commands.get( 'outdentBlock' );\n\n\t\tif ( command.isEnabled && !isInTable() ) {\n\t\t\tcommand.execute();\n\t\t\tcancel();\n\t\t}\n\t} );\n\n\t// in table TAB should switch cells\n\tfunction isInTable() {\n\t\tlet el = editor.model.document.selection.getFirstPosition();\n\n\t\twhile (el) {\n\t\t\tif (el.name === 'tableCell') {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tel = el.parent;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","// A simple plugin that extends the remove format feature to consider links.\nexport default function removeFormatLinksPlugin( editor ) {\n\t// Extend the editor schema and mark the \"linkHref\" model attribute as formatting.\n\teditor.model.schema.setAttributeProperties( 'linkHref', {\n\t\tisFormatting: true\n\t} );\n}\n","import Plugin from '@ckeditor/ckeditor5-core/src/plugin';\nimport Widget from '@ckeditor/ckeditor5-widget/src/widget';\n\nimport MathUI from './mathui';\nimport MathEditing from './mathediting';\nimport AutoMath from './automath';\n\nexport default class Math extends Plugin {\n\tstatic get requires() {\n\t\treturn [ MathEditing, MathUI, AutoMath, Widget ];\n\t}\n\n\tstatic get pluginName() {\n\t\treturn 'Math';\n\t}\n}\n"],"sourceRoot":""}