├── .babelrc
├── .eslintrc
├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── dist
├── vue-ckeditor5.js
└── vue-ckeditor5.js.map
├── examples
├── custom-editors
│ ├── ckeditor.js
│ ├── ckeditor.js.map
│ └── translations
│ │ └── ru.js
├── example1
│ └── index.html
├── example2
│ └── index.html
├── example4
│ ├── index.html
│ └── style.css
├── example5
│ └── index.html
└── example6
│ └── index.html
├── package.json
├── src
├── index.js
└── vue-ckeditor.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"]
3 | }
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "extends": "standard",
4 | "globals": {
5 | "VERSION": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
3 | *.html text eol=lf
4 | *.js text eol=lf
5 | *.json text eol=lf
6 | *.md text eol=lf
7 | .babelrc text eol=lf
8 | .eslintrc text eol=lf
9 | .gitattributes text eol=lf
10 | .gitignore text eol=lf
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .idea
3 | .git
4 |
5 | package-lock.json
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 igorxut
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
VueCkeditor5
2 |
3 | [](https://github.com/igorxut/vue-ckeditor5/blob/master/LICENSE)
4 | [](https://www.npmjs.com/package/vue-ckeditor5)
5 | [](https://github.com/igorxut/vue-ckeditor5/blob/master/dist/vue-ckeditor5.js)
6 |
7 | Description
8 |
9 |
10 |
11 |
12 |
13 |
14 | Component CKEditor 5 for Vue 2.
15 |
16 | Project is outdated. See official release .
17 |
18 | Installation
19 |
20 | NMP
21 |
22 | ```shell
23 | npm install vue-ckeditor5
24 | ```
25 |
26 | Manual
27 |
28 | Download file from repository, paste it in your project and insert path to it in your page by code:
29 |
30 | ```html
31 |
32 | ```
33 |
34 |
35 |
36 |
37 | Usage
38 |
39 | How to
40 |
41 | You must paste CKEditor's 5 implementations to vue component. You can use even custom build of CKEditor 5.
42 |
43 | See examples .
44 |
45 | First way - Global
46 |
47 | You can register component globaly by plugin (recommended):
48 |
49 | ```javascript
50 | import Vue from 'vue'
51 | import ClassicEditor from '@ckeditor/ckeditor5-build-classic'
52 | import VueCkeditor from 'vue-ckeditor5'
53 |
54 | const options = {
55 | editors: {
56 | classic: ClassicEditor,
57 | },
58 | name: 'ckeditor'
59 | }
60 |
61 | Vue.use(VueCkeditor.plugin, options);
62 | ```
63 |
64 | Then you can use the component in your template:
65 |
66 | ```html
67 |
68 | ```
69 |
70 | Plugin options
71 |
72 |
73 |
74 |
75 | property
76 | type
77 | required
78 | default
79 | description
80 |
81 |
82 |
83 |
84 | editors
85 | Object
86 | true
87 |
88 |
89 | Map of editors:
90 |
91 | value - CKEditor 5 implementation
92 | key - alias for it (for prop 'type ')
93 |
94 |
95 |
96 |
97 | name
98 | String
99 | false
100 | 'vue-ckeditor'
101 | Name of component.
102 |
103 |
104 |
105 |
106 | Second way - Local
107 |
108 | You can register component localy:
109 |
110 | ```javascript
111 | import Vue from 'vue'
112 | import ClassicEditor from '@ckeditor/ckeditor5-build-classic'
113 | import VueCkeditor from 'vue-ckeditor5'
114 |
115 | new Vue({
116 | el: '#app',
117 | components: {
118 | 'vue-ckeditor': VueCkeditor.component
119 | },
120 | data: {
121 | value1: 'hello',
122 | value2: 'world',
123 | editors: {
124 | classic: ClassicEditor
125 | }
126 | },
127 | template:
128 | ` `
129 | })
130 | ```
131 |
132 | Component's props
133 |
134 |
135 |
136 |
137 | prop
138 | type
139 | required
140 | default
141 | description
142 |
143 |
144 |
145 |
146 | config
147 | Object
148 | false
149 | {language:'en'}
150 | Object with config properties for CKEditor 5 instance.
151 |
152 |
153 | editors
154 | Object
155 | false
156 | {}
157 |
158 | Map of editors:
159 |
160 | value - CKEditor 5 implementation
161 | key - alias for it (for prop 'type ')
162 |
163 |
164 |
165 |
166 | emptyValue
167 |
168 | false
169 |
170 | Set if you want to change the 'v-model ' value of emptiness editor.
171 |
172 |
173 | readonly
174 | Boolean
175 | false
176 | false
177 | Read-only mode for CKEditor 5 instance.
178 |
179 |
180 | tag
181 | String
182 | false
183 | div
184 | HTMLElement for rendering.
185 |
186 |
187 | toolbarContainer
188 | String
189 | false
190 | null
191 | CSS-selector of DOM-element for CKEditor toolbar. The element is searched by Document.querySelector() .
192 |
193 |
194 | type
195 | String
196 | true
197 |
198 | Key for CKEditor 5 implementation of 'editors ' prop.
199 |
200 |
201 | value
202 | String
203 | true
204 | ''
205 | Value for data bindings. Use 'v-model ' for it.
206 |
207 |
208 |
209 |
210 | Normal HTML attributes
211 |
212 | You can bind normal HTML attributes to component like this (data-api
for example):
213 |
214 | ```html
215 |
216 | ```
217 |
218 | Component's events
219 |
220 |
221 |
222 |
223 | name
224 | parameters
225 | description
226 |
227 |
228 |
229 |
230 | ready(instance)
231 |
232 |
233 | instance
234 | Instance of CKEditor.
235 |
236 |
237 | Instance of CKEditor is ready.
238 |
239 |
240 | destroy(instance)
241 |
242 |
243 | instance
244 | Instance of CKEditor.
245 |
246 |
247 | Instance of CKEditor is destroyed.
248 |
249 |
250 | input(newValue, instance, eventInfo, batch)
251 |
252 |
253 | newValue
254 | New value of CKEditor's data.
255 | instance
256 | Instance of CKEditor.
257 | eventInfo
258 | An object containing information about the fired event.
259 | batch
260 | The batch that was used in the executed changes block.
261 |
262 |
263 | Data is changed.
264 |
265 |
266 |
267 |
268 | Events from engine.view.document (check example5 ).
269 |
270 | License
271 |
272 | MIT
273 |
--------------------------------------------------------------------------------
/dist/vue-ckeditor5.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.VueCkeditor=t():e.VueCkeditor=t()}(window,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);var r={name:"vue-ckeditor",render:function(e){return e(this.tag,{attrs:this.$attrs})},props:{config:{default:function(){return{language:"en"}},required:!1,type:Object},editors:{default:function(){return{}},required:!1,type:Object},readonly:{default:function(){return!1},required:!1,type:Boolean},emptyValue:{required:!1,type:String},tag:{default:function(){return"div"},required:!1,type:String},toolbarContainer:{default:function(){return null},required:!1,type:String},type:{required:!0,type:String},value:{default:function(){return""},required:!1,type:String}},data:function(){return{instance:null}},watch:{value:function(e){var t=this.instance;null==t||e===t.getData()||this.emptyValueProvided&&e===this.emptyValue||t.setData(e)}},computed:{emptyValueProvided:function(){return Object.prototype.hasOwnProperty.call(this.$options.propsData,"emptyValue")},isEmpty:function(){var e=this.instance.model.document;return!e.model.hasContent(e.getRoot())}},methods:{create:function(){var e=this;if(null==this.instance){var t=this.type,n=this.$VueCkeditorEditors||this.editors;if(!Object.keys(n).length)throw new Error("There are no CKEditor 5 implementations.");var r=n[t];if(null==r)throw new Error("Wrong key '".concat(t,"'. Allowed keys: ").concat(Object.keys(n)));r.create(this.$el,this.config).then((function(t){e.instance=t;var n=e.instance;e.createToolbarContainer(),e.setEventListeners(),n.isReadOnly=e.readonly,n.setData(e.value),e.$emit("ready",n)})).catch((function(e){console.log(e)}))}},createToolbarContainer:function(){var e=this.instance,t=this.toolbarContainer;if(null!=t&&null!=e){var n=document.querySelector(t);null!=n&&n.appendChild(e.ui.view.toolbar.element)}},destroy:function(){var e=this.instance;null!=e&&(e.destroy(),this.$emit("destroy",e))},setEventListeners:function(){var e=this,t=this.instance;if(null!=t){t.model.document.on("change:data",(function(){var n=t.getData();if(e.value!==n){e.emptyValueProvided&&e.isEmpty&&(n=e.emptyValue);for(var r=arguments.length,o=new Array(r),i=0;i {\n return {\n language: 'en'\n }\n },\n required: false,\n type: Object\n },\n\n editors: {\n default: () => {\n return {}\n },\n required: false,\n type: Object\n },\n\n readonly: {\n default: () => false,\n required: false,\n type: Boolean\n },\n\n emptyValue: {\n required: false,\n type: String\n },\n\n tag: {\n default: () => 'div',\n required: false,\n type: String\n },\n\n toolbarContainer: {\n default: () => null,\n required: false,\n type: String\n },\n\n type: {\n required: true,\n type: String\n },\n\n value: {\n default: () => '',\n required: false,\n type: String\n }\n },\n\n data () {\n return {\n instance: null\n }\n },\n\n watch: {\n value (newValue) {\n const instance = this.instance\n\n if (\n instance != null &&\n newValue !== instance.getData() &&\n !(\n this.emptyValueProvided &&\n newValue === this.emptyValue\n )\n ) {\n instance.setData(newValue)\n }\n }\n },\n\n computed: {\n emptyValueProvided () {\n return Object.prototype.hasOwnProperty.call(this.$options.propsData, 'emptyValue')\n },\n isEmpty () {\n const document = this.instance.model.document\n return !document.model.hasContent(document.getRoot())\n }\n },\n\n methods: {\n create () {\n if (this.instance == null) {\n const type = this.type\n const editors = this.$VueCkeditorEditors || this.editors\n\n if (!Object.keys(editors).length) {\n throw new Error('There are no CKEditor 5 implementations.')\n }\n\n const editor = editors[type]\n\n if (editor == null) {\n throw new Error(`Wrong key '${type}'. Allowed keys: ${Object.keys(editors)}`)\n }\n\n editor\n .create(this.$el, this.config)\n .then(editor => {\n this.instance = editor\n const instance = this.instance\n\n this.createToolbarContainer()\n\n this.setEventListeners()\n\n instance.isReadOnly = this.readonly\n instance.setData(this.value)\n\n this.$emit('ready', instance)\n })\n .catch(error => {\n console.log(error)\n })\n }\n },\n createToolbarContainer () {\n const instance = this.instance\n const toolbarContainer = this.toolbarContainer\n\n if (\n toolbarContainer != null &&\n instance != null\n ) {\n const toolbarContainerElement = document.querySelector(toolbarContainer)\n\n if (toolbarContainerElement != null) {\n toolbarContainerElement.appendChild(instance.ui.view.toolbar.element)\n }\n }\n },\n destroy () {\n const instance = this.instance\n\n if (instance != null) {\n instance.destroy()\n this.$emit('destroy', instance)\n }\n },\n setEventListeners () {\n const instance = this.instance\n\n if (instance != null) {\n instance.model.document.on('change:data', (...args) => {\n let newValue = instance.getData()\n\n if (this.value !== newValue) {\n if (\n this.emptyValueProvided &&\n this.isEmpty\n ) {\n newValue = this.emptyValue\n }\n\n this.$emit('input', newValue, instance, ...args)\n }\n })\n\n const editingViewDocument = instance.editing.view.document\n const events = editingViewDocument._events\n for (const key of Object.keys(events)) {\n editingViewDocument.on(key, (...args) => {\n this.$emit(key, instance, ...args)\n })\n }\n }\n }\n },\n\n mounted () {\n this.create()\n },\n\n beforeDestroy () {\n this.destroy()\n }\n}\n","import VueCkeditorComponent from './vue-ckeditor'\n\nconst VueCkeditor = {\n version: VERSION,\n component: VueCkeditorComponent,\n plugin: {\n install (Vue, { name, editors }) {\n Vue.prototype.$VueCkeditorEditors = editors || {}\n\n Vue.component(name || VueCkeditorComponent.name, VueCkeditorComponent)\n }\n }\n}\n\nexport default VueCkeditor\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/examples/custom-editors/translations/ru.js:
--------------------------------------------------------------------------------
1 | (function(d){d['ru']=Object.assign(d['ru']||{},{a:"Невозможно загрузить файл",b:"Image toolbar",c:"Table toolbar",d:"Выравнивание по левому краю",e:"Выравнивание по правому краю",f:"Выравнивание по центру",g:"Выравнивание по ширине",h:"Выравнивание текста",i:"Выравнивание",j:"Жирный",k:"Вставьте изображение или файл",l:"Исходный код",m:"Зачеркнутый",n:"медиа-виджет",o:"Идёт загрузка",p:"Вставить таблицу",q:"Столбец заголовков",r:"Вставить столбец слева",s:"Вставить столбец справа",t:"Удалить столбец",u:"Столбец",v:"Строка заголовков",w:"Вставить строку ниже",x:"Вставить строку выше",y:"Удалить строку",z:"Строка",aa:"Объединить с ячейкой сверху",ab:"Объединить с ячейкой справа",ac:"Объединить с ячейкой снизу",ad:"Объединить с ячейкой слева",ae:"Разделить ячейку вертикально",af:"Разделить ячейку горизонтально",ag:"Объединить ячейки",ah:"Нумерованный список",ai:"Маркированный список",aj:"Вставить медиа",ak:"URL не должен быть пустым.",al:"Этот URL медиа не поддерживается.",am:"Увеличить отступ",an:"Уменьшить отступ",ao:"Загрузка не выполнена",ap:"Вставить изображение",aq:"Ссылка",ar:"Подпись к изображению",as:"Оригинальный размер изображения",at:"Боковое изображение",au:"Выравнивание по левому краю",av:"Выравнивание по центру",aw:"Выравнивание по правому краю",ax:"Виджет изображений",ay:"Выделение жёлтым маркером",az:"Выделение зелёным маркером",ba:"Выделение розовым маркером",bb:"Выделение синим маркером",bc:"Красный цвет текста",bd:"Зеленый цвет текста",be:"Убрать выделение",bf:"Выделить",bg:"Text highlight toolbar",bh:"Не удалось получить URL с измененным размером изображения.",bi:"Выбор изображения с измененным размером не удался",bj:"Нельзя вставить изображение на текущую позицию.",bk:"Вставка изображения не удалась",bl:"Widget toolbar",bm:"Редактор",bn:"Editor toolbar",bo:"Show more items",bp:"Dropdown toolbar",bq:"Редактор, %0",br:"Open in a new tab",bs:"Downloadable",bt:"Редактировать альтернативный текст",bu:"Убрать ссылку",bv:"Редактировать ссылку",bw:"Открыть ссылку в новой вкладке",bx:"Для этой ссылки не установлен адрес URL",by:"Сохранить",bz:"Отмена",ca:"Ссылка URL",cb:"%0 of %1",cc:"Previous",cd:"Next",ce:"Альтернативный текст",cf:"Вставьте URL медиа в поле ввода.",cg:"Подсказка: Вставьте URL в контент для быстрого включения.",ch:"URL медиа",ci:"Отменить",cj:"Повторить",ck:"Выбрать заголовок",cl:"Заголовок",cm:"Размер шрифта",cn:"По умолчанию",co:"Очень мелкий",cp:"Мелкий",cq:"Крупный",cr:"Очень крупный",cs:"Цитата",ct:"Семейство шрифтов",cu:"Подчеркнутый",cv:"Курсив",cw:"Параграф",cx:"Заголовок 1",cy:"Заголовок 2",cz:"Заголовок 3",da:"Заголовок 4",db:"Заголовок 5",dc:"Заголовок 6",dd:"Чёрный",de:"Тёмно-серый",df:"Серый",dg:"Светло-серый",dh:"Белый",di:"Красный",dj:"Оранжевый",dk:"Жёлтый",dl:"Салатовый",dm:"Зелёный",dn:"Аквамариновый",do:"Бирюзовый",dp:"Голубой",dq:"Синий",dr:"Фиолетовый"})})(window.CKEDITOR_TRANSLATIONS||(window.CKEDITOR_TRANSLATIONS={}));
--------------------------------------------------------------------------------
/examples/example1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Custom CKEditor example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/examples/example2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | List Rendering
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/examples/example4/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | DecoupledEditor example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/examples/example4/style.css:
--------------------------------------------------------------------------------
1 | .document-editor {
2 | border: 1px solid var(--ck-color-base-border);
3 | border-radius: var(--ck-border-radius);
4 |
5 | /* Set vertical boundaries for the document editor. */
6 | max-height: 700px;
7 |
8 | /* This element is a flex container for easier rendering. */
9 | display: flex;
10 | flex-flow: column nowrap;
11 | }
12 |
13 | .document-editor__toolbar {
14 | /* Make sure the toolbar container is always above the editable. */
15 | z-index: 1;
16 |
17 | /* Create the illusion of the toolbar floating over the editable. */
18 | box-shadow: 0 0 5px hsla( 0,0%,0%,.2 );
19 |
20 | /* Use the CKEditor CSS variables to keep the UI consistent. */
21 | border-bottom: 1px solid var(--ck-color-toolbar-border);
22 | }
23 |
24 | /* Adjust the look of the toolbar inside the container. */
25 | .document-editor__toolbar .ck-toolbar {
26 | border: 0;
27 | border-radius: 0;
28 | }
29 |
30 | /* Make the editable container look like the inside of a native word processor application. */
31 | .document-editor__editable-container {
32 | padding: calc( 2 * var(--ck-spacing-large) );
33 | background: var(--ck-color-base-foreground);
34 |
35 | /* Make it possible to scroll the "page" of the edited content. */
36 | overflow-y: scroll;
37 | }
38 |
39 | .document-editor__editable-container .ck-editor__editable {
40 | /* Set the dimensions of the "page". */
41 | width: 15.8cm;
42 | min-height: 21cm;
43 |
44 | /* Keep the "page" off the boundaries of the container. */
45 | padding: 1cm 2cm 2cm;
46 |
47 | border: 1px hsl( 0,0%,82.7% ) solid;
48 | border-radius: var(--ck-border-radius);
49 | background: white;
50 |
51 | /* The "page" should cast a slight shadow (3D illusion). */
52 | box-shadow: 0 0 5px hsla( 0,0%,0%,.1 );
53 |
54 | /* Center the "page". */
55 | margin: 0 auto;
56 | }
57 |
58 | /* Set the default font for the "page" of the content. */
59 | .document-editor .ck-content,
60 | .document-editor .ck-heading-dropdown .ck-list .ck-button__label {
61 | font: 16px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
62 | }
63 |
64 | /* Adjust the headings dropdown to host some larger heading styles. */
65 | .document-editor .ck-heading-dropdown .ck-list .ck-button__label {
66 | line-height: calc( 1.7 * var(--ck-line-height-base) * var(--ck-font-size-base) );
67 | min-width: 6em;
68 | }
69 |
70 | /* Scale down all heading previews because they are way too big to be presented in the UI.
71 | Preserve the relative scale, though. */
72 | .document-editor .ck-heading-dropdown .ck-list .ck-button:not(.ck-heading_paragraph) .ck-button__label {
73 | transform: scale(0.8);
74 | transform-origin: left;
75 | }
76 |
77 | /* Set the styles for "Heading 1". */
78 | .document-editor .ck-content h2,
79 | .document-editor .ck-heading-dropdown .ck-heading_heading1 .ck-button__label {
80 | font-size: 2.18em;
81 | font-weight: normal;
82 | }
83 |
84 | .document-editor .ck-content h2 {
85 | line-height: 1.37em;
86 | padding-top: .342em;
87 | margin-bottom: .142em;
88 | }
89 |
90 | /* Set the styles for "Heading 2". */
91 | .document-editor .ck-content h3,
92 | .document-editor .ck-heading-dropdown .ck-heading_heading2 .ck-button__label {
93 | font-size: 1.75em;
94 | font-weight: normal;
95 | color: hsl( 203, 100%, 50% );
96 | }
97 |
98 | .document-editor .ck-heading-dropdown .ck-heading_heading2.ck-on .ck-button__label {
99 | color: var(--ck-color-list-button-on-text);
100 | }
101 |
102 | /* Set the styles for "Heading 2". */
103 | .document-editor .ck-content h3 {
104 | line-height: 1.86em;
105 | padding-top: .171em;
106 | margin-bottom: .357em;
107 | }
108 |
109 | /* Set the styles for "Heading 3". */
110 | .document-editor .ck-content h4,
111 | .document-editor .ck-heading-dropdown .ck-heading_heading3 .ck-button__label {
112 | font-size: 1.31em;
113 | font-weight: bold;
114 | }
115 |
116 | .document-editor .ck-content h4 {
117 | line-height: 1.24em;
118 | padding-top: .286em;
119 | margin-bottom: .952em;
120 | }
121 |
122 | /* Set the styles for "Paragraph". */
123 | .document-editor .ck-content p {
124 | font-size: 1em;
125 | line-height: 1.63em;
126 | padding-top: .5em;
127 | margin-bottom: 1.13em;
128 | }
129 |
130 | /* Make the block quoted text serif with some additional spacing. */
131 | .document-editor .ck-content blockquote {
132 | font-family: Georgia, serif;
133 | margin-left: calc( 2 * var(--ck-spacing-large) );
134 | margin-right: calc( 2 * var(--ck-spacing-large) );
135 | }
136 |
--------------------------------------------------------------------------------
/examples/example5/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Check events
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
27 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/examples/example6/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Empty value
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
33 |
34 |
35 |
36 |
37 |
38 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-ckeditor5",
3 | "version": "0.5.0",
4 | "description": "CKEditor 5 component for Vue 2.",
5 | "author": "Igor Iakovlev ",
6 | "license": "MIT",
7 | "private": false,
8 | "main": "dist/vue-ckeditor5.js",
9 | "files": [
10 | "dist",
11 | "src"
12 | ],
13 | "keywords": [
14 | "ckeditor",
15 | "component",
16 | "plugin",
17 | "vue",
18 | "vuejs"
19 | ],
20 | "bugs": {
21 | "url": "https://github.com/igorxut/vue-ckeditor5/issues"
22 | },
23 | "homepage": "https://github.com/igorxut/vue-ckeditor5#readme",
24 | "repository": {
25 | "type": "git",
26 | "url": "https://github.com/igorxut/vue-ckeditor5.git"
27 | },
28 | "scripts": {
29 | "lint": "eslint src",
30 | "build": "webpack"
31 | },
32 | "peerDependencies": {
33 | "vue": "^2.6.11"
34 | },
35 | "devDependencies": {
36 | "@babel/core": "^7.8.3",
37 | "@babel/preset-env": "^7.8.3",
38 | "babel-loader": "^8.0.6",
39 | "eslint": "^6.8.0",
40 | "eslint-config-standard": "^14.1.0",
41 | "eslint-plugin-import": "^2.20.0",
42 | "eslint-plugin-node": "^11.0.0",
43 | "eslint-plugin-promise": "^4.2.1",
44 | "eslint-plugin-standard": "^4.0.1",
45 | "webpack": "^4.41.5",
46 | "webpack-cli": "^3.3.10"
47 | },
48 | "engines": {
49 | "node": ">= 12.14.1",
50 | "npm": ">= 6.13.6"
51 | },
52 | "browserslist": [
53 | "> 1%",
54 | "last 2 versions",
55 | "not ie <= 8"
56 | ]
57 | }
58 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import VueCkeditorComponent from './vue-ckeditor'
2 |
3 | const VueCkeditor = {
4 | version: VERSION,
5 | component: VueCkeditorComponent,
6 | plugin: {
7 | install (Vue, { name, editors }) {
8 | Vue.prototype.$VueCkeditorEditors = editors || {}
9 |
10 | Vue.component(name || VueCkeditorComponent.name, VueCkeditorComponent)
11 | }
12 | }
13 | }
14 |
15 | export default VueCkeditor
16 |
--------------------------------------------------------------------------------
/src/vue-ckeditor.js:
--------------------------------------------------------------------------------
1 | export default {
2 | name: 'vue-ckeditor',
3 |
4 | render (createElement) {
5 | return createElement(this.tag, {
6 | attrs: this.$attrs
7 | })
8 | },
9 |
10 | props: {
11 | config: {
12 | default: () => {
13 | return {
14 | language: 'en'
15 | }
16 | },
17 | required: false,
18 | type: Object
19 | },
20 |
21 | editors: {
22 | default: () => {
23 | return {}
24 | },
25 | required: false,
26 | type: Object
27 | },
28 |
29 | readonly: {
30 | default: () => false,
31 | required: false,
32 | type: Boolean
33 | },
34 |
35 | emptyValue: {
36 | required: false,
37 | type: String
38 | },
39 |
40 | tag: {
41 | default: () => 'div',
42 | required: false,
43 | type: String
44 | },
45 |
46 | toolbarContainer: {
47 | default: () => null,
48 | required: false,
49 | type: String
50 | },
51 |
52 | type: {
53 | required: true,
54 | type: String
55 | },
56 |
57 | value: {
58 | default: () => '',
59 | required: false,
60 | type: String
61 | }
62 | },
63 |
64 | data () {
65 | return {
66 | instance: null
67 | }
68 | },
69 |
70 | watch: {
71 | value (newValue) {
72 | const instance = this.instance
73 |
74 | if (
75 | instance != null &&
76 | newValue !== instance.getData() &&
77 | !(
78 | this.emptyValueProvided &&
79 | newValue === this.emptyValue
80 | )
81 | ) {
82 | instance.setData(newValue)
83 | }
84 | }
85 | },
86 |
87 | computed: {
88 | emptyValueProvided () {
89 | return Object.prototype.hasOwnProperty.call(this.$options.propsData, 'emptyValue')
90 | },
91 | isEmpty () {
92 | const document = this.instance.model.document
93 | return !document.model.hasContent(document.getRoot())
94 | }
95 | },
96 |
97 | methods: {
98 | create () {
99 | if (this.instance == null) {
100 | const type = this.type
101 | const editors = this.$VueCkeditorEditors || this.editors
102 |
103 | if (!Object.keys(editors).length) {
104 | throw new Error('There are no CKEditor 5 implementations.')
105 | }
106 |
107 | const editor = editors[type]
108 |
109 | if (editor == null) {
110 | throw new Error(`Wrong key '${type}'. Allowed keys: ${Object.keys(editors)}`)
111 | }
112 |
113 | editor
114 | .create(this.$el, this.config)
115 | .then(editor => {
116 | this.instance = editor
117 | const instance = this.instance
118 |
119 | this.createToolbarContainer()
120 |
121 | this.setEventListeners()
122 |
123 | instance.isReadOnly = this.readonly
124 | instance.setData(this.value)
125 |
126 | this.$emit('ready', instance)
127 | })
128 | .catch(error => {
129 | console.log(error)
130 | })
131 | }
132 | },
133 | createToolbarContainer () {
134 | const instance = this.instance
135 | const toolbarContainer = this.toolbarContainer
136 |
137 | if (
138 | toolbarContainer != null &&
139 | instance != null
140 | ) {
141 | const toolbarContainerElement = document.querySelector(toolbarContainer)
142 |
143 | if (toolbarContainerElement != null) {
144 | toolbarContainerElement.appendChild(instance.ui.view.toolbar.element)
145 | }
146 | }
147 | },
148 | destroy () {
149 | const instance = this.instance
150 |
151 | if (instance != null) {
152 | instance.destroy()
153 | this.$emit('destroy', instance)
154 | }
155 | },
156 | setEventListeners () {
157 | const instance = this.instance
158 |
159 | if (instance != null) {
160 | instance.model.document.on('change:data', (...args) => {
161 | let newValue = instance.getData()
162 |
163 | if (this.value !== newValue) {
164 | if (
165 | this.emptyValueProvided &&
166 | this.isEmpty
167 | ) {
168 | newValue = this.emptyValue
169 | }
170 |
171 | this.$emit('input', newValue, instance, ...args)
172 | }
173 | })
174 |
175 | const editingViewDocument = instance.editing.view.document
176 | const events = editingViewDocument._events
177 | for (const key of Object.keys(events)) {
178 | editingViewDocument.on(key, (...args) => {
179 | this.$emit(key, instance, ...args)
180 | })
181 | }
182 | }
183 | }
184 | },
185 |
186 | mounted () {
187 | this.create()
188 | },
189 |
190 | beforeDestroy () {
191 | this.destroy()
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | const DefinePlugin = require('webpack').DefinePlugin
3 |
4 | module.exports = {
5 | mode: 'production',
6 | devtool: 'source-map',
7 | entry: './src/index.js',
8 | resolve: {
9 | extensions: [
10 | '.js'
11 | ],
12 | alias: {
13 | 'vue-ckeditor5': path.join(__dirname, 'dist', 'vue-ckeditor5')
14 | }
15 | },
16 | output: {
17 | path: path.join(__dirname, 'dist'),
18 | filename: 'vue-ckeditor5.js',
19 | library: 'VueCkeditor',
20 | libraryExport: 'default',
21 | libraryTarget: 'umd'
22 | },
23 | module: {
24 | rules: [
25 | {
26 | test: /\.js$/,
27 | include: [
28 | path.join(__dirname, 'src')
29 | ],
30 | use: [
31 | {
32 | loader: 'babel-loader'
33 | }
34 | ]
35 | }
36 | ]
37 | },
38 | plugins: [
39 | new DefinePlugin({
40 | VERSION: JSON.stringify(require('./package.json').version)
41 | })
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------