From 52d87246efcee1d6a78a608813df26a364ec854e Mon Sep 17 00:00:00 2001
From: 27Lia
- Edit
+ You’re ready to ask a programming-related question and this form
+ will help guide you through the process.
+
+ Looking to ask a non-programming question? See the topics here to
+ find a relevant site.
+ This is the editor content.&*j;=u%25ay-%>3@81tGe^_z*C7pb9y*Ed^H3t$BIKH2o+olp#$q;)_
zfpjCb_^VFg5fU~K)nf*d*r@BCC>UZ!0&b?AGk_jTPXaSnCuW110wjHPPe^9R^;jo3
zwvzTl)C`Zl5}O2}3lec=hZ*$JnkW#7enKKc)(pM${_$9Hc=Sr_A9Biwe*Y=T?~1CK
z6eZ9uPICjy-sMGbZl$yQmpB&`ouS8v{58__t0$JP%i3R&%QR
%*1_<3D4NX
zeVTi-JGl2uP_2@0F{G({pxQOXt_d{g_CV6b?jNpfUG9;8yle-^4KHRvZs-_2siata
zt+d_T@U$&t*xaD22(fH(W1r$Mo?3dc%Tncm=C6{V9y{v&VT#^1L04vDrLM9qBoZ4@
z6DBN#m57hX7$C(=#$Y5$bJmwA$T8jKD8+6A!-IJwA{WOfs%s}yxUw^?MRZjF$n_KN
z6`_bGXcmE#5e4Ym)aQJ)xg3Pg0@k`iGuHe?f(5LtuzSq=nS^5z>vqU0EuZ&75V%Z{
zYyhRLN^)$c6Ds{f7*FBpE;n5iglx5PkHfWrj3src/App.js
and save to reload.
- Ask a public question
+ Writing a good question
+ step
+
+
+
### ✨ Front-end
+
이미지태그
@@ -34,6 +37,7 @@
## 🎯프로젝트 명
+
- Stackoverflow
## 📅프로젝트 기간
+
- 2023년 8월 4일(금) ~ 2023년 8월 23일(수)
## 🗂️프로젝트 핵심기술 및 기능
+
### ✨ Back-end
+
![Java](https://img.shields.io/badge/java-007396?style=for-the-badge&logo=java&logoColor=white")
![Spring](https://img.shields.io/badge/spring-6DB33F?style=for-the-badge&logo=spring&logoColor=white)
![Spring Boot](https://img.shields.io/badge/spring_boot_jpa-6DB33F?style=for-the-badge&logo=springboot&logoColor=white)
@@ -78,6 +86,7 @@
![Ngrok](https://img.shields.io/badge/ngrok-1F1E37?style=for-the-badge&logo=ngrok&logoColor=white)
### ✨ Front-end
+
![HTML](https://img.shields.io/badge/html5-E34F26?style=for-the-badge&logo=html5&logoColor=white)
![CSS](https://img.shields.io/badge/css-1572B6?style=for-the-badge&logo=css3&logoColor=white)
![JavaScript](https://img.shields.io/badge/javascript-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black)
@@ -85,6 +94,7 @@
![Redux](https://img.shields.io/badge/redux-764ABC?style=for-the-badge&logo=redux&logoColor=white)
## 🛠️협업툴
+
![Github](https://img.shields.io/badge/github-181717?style=for-the-badge&logo=github&logoColor=white)
![Discord](https://img.shields.io/badge/discord-5865F2?style=for-the-badge&logo=discord&logoColor=white)
![Notion](https://img.shields.io/badge/notion-000000?style=for-the-badge&logo=notion&logoColor=white)
diff --git a/client/src/component/Editor.js b/client/src/component/Editor.js
new file mode 100644
index 00000000..e5ec861a
--- /dev/null
+++ b/client/src/component/Editor.js
@@ -0,0 +1,5 @@
+function Editor() {
+ return ;
+}
+
+export default Editor;
diff --git a/client/src/pages/AskQuestionPage.js b/client/src/pages/AskQuestionPage.js
index ebbac211..f0e3c091 100644
--- a/client/src/pages/AskQuestionPage.js
+++ b/client/src/pages/AskQuestionPage.js
@@ -1,4 +1,5 @@
import { styled } from 'styled-components';
+import Editor from '../component/Editor';
const StyleAskPage = styled.div`
background-color: #f8f9f9;
@@ -47,7 +48,8 @@ const StyleAskPage = styled.div`
margin-bottom: 48px;
}
- .title-container {
+ .title-container,
+ .tag-container {
max-width: 800px;
height: 124px;
padding: 24px;
@@ -56,13 +58,15 @@ const StyleAskPage = styled.div`
flex-direction: column;
justify-content: center;
border-radius: 7px;
+ background-color: #ffffff;
}
.explanation-box {
font-size: 13px;
}
- .title-input {
+ .title-input,
+ .tag-input {
height: 33px;
width: 100%;
padding: 8px;
@@ -118,6 +122,23 @@ function AskQuestionPage() {
>
+ 이미지태그
@@ -62,13 +66,17 @@
+Copyright (c) 2003-2023, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
+
+Sources of Intellectual Property Included in CKEditor
+-----------------------------------------------------
+
+Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
+
+Trademarks
+----------
+
+**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
diff --git a/node_modules/@ckeditor/ckeditor5-adapter-ckfinder/README.md b/node_modules/@ckeditor/ckeditor5-adapter-ckfinder/README.md
new file mode 100644
index 00000000..2bd1f3da
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-adapter-ckfinder/README.md
@@ -0,0 +1,18 @@
+CKEditor 5 CKFinder adapter
+========================================
+
+[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-adapter-ckfinder.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-adapter-ckfinder)
+[![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5?branch=master)
+[![Build Status](https://travis-ci.com/ckeditor/ckeditor5.svg?branch=master)](https://app.travis-ci.com/github/ckeditor/ckeditor5)
+
+This package implements a CKEditor 5 upload adapter compatible with the [CKFinder file manager and uploader](https://ckeditor.com/ckfinder/)'s server–side connector.
+
+## Documentation
+
+See the ["CKFinder integration" guide](https://ckeditor.com/docs/ckeditor5/latest/features/ckfinder.html) and the [plugin documentation](https://ckeditor.com/docs/ckeditor5/latest/api/adapter-ckfinder.html) to learn how to configure the adapter.
+
+Check out the {@link features/image-upload/image-upload comprehensive "Image upload overview"} to learn about other ways to upload images into CKEditor 5.
+
+## License
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). For full details about the license, please check the `LICENSE.md` file or [https://ckeditor.com/legal/ckeditor-oss-license](https://ckeditor.com/legal/ckeditor-oss-license).
diff --git a/node_modules/@ckeditor/ckeditor5-adapter-ckfinder/build/adapter-ckfinder.js b/node_modules/@ckeditor/ckeditor5-adapter-ckfinder/build/adapter-ckfinder.js
new file mode 100644
index 00000000..059fe5bf
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-adapter-ckfinder/build/adapter-ckfinder.js
@@ -0,0 +1,4 @@
+/*!
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */(()=>{var e={704:(e,t,r)=>{e.exports=r(79)("./src/core.js")},448:(e,t,r)=>{e.exports=r(79)("./src/upload.js")},79:e=>{"use strict";e.exports=CKEditor5.dll}},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var s=t[o]={exports:{}};return e[o](s,s.exports,r),s.exports}r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};(()=>{"use strict";r.r(o),r.d(o,{UploadAdapter:()=>d});var e=r(704),t=r(448);const n="ckCsrfToken",s="abcdefghijklmnopqrstuvwxyz0123456789";function i(){let e=function(e){e=e.toLowerCase();const t=document.cookie.split(";");for(const r of t){const t=r.split("=");if(decodeURIComponent(t[0].trim().toLowerCase())===e)return decodeURIComponent(t[1])}return null}(n);var t,r;return e&&40==e.length||(e=function(e){let t="";const r=new Uint8Array(e);window.crypto.getRandomValues(r);for(let e=0;e` to the wrapped fragment of text. Closes [#35](https://github.com/ckeditor/ckeditor5-autoformat/issues/35). ([3e93bf6](https://github.com/ckeditor/ckeditor5-autoformat/commit/3e93bf6))
+
+
+## [0.6.0](https://github.com/ckeditor/ckeditor5-autoformat/compare/v0.5.1...v0.6.0) (2017-09-03)
+
+### Bug fixes
+
+* The `Autoformat` plugin should not require other features. Closes [#5](https://github.com/ckeditor/ckeditor5-autoformat/issues/5) and [#17](https://github.com/ckeditor/ckeditor5-autoformat/issues/17). ([d22c5b6](https://github.com/ckeditor/ckeditor5-autoformat/commit/d22c5b6))
+* Autoformatting will not be triggered if the batch with changes is `transparent` (e.g. it represents other user's changes). ([f1131bc](https://github.com/ckeditor/ckeditor5-autoformat/commit/f1131bc))
+
+### Features
+
+* Added support for block quotes. Closes [#26](https://github.com/ckeditor/ckeditor5-autoformat/issues/26). ([4c1e83e](https://github.com/ckeditor/ckeditor5-autoformat/commit/4c1e83e))
+
+### Other changes
+
+* Aligned the implementation to the new Command API (see https://github.com/ckeditor/ckeditor5-core/issues/88). ([f20ef7d](https://github.com/ckeditor/ckeditor5-autoformat/commit/f20ef7d))
+* The autoformat feature will not depend on the configuration of the heading feature but it will use the available `heading*` commands. Closes [#29](https://github.com/ckeditor/ckeditor5-autoformat/issues/29). ([d0cee1f](https://github.com/ckeditor/ckeditor5-autoformat/commit/d0cee1f))
+
+### BREAKING CHANGES
+
+* The command API has been changed.
+
+### NOTE
+
+* The Autoformat feature doesn't require Bold, Italic, Heading, etc. any longer. In order to make the most of the plugin, please make sure that relevant features are loaded in your editor.
+
+
+## [0.5.1](https://github.com/ckeditor/ckeditor5-autoformat/compare/v0.5.0...v0.5.1) (2017-05-07)
+
+Internal changes only (updated dependencies, documentation, etc.).
+
+## [0.5.0](https://github.com/ckeditor/ckeditor5-autoformat/compare/v0.4.1...v0.5.0) (2017-04-05)
+
+### Features
+
+* Named existing plugin(s). ([e043947](https://github.com/ckeditor/ckeditor5-autoformat/commit/e043947))
+
+### Other changes
+
+* Updated command names to match the latest API of the Heading feature. Closes [#22](https://github.com/ckeditor/ckeditor5-autoformat/issues/22). ([10b5561](https://github.com/ckeditor/ckeditor5-autoformat/commit/10b5561))
+
+
+## [0.4.1](https://github.com/ckeditor/ckeditor5-autoformat/compare/v0.4.0...v0.4.1) (2017-03-06)
+
+### Other changes
+
+* Aligned the use of the `heading` command to the changes in the `ckeditor5-heading` package. Closes [#20](https://github.com/ckeditor/ckeditor5/issues/20). ([6b8b759](https://github.com/ckeditor/ckeditor5-autoformat/commit/6b8b759))
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/LICENSE.md b/node_modules/@ckeditor/ckeditor5-autoformat/LICENSE.md
new file mode 100644
index 00000000..774c74ec
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/LICENSE.md
@@ -0,0 +1,17 @@
+Software License Agreement
+==========================
+
+**CKEditor 5 autoformat feature** – https://github.com/ckeditor/ckeditor5-autoformat
+Copyright (c) 2003-2023, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
+
+Sources of Intellectual Property Included in CKEditor
+-----------------------------------------------------
+
+Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
+
+Trademarks
+----------
+
+**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/README.md b/node_modules/@ckeditor/ckeditor5-autoformat/README.md
new file mode 100644
index 00000000..d80ade98
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/README.md
@@ -0,0 +1,20 @@
+CKEditor 5 autoformat feature
+========================================
+
+[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-autoformat.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-autoformat)
+[![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5?branch=master)
+[![Build Status](https://travis-ci.com/ckeditor/ckeditor5.svg?branch=master)](https://app.travis-ci.com/github/ckeditor/ckeditor5)
+
+This package implements the autoformatting feature for CKEditor 5. It allows styling text by typing sequences like `**bold this**`.
+
+## Demo
+
+Check out the [demo in the autoformat feature guide](https://ckeditor.com/docs/ckeditor5/latest/features/autoformat.html#demo).
+
+## Documentation
+
+See the [`@ckeditor/ckeditor5-autoformat` package](https://ckeditor.com/docs/ckeditor5/latest/api/autoformat.html) page in [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest/).
+
+## License
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). For full details about the license, please check the `LICENSE.md` file or [https://ckeditor.com/legal/ckeditor-oss-license](https://ckeditor.com/legal/ckeditor-oss-license).
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/build/autoformat.js b/node_modules/@ckeditor/ckeditor5-autoformat/build/autoformat.js
new file mode 100644
index 00000000..1549a990
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/build/autoformat.js
@@ -0,0 +1,4 @@
+/*!
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */(()=>{var t={704:(t,e,o)=>{t.exports=o(79)("./src/core.js")},492:(t,e,o)=>{t.exports=o(79)("./src/engine.js")},181:(t,e,o)=>{t.exports=o(79)("./src/typing.js")},209:(t,e,o)=>{t.exports=o(79)("./src/utils.js")},79:t=>{"use strict";t.exports=CKEditor5.dll}},e={};function o(i){var s=e[i];if(void 0!==s)return s.exports;var n=e[i]={exports:{}};return t[i](n,n.exports,o),n.exports}o.d=(t,e)=>{for(var i in e)o.o(e,i)&&!o.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},o.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),o.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var i={};(()=>{"use strict";o.r(i),o.d(i,{Autoformat:()=>c});var t=o(704),e=o(181),s=o(492),n=o(209);function r(t,e,o,i){let r,d=null;"function"==typeof i?r=i:(d=t.commands.get(i),r=()=>{t.execute(i)}),t.model.document.on("change:data",((a,c)=>{if(d&&!d.isEnabled||!e.isEnabled)return;const l=(0,n.first)(t.model.document.selection.getRanges());if(!l.isCollapsed)return;if(c.isUndo||!c.isLocal)return;const u=Array.from(t.model.document.differ.getChanges()),h=u[0];if(1!=u.length||"insert"!==h.type||"$text"!=h.name||1!=h.length)return;const g=h.position.parent;if(g.is("element","codeBlock"))return;if(g.is("element","listItem")&&"function"!=typeof i&&!["numberedList","bulletedList","todoList"].includes(i))return;if(d&&!0===d.value)return;const m=g.getChild(0),f=t.model.createRangeOn(m);if(!f.containsRange(l)&&!l.end.isEqual(f.end))return;const p=o.exec(m.data.substr(0,l.end.offset));p&&t.model.enqueueChange((e=>{const o=e.createPositionAt(g,0),i=e.createPositionAt(g,p[0].length),n=new s.LiveRange(o,i);if(!1!==r({match:p})){e.remove(n);const o=t.model.document.selection.getFirstRange(),i=e.createRangeIn(g);!g.isEmpty||i.isEqual(o)||i.containsRange(o,!0)||e.remove(g)}n.detach(),t.model.enqueueChange((()=>{t.plugins.get("Delete").requestUndoOnBackspace()}))}))}))}function d(t,e,o,i){let s,n;o instanceof RegExp?s=o:n=o,n=n||(t=>{let e;const o=[],i=[];for(;null!==(e=s.exec(t))&&!(e&&e.length<4);){let{index:t,1:s,2:n,3:r}=e;const d=s+n+r;t+=e[0].length-d.length;const a=[t,t+s.length],c=[t+s.length+n.length,t+s.length+n.length+r.length];o.push(a),o.push(c),i.push([t+s.length,t+s.length+n.length])}return{remove:o,format:i}}),t.model.document.on("change:data",((o,s)=>{if(s.isUndo||!s.isLocal||!e.isEnabled)return;const r=t.model,d=r.document.selection;if(!d.isCollapsed)return;const c=Array.from(r.document.differ.getChanges()),l=c[0];if(1!=c.length||"insert"!==l.type||"$text"!=l.name||1!=l.length)return;const u=d.focus,h=u.parent,{text:g,range:m}=function(t,e){let o=t.start;const i=Array.from(t.getItems()).reduce(((t,i)=>!i.is("$text")&&!i.is("$textProxy")||i.getAttribute("code")?(o=e.createPositionAfter(i),""):t+i.data),"");return{text:i,range:e.createRange(o,t.end)}}(r.createRange(r.createPositionAt(h,0),u),r),f=n(g),p=a(m.start,f.format,r),x=a(m.start,f.remove,r);p.length&&x.length&&r.enqueueChange((e=>{if(!1!==i(e,p)){for(const t of x.reverse())e.remove(t);r.enqueueChange((()=>{t.plugins.get("Delete").requestUndoOnBackspace()}))}}))}))}function a(t,e,o){return e.filter((t=>void 0!==t[0]&&void 0!==t[1])).map((e=>o.createRange(t.getShiftedBy(e[0]),t.getShiftedBy(e[1]))))}class c extends t.Plugin{static get requires(){return[e.Delete]}static get pluginName(){return"Autoformat"}afterInit(){this._addListAutoformats(),this._addBasicStylesAutoformats(),this._addHeadingAutoformats(),this._addBlockQuoteAutoformats(),this._addCodeBlockAutoformats(),this._addHorizontalLineAutoformats()}_addListAutoformats(){const t=this.editor.commands;t.get("bulletedList")&&r(this.editor,this,/^[*-]\s$/,"bulletedList"),t.get("numberedList")&&r(this.editor,this,/^1[.|)]\s$/,"numberedList"),t.get("todoList")&&r(this.editor,this,/^\[\s?\]\s$/,"todoList"),t.get("checkTodoList")&&r(this.editor,this,/^\[\s?x\s?\]\s$/,(()=>{this.editor.execute("todoList"),this.editor.execute("checkTodoList")}))}_addBasicStylesAutoformats(){const t=this.editor.commands;if(t.get("bold")){const t=l(this.editor,"bold");d(this.editor,this,/(?:^|\s)(\*\*)([^*]+)(\*\*)$/g,t),d(this.editor,this,/(?:^|\s)(__)([^_]+)(__)$/g,t)}if(t.get("italic")){const t=l(this.editor,"italic");d(this.editor,this,/(?:^|\s)(\*)([^*_]+)(\*)$/g,t),d(this.editor,this,/(?:^|\s)(_)([^_]+)(_)$/g,t)}if(t.get("code")){const t=l(this.editor,"code");d(this.editor,this,/(`)([^`]+)(`)$/g,t)}if(t.get("strikethrough")){const t=l(this.editor,"strikethrough");d(this.editor,this,/(~~)([^~]+)(~~)$/g,t)}}_addHeadingAutoformats(){const t=this.editor.commands.get("heading");t&&t.modelElements.filter((t=>t.match(/^heading[1-6]$/))).forEach((e=>{const o=e[7],i=new RegExp(`^(#{${o}})\\s$`);r(this.editor,this,i,(()=>{if(!t.isEnabled||t.value===e)return!1;this.editor.execute("heading",{value:e})}))}))}_addBlockQuoteAutoformats(){this.editor.commands.get("blockQuote")&&r(this.editor,this,/^>\s$/,"blockQuote")}_addCodeBlockAutoformats(){const t=this.editor,e=t.model.document.selection;t.commands.get("codeBlock")&&r(t,this,/^```$/,(()=>{if(e.getFirstPosition().parent.is("element","listItem"))return!1;this.editor.execute("codeBlock",{usePreviousLanguageChoice:!0})}))}_addHorizontalLineAutoformats(){this.editor.commands.get("horizontalLine")&&r(this.editor,this,/^---$/,"horizontalLine")}}function l(t,e){return(o,i)=>{if(!t.commands.get(e).isEnabled)return!1;const s=t.model.schema.getValidRanges(i,e);for(const t of s)o.setAttribute(e,!0,t);o.removeSelectionAttribute(e)}}})(),(window.CKEditor5=window.CKEditor5||{}).autoformat=i})();
\ No newline at end of file
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/ckeditor5-metadata.json b/node_modules/@ckeditor/ckeditor5-autoformat/ckeditor5-metadata.json
new file mode 100644
index 00000000..73fa5b52
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/ckeditor5-metadata.json
@@ -0,0 +1,11 @@
+{
+ "plugins": [
+ {
+ "name": "Autoformat",
+ "className": "Autoformat",
+ "description": "Enables a set of predefined autoformatting actions. It allows for formatting text by typing sequences like **bold this**.",
+ "docs": "features/autoformat.html",
+ "path": "src/autoformat.js"
+ }
+ ]
+}
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/package.json b/node_modules/@ckeditor/ckeditor5-autoformat/package.json
new file mode 100644
index 00000000..06c4f84f
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/package.json
@@ -0,0 +1,40 @@
+{
+ "name": "@ckeditor/ckeditor5-autoformat",
+ "version": "39.0.0",
+ "description": "Autoformatting feature for CKEditor 5.",
+ "keywords": [
+ "ckeditor",
+ "ckeditor5",
+ "ckeditor 5",
+ "ckeditor5-feature",
+ "ckeditor5-plugin",
+ "ckeditor5-dll"
+ ],
+ "main": "src/index.js",
+ "dependencies": {
+ "ckeditor5": "39.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0",
+ "npm": ">=5.7.1"
+ },
+ "author": "CKSource (http://cksource.com/)",
+ "license": "GPL-2.0-or-later",
+ "homepage": "https://ckeditor.com/ckeditor-5",
+ "bugs": "https://github.com/ckeditor/ckeditor5/issues",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/ckeditor/ckeditor5.git",
+ "directory": "packages/ckeditor5-autoformat"
+ },
+ "files": [
+ "lang",
+ "src/**/*.js",
+ "src/**/*.d.ts",
+ "theme",
+ "build",
+ "ckeditor5-metadata.json",
+ "CHANGELOG.md"
+ ],
+ "types": "src/index.d.ts"
+}
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.d.ts b/node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.d.ts
new file mode 100644
index 00000000..fa564f65
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.d.ts
@@ -0,0 +1,10 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+import type { Autoformat } from './index';
+declare module '@ckeditor/ckeditor5-core' {
+ interface PluginsMap {
+ [Autoformat.pluginName]: Autoformat;
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.js b/node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.js
new file mode 100644
index 00000000..52f0f122
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/augmentation.js
@@ -0,0 +1,5 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+export {};
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.d.ts b/node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.d.ts
new file mode 100644
index 00000000..84411ad8
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.d.ts
@@ -0,0 +1,81 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import { Delete } from 'ckeditor5/src/typing';
+/**
+ * Enables a set of predefined autoformatting actions.
+ *
+ * For a detailed overview, check the {@glink features/autoformat Autoformatting} feature guide
+ * and the {@glink api/autoformat package page}.
+ */
+export default class Autoformat extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires(): readonly [typeof Delete];
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "Autoformat";
+ /**
+ * @inheritDoc
+ */
+ afterInit(): void;
+ /**
+ * Adds autoformatting related to the {@link module:list/list~List}.
+ *
+ * When typed:
+ * - `* ` or `- ` – A paragraph will be changed into a bulleted list.
+ * - `1. ` or `1) ` – A paragraph will be changed into a numbered list ("1" can be any digit or a list of digits).
+ * - `[] ` or `[ ] ` – A paragraph will be changed into a to-do list.
+ * - `[x] ` or `[ x ] ` – A paragraph will be changed into a checked to-do list.
+ */
+ private _addListAutoformats;
+ /**
+ * Adds autoformatting related to the {@link module:basic-styles/bold~Bold},
+ * {@link module:basic-styles/italic~Italic}, {@link module:basic-styles/code~Code}
+ * and {@link module:basic-styles/strikethrough~Strikethrough}
+ *
+ * When typed:
+ * - `**foobar**` – `**` characters are removed and `foobar` is set to bold,
+ * - `__foobar__` – `__` characters are removed and `foobar` is set to bold,
+ * - `*foobar*` – `*` characters are removed and `foobar` is set to italic,
+ * - `_foobar_` – `_` characters are removed and `foobar` is set to italic,
+ * - ``` `foobar` – ``` ` ``` characters are removed and `foobar` is set to code,
+ * - `~~foobar~~` – `~~` characters are removed and `foobar` is set to strikethrough.
+ */
+ private _addBasicStylesAutoformats;
+ /**
+ * Adds autoformatting related to {@link module:heading/heading~Heading}.
+ *
+ * It is using a number at the end of the command name to associate it with the proper trigger:
+ *
+ * * `heading` with a `heading1` value will be executed when typing `#`,
+ * * `heading` with a `heading2` value will be executed when typing `##`,
+ * * ... up to `heading6` for `######`.
+ */
+ private _addHeadingAutoformats;
+ /**
+ * Adds autoformatting related to {@link module:block-quote/blockquote~BlockQuote}.
+ *
+ * When typed:
+ * * `> ` – A paragraph will be changed to a block quote.
+ */
+ private _addBlockQuoteAutoformats;
+ /**
+ * Adds autoformatting related to {@link module:code-block/codeblock~CodeBlock}.
+ *
+ * When typed:
+ * - `` ``` `` – A paragraph will be changed to a code block.
+ */
+ private _addCodeBlockAutoformats;
+ /**
+ * Adds autoformatting related to {@link module:horizontal-line/horizontalline~HorizontalLine}.
+ *
+ * When typed:
+ * - `` --- `` – Will be replaced with a horizontal line.
+ */
+ private _addHorizontalLineAutoformats;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.js b/node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.js
new file mode 100644
index 00000000..ff6adfaf
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/autoformat.js
@@ -0,0 +1,189 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import { Delete } from 'ckeditor5/src/typing';
+import blockAutoformatEditing from './blockautoformatediting';
+import inlineAutoformatEditing from './inlineautoformatediting';
+/**
+ * Enables a set of predefined autoformatting actions.
+ *
+ * For a detailed overview, check the {@glink features/autoformat Autoformatting} feature guide
+ * and the {@glink api/autoformat package page}.
+ */
+export default class Autoformat extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires() {
+ return [Delete];
+ }
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'Autoformat';
+ }
+ /**
+ * @inheritDoc
+ */
+ afterInit() {
+ this._addListAutoformats();
+ this._addBasicStylesAutoformats();
+ this._addHeadingAutoformats();
+ this._addBlockQuoteAutoformats();
+ this._addCodeBlockAutoformats();
+ this._addHorizontalLineAutoformats();
+ }
+ /**
+ * Adds autoformatting related to the {@link module:list/list~List}.
+ *
+ * When typed:
+ * - `* ` or `- ` – A paragraph will be changed into a bulleted list.
+ * - `1. ` or `1) ` – A paragraph will be changed into a numbered list ("1" can be any digit or a list of digits).
+ * - `[] ` or `[ ] ` – A paragraph will be changed into a to-do list.
+ * - `[x] ` or `[ x ] ` – A paragraph will be changed into a checked to-do list.
+ */
+ _addListAutoformats() {
+ const commands = this.editor.commands;
+ if (commands.get('bulletedList')) {
+ blockAutoformatEditing(this.editor, this, /^[*-]\s$/, 'bulletedList');
+ }
+ if (commands.get('numberedList')) {
+ blockAutoformatEditing(this.editor, this, /^1[.|)]\s$/, 'numberedList');
+ }
+ if (commands.get('todoList')) {
+ blockAutoformatEditing(this.editor, this, /^\[\s?\]\s$/, 'todoList');
+ }
+ if (commands.get('checkTodoList')) {
+ blockAutoformatEditing(this.editor, this, /^\[\s?x\s?\]\s$/, () => {
+ this.editor.execute('todoList');
+ this.editor.execute('checkTodoList');
+ });
+ }
+ }
+ /**
+ * Adds autoformatting related to the {@link module:basic-styles/bold~Bold},
+ * {@link module:basic-styles/italic~Italic}, {@link module:basic-styles/code~Code}
+ * and {@link module:basic-styles/strikethrough~Strikethrough}
+ *
+ * When typed:
+ * - `**foobar**` – `**` characters are removed and `foobar` is set to bold,
+ * - `__foobar__` – `__` characters are removed and `foobar` is set to bold,
+ * - `*foobar*` – `*` characters are removed and `foobar` is set to italic,
+ * - `_foobar_` – `_` characters are removed and `foobar` is set to italic,
+ * - ``` `foobar` – ``` ` ``` characters are removed and `foobar` is set to code,
+ * - `~~foobar~~` – `~~` characters are removed and `foobar` is set to strikethrough.
+ */
+ _addBasicStylesAutoformats() {
+ const commands = this.editor.commands;
+ if (commands.get('bold')) {
+ const boldCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'bold');
+ inlineAutoformatEditing(this.editor, this, /(?:^|\s)(\*\*)([^*]+)(\*\*)$/g, boldCallback);
+ inlineAutoformatEditing(this.editor, this, /(?:^|\s)(__)([^_]+)(__)$/g, boldCallback);
+ }
+ if (commands.get('italic')) {
+ const italicCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'italic');
+ // The italic autoformatter cannot be triggered by the bold markers, so we need to check the
+ // text before the pattern (e.g. `(?:^|[^\*])`).
+ inlineAutoformatEditing(this.editor, this, /(?:^|\s)(\*)([^*_]+)(\*)$/g, italicCallback);
+ inlineAutoformatEditing(this.editor, this, /(?:^|\s)(_)([^_]+)(_)$/g, italicCallback);
+ }
+ if (commands.get('code')) {
+ const codeCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'code');
+ inlineAutoformatEditing(this.editor, this, /(`)([^`]+)(`)$/g, codeCallback);
+ }
+ if (commands.get('strikethrough')) {
+ const strikethroughCallback = getCallbackFunctionForInlineAutoformat(this.editor, 'strikethrough');
+ inlineAutoformatEditing(this.editor, this, /(~~)([^~]+)(~~)$/g, strikethroughCallback);
+ }
+ }
+ /**
+ * Adds autoformatting related to {@link module:heading/heading~Heading}.
+ *
+ * It is using a number at the end of the command name to associate it with the proper trigger:
+ *
+ * * `heading` with a `heading1` value will be executed when typing `#`,
+ * * `heading` with a `heading2` value will be executed when typing `##`,
+ * * ... up to `heading6` for `######`.
+ */
+ _addHeadingAutoformats() {
+ const command = this.editor.commands.get('heading');
+ if (command) {
+ command.modelElements
+ .filter(name => name.match(/^heading[1-6]$/))
+ .forEach(modelName => {
+ const level = modelName[7];
+ const pattern = new RegExp(`^(#{${level}})\\s$`);
+ blockAutoformatEditing(this.editor, this, pattern, () => {
+ // Should only be active if command is enabled and heading style associated with pattern is inactive.
+ if (!command.isEnabled || command.value === modelName) {
+ return false;
+ }
+ this.editor.execute('heading', { value: modelName });
+ });
+ });
+ }
+ }
+ /**
+ * Adds autoformatting related to {@link module:block-quote/blockquote~BlockQuote}.
+ *
+ * When typed:
+ * * `> ` – A paragraph will be changed to a block quote.
+ */
+ _addBlockQuoteAutoformats() {
+ if (this.editor.commands.get('blockQuote')) {
+ blockAutoformatEditing(this.editor, this, /^>\s$/, 'blockQuote');
+ }
+ }
+ /**
+ * Adds autoformatting related to {@link module:code-block/codeblock~CodeBlock}.
+ *
+ * When typed:
+ * - `` ``` `` – A paragraph will be changed to a code block.
+ */
+ _addCodeBlockAutoformats() {
+ const editor = this.editor;
+ const selection = editor.model.document.selection;
+ if (editor.commands.get('codeBlock')) {
+ blockAutoformatEditing(editor, this, /^```$/, () => {
+ if (selection.getFirstPosition().parent.is('element', 'listItem')) {
+ return false;
+ }
+ this.editor.execute('codeBlock', {
+ usePreviousLanguageChoice: true
+ });
+ });
+ }
+ }
+ /**
+ * Adds autoformatting related to {@link module:horizontal-line/horizontalline~HorizontalLine}.
+ *
+ * When typed:
+ * - `` --- `` – Will be replaced with a horizontal line.
+ */
+ _addHorizontalLineAutoformats() {
+ if (this.editor.commands.get('horizontalLine')) {
+ blockAutoformatEditing(this.editor, this, /^---$/, 'horizontalLine');
+ }
+ }
+}
+/**
+ * Helper function for getting `inlineAutoformatEditing` callbacks that checks if command is enabled.
+ */
+function getCallbackFunctionForInlineAutoformat(editor, attributeKey) {
+ return (writer, rangesToFormat) => {
+ const command = editor.commands.get(attributeKey);
+ if (!command.isEnabled) {
+ return false;
+ }
+ const validRanges = editor.model.schema.getValidRanges(rangesToFormat, attributeKey);
+ for (const range of validRanges) {
+ writer.setAttribute(attributeKey, true, range);
+ }
+ // After applying attribute to the text, remove given attribute from the selection.
+ // This way user is able to type a text without attribute used by auto formatter.
+ writer.removeSelectionAttribute(attributeKey);
+ };
+}
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.d.ts b/node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.d.ts
new file mode 100644
index 00000000..02b279b8
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.d.ts
@@ -0,0 +1,57 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+import type { Editor } from 'ckeditor5/src/core';
+import type Autoformat from './autoformat';
+/**
+ * The block autoformatting engine. It allows to format various block patterns. For example,
+ * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item.
+ *
+ * The autoformatting operation is integrated with the undo manager,
+ * so the autoformatting step can be undone if the user's intention was not to format the text.
+ *
+ * See the {@link module:autoformat/blockautoformatediting~blockAutoformatEditing `blockAutoformatEditing`} documentation
+ * to learn how to create custom block autoformatters. You can also use
+ * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters
+ * (lists, headings, bold and italic).
+ *
+ * @module autoformat/blockautoformatediting
+ */
+/**
+ * Creates a listener triggered on {@link module:engine/model/document~Document#event:change:data `change:data`} event in the document.
+ * Calls the callback when inserted text matches the regular expression or the command name
+ * if provided instead of the callback.
+ *
+ * Examples of usage:
+ *
+ * To convert a paragraph into heading 1 when `- ` is typed, using just the command name:
+ *
+ * ```ts
+ * blockAutoformatEditing( editor, plugin, /^\- $/, 'heading1' );
+ * ```
+ *
+ * To convert a paragraph into heading 1 when `- ` is typed, using just the callback:
+ *
+ * ```ts
+ * blockAutoformatEditing( editor, plugin, /^\- $/, ( context ) => {
+ * const { match } = context;
+ * const headingLevel = match[ 1 ].length;
+ *
+ * editor.execute( 'heading', {
+ * formatId: `heading${ headingLevel }`
+ * } );
+ * } );
+ * ```
+ *
+ * @param editor The editor instance.
+ * @param plugin The autoformat plugin instance.
+ * @param pattern The regular expression to execute on just inserted text. The regular expression is tested against the text
+ * from the beginning until the caret position.
+ * @param callbackOrCommand The callback to execute or the command to run when the text is matched.
+ * In case of providing the callback, it receives the following parameter:
+ * * match RegExp.exec() result of matching the pattern to inserted text.
+ */
+export default function blockAutoformatEditing(editor: Editor, plugin: Autoformat, pattern: RegExp, callbackOrCommand: string | ((context: {
+ match: RegExpExecArray;
+}) => unknown)): void;
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.js b/node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.js
new file mode 100644
index 00000000..8a267ae4
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/blockautoformatediting.js
@@ -0,0 +1,137 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+import { LiveRange } from 'ckeditor5/src/engine';
+import { first } from 'ckeditor5/src/utils';
+/**
+ * The block autoformatting engine. It allows to format various block patterns. For example,
+ * it can be configured to turn a paragraph starting with `*` and followed by a space into a list item.
+ *
+ * The autoformatting operation is integrated with the undo manager,
+ * so the autoformatting step can be undone if the user's intention was not to format the text.
+ *
+ * See the {@link module:autoformat/blockautoformatediting~blockAutoformatEditing `blockAutoformatEditing`} documentation
+ * to learn how to create custom block autoformatters. You can also use
+ * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters
+ * (lists, headings, bold and italic).
+ *
+ * @module autoformat/blockautoformatediting
+ */
+/**
+ * Creates a listener triggered on {@link module:engine/model/document~Document#event:change:data `change:data`} event in the document.
+ * Calls the callback when inserted text matches the regular expression or the command name
+ * if provided instead of the callback.
+ *
+ * Examples of usage:
+ *
+ * To convert a paragraph into heading 1 when `- ` is typed, using just the command name:
+ *
+ * ```ts
+ * blockAutoformatEditing( editor, plugin, /^\- $/, 'heading1' );
+ * ```
+ *
+ * To convert a paragraph into heading 1 when `- ` is typed, using just the callback:
+ *
+ * ```ts
+ * blockAutoformatEditing( editor, plugin, /^\- $/, ( context ) => {
+ * const { match } = context;
+ * const headingLevel = match[ 1 ].length;
+ *
+ * editor.execute( 'heading', {
+ * formatId: `heading${ headingLevel }`
+ * } );
+ * } );
+ * ```
+ *
+ * @param editor The editor instance.
+ * @param plugin The autoformat plugin instance.
+ * @param pattern The regular expression to execute on just inserted text. The regular expression is tested against the text
+ * from the beginning until the caret position.
+ * @param callbackOrCommand The callback to execute or the command to run when the text is matched.
+ * In case of providing the callback, it receives the following parameter:
+ * * match RegExp.exec() result of matching the pattern to inserted text.
+ */
+export default function blockAutoformatEditing(editor, plugin, pattern, callbackOrCommand) {
+ let callback;
+ let command = null;
+ if (typeof callbackOrCommand == 'function') {
+ callback = callbackOrCommand;
+ }
+ else {
+ // We assume that the actual command name was provided.
+ command = editor.commands.get(callbackOrCommand);
+ callback = () => {
+ editor.execute(callbackOrCommand);
+ };
+ }
+ editor.model.document.on('change:data', (evt, batch) => {
+ if (command && !command.isEnabled || !plugin.isEnabled) {
+ return;
+ }
+ const range = first(editor.model.document.selection.getRanges());
+ if (!range.isCollapsed) {
+ return;
+ }
+ if (batch.isUndo || !batch.isLocal) {
+ return;
+ }
+ const changes = Array.from(editor.model.document.differ.getChanges());
+ const entry = changes[0];
+ // Typing is represented by only a single change.
+ if (changes.length != 1 || entry.type !== 'insert' || entry.name != '$text' || entry.length != 1) {
+ return;
+ }
+ const blockToFormat = entry.position.parent;
+ // Block formatting should be disabled in codeBlocks (#5800).
+ if (blockToFormat.is('element', 'codeBlock')) {
+ return;
+ }
+ // Only list commands and custom callbacks can be applied inside a list.
+ if (blockToFormat.is('element', 'listItem') &&
+ typeof callbackOrCommand !== 'function' &&
+ !['numberedList', 'bulletedList', 'todoList'].includes(callbackOrCommand)) {
+ return;
+ }
+ // In case a command is bound, do not re-execute it over an existing block style which would result in a style removal.
+ // Instead, just drop processing so that autoformat trigger text is not lost. E.g. writing "# " in a level 1 heading.
+ if (command && command.value === true) {
+ return;
+ }
+ const firstNode = blockToFormat.getChild(0);
+ const firstNodeRange = editor.model.createRangeOn(firstNode);
+ // Range is only expected to be within or at the very end of the first text node.
+ if (!firstNodeRange.containsRange(range) && !range.end.isEqual(firstNodeRange.end)) {
+ return;
+ }
+ const match = pattern.exec(firstNode.data.substr(0, range.end.offset));
+ // ...and this text node's data match the pattern.
+ if (!match) {
+ return;
+ }
+ // Use enqueueChange to create new batch to separate typing batch from the auto-format changes.
+ editor.model.enqueueChange(writer => {
+ // Matched range.
+ const start = writer.createPositionAt(blockToFormat, 0);
+ const end = writer.createPositionAt(blockToFormat, match[0].length);
+ const range = new LiveRange(start, end);
+ const wasChanged = callback({ match });
+ // Remove matched text.
+ if (wasChanged !== false) {
+ writer.remove(range);
+ const selectionRange = editor.model.document.selection.getFirstRange();
+ const blockRange = writer.createRangeIn(blockToFormat);
+ // If the block is empty and the document selection has been moved when
+ // applying formatting (e.g. is now in newly created block).
+ if (blockToFormat.isEmpty && !blockRange.isEqual(selectionRange) && !blockRange.containsRange(selectionRange, true)) {
+ writer.remove(blockToFormat);
+ }
+ }
+ range.detach();
+ editor.model.enqueueChange(() => {
+ const deletePlugin = editor.plugins.get('Delete');
+ deletePlugin.requestUndoOnBackspace();
+ });
+ });
+ });
+}
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/index.d.ts b/node_modules/@ckeditor/ckeditor5-autoformat/src/index.d.ts
new file mode 100644
index 00000000..99cc1771
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/index.d.ts
@@ -0,0 +1,9 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module autoformat
+ */
+export { default as Autoformat } from './autoformat';
+import './augmentation';
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/index.js b/node_modules/@ckeditor/ckeditor5-autoformat/src/index.js
new file mode 100644
index 00000000..99cc1771
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/index.js
@@ -0,0 +1,9 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module autoformat
+ */
+export { default as Autoformat } from './autoformat';
+import './augmentation';
diff --git a/node_modules/@ckeditor/ckeditor5-autoformat/src/inlineautoformatediting.d.ts b/node_modules/@ckeditor/ckeditor5-autoformat/src/inlineautoformatediting.d.ts
new file mode 100644
index 00000000..30877423
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-autoformat/src/inlineautoformatediting.d.ts
@@ -0,0 +1,83 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * The inline autoformatting engine. It allows to format various inline patterns. For example,
+ * it can be configured to make "foo" bold when typed `**foo**` (the `**` markers will be removed).
+ *
+ * The autoformatting operation is integrated with the undo manager,
+ * so the autoformatting step can be undone if the user's intention was not to format the text.
+ *
+ * See the {@link module:autoformat/inlineautoformatediting~inlineAutoformatEditing `inlineAutoformatEditing`} documentation
+ * to learn how to create custom inline autoformatters. You can also use
+ * the {@link module:autoformat/autoformat~Autoformat} feature which enables a set of default autoformatters
+ * (lists, headings, bold and italic).
+ *
+ * @module autoformat/inlineautoformatediting
+ */
+import type { Editor } from 'ckeditor5/src/core';
+import type { Range, Writer } from 'ckeditor5/src/engine';
+import type Autoformat from './autoformat';
+export type TestCallback = (text: string) => {
+ remove: Array
+Copyright (c) 2003-2023, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
+
+Sources of Intellectual Property Included in CKEditor
+-----------------------------------------------------
+
+Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
+
+Trademarks
+----------
+
+**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/README.md b/node_modules/@ckeditor/ckeditor5-basic-styles/README.md
new file mode 100644
index 00000000..4f7a6249
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/README.md
@@ -0,0 +1,20 @@
+CKEditor 5 basic styles feature
+========================================
+
+[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-basic-styles.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-basic-styles)
+[![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5?branch=master)
+[![Build Status](https://travis-ci.com/ckeditor/ckeditor5.svg?branch=master)](https://app.travis-ci.com/github/ckeditor/ckeditor5)
+
+This package contains CKEditor 5 features allowing to apply basic text formatting such as bold, italic, underline, and code in CKEditor 5.
+
+## Demo
+
+Check out the [demo in the basic styles feature guide](https://ckeditor.com/docs/ckeditor5/latest/features/basic-styles.html#demo).
+
+## Documentation
+
+See the [`@ckeditor/ckeditor5-basic-styles` package](https://ckeditor.com/docs/ckeditor5/latest/api/basic-styles.html) page in [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest/).
+
+## License
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). For full details about the license, please check the `LICENSE.md` file or [https://ckeditor.com/legal/ckeditor-oss-license](https://ckeditor.com/legal/ckeditor-oss-license).
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/build/basic-styles.js b/node_modules/@ckeditor/ckeditor5-basic-styles/build/basic-styles.js
new file mode 100644
index 00000000..68db0fa0
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/build/basic-styles.js
@@ -0,0 +1,5 @@
+!function(t){const e=t.en=t.en||{};e.dictionary=Object.assign(e.dictionary||{},{Bold:"Bold",Code:"Code",Italic:"Italic",Strikethrough:"Strikethrough",Subscript:"Subscript",Superscript:"Superscript",Underline:"Underline"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})),
+/*!
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */(()=>{var t={55:(t,e,i)=>{"use strict";i.d(e,{Z:()=>r});var n=i(609),s=i.n(n)()((function(t){return t[1]}));s.push([t.id,".ck-content code{background-color:hsla(0,0%,78%,.3);border-radius:2px;padding:.15em}.ck.ck-editor__editable .ck-code_selected{background-color:hsla(0,0%,78%,.5)}",""]);const r=s},609:t=>{"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var i=t(e);return e[2]?"@media ".concat(e[2]," {").concat(i,"}"):i})).join("")},e.i=function(t,i,n){"string"==typeof t&&(t=[[null,t,""]]);var s={};if(n)for(var r=0;r` element.
+ */
+export default class CodeEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "CodeEditing";
+ /**
+ * @inheritDoc
+ */
+ static get requires(): readonly [typeof TwoStepCaretMovement];
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js
new file mode 100644
index 00000000..f8120abf
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeediting.js
@@ -0,0 +1,59 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/code/codeediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import { TwoStepCaretMovement, inlineHighlight } from 'ckeditor5/src/typing';
+import AttributeCommand from '../attributecommand';
+const CODE = 'code';
+const HIGHLIGHT_CLASS = 'ck-code_selected';
+/**
+ * The code editing feature.
+ *
+ * It registers the `'code'` command and introduces the `code` attribute in the model which renders to the view
+ * as a `
` element.
+ */
+export default class CodeEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'CodeEditing';
+ }
+ /**
+ * @inheritDoc
+ */
+ static get requires() {
+ return [TwoStepCaretMovement];
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ // Allow code attribute on text nodes.
+ editor.model.schema.extend('$text', { allowAttributes: CODE });
+ editor.model.schema.setAttributeProperties(CODE, {
+ isFormatting: true,
+ copyOnEnter: false
+ });
+ editor.conversion.attributeToElement({
+ model: CODE,
+ view: 'code',
+ upcastAlso: {
+ styles: {
+ 'word-wrap': 'break-word'
+ }
+ }
+ });
+ // Create code command.
+ editor.commands.add(CODE, new AttributeCommand(editor, CODE));
+ // Enable two-step caret movement for `code` attribute.
+ editor.plugins.get(TwoStepCaretMovement).registerAttribute(CODE);
+ // Setup highlight over selected element.
+ inlineHighlight(editor, CODE, 'code', HIGHLIGHT_CLASS);
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.d.ts
new file mode 100644
index 00000000..5403fdf9
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.d.ts
@@ -0,0 +1,22 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/code/codeui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import '../../theme/code.css';
+/**
+ * The code UI feature. It introduces the Code button.
+ */
+export default class CodeUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "CodeUI";
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js
new file mode 100644
index 00000000..74db1148
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/code/codeui.js
@@ -0,0 +1,48 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/code/codeui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import { ButtonView } from 'ckeditor5/src/ui';
+import codeIcon from '../../theme/icons/code.svg';
+import '../../theme/code.css';
+const CODE = 'code';
+/**
+ * The code UI feature. It introduces the Code button.
+ */
+export default class CodeUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'CodeUI';
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ const t = editor.t;
+ // Add code button to feature components.
+ editor.ui.componentFactory.add(CODE, locale => {
+ const command = editor.commands.get(CODE);
+ const view = new ButtonView(locale);
+ view.set({
+ label: t('Code'),
+ icon: codeIcon,
+ tooltip: true,
+ isToggleable: true
+ });
+ view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
+ // Execute command.
+ this.listenTo(view, 'execute', () => {
+ editor.execute(CODE);
+ editor.editing.view.focus();
+ });
+ return view;
+ });
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/index.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/index.d.ts
new file mode 100644
index 00000000..2d5de224
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/index.d.ts
@@ -0,0 +1,30 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles
+ */
+export { default as Bold } from './bold';
+export { default as BoldEditing } from './bold/boldediting';
+export { default as BoldUI } from './bold/boldui';
+export { default as Code } from './code';
+export { default as CodeEditing } from './code/codeediting';
+export { default as CodeUI } from './code/codeui';
+export { default as Italic } from './italic';
+export { default as ItalicEditing } from './italic/italicediting';
+export { default as ItalicUI } from './italic/italicui';
+export { default as Strikethrough } from './strikethrough';
+export { default as StrikethroughEditing } from './strikethrough/strikethroughediting';
+export { default as StrikethroughUI } from './strikethrough/strikethroughui';
+export { default as Subscript } from './subscript';
+export { default as SubscriptEditing } from './subscript/subscriptediting';
+export { default as SubscriptUI } from './subscript/subscriptui';
+export { default as Superscript } from './superscript';
+export { default as SuperscriptEditing } from './superscript/superscriptediting';
+export { default as SuperscriptUI } from './superscript/superscriptui';
+export { default as Underline } from './underline';
+export { default as UnderlineEditing } from './underline/underlineediting';
+export { default as UnderlineUI } from './underline/underlineui';
+export type { default as AttributeCommand } from './attributecommand';
+import './augmentation';
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/index.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/index.js
new file mode 100644
index 00000000..683c8927
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/index.js
@@ -0,0 +1,29 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles
+ */
+export { default as Bold } from './bold';
+export { default as BoldEditing } from './bold/boldediting';
+export { default as BoldUI } from './bold/boldui';
+export { default as Code } from './code';
+export { default as CodeEditing } from './code/codeediting';
+export { default as CodeUI } from './code/codeui';
+export { default as Italic } from './italic';
+export { default as ItalicEditing } from './italic/italicediting';
+export { default as ItalicUI } from './italic/italicui';
+export { default as Strikethrough } from './strikethrough';
+export { default as StrikethroughEditing } from './strikethrough/strikethroughediting';
+export { default as StrikethroughUI } from './strikethrough/strikethroughui';
+export { default as Subscript } from './subscript';
+export { default as SubscriptEditing } from './subscript/subscriptediting';
+export { default as SubscriptUI } from './subscript/subscriptui';
+export { default as Superscript } from './superscript';
+export { default as SuperscriptEditing } from './superscript/superscriptediting';
+export { default as SuperscriptUI } from './superscript/superscriptui';
+export { default as Underline } from './underline';
+export { default as UnderlineEditing } from './underline/underlineediting';
+export { default as UnderlineUI } from './underline/underlineui';
+import './augmentation';
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.d.ts
new file mode 100644
index 00000000..393fe3ae
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.d.ts
@@ -0,0 +1,29 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/italic
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import ItalicEditing from './italic/italicediting';
+import ItalicUI from './italic/italicui';
+/**
+ * The italic feature.
+ *
+ * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide
+ * and the {@glink api/basic-styles package page}.
+ *
+ * This is a "glue" plugin which loads the {@link module:basic-styles/italic/italicediting~ItalicEditing} and
+ * {@link module:basic-styles/italic/italicui~ItalicUI} plugins.
+ */
+export default class Italic extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires(): readonly [typeof ItalicEditing, typeof ItalicUI];
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "Italic";
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.js
new file mode 100644
index 00000000..055c12b6
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic.js
@@ -0,0 +1,33 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/italic
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import ItalicEditing from './italic/italicediting';
+import ItalicUI from './italic/italicui';
+/**
+ * The italic feature.
+ *
+ * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide
+ * and the {@glink api/basic-styles package page}.
+ *
+ * This is a "glue" plugin which loads the {@link module:basic-styles/italic/italicediting~ItalicEditing} and
+ * {@link module:basic-styles/italic/italicui~ItalicUI} plugins.
+ */
+export default class Italic extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires() {
+ return [ItalicEditing, ItalicUI];
+ }
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'Italic';
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.d.ts
new file mode 100644
index 00000000..e050a5fe
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.d.ts
@@ -0,0 +1,24 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/italic/italicediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+/**
+ * The italic editing feature.
+ *
+ * It registers the `'italic'` command, the Ctrl+I keystroke and introduces the `italic` attribute in the model
+ * which renders to the view as an `` element.
+ */
+export default class ItalicEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "ItalicEditing";
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js
new file mode 100644
index 00000000..18ee9b9b
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicediting.js
@@ -0,0 +1,52 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/italic/italicediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import AttributeCommand from '../attributecommand';
+const ITALIC = 'italic';
+/**
+ * The italic editing feature.
+ *
+ * It registers the `'italic'` command, the Ctrl+I keystroke and introduces the `italic` attribute in the model
+ * which renders to the view as an `` element.
+ */
+export default class ItalicEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'ItalicEditing';
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ // Allow italic attribute on text nodes.
+ editor.model.schema.extend('$text', { allowAttributes: ITALIC });
+ editor.model.schema.setAttributeProperties(ITALIC, {
+ isFormatting: true,
+ copyOnEnter: true
+ });
+ editor.conversion.attributeToElement({
+ model: ITALIC,
+ view: 'i',
+ upcastAlso: [
+ 'em',
+ {
+ styles: {
+ 'font-style': 'italic'
+ }
+ }
+ ]
+ });
+ // Create italic command.
+ editor.commands.add(ITALIC, new AttributeCommand(editor, ITALIC));
+ // Set the Ctrl+I keystroke.
+ editor.keystrokes.set('CTRL+I', ITALIC);
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.d.ts
new file mode 100644
index 00000000..a93d3b6c
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.d.ts
@@ -0,0 +1,21 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/italic/italicui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+/**
+ * The italic UI feature. It introduces the Italic button.
+ */
+export default class ItalicUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "ItalicUI";
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js
new file mode 100644
index 00000000..c1a9314a
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/italic/italicui.js
@@ -0,0 +1,48 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/italic/italicui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import { ButtonView } from 'ckeditor5/src/ui';
+import italicIcon from '../../theme/icons/italic.svg';
+const ITALIC = 'italic';
+/**
+ * The italic UI feature. It introduces the Italic button.
+ */
+export default class ItalicUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'ItalicUI';
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ const t = editor.t;
+ // Add bold button to feature components.
+ editor.ui.componentFactory.add(ITALIC, locale => {
+ const command = editor.commands.get(ITALIC);
+ const view = new ButtonView(locale);
+ view.set({
+ label: t('Italic'),
+ icon: italicIcon,
+ keystroke: 'CTRL+I',
+ tooltip: true,
+ isToggleable: true
+ });
+ view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
+ // Execute command.
+ this.listenTo(view, 'execute', () => {
+ editor.execute(ITALIC);
+ editor.editing.view.focus();
+ });
+ return view;
+ });
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.d.ts
new file mode 100644
index 00000000..0216dbde
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.d.ts
@@ -0,0 +1,29 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/strikethrough
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import StrikethroughEditing from './strikethrough/strikethroughediting';
+import StrikethroughUI from './strikethrough/strikethroughui';
+/**
+ * The strikethrough feature.
+ *
+ * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide
+ * and the {@glink api/basic-styles package page}.
+ *
+ * This is a "glue" plugin which loads the {@link module:basic-styles/strikethrough/strikethroughediting~StrikethroughEditing} and
+ * {@link module:basic-styles/strikethrough/strikethroughui~StrikethroughUI} plugins.
+ */
+export default class Strikethrough extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires(): readonly [typeof StrikethroughEditing, typeof StrikethroughUI];
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "Strikethrough";
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.js
new file mode 100644
index 00000000..df00fcbb
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough.js
@@ -0,0 +1,33 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/strikethrough
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import StrikethroughEditing from './strikethrough/strikethroughediting';
+import StrikethroughUI from './strikethrough/strikethroughui';
+/**
+ * The strikethrough feature.
+ *
+ * For a detailed overview check the {@glink features/basic-styles Basic styles feature} guide
+ * and the {@glink api/basic-styles package page}.
+ *
+ * This is a "glue" plugin which loads the {@link module:basic-styles/strikethrough/strikethroughediting~StrikethroughEditing} and
+ * {@link module:basic-styles/strikethrough/strikethroughui~StrikethroughUI} plugins.
+ */
+export default class Strikethrough extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires() {
+ return [StrikethroughEditing, StrikethroughUI];
+ }
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'Strikethrough';
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.d.ts
new file mode 100644
index 00000000..aa8421cd
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.d.ts
@@ -0,0 +1,25 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/strikethrough/strikethroughediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+/**
+ * The strikethrough editing feature.
+ *
+ * It registers the `'strikethrough'` command, the Ctrl+Shift+X keystroke and introduces the
+ * `strikethroughsthrough` attribute in the model which renders to the view
+ * as a `
` element.
+ */
+export default class StrikethroughEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "StrikethroughEditing";
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js
new file mode 100644
index 00000000..1779ba60
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughediting.js
@@ -0,0 +1,54 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/strikethrough/strikethroughediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import AttributeCommand from '../attributecommand';
+const STRIKETHROUGH = 'strikethrough';
+/**
+ * The strikethrough editing feature.
+ *
+ * It registers the `'strikethrough'` command, the Ctrl+Shift+X keystroke and introduces the
+ * `strikethroughsthrough` attribute in the model which renders to the view
+ * as a `` element.
+ */
+export default class StrikethroughEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'StrikethroughEditing';
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ // Allow strikethrough attribute on text nodes.
+ editor.model.schema.extend('$text', { allowAttributes: STRIKETHROUGH });
+ editor.model.schema.setAttributeProperties(STRIKETHROUGH, {
+ isFormatting: true,
+ copyOnEnter: true
+ });
+ editor.conversion.attributeToElement({
+ model: STRIKETHROUGH,
+ view: 's',
+ upcastAlso: [
+ 'del',
+ 'strike',
+ {
+ styles: {
+ 'text-decoration': 'line-through'
+ }
+ }
+ ]
+ });
+ // Create strikethrough command.
+ editor.commands.add(STRIKETHROUGH, new AttributeCommand(editor, STRIKETHROUGH));
+ // Set the Ctrl+Shift+X keystroke.
+ editor.keystrokes.set('CTRL+SHIFT+X', 'strikethrough');
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.d.ts
new file mode 100644
index 00000000..9d3beae3
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.d.ts
@@ -0,0 +1,21 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/strikethrough/strikethroughui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+/**
+ * The strikethrough UI feature. It introduces the Strikethrough button.
+ */
+export default class StrikethroughUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "StrikethroughUI";
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js
new file mode 100644
index 00000000..34e042c4
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/strikethrough/strikethroughui.js
@@ -0,0 +1,48 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/strikethrough/strikethroughui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import { ButtonView } from 'ckeditor5/src/ui';
+import strikethroughIcon from '../../theme/icons/strikethrough.svg';
+const STRIKETHROUGH = 'strikethrough';
+/**
+ * The strikethrough UI feature. It introduces the Strikethrough button.
+ */
+export default class StrikethroughUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'StrikethroughUI';
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ const t = editor.t;
+ // Add strikethrough button to feature components.
+ editor.ui.componentFactory.add(STRIKETHROUGH, locale => {
+ const command = editor.commands.get(STRIKETHROUGH);
+ const view = new ButtonView(locale);
+ view.set({
+ label: t('Strikethrough'),
+ icon: strikethroughIcon,
+ keystroke: 'CTRL+SHIFT+X',
+ tooltip: true,
+ isToggleable: true
+ });
+ view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
+ // Execute command.
+ this.listenTo(view, 'execute', () => {
+ editor.execute(STRIKETHROUGH);
+ editor.editing.view.focus();
+ });
+ return view;
+ });
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.d.ts
new file mode 100644
index 00000000..a0181b93
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.d.ts
@@ -0,0 +1,26 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/subscript
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import SubscriptEditing from './subscript/subscriptediting';
+import SubscriptUI from './subscript/subscriptui';
+/**
+ * The subscript feature.
+ *
+ * It loads the {@link module:basic-styles/subscript/subscriptediting~SubscriptEditing} and
+ * {@link module:basic-styles/subscript/subscriptui~SubscriptUI} plugins.
+ */
+export default class Subscript extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires(): readonly [typeof SubscriptEditing, typeof SubscriptUI];
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "Subscript";
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.js
new file mode 100644
index 00000000..3bdb20f5
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript.js
@@ -0,0 +1,30 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/subscript
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import SubscriptEditing from './subscript/subscriptediting';
+import SubscriptUI from './subscript/subscriptui';
+/**
+ * The subscript feature.
+ *
+ * It loads the {@link module:basic-styles/subscript/subscriptediting~SubscriptEditing} and
+ * {@link module:basic-styles/subscript/subscriptui~SubscriptUI} plugins.
+ */
+export default class Subscript extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires() {
+ return [SubscriptEditing, SubscriptUI];
+ }
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'Subscript';
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.d.ts
new file mode 100644
index 00000000..90e2278d
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.d.ts
@@ -0,0 +1,24 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/subscript/subscriptediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+/**
+ * The subscript editing feature.
+ *
+ * It registers the `sub` command and introduces the `sub` attribute in the model which renders to the view
+ * as a `` element.
+ */
+export default class SubscriptEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "SubscriptEditing";
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js
new file mode 100644
index 00000000..8ef8576d
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptediting.js
@@ -0,0 +1,50 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/subscript/subscriptediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import AttributeCommand from '../attributecommand';
+const SUBSCRIPT = 'subscript';
+/**
+ * The subscript editing feature.
+ *
+ * It registers the `sub` command and introduces the `sub` attribute in the model which renders to the view
+ * as a `` element.
+ */
+export default class SubscriptEditing extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'SubscriptEditing';
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ // Allow sub attribute on text nodes.
+ editor.model.schema.extend('$text', { allowAttributes: SUBSCRIPT });
+ editor.model.schema.setAttributeProperties(SUBSCRIPT, {
+ isFormatting: true,
+ copyOnEnter: true
+ });
+ // Build converter from model to view for data and editing pipelines.
+ editor.conversion.attributeToElement({
+ model: SUBSCRIPT,
+ view: 'sub',
+ upcastAlso: [
+ {
+ styles: {
+ 'vertical-align': 'sub'
+ }
+ }
+ ]
+ });
+ // Create sub command.
+ editor.commands.add(SUBSCRIPT, new AttributeCommand(editor, SUBSCRIPT));
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.d.ts
new file mode 100644
index 00000000..bd8f0569
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.d.ts
@@ -0,0 +1,21 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/subscript/subscriptui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+/**
+ * The subscript UI feature. It introduces the Subscript button.
+ */
+export default class SubscriptUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "SubscriptUI";
+ /**
+ * @inheritDoc
+ */
+ init(): void;
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js
new file mode 100644
index 00000000..66631bbc
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/subscript/subscriptui.js
@@ -0,0 +1,47 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/subscript/subscriptui
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import { ButtonView } from 'ckeditor5/src/ui';
+import subscriptIcon from '../../theme/icons/subscript.svg';
+const SUBSCRIPT = 'subscript';
+/**
+ * The subscript UI feature. It introduces the Subscript button.
+ */
+export default class SubscriptUI extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'SubscriptUI';
+ }
+ /**
+ * @inheritDoc
+ */
+ init() {
+ const editor = this.editor;
+ const t = editor.t;
+ // Add subscript button to feature components.
+ editor.ui.componentFactory.add(SUBSCRIPT, locale => {
+ const command = editor.commands.get(SUBSCRIPT);
+ const view = new ButtonView(locale);
+ view.set({
+ label: t('Subscript'),
+ icon: subscriptIcon,
+ tooltip: true,
+ isToggleable: true
+ });
+ view.bind('isOn', 'isEnabled').to(command, 'value', 'isEnabled');
+ // Execute command.
+ this.listenTo(view, 'execute', () => {
+ editor.execute(SUBSCRIPT);
+ editor.editing.view.focus();
+ });
+ return view;
+ });
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.d.ts
new file mode 100644
index 00000000..7fba3989
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.d.ts
@@ -0,0 +1,26 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/superscript
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import SuperscriptEditing from './superscript/superscriptediting';
+import SuperscriptUI from './superscript/superscriptui';
+/**
+ * The superscript feature.
+ *
+ * It loads the {@link module:basic-styles/superscript/superscriptediting~SuperscriptEditing} and
+ * {@link module:basic-styles/superscript/superscriptui~SuperscriptUI} plugins.
+ */
+export default class Superscript extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires(): readonly [typeof SuperscriptEditing, typeof SuperscriptUI];
+ /**
+ * @inheritDoc
+ */
+ static get pluginName(): "Superscript";
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.js b/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.js
new file mode 100644
index 00000000..563550f6
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript.js
@@ -0,0 +1,30 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/superscript
+ */
+import { Plugin } from 'ckeditor5/src/core';
+import SuperscriptEditing from './superscript/superscriptediting';
+import SuperscriptUI from './superscript/superscriptui';
+/**
+ * The superscript feature.
+ *
+ * It loads the {@link module:basic-styles/superscript/superscriptediting~SuperscriptEditing} and
+ * {@link module:basic-styles/superscript/superscriptui~SuperscriptUI} plugins.
+ */
+export default class Superscript extends Plugin {
+ /**
+ * @inheritDoc
+ */
+ static get requires() {
+ return [SuperscriptEditing, SuperscriptUI];
+ }
+ /**
+ * @inheritDoc
+ */
+ static get pluginName() {
+ return 'Superscript';
+ }
+}
diff --git a/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.d.ts b/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.d.ts
new file mode 100644
index 00000000..1adc4b58
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-basic-styles/src/superscript/superscriptediting.d.ts
@@ -0,0 +1,24 @@
+/**
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+/**
+ * @module basic-styles/superscript/superscriptediting
+ */
+import { Plugin } from 'ckeditor5/src/core';
+/**
+ * The superscript editing feature.
+ *
+ * It registers the `super` command and introduces the `super` attribute in the model which renders to the view
+ * as a `
+Copyright (c) 2003-2023, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
+
+Sources of Intellectual Property Included in CKEditor
+-----------------------------------------------------
+
+Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
+
+Trademarks
+----------
+
+**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
diff --git a/node_modules/@ckeditor/ckeditor5-block-quote/README.md b/node_modules/@ckeditor/ckeditor5-block-quote/README.md
new file mode 100644
index 00000000..65c8ca63
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-block-quote/README.md
@@ -0,0 +1,20 @@
+CKEditor 5 block quote feature
+========================================
+
+[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-block-quote.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-block-quote)
+[![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5?branch=master)
+[![Build Status](https://travis-ci.com/ckeditor/ckeditor5.svg?branch=master)](https://app.travis-ci.com/github/ckeditor/ckeditor5)
+
+This package implements block quote support for CKEditor 5.
+
+## Demo
+
+Check out the [demo in the block quote feature guide](https://ckeditor.com/docs/ckeditor5/latest/features/block-quote.html#demo).
+
+## Documentation
+
+See the [`@ckeditor/ckeditor5-block-quote` package](https://ckeditor.com/docs/ckeditor5/latest/api/block-quote.html) page in [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest/).
+
+## License
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). For full details about the license, please check the `LICENSE.md` file or [https://ckeditor.com/legal/ckeditor-oss-license](https://ckeditor.com/legal/ckeditor-oss-license).
diff --git a/node_modules/@ckeditor/ckeditor5-block-quote/build/block-quote.js b/node_modules/@ckeditor/ckeditor5-block-quote/build/block-quote.js
new file mode 100644
index 00000000..a60efe31
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-block-quote/build/block-quote.js
@@ -0,0 +1,5 @@
+!function(e){const t=e.en=e.en||{};t.dictionary=Object.assign(t.dictionary||{},{"Block quote":"Block quote"})}(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={})),
+/*!
+ * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */(()=>{var e={93:(e,t,o)=>{"use strict";o.d(t,{Z:()=>i});var n=o(609),r=o.n(n)()((function(e){return e[1]}));r.push([e.id,".ck-content blockquote{border-left:5px solid #ccc;font-style:italic;margin-left:0;margin-right:0;overflow:hidden;padding-left:1.5em;padding-right:1.5em}.ck-content[dir=rtl] blockquote{border-left:0;border-right:5px solid #ccc}",""]);const i=r},609:e=>{"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map((function(t){var o=e(t);return t[2]?"@media ".concat(t[2]," {").concat(o,"}"):o})).join("")},t.i=function(e,o,n){"string"==typeof e&&(e=[[null,e,""]]);var r={};if(n)for(var i=0;i
+Copyright (c) 2003-2023, [CKSource Holding sp. z o.o.](https://cksource.com) All rights reserved.
+
+Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).
+
+Sources of Intellectual Property Included in CKEditor
+-----------------------------------------------------
+
+Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission.
+
+The following libraries are included in CKEditor under the [MIT license](https://opensource.org/licenses/MIT):
+
+* lodash - Copyright (c) JS Foundation and other contributors https://js.foundation/. Based on Underscore.js, copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors http://underscorejs.org/.
+
+Trademarks
+----------
+
+**CKEditor** is a trademark of [CKSource Holding sp. z o.o.](https://cksource.com) All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
diff --git a/node_modules/@ckeditor/ckeditor5-build-classic/README.md b/node_modules/@ckeditor/ckeditor5-build-classic/README.md
new file mode 100644
index 00000000..9e44c9b1
--- /dev/null
+++ b/node_modules/@ckeditor/ckeditor5-build-classic/README.md
@@ -0,0 +1,70 @@
+CKEditor 5 classic editor build
+========================================
+
+[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-build-classic.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-build-classic)
+[![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5?branch=master)
+[![Build Status](https://travis-ci.com/ckeditor/ckeditor5.svg?branch=master)](https://app.travis-ci.com/github/ckeditor/ckeditor5)
+
+The classic editor build for CKEditor 5. Read more about the [classic editor build](https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/predefined-builds.html#classic-editor) and see the [demo](https://ckeditor.com/docs/ckeditor5/latest/examples/builds/classic-editor.html).
+
+![CKEditor 5 classic editor build screenshot](https://c.cksource.com/a/1/img/npm/ckeditor5-build-classic.png)
+
+## Documentation
+
+See:
+
+* [Installation](https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/quick-start.html) for how to install this package and what it contains.
+* [Editor lifecycle](https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/editor-lifecycle.html) for how to create an editor and interact with it.
+* [Configuration](https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/configuration.html) for how to configure the editor.
+* [Creating custom builds](https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/quick-start.html#building-the-editor-from-source) for how to customize the build (configure and rebuild the editor bundle).
+
+## Quick start
+
+First, install the build from npm:
+
+```bash
+npm install --save @ckeditor/ckeditor5-build-classic
+```
+
+And use it in your website:
+
+```html
+
").replace(/\r?\n/g,"
").replace(/\t/g," ").replace(/^\s/," ").replace(/\s$/," ").replace(/\s\s/g," ")).includes("
")||r.includes("
"))&&(r=`
${r}
`),t=r),i=this.editor.data.htmlProcessor.toView(t)}var r;const s=new p(this,"inputTransformation");this.fire(s,{content:i,dataTransfer:o,targetRanges:e.targetRanges,method:e.method}),s.stop.called&&t.stop(),n.scrollToTheSelection()}),{priority:"low"}),this.listenTo(this,"inputTransformation",((t,n)=>{if(n.content.isEmpty)return;const o=this.editor.data.toModel(n.content,"$clipboardHolder");0!=o.childCount&&(t.stop(),e.change((()=>{this.fire("contentInsertion",{content:o,method:n.method,dataTransfer:n.dataTransfer,targetRanges:n.targetRanges})})))}),{priority:"low"}),this.listenTo(this,"contentInsertion",((t,n)=>{n.resultRange=e.insertContent(n.content)}),{priority:"low"})}_setupCopyCut(){const t=this.editor,e=t.model.document,n=t.editing.view.document,o=(o,i)=>{const r=i.dataTransfer;i.preventDefault();const s=t.data.toView(t.model.getSelectedContent(e.selection));n.fire("clipboardOutput",{dataTransfer:r,content:s,method:o.name})};this.listenTo(n,"copy",o,{priority:"low"}),this.listenTo(n,"cut",((e,n)=>{t.model.canEditAt(t.model.document.selection)?o(e,n):n.preventDefault()}),{priority:"low"}),this.listenTo(n,"clipboardOutput",((n,o)=>{o.content.isEmpty||(o.dataTransfer.setData("text/html",this.editor.data.htmlProcessor.toData(o.content)),o.dataTransfer.setData("text/plain",_f(o.content))),"cut"==o.method&&t.model.deleteContent(e.selection)}),{priority:"low"})}}class yf{constructor(t,e=20){this._batch=null,this.model=t,this._size=0,this.limit=e,this._isLocked=!1,this._changeCallback=(t,e)=>{e.isLocal&&e.isUndoable&&e!==this._batch&&this._reset(!0)},this._selectionChangeCallback=()=>{this._reset()},this.model.document.on("change",this._changeCallback),this.model.document.selection.on("change:range",this._selectionChangeCallback),this.model.document.selection.on("change:attribute",this._selectionChangeCallback)}get batch(){return this._batch||(this._batch=this.model.createBatch({isTyping:!0})),this._batch}get size(){return this._size}input(t){this._size+=t,this._size>=this.limit&&this._reset(!0)}get isLocked(){return this._isLocked}lock(){this._isLocked=!0}unlock(){this._isLocked=!1}destroy(){this.model.document.off("change",this._changeCallback),this.model.document.selection.off("change:range",this._selectionChangeCallback),this.model.document.selection.off("change:attribute",this._selectionChangeCallback)}_reset(t=!1){this.isLocked&&!t||(this._batch=null,this._size=0)}}class xf extends Yr{constructor(t,e){super(t),this._buffer=new yf(t.model,e),this._isEnabledBasedOnSelection=!1}get buffer(){return this._buffer}destroy(){super.destroy(),this._buffer.destroy()}execute(t={}){const e=this.editor.model,n=e.document,o=t.text||"",i=o.length;let r=n.selection;if(t.selection?r=t.selection:t.range&&(r=e.createSelection(t.range)),!e.canEditAt(r))return;const s=t.resultRange;e.enqueueChange(this._buffer.batch,(t=>{this._buffer.lock(),e.deleteContent(r),o&&e.insertContent(t.createText(o,n.selection.getAttributes()),r),s?t.setSelection(s):r.is("documentSelection")||t.setSelection(r),this._buffer.unlock(),this._buffer.input(i)}))}}const Ef=["insertText","insertReplacementText"];class Df extends Mc{constructor(t){super(t),this.focusObserver=t.getObserver(bl),a.isAndroid&&Ef.push("insertCompositionText");const e=t.document;e.on("beforeinput",((n,o)=>{if(!this.isEnabled)return;const{data:i,targetRanges:r,inputType:s,domEvent:a}=o;if(!Ef.includes(s))return;this.focusObserver.flush();const c=new p(e,"insertText");e.fire(c,new Bc(t,a,{text:i,selection:t.createSelection(r)})),c.stop.called&&n.stop()})),e.on("compositionend",((n,{data:o,domEvent:i})=>{this.isEnabled&&!a.isAndroid&&o&&e.fire("insertText",new Bc(t,i,{text:o,selection:e.selection}))}),{priority:"lowest"})}observe(){}stopObserving(){}}class Sf extends Wr{static get pluginName(){return"Input"}init(){const t=this.editor,e=t.model,n=t.editing.view,o=e.document.selection;n.addObserver(Df);const i=new xf(t,t.config.get("typing.undoStep")||20);t.commands.add("insertText",i),t.commands.add("input",i),this.listenTo(n.document,"insertText",((o,i)=>{n.document.isComposing||i.preventDefault();const{text:r,selection:s,resultRange:c}=i,l=Array.from(s.getRanges()).map((e=>t.editing.mapper.toModelRange(e)));let d=r;if(a.isAndroid){const t=Array.from(l[0].getItems()).reduce(((t,e)=>t+(e.is("$textProxy")?e.data:"")),"");t&&(t.length<=d.length?d.startsWith(t)&&(d=d.substring(t.length),l[0].start=l[0].start.getShiftedBy(t.length)):t.startsWith(d)&&(l[0].start=l[0].start.getShiftedBy(d.length),d=""))}const u={text:d,selection:e.createSelection(l)};c&&(u.resultRange=t.editing.mapper.toModelRange(c)),t.execute("insertText",u),n.scrollToTheSelection()})),a.isAndroid?this.listenTo(n.document,"keydown",((t,r)=>{!o.isCollapsed&&229==r.keyCode&&n.document.isComposing&&If(e,i)})):this.listenTo(n.document,"compositionstart",(()=>{o.isCollapsed||If(e,i)}))}}function If(t,e){if(!e.isEnabled)return;const n=e.buffer;n.lock(),t.enqueueChange(n.batch,(()=>{t.deleteContent(t.document.selection)})),n.unlock()}class Mf extends Yr{constructor(t,e){super(t),this.direction=e,this._buffer=new yf(t.model,t.config.get("typing.undoStep")),this._isEnabledBasedOnSelection=!1}get buffer(){return this._buffer}execute(t={}){const e=this.editor.model,n=e.document;e.enqueueChange(this._buffer.batch,(o=>{this._buffer.lock();const i=o.createSelection(t.selection||n.selection);if(!e.canEditAt(i))return;const r=t.sequence||1,s=i.isCollapsed;if(i.isCollapsed&&e.modifySelection(i,{direction:this.direction,unit:t.unit,treatEmojiAsSingleUnit:!0}),this._shouldEntireContentBeReplacedWithParagraph(r))return void this._replaceEntireContentWithParagraph(o);if(this._shouldReplaceFirstBlockWithParagraph(i,r))return void this.editor.execute("paragraph",{selection:i});if(i.isCollapsed)return;let a=0;i.getFirstRange().getMinimalFlatRanges().forEach((t=>{a+=tt(t.getWalker({singleCharacters:!0,ignoreElementEnd:!0,shallow:!0}))})),e.deleteContent(i,{doNotResetEntireContent:s,direction:this.direction}),this._buffer.input(a),o.setSelection(i),this._buffer.unlock()}))}_shouldEntireContentBeReplacedWithParagraph(t){if(t>1)return!1;const e=this.editor.model,n=e.document.selection,o=e.schema.getLimitElement(n);if(!(n.isCollapsed&&n.containsEntireContent(o)))return!1;if(!e.schema.checkChild(o,"paragraph"))return!1;const i=o.getChild(0);return!i||!i.is("element","paragraph")}_replaceEntireContentWithParagraph(t){const e=this.editor.model,n=e.document.selection,o=e.schema.getLimitElement(n),i=t.createElement("paragraph");t.remove(t.createRangeIn(o)),t.insert(i,o),t.setSelection(i,0)}_shouldReplaceFirstBlockWithParagraph(t,e){const n=this.editor.model;if(e>1||"backward"!=this.direction)return!1;if(!t.isCollapsed)return!1;const o=t.getFirstPosition(),i=n.schema.getLimitElement(o),r=i.getChild(0);return o.parent==r&&(!!t.containsEntireContent(r)&&(!!n.schema.checkChild(i,"paragraph")&&"paragraph"!=r.name))}}const Tf="word",Bf="selection",Nf="backward",Pf="forward",zf={deleteContent:{unit:Bf,direction:Nf},deleteContentBackward:{unit:"codePoint",direction:Nf},deleteWordBackward:{unit:Tf,direction:Nf},deleteHardLineBackward:{unit:Bf,direction:Nf},deleteSoftLineBackward:{unit:Bf,direction:Nf},deleteContentForward:{unit:"character",direction:Pf},deleteWordForward:{unit:Tf,direction:Pf},deleteHardLineForward:{unit:Bf,direction:Pf},deleteSoftLineForward:{unit:Bf,direction:Pf}};class Of extends Mc{constructor(t){super(t);const e=t.document;let n=0;e.on("keydown",(()=>{n++})),e.on("keyup",(()=>{n=0})),e.on("beforeinput",((o,i)=>{if(!this.isEnabled)return;const{targetRanges:r,domEvent:s,inputType:c}=i,l=zf[c];if(!l)return;const d={direction:l.direction,unit:l.unit,sequence:n};d.unit==Bf&&(d.selectionToRemove=t.createSelection(r[0])),"deleteContentBackward"===c&&(a.isAndroid&&(d.sequence=1),function(t){if(1!=t.length||t[0].isCollapsed)return!1;const e=t[0].getWalker({direction:"backward",singleCharacters:!0,ignoreElementEnd:!0});let n=0;for(const{nextPosition:t}of e){if(t.parent.is("$text")){const e=t.parent.data,o=t.offset;if(Pi(e,o)||zi(e,o)||Li(e,o))continue;n++}else n++;if(n>1)return!0}return!1}(r)&&(d.unit=Bf,d.selectionToRemove=t.createSelection(r)));const u=new Da(e,"delete",r[0]);e.fire(u,new Bc(t,s,d)),u.stop.called&&o.stop()})),a.isBlink&&function(t){const e=t.view,n=e.document;let o=null,i=!1;function r(t){return t==ki.backspace||t==ki.delete}function s(t){return t==ki.backspace?Nf:Pf}n.on("keydown",((t,{keyCode:e})=>{o=e,i=!1})),n.on("keyup",((a,{keyCode:c,domEvent:l})=>{const d=n.selection,u=t.isEnabled&&c==o&&r(c)&&!d.isCollapsed&&!i;if(o=null,u){const t=d.getFirstRange(),o=new Da(n,"delete",t),i={unit:Bf,direction:s(c),selectionToRemove:d};n.fire(o,new Bc(e,l,i))}})),n.on("beforeinput",((t,{inputType:e})=>{const n=zf[e];r(o)&&n&&n.direction==s(o)&&(i=!0)}),{priority:"high"}),n.on("beforeinput",((t,{inputType:e,data:n})=>{o==ki.delete&&"insertText"==e&&""==n&&t.stop()}),{priority:"high"})}(this)}observe(){}stopObserving(){}}class Lf extends Wr{static get pluginName(){return"Delete"}init(){const t=this.editor,e=t.editing.view,n=e.document,o=t.model.document;e.addObserver(Of),this._undoOnBackspace=!1;const i=new Mf(t,"forward");t.commands.add("deleteForward",i),t.commands.add("forwardDelete",i),t.commands.add("delete",new Mf(t,"backward")),this.listenTo(n,"delete",((o,i)=>{n.isComposing||i.preventDefault();const{direction:r,sequence:s,selectionToRemove:a,unit:c}=i,l="forward"===r?"deleteForward":"delete",d={sequence:s};if("selection"==c){const e=Array.from(a.getRanges()).map((e=>t.editing.mapper.toModelRange(e)));d.selection=t.model.createSelection(e)}else d.unit=c;t.execute(l,d),e.scrollToTheSelection()}),{priority:"low"}),this.editor.plugins.has("UndoEditing")&&(this.listenTo(n,"delete",((e,n)=>{this._undoOnBackspace&&"backward"==n.direction&&1==n.sequence&&"codePoint"==n.unit&&(this._undoOnBackspace=!1,t.execute("undo"),n.preventDefault(),e.stop())}),{context:"$capture"}),this.listenTo(o,"change",(()=>{this._undoOnBackspace=!1})))}requestUndoOnBackspace(){this.editor.plugins.has("UndoEditing")&&(this._undoOnBackspace=!0)}}class jf extends Wr{static get requires(){return[Sf,Lf]}static get pluginName(){return"Typing"}}function Rf(t,e){let n=t.start;return{text:Array.from(t.getWalker({ignoreElementEnd:!1})).reduce(((t,{item:o})=>o.is("$text")||o.is("$textProxy")?t+o.data:(n=e.createPositionAfter(o),"")),""),range:e.createRange(n,t.end)}}class Ff extends(K()){constructor(t,e){super(),this.model=t,this.testCallback=e,this._hasMatch=!1,this.set("isEnabled",!0),this.on("change:isEnabled",(()=>{this.isEnabled?this._startListening():(this.stopListening(t.document.selection),this.stopListening(t.document))})),this._startListening()}get hasMatch(){return this._hasMatch}_startListening(){const t=this.model.document;this.listenTo(t.selection,"change:range",((e,{directChange:n})=>{n&&(t.selection.isCollapsed?this._evaluateTextBeforeSelection("selection"):this.hasMatch&&(this.fire("unmatched"),this._hasMatch=!1))})),this.listenTo(t,"change:data",((t,e)=>{!e.isUndo&&e.isLocal&&this._evaluateTextBeforeSelection("data",{batch:e})}))}_evaluateTextBeforeSelection(t,e={}){const n=this.model,o=n.document.selection,i=n.createRange(n.createPositionAt(o.focus.parent,0),o.focus),{text:r,range:s}=Rf(i,n),a=this.testCallback(r);if(!a&&this.hasMatch&&this.fire("unmatched"),this._hasMatch=!!a,a){const n=Object.assign(e,{text:r,range:s});"object"==typeof a&&Object.assign(n,a),this.fire(`matched:${t}`,n)}}}class Vf extends Wr{constructor(t){super(t),this.attributes=new Set,this._overrideUid=null}static get pluginName(){return"TwoStepCaretMovement"}init(){const t=this.editor,e=t.model,n=t.editing.view,o=t.locale,i=e.document.selection;this.listenTo(n.document,"arrowKey",((t,e)=>{if(!i.isCollapsed)return;if(e.shiftKey||e.altKey||e.ctrlKey)return;const n=e.keyCode==ki.arrowright,r=e.keyCode==ki.arrowleft;if(!n&&!r)return;const s=o.contentLanguageDirection;let a=!1;a="ltr"===s&&n||"rtl"===s&&r?this._handleForwardMovement(e):this._handleBackwardMovement(e),!0===a&&t.stop()}),{context:"$text",priority:"highest"}),this._isNextGravityRestorationSkipped=!1,this.listenTo(i,"change:range",((t,e)=>{this._isNextGravityRestorationSkipped?this._isNextGravityRestorationSkipped=!1:this._isGravityOverridden&&(!e.directChange&&qf(i.getFirstPosition(),this.attributes)||this._restoreGravity())}))}registerAttribute(t){this.attributes.add(t)}_handleForwardMovement(t){const e=this.attributes,n=this.editor.model.document.selection,o=n.getFirstPosition();return!this._isGravityOverridden&&((!o.isAtStart||!Uf(n,e))&&(!!qf(o,e)&&(Gf(t),this._overrideGravity(),!0)))}_handleBackwardMovement(t){const e=this.attributes,n=this.editor.model,o=n.document.selection,i=o.getFirstPosition();return this._isGravityOverridden?(Gf(t),this._restoreGravity(),Hf(n,e,i),!0):i.isAtStart?!!Uf(o,e)&&(Gf(t),Hf(n,e,i),!0):!!function(t,e){const n=t.getShiftedBy(-1);return qf(n,e)}(i,e)&&(i.isAtEnd&&!Uf(o,e)&&qf(i,e)?(Gf(t),Hf(n,e,i),!0):(this._isNextGravityRestorationSkipped=!0,this._overrideGravity(),!1))}get _isGravityOverridden(){return!!this._overrideUid}_overrideGravity(){this._overrideUid=this.editor.model.change((t=>t.overrideSelectionGravity()))}_restoreGravity(){this.editor.model.change((t=>{t.restoreSelectionGravity(this._overrideUid),this._overrideUid=null}))}}function Uf(t,e){for(const n of e)if(t.hasAttribute(n))return!0;return!1}function Hf(t,e,n){const o=n.nodeBefore;t.change((n=>{if(o){const e=[],i=t.schema.isObject(o)&&t.schema.isInline(o);for(const[n,r]of o.getAttributes())!t.schema.checkAttribute("$text",n)||i&&!1===t.schema.getAttributeProperties(n).copyFromObject||e.push([n,r]);n.setSelectionAttribute(e)}else n.removeSelectionAttribute(e)}))}function Gf(t){t.preventDefault()}function qf(t,e){const{nodeBefore:n,nodeAfter:o}=t;for(const t of e){const e=n?n.getAttribute(t):void 0;if((o?o.getAttribute(t):void 0)!==e)return!0}return!1}var Wf=/[\\^$.*+?()[\]{}|]/g,Kf=RegExp(Wf.source);const Yf=function(t){return(t=Bs(t))&&Kf.test(t)?t.replace(Wf,"\\$&"):t},$f={copyright:{from:"(c)",to:"©"},registeredTrademark:{from:"(r)",to:"®"},trademark:{from:"(tm)",to:"™"},oneHalf:{from:/(^|[^/a-z0-9])(1\/2)([^/a-z0-9])$/i,to:[null,"½",null]},oneThird:{from:/(^|[^/a-z0-9])(1\/3)([^/a-z0-9])$/i,to:[null,"⅓",null]},twoThirds:{from:/(^|[^/a-z0-9])(2\/3)([^/a-z0-9])$/i,to:[null,"⅔",null]},oneForth:{from:/(^|[^/a-z0-9])(1\/4)([^/a-z0-9])$/i,to:[null,"¼",null]},threeQuarters:{from:/(^|[^/a-z0-9])(3\/4)([^/a-z0-9])$/i,to:[null,"¾",null]},lessThanOrEqual:{from:"<=",to:"≤"},greaterThanOrEqual:{from:">=",to:"≥"},notEqual:{from:"!=",to:"≠"},arrowLeft:{from:"<-",to:"←"},arrowRight:{from:"->",to:"→"},horizontalEllipsis:{from:"...",to:"…"},enDash:{from:/(^| )(--)( )$/,to:[null,"–",null]},emDash:{from:/(^| )(---)( )$/,to:[null,"—",null]},quotesPrimary:{from:ek('"'),to:[null,"“",null,"”"]},quotesSecondary:{from:ek("'"),to:[null,"‘",null,"’"]},quotesPrimaryEnGb:{from:ek("'"),to:[null,"‘",null,"’"]},quotesSecondaryEnGb:{from:ek('"'),to:[null,"“",null,"”"]},quotesPrimaryPl:{from:ek('"'),to:[null,"„",null,"”"]},quotesSecondaryPl:{from:ek("'"),to:[null,"‚",null,"’"]}},Zf={symbols:["copyright","registeredTrademark","trademark"],mathematical:["oneHalf","oneThird","twoThirds","oneForth","threeQuarters","lessThanOrEqual","greaterThanOrEqual","notEqual","arrowLeft","arrowRight"],typography:["horizontalEllipsis","enDash","emDash"],quotes:["quotesPrimary","quotesSecondary"]},Qf=["symbols","mathematical","typography","quotes"];function Jf(t){return"string"==typeof t?new RegExp(`(${Yf(t)})$`):t}function Xf(t){return"string"==typeof t?()=>[t]:t instanceof Array?()=>t:t}function tk(t){return(t.textNode?t.textNode:t.nodeAfter).getAttributes()}function ek(t){return new RegExp(`(^|\\s)(${t})([^${t}]*)(${t})$`)}function nk(t,e,n,o){return o.createRange(ok(t,e,n,!0,o),ok(t,e,n,!1,o))}function ok(t,e,n,o,i){let r=t.textNode||(o?t.nodeBefore:t.nodeAfter),s=null;for(;r&&r.getAttribute(e)==n;)s=r,r=o?r.previousSibling:r.nextSibling;return s?i.createPositionAt(s,o?"before":"after"):t}function*ik(t,e){for(const n of e)n&&t.getAttributeProperties(n[0]).copyOnEnter&&(yield n)}class rk extends Yr{execute(){this.editor.model.change((t=>{this.enterBlock(t),this.fire("afterExecute",{writer:t})}))}enterBlock(t){const e=this.editor.model,n=e.document.selection,o=e.schema,i=n.isCollapsed,r=n.getFirstRange(),s=r.start.parent,a=r.end.parent;if(o.isLimit(s)||o.isLimit(a))return i||s!=a||e.deleteContent(n),!1;if(i){const e=ik(t.model.schema,n.getAttributes());return sk(t,r.start),t.setSelectionAttribute(e),!0}{const o=!(r.start.isAtStart&&r.end.isAtEnd),i=s==a;if(e.deleteContent(n,{leaveUnmerged:o}),o){if(i)return sk(t,n.focus),!0;t.setSelection(a,0)}}return!1}}function sk(t,e){t.split(e),t.setSelection(e.parent.nextSibling,0)}const ak={insertParagraph:{isSoft:!1},insertLineBreak:{isSoft:!0}};class ck extends Mc{constructor(t){super(t);const e=this.document;let n=!1;e.on("keydown",((t,e)=>{n=e.shiftKey})),e.on("beforeinput",((o,i)=>{if(!this.isEnabled)return;let r=i.inputType;a.isSafari&&n&&"insertParagraph"==r&&(r="insertLineBreak");const s=i.domEvent,c=ak[r];if(!c)return;const l=new Da(e,"enter",i.targetRanges[0]);e.fire(l,new Bc(t,s,{isSoft:c.isSoft})),l.stop.called&&o.stop()}))}observe(){}stopObserving(){}}class lk extends Wr{static get pluginName(){return"Enter"}init(){const t=this.editor,e=t.editing.view,n=e.document;e.addObserver(ck),t.commands.add("enter",new rk(t)),this.listenTo(n,"enter",((o,i)=>{n.isComposing||i.preventDefault(),i.isSoft||(t.execute("enter"),e.scrollToTheSelection())}),{priority:"low"})}}class dk extends Yr{execute(){const t=this.editor.model,e=t.document;t.change((n=>{!function(t,e,n){const o=n.isCollapsed,i=n.getFirstRange(),r=i.start.parent,s=i.end.parent,a=r==s;if(o){const o=ik(t.schema,n.getAttributes());uk(t,e,i.end),e.removeSelectionAttribute(n.getAttributeKeys()),e.setSelectionAttribute(o)}else{const o=!(i.start.isAtStart&&i.end.isAtEnd);t.deleteContent(n,{leaveUnmerged:o}),a?uk(t,e,n.focus):o&&e.setSelection(s,0)}}(t,n,e.selection),this.fire("afterExecute",{writer:n})}))}refresh(){const t=this.editor.model,e=t.document;this.isEnabled=function(t,e){if(e.rangeCount>1)return!1;const n=e.anchor;if(!n||!t.checkChild(n,"softBreak"))return!1;const o=e.getFirstRange(),i=o.start.parent,r=o.end.parent;if((hk(i,t)||hk(r,t))&&i!==r)return!1;return!0}(t.schema,e.selection)}}function uk(t,e,n){const o=e.createElement("softBreak");t.insertContent(o,n),e.setSelection(o,"after")}function hk(t,e){return!t.is("rootElement")&&(e.isLimit(t)||hk(t.parent,e))}class gk extends Wr{static get pluginName(){return"ShiftEnter"}init(){const t=this.editor,e=t.model.schema,n=t.conversion,o=t.editing.view,i=o.document;e.register("softBreak",{allowWhere:"$text",isInline:!0}),n.for("upcast").elementToElement({model:"softBreak",view:"br"}),n.for("downcast").elementToElement({model:"softBreak",view:(t,{writer:e})=>e.createEmptyElement("br")}),o.addObserver(ck),t.commands.add("shiftEnter",new dk(t)),this.listenTo(i,"enter",((e,n)=>{i.isComposing||n.preventDefault(),n.isSoft&&(t.execute("shiftEnter"),o.scrollToTheSelection())}),{priority:"low"})}}class pk extends(B()){constructor(){super(...arguments),this._stack=[]}add(t,e){const n=this._stack,o=n[0];this._insertDescriptor(t);const i=n[0];o===i||mk(o,i)||this.fire("change:top",{oldDescriptor:o,newDescriptor:i,writer:e})}remove(t,e){const n=this._stack,o=n[0];this._removeDescriptor(t);const i=n[0];o===i||mk(o,i)||this.fire("change:top",{oldDescriptor:o,newDescriptor:i,writer:e})}_insertDescriptor(t){const e=this._stack,n=e.findIndex((e=>e.id===t.id));if(mk(t,e[n]))return;n>-1&&e.splice(n,1);let o=0;for(;e[o]&&fk(e[o],t);)o++;e.splice(o,0,t)}_removeDescriptor(t){const e=this._stack,n=e.findIndex((e=>e.id===t));n>-1&&e.splice(n,1)}}function mk(t,e){return t&&e&&t.priority==e.priority&&kk(t.classes)==kk(e.classes)}function fk(t,e){return t.priority>e.priority||!(t.priorityabc
\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//abc
-->abc
\n\t\t\t//abc
-->abc
\n\t\t\telse if ( isText || !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// --> \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\tprivate _unwrapChildren( parent: Element, startOffset: number, endOffset: number, unwrapElement: AttributeElement ) {\n\t\tlet i = startOffset;\n\t\tconst unwrapPositions: Arrayabcxyz
-->abcxyz
\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//abcxyz
-->\n\t\t\t// xyz
abcxyz
-->abcxyz
\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//abc
-->
abc
\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 * @returns New range after wrapping, spanning over wrapping attribute element.\n\t */\n\tprivate _wrapRange( range: Range, attribute: AttributeElement ): Range {\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 as Element;\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 * @returns New position after wrapping.\n\t */\n\tprivate _wrapPosition( position: Position, attribute: AttributeElement ): Position {\n\t\t// Return same position when trying to wrap with attribute similar to position parent.\n\t\tif ( attribute.isSimilar( position.parent as any ) ) {\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 fakeElement = this.createAttributeElement( '_wrapPosition-fake-element' );\n\t\t( fakeElement as any )._priority = Number.POSITIVE_INFINITY;\n\t\tfakeElement.isSimilar = () => false;\n\n\t\t// Insert fake element in position location.\n\t\t( position.parent as Element )._insertChild( position.offset, fakeElement );\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( fakeElement.parent!, fakeElement.index! );\n\t\tfakeElement._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 * Wraps one {@link module:engine/view/attributeelement~AttributeElement AttributeElement} into another by\n\t * merging them if possible. When merging is possible - all attributes, styles and classes are moved from wrapper\n\t * element to element being wrapped.\n\t *\n\t * @param wrapper Wrapper AttributeElement.\n\t * @param toWrap AttributeElement to wrap using wrapper element.\n\t * @returns Returns `true` if elements are merged.\n\t */\n\tprivate _wrapAttributeElement( wrapper: AttributeElement, toWrap: AttributeElement ): boolean {\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 * @param wrapper Wrapper AttributeElement.\n\t * @param toUnwrap AttributeElement to unwrap using wrapper element.\n\t * @returns Returns `true` if elements are unwrapped.\n\t **/\n\tprivate _unwrapAttributeElement( wrapper: AttributeElement, toUnwrap: AttributeElement ): boolean {\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 * @param range Range which `start` and `end` positions will be used to break attributes.\n\t * @param forceSplitText 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 New range with located at break positions.\n\t */\n\tprivate _breakAttributesRange( range: Range, forceSplitText: boolean = 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 as Element ).childCount;\n\t\tconst breakStart = this._breakAttributes( rangeStart, forceSplitText );\n\n\t\t// Calculate new break end offset.\n\t\tbreakEnd.offset += ( breakEnd.parent as Element ).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 * @param position Position where to break attributes.\n\t * @param forceSplitText 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 New position after breaking the attributes.\n\t */\n\tprivate _breakAttributes( position: Position, forceSplitText: boolean = false ): Position {\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 as any ).childCount;\n\n\t\t//
foobar{}
\n\t\t//foobar[]
\n\t\t//foobar[]
\n\t\tif ( positionOffset == length ) {\n\t\t\tconst newPosition = new Position( positionParent.parent as any, ( positionParent as any ).index + 1 );\n\n\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t} else {\n\t\t\t//foo{}bar
\n\t\t\t//foo[]bar
\n\t\t\t//foo{}bar
\n\t\t\tif ( positionOffset === 0 ) {\n\t\t\t\tconst newPosition = new Position( positionParent.parent as Element, ( positionParent as any ).index );\n\n\t\t\t\treturn this._breakAttributes( newPosition, forceSplitText );\n\t\t\t}\n\t\t\t//foob{}ar
\n\t\t\t//foob[]ar
\n\t\t\t//foob[]ar
\n\t\t\t//foob[]ar
\n\t\t\telse {\n\t\t\t\tconst offsetAfter = ( positionParent as any ).index + 1;\n\n\t\t\t\t// Break element.\n\t\t\t\tconst clonedNode = ( positionParent as any )._clone();\n\n\t\t\t\t// Insert cloned node to position's parent node.\n\t\t\t\t( positionParent.parent as any )._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 as any ).childCount - positionOffset;\n\t\t\t\tconst nodesToMove = ( positionParent as any )._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 as any ).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 * @param element Attribute element to save.\n\t */\n\tprivate _addToClonedElementsGroup( element: Node ): void {\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 as any ).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 as AttributeElement );\n\t\t( element as any )._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 * @param element Attribute element to remove.\n\t */\n\tprivate _removeFromClonedElementsGroup( element: Node ) {\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 as any ).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 as AttributeElement );\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: Element ): boolean {\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/**\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 position Position used as a start point to locate parent container.\n * @returns Parent container element or `undefined` if container is not found.\n */\nfunction getParentContainer( position: Position ): ContainerElement | DocumentFragment | undefined {\n\tlet parent = position.parent;\n\n\twhile ( !isContainerOrFragment( parent ) ) {\n\t\tif ( !parent ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tparent = parent.parent as any;\n\t}\n\n\treturn ( parent as ContainerElement | DocumentFragment );\n}\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 */\nfunction shouldABeOutsideB( a: AttributeElement, b: AttributeElement ): boolean {\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/**\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 * ```html\n *foo[]
->foo{}
\n *[]foo
->{}foo
\n * ```\n *\n * @returns Position located inside text node or same position if there is no text nodes\n * before or after position location.\n */\nfunction movePositionToTextNode( position: Position ): 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/**\n * Breaks text node into two text nodes when possible.\n *\n * ```html\n *foo{}bar
->foo[]bar
\n *{}foobar
->[]foobar
\n *foobar{}
->foobar[]
\n * ```\n *\n * @param position Position that need to be placed inside text node.\n * @returns New position after breaking text node.\n */\nfunction breakTextNode( position: Position ): Position {\n\tif ( position.offset == ( position.parent as Text ).data.length ) {\n\t\treturn new Position( position.parent.parent as any, ( position.parent as Text ).index! + 1 );\n\t}\n\n\tif ( position.offset === 0 ) {\n\t\treturn new Position( position.parent.parent as any, ( position.parent as Text ).index! );\n\t}\n\n\t// Get part of the text that need to be moved.\n\tconst textToMove = ( position.parent as Text ).data.slice( position.offset );\n\n\t// Leave rest of the text in position's parent.\n\t( position.parent as Text )._data = ( position.parent as Text ).data.slice( 0, position.offset );\n\n\t// Insert new text node after position's parent text node.\n\t( position.parent.parent as any )._insertChild(\n\t\t( position.parent as Text ).index! + 1,\n\t\tnew Text( position.root.document, textToMove )\n\t);\n\n\t// Return new position between two newly created text nodes.\n\treturn new Position( position.parent.parent as any, ( position.parent as Text ).index! + 1 );\n}\n\n/**\n * Merges two text nodes into first node. Removes second node and returns merge position.\n *\n * @param t1 First text node to merge. Data from second text node will be moved at the end of this text node.\n * @param t2 Second text node to merge. This node will be removed after merging.\n * @returns Position after merging text nodes.\n */\nfunction mergeTextNodes( t1: Text, t2: Text ): Position {\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\nconst validNodesToInsert = [ Text, AttributeElement, ContainerElement, EmptyElement, RawElement, UIElement ];\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 */\nfunction validateNodesToInsert( nodes: Iterable`. CKEditor uses `
` as a block filler during the editing,\n * as browsers do natively. So instead of an empty `
` there will be `
FooBarBazBax
\n\t * Expected DOM:\tBar123Baz456
\n\t * Input actions:\t[ insert, insert, delete, delete, equal, insert, delete ]\n\t * Output actions:\t[ insert, replace, delete, equal, replace ]\n\t * ```\n\t *\n\t * @param actions Actions array which is a result of the {@link module:utils/diff~diff} function.\n\t * @param actualDom Actual DOM children\n\t * @param expectedDom Expected DOM children.\n\t * @param comparator A comparator function that should return `true` if the given node should be reused\n\t * (either by the update of a text node data or an element children list for similar elements).\n\t * @returns Actions array modified with the `update` actions.\n\t */\n\tprivate _findUpdateActions(\n\t\tactions: Arrayfoo
[]