├── .gitignore
├── README.md
├── dist
├── index.js
└── index.mjs
├── package.json
├── rollup.config.js
├── samples
├── .gitignore
├── README.md
├── package.json
├── public
│ ├── bundle.css
│ ├── bundle.js
│ ├── bundle.js.map
│ ├── favicon.png
│ ├── global.css
│ ├── index.html
│ └── public
│ │ └── bundle.css
├── rollup.config.js
└── src
│ ├── App.svelte
│ └── main.js
└── src
├── Ckeditor.svelte
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | yarn.lock
4 | package-lock.json
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## CKEditor5 editor component for Svelte 3
2 |
3 | This component is a thin wrapper around ckeditor5 document editor.
4 | Below are the set of instructions to create svelte project, install component and a basic setup with CKEditor DocumentEditor build.
5 |
6 | ### How to install package
7 |
8 | ```bash
9 | $ npm i ckeditor5-svelte
10 | ```
11 |
12 | ### Getting started
13 |
14 | #### Create a new svelte project and install dependencies
15 |
16 | ```bash
17 | npx degit sveltejs/template my-svelte-project
18 | # or download and extract
19 | cd my-svelte-project
20 | # to use Typescript run:
21 | # node scripts/setupTypeScript.js
22 |
23 | npm install
24 | ```
25 |
26 | #### Install ckeditor5-svelte package
27 |
28 | ```bash
29 | npm i ckeditor5-svelte
30 | ```
31 |
32 | #### Install DocumentEditor build of ckeditor
33 |
34 | ```bash
35 | npm i @ckeditor/ckeditor5-build-decoupled-document
36 | ```
37 |
38 | #### Update App.svelte in your project with the following
39 |
40 | ```js
41 |
80 |
81 |
83 |
84 |
85 |
86 |
91 |
92 |
93 | ```
94 |
95 | #### Run your project
96 |
97 | ```bash
98 | npm run dev
99 | ```
100 |
--------------------------------------------------------------------------------
/dist/index.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 | typeof define === 'function' && define.amd ? define(factory) :
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Ckeditor = factory());
5 | }(this, (function () { 'use strict';
6 |
7 | function noop() { }
8 | function run(fn) {
9 | return fn();
10 | }
11 | function blank_object() {
12 | return Object.create(null);
13 | }
14 | function run_all(fns) {
15 | fns.forEach(run);
16 | }
17 | function is_function(thing) {
18 | return typeof thing === 'function';
19 | }
20 | function safe_not_equal(a, b) {
21 | return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
22 | }
23 | function is_empty(obj) {
24 | return Object.keys(obj).length === 0;
25 | }
26 | function insert(target, node, anchor) {
27 | target.insertBefore(node, anchor || null);
28 | }
29 | function detach(node) {
30 | node.parentNode.removeChild(node);
31 | }
32 | function element(name) {
33 | return document.createElement(name);
34 | }
35 | function attr(node, attribute, value) {
36 | if (value == null)
37 | node.removeAttribute(attribute);
38 | else if (node.getAttribute(attribute) !== value)
39 | node.setAttribute(attribute, value);
40 | }
41 | function children(element) {
42 | return Array.from(element.childNodes);
43 | }
44 | function custom_event(type, detail) {
45 | const e = document.createEvent('CustomEvent');
46 | e.initCustomEvent(type, false, false, detail);
47 | return e;
48 | }
49 |
50 | let current_component;
51 | function set_current_component(component) {
52 | current_component = component;
53 | }
54 | function get_current_component() {
55 | if (!current_component)
56 | throw new Error('Function called outside component initialization');
57 | return current_component;
58 | }
59 | function onMount(fn) {
60 | get_current_component().$$.on_mount.push(fn);
61 | }
62 | function onDestroy(fn) {
63 | get_current_component().$$.on_destroy.push(fn);
64 | }
65 | function createEventDispatcher() {
66 | const component = get_current_component();
67 | return (type, detail) => {
68 | const callbacks = component.$$.callbacks[type];
69 | if (callbacks) {
70 | // TODO are there situations where events could be dispatched
71 | // in a server (non-DOM) environment?
72 | const event = custom_event(type, detail);
73 | callbacks.slice().forEach(fn => {
74 | fn.call(component, event);
75 | });
76 | }
77 | };
78 | }
79 |
80 | const dirty_components = [];
81 | const binding_callbacks = [];
82 | const render_callbacks = [];
83 | const flush_callbacks = [];
84 | const resolved_promise = Promise.resolve();
85 | let update_scheduled = false;
86 | function schedule_update() {
87 | if (!update_scheduled) {
88 | update_scheduled = true;
89 | resolved_promise.then(flush);
90 | }
91 | }
92 | function add_render_callback(fn) {
93 | render_callbacks.push(fn);
94 | }
95 | let flushing = false;
96 | const seen_callbacks = new Set();
97 | function flush() {
98 | if (flushing)
99 | return;
100 | flushing = true;
101 | do {
102 | // first, call beforeUpdate functions
103 | // and update components
104 | for (let i = 0; i < dirty_components.length; i += 1) {
105 | const component = dirty_components[i];
106 | set_current_component(component);
107 | update(component.$$);
108 | }
109 | set_current_component(null);
110 | dirty_components.length = 0;
111 | while (binding_callbacks.length)
112 | binding_callbacks.pop()();
113 | // then, once components are updated, call
114 | // afterUpdate functions. This may cause
115 | // subsequent updates...
116 | for (let i = 0; i < render_callbacks.length; i += 1) {
117 | const callback = render_callbacks[i];
118 | if (!seen_callbacks.has(callback)) {
119 | // ...so guard against infinite loops
120 | seen_callbacks.add(callback);
121 | callback();
122 | }
123 | }
124 | render_callbacks.length = 0;
125 | } while (dirty_components.length);
126 | while (flush_callbacks.length) {
127 | flush_callbacks.pop()();
128 | }
129 | update_scheduled = false;
130 | flushing = false;
131 | seen_callbacks.clear();
132 | }
133 | function update($$) {
134 | if ($$.fragment !== null) {
135 | $$.update();
136 | run_all($$.before_update);
137 | const dirty = $$.dirty;
138 | $$.dirty = [-1];
139 | $$.fragment && $$.fragment.p($$.ctx, dirty);
140 | $$.after_update.forEach(add_render_callback);
141 | }
142 | }
143 | const outroing = new Set();
144 | function transition_in(block, local) {
145 | if (block && block.i) {
146 | outroing.delete(block);
147 | block.i(local);
148 | }
149 | }
150 | function mount_component(component, target, anchor) {
151 | const { fragment, on_mount, on_destroy, after_update } = component.$$;
152 | fragment && fragment.m(target, anchor);
153 | // onMount happens before the initial afterUpdate
154 | add_render_callback(() => {
155 | const new_on_destroy = on_mount.map(run).filter(is_function);
156 | if (on_destroy) {
157 | on_destroy.push(...new_on_destroy);
158 | }
159 | else {
160 | // Edge case - component was destroyed immediately,
161 | // most likely as a result of a binding initialising
162 | run_all(new_on_destroy);
163 | }
164 | component.$$.on_mount = [];
165 | });
166 | after_update.forEach(add_render_callback);
167 | }
168 | function destroy_component(component, detaching) {
169 | const $$ = component.$$;
170 | if ($$.fragment !== null) {
171 | run_all($$.on_destroy);
172 | $$.fragment && $$.fragment.d(detaching);
173 | // TODO null out other refs, including component.$$ (but need to
174 | // preserve final state?)
175 | $$.on_destroy = $$.fragment = null;
176 | $$.ctx = [];
177 | }
178 | }
179 | function make_dirty(component, i) {
180 | if (component.$$.dirty[0] === -1) {
181 | dirty_components.push(component);
182 | schedule_update();
183 | component.$$.dirty.fill(0);
184 | }
185 | component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
186 | }
187 | function init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) {
188 | const parent_component = current_component;
189 | set_current_component(component);
190 | const $$ = component.$$ = {
191 | fragment: null,
192 | ctx: null,
193 | // state
194 | props,
195 | update: noop,
196 | not_equal,
197 | bound: blank_object(),
198 | // lifecycle
199 | on_mount: [],
200 | on_destroy: [],
201 | before_update: [],
202 | after_update: [],
203 | context: new Map(parent_component ? parent_component.$$.context : []),
204 | // everything else
205 | callbacks: blank_object(),
206 | dirty,
207 | skip_bound: false
208 | };
209 | let ready = false;
210 | $$.ctx = instance
211 | ? instance(component, options.props || {}, (i, ret, ...rest) => {
212 | const value = rest.length ? rest[0] : ret;
213 | if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
214 | if (!$$.skip_bound && $$.bound[i])
215 | $$.bound[i](value);
216 | if (ready)
217 | make_dirty(component, i);
218 | }
219 | return ret;
220 | })
221 | : [];
222 | $$.update();
223 | ready = true;
224 | run_all($$.before_update);
225 | // `false` as a special case of no DOM component
226 | $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
227 | if (options.target) {
228 | if (options.hydrate) {
229 | const nodes = children(options.target);
230 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
231 | $$.fragment && $$.fragment.l(nodes);
232 | nodes.forEach(detach);
233 | }
234 | else {
235 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
236 | $$.fragment && $$.fragment.c();
237 | }
238 | if (options.intro)
239 | transition_in(component.$$.fragment);
240 | mount_component(component, options.target, options.anchor);
241 | flush();
242 | }
243 | set_current_component(parent_component);
244 | }
245 | /**
246 | * Base class for Svelte components. Used when dev=false.
247 | */
248 | class SvelteComponent {
249 | $destroy() {
250 | destroy_component(this, 1);
251 | this.$destroy = noop;
252 | }
253 | $on(type, callback) {
254 | const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
255 | callbacks.push(callback);
256 | return () => {
257 | const index = callbacks.indexOf(callback);
258 | if (index !== -1)
259 | callbacks.splice(index, 1);
260 | };
261 | }
262 | $set($$props) {
263 | if (this.$$set && !is_empty($$props)) {
264 | this.$$.skip_bound = true;
265 | this.$$set($$props);
266 | this.$$.skip_bound = false;
267 | }
268 | }
269 | }
270 |
271 | var justDebounceIt = debounce;
272 |
273 | function debounce(fn, wait, callFirst) {
274 | var timeout;
275 | return function() {
276 | if (!wait) {
277 | return fn.apply(this, arguments);
278 | }
279 | var context = this;
280 | var args = arguments;
281 | var callNow = callFirst && !timeout;
282 | clearTimeout(timeout);
283 | timeout = setTimeout(function() {
284 | timeout = null;
285 | if (!callNow) {
286 | return fn.apply(context, args);
287 | }
288 | }, wait);
289 |
290 | if (callNow) {
291 | return fn.apply(this, arguments);
292 | }
293 | };
294 | }
295 |
296 | /* src/Ckeditor.svelte generated by Svelte v3.32.1 */
297 |
298 | function create_fragment(ctx) {
299 | let div;
300 |
301 | return {
302 | c() {
303 | div = element("div");
304 | attr(div, "id", "_editor");
305 | },
306 | m(target, anchor) {
307 | insert(target, div, anchor);
308 | },
309 | p: noop,
310 | i: noop,
311 | o: noop,
312 | d(detaching) {
313 | if (detaching) detach(div);
314 | }
315 | };
316 | }
317 |
318 | const INPUT_EVENT_DEBOUNCE_WAIT = 300;
319 |
320 | function instance_1($$self, $$props, $$invalidate) {
321 | let { editor = null } = $$props;
322 | let { value = "" } = $$props;
323 | let { config = () => ({}) } = $$props;
324 | let { disabled = false } = $$props;
325 |
326 | // Instance variables
327 | let instance = null;
328 |
329 | let lastEditorData = "";
330 | let editorElement;
331 | const dispatch = createEventDispatcher();
332 |
333 | function watchValue(x) {
334 | if (instance && x !== lastEditorData) {
335 | instance.setData(x);
336 | }
337 | }
338 |
339 | onMount(() => {
340 | // If value is passed then add it to config
341 | if (value) {
342 | Object.assign(config, { initialData: value });
343 | }
344 |
345 | // Get dom element to mount initialised editor instance
346 | editorElement = document.getElementById("_editor");
347 |
348 | editor.create(editorElement, config).then(editor => {
349 | // Save the reference to the instance for future use.
350 | instance = editor;
351 |
352 | // Set initial disabled state.
353 | editor.isReadOnly = disabled;
354 |
355 | // Let the world know the editor is ready.
356 | dispatch("ready", editor);
357 |
358 | setUpEditorEvents();
359 | }).catch(error => {
360 | console.error(error);
361 | });
362 | });
363 |
364 | onDestroy(() => {
365 | if (instance) {
366 | instance.destroy();
367 | instance = null;
368 | }
369 |
370 | // Note: By the time the editor is destroyed (promise resolved, editor#destroy fired)
371 | // the Vue component will not be able to emit any longer.
372 | // So emitting #destroy a bit earlier.
373 | dispatch("destroy", instance);
374 | });
375 |
376 | function setUpEditorEvents() {
377 | const emitInputEvent = evt => {
378 | // Cache the last editor data. This kind of data is a result of typing,
379 | // editor command execution, collaborative changes to the document, etc.
380 | // This data is compared when the component value changes in a 2-way binding.
381 | const data = $$invalidate(0, value = lastEditorData = instance.getData());
382 |
383 | dispatch("input", { data, evt, instance });
384 | };
385 |
386 | // Debounce emitting the #input event. When data is huge, instance#getData()
387 | // takes a lot of time to execute on every single key press and ruins the UX.
388 | instance.model.document.on("change:data", justDebounceIt(emitInputEvent, INPUT_EVENT_DEBOUNCE_WAIT));
389 |
390 | instance.editing.view.document.on("focus", evt => {
391 | dispatch("focus", { evt, instance });
392 | });
393 |
394 | instance.editing.view.document.on("blur", evt => {
395 | dispatch("blur", { evt, instance });
396 | });
397 | }
398 |
399 | $$self.$$set = $$props => {
400 | if ("editor" in $$props) $$invalidate(1, editor = $$props.editor);
401 | if ("value" in $$props) $$invalidate(0, value = $$props.value);
402 | if ("config" in $$props) $$invalidate(2, config = $$props.config);
403 | if ("disabled" in $$props) $$invalidate(3, disabled = $$props.disabled);
404 | };
405 |
406 | $$self.$$.update = () => {
407 | if ($$self.$$.dirty & /*value*/ 1) {
408 | watchValue(value);
409 | }
410 | };
411 |
412 | return [value, editor, config, disabled];
413 | }
414 |
415 | class Ckeditor extends SvelteComponent {
416 | constructor(options) {
417 | super();
418 |
419 | init(this, options, instance_1, create_fragment, safe_not_equal, {
420 | editor: 1,
421 | value: 0,
422 | config: 2,
423 | disabled: 3
424 | });
425 | }
426 | }
427 |
428 | return Ckeditor;
429 |
430 | })));
431 |
--------------------------------------------------------------------------------
/dist/index.mjs:
--------------------------------------------------------------------------------
1 | function noop() { }
2 | function run(fn) {
3 | return fn();
4 | }
5 | function blank_object() {
6 | return Object.create(null);
7 | }
8 | function run_all(fns) {
9 | fns.forEach(run);
10 | }
11 | function is_function(thing) {
12 | return typeof thing === 'function';
13 | }
14 | function safe_not_equal(a, b) {
15 | return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
16 | }
17 | function is_empty(obj) {
18 | return Object.keys(obj).length === 0;
19 | }
20 | function insert(target, node, anchor) {
21 | target.insertBefore(node, anchor || null);
22 | }
23 | function detach(node) {
24 | node.parentNode.removeChild(node);
25 | }
26 | function element(name) {
27 | return document.createElement(name);
28 | }
29 | function attr(node, attribute, value) {
30 | if (value == null)
31 | node.removeAttribute(attribute);
32 | else if (node.getAttribute(attribute) !== value)
33 | node.setAttribute(attribute, value);
34 | }
35 | function children(element) {
36 | return Array.from(element.childNodes);
37 | }
38 | function custom_event(type, detail) {
39 | const e = document.createEvent('CustomEvent');
40 | e.initCustomEvent(type, false, false, detail);
41 | return e;
42 | }
43 |
44 | let current_component;
45 | function set_current_component(component) {
46 | current_component = component;
47 | }
48 | function get_current_component() {
49 | if (!current_component)
50 | throw new Error('Function called outside component initialization');
51 | return current_component;
52 | }
53 | function onMount(fn) {
54 | get_current_component().$$.on_mount.push(fn);
55 | }
56 | function onDestroy(fn) {
57 | get_current_component().$$.on_destroy.push(fn);
58 | }
59 | function createEventDispatcher() {
60 | const component = get_current_component();
61 | return (type, detail) => {
62 | const callbacks = component.$$.callbacks[type];
63 | if (callbacks) {
64 | // TODO are there situations where events could be dispatched
65 | // in a server (non-DOM) environment?
66 | const event = custom_event(type, detail);
67 | callbacks.slice().forEach(fn => {
68 | fn.call(component, event);
69 | });
70 | }
71 | };
72 | }
73 |
74 | const dirty_components = [];
75 | const binding_callbacks = [];
76 | const render_callbacks = [];
77 | const flush_callbacks = [];
78 | const resolved_promise = Promise.resolve();
79 | let update_scheduled = false;
80 | function schedule_update() {
81 | if (!update_scheduled) {
82 | update_scheduled = true;
83 | resolved_promise.then(flush);
84 | }
85 | }
86 | function add_render_callback(fn) {
87 | render_callbacks.push(fn);
88 | }
89 | let flushing = false;
90 | const seen_callbacks = new Set();
91 | function flush() {
92 | if (flushing)
93 | return;
94 | flushing = true;
95 | do {
96 | // first, call beforeUpdate functions
97 | // and update components
98 | for (let i = 0; i < dirty_components.length; i += 1) {
99 | const component = dirty_components[i];
100 | set_current_component(component);
101 | update(component.$$);
102 | }
103 | set_current_component(null);
104 | dirty_components.length = 0;
105 | while (binding_callbacks.length)
106 | binding_callbacks.pop()();
107 | // then, once components are updated, call
108 | // afterUpdate functions. This may cause
109 | // subsequent updates...
110 | for (let i = 0; i < render_callbacks.length; i += 1) {
111 | const callback = render_callbacks[i];
112 | if (!seen_callbacks.has(callback)) {
113 | // ...so guard against infinite loops
114 | seen_callbacks.add(callback);
115 | callback();
116 | }
117 | }
118 | render_callbacks.length = 0;
119 | } while (dirty_components.length);
120 | while (flush_callbacks.length) {
121 | flush_callbacks.pop()();
122 | }
123 | update_scheduled = false;
124 | flushing = false;
125 | seen_callbacks.clear();
126 | }
127 | function update($$) {
128 | if ($$.fragment !== null) {
129 | $$.update();
130 | run_all($$.before_update);
131 | const dirty = $$.dirty;
132 | $$.dirty = [-1];
133 | $$.fragment && $$.fragment.p($$.ctx, dirty);
134 | $$.after_update.forEach(add_render_callback);
135 | }
136 | }
137 | const outroing = new Set();
138 | function transition_in(block, local) {
139 | if (block && block.i) {
140 | outroing.delete(block);
141 | block.i(local);
142 | }
143 | }
144 | function mount_component(component, target, anchor) {
145 | const { fragment, on_mount, on_destroy, after_update } = component.$$;
146 | fragment && fragment.m(target, anchor);
147 | // onMount happens before the initial afterUpdate
148 | add_render_callback(() => {
149 | const new_on_destroy = on_mount.map(run).filter(is_function);
150 | if (on_destroy) {
151 | on_destroy.push(...new_on_destroy);
152 | }
153 | else {
154 | // Edge case - component was destroyed immediately,
155 | // most likely as a result of a binding initialising
156 | run_all(new_on_destroy);
157 | }
158 | component.$$.on_mount = [];
159 | });
160 | after_update.forEach(add_render_callback);
161 | }
162 | function destroy_component(component, detaching) {
163 | const $$ = component.$$;
164 | if ($$.fragment !== null) {
165 | run_all($$.on_destroy);
166 | $$.fragment && $$.fragment.d(detaching);
167 | // TODO null out other refs, including component.$$ (but need to
168 | // preserve final state?)
169 | $$.on_destroy = $$.fragment = null;
170 | $$.ctx = [];
171 | }
172 | }
173 | function make_dirty(component, i) {
174 | if (component.$$.dirty[0] === -1) {
175 | dirty_components.push(component);
176 | schedule_update();
177 | component.$$.dirty.fill(0);
178 | }
179 | component.$$.dirty[(i / 31) | 0] |= (1 << (i % 31));
180 | }
181 | function init(component, options, instance, create_fragment, not_equal, props, dirty = [-1]) {
182 | const parent_component = current_component;
183 | set_current_component(component);
184 | const $$ = component.$$ = {
185 | fragment: null,
186 | ctx: null,
187 | // state
188 | props,
189 | update: noop,
190 | not_equal,
191 | bound: blank_object(),
192 | // lifecycle
193 | on_mount: [],
194 | on_destroy: [],
195 | before_update: [],
196 | after_update: [],
197 | context: new Map(parent_component ? parent_component.$$.context : []),
198 | // everything else
199 | callbacks: blank_object(),
200 | dirty,
201 | skip_bound: false
202 | };
203 | let ready = false;
204 | $$.ctx = instance
205 | ? instance(component, options.props || {}, (i, ret, ...rest) => {
206 | const value = rest.length ? rest[0] : ret;
207 | if ($$.ctx && not_equal($$.ctx[i], $$.ctx[i] = value)) {
208 | if (!$$.skip_bound && $$.bound[i])
209 | $$.bound[i](value);
210 | if (ready)
211 | make_dirty(component, i);
212 | }
213 | return ret;
214 | })
215 | : [];
216 | $$.update();
217 | ready = true;
218 | run_all($$.before_update);
219 | // `false` as a special case of no DOM component
220 | $$.fragment = create_fragment ? create_fragment($$.ctx) : false;
221 | if (options.target) {
222 | if (options.hydrate) {
223 | const nodes = children(options.target);
224 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
225 | $$.fragment && $$.fragment.l(nodes);
226 | nodes.forEach(detach);
227 | }
228 | else {
229 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
230 | $$.fragment && $$.fragment.c();
231 | }
232 | if (options.intro)
233 | transition_in(component.$$.fragment);
234 | mount_component(component, options.target, options.anchor);
235 | flush();
236 | }
237 | set_current_component(parent_component);
238 | }
239 | /**
240 | * Base class for Svelte components. Used when dev=false.
241 | */
242 | class SvelteComponent {
243 | $destroy() {
244 | destroy_component(this, 1);
245 | this.$destroy = noop;
246 | }
247 | $on(type, callback) {
248 | const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
249 | callbacks.push(callback);
250 | return () => {
251 | const index = callbacks.indexOf(callback);
252 | if (index !== -1)
253 | callbacks.splice(index, 1);
254 | };
255 | }
256 | $set($$props) {
257 | if (this.$$set && !is_empty($$props)) {
258 | this.$$.skip_bound = true;
259 | this.$$set($$props);
260 | this.$$.skip_bound = false;
261 | }
262 | }
263 | }
264 |
265 | var justDebounceIt = debounce;
266 |
267 | function debounce(fn, wait, callFirst) {
268 | var timeout;
269 | return function() {
270 | if (!wait) {
271 | return fn.apply(this, arguments);
272 | }
273 | var context = this;
274 | var args = arguments;
275 | var callNow = callFirst && !timeout;
276 | clearTimeout(timeout);
277 | timeout = setTimeout(function() {
278 | timeout = null;
279 | if (!callNow) {
280 | return fn.apply(context, args);
281 | }
282 | }, wait);
283 |
284 | if (callNow) {
285 | return fn.apply(this, arguments);
286 | }
287 | };
288 | }
289 |
290 | /* src/Ckeditor.svelte generated by Svelte v3.32.1 */
291 |
292 | function create_fragment(ctx) {
293 | let div;
294 |
295 | return {
296 | c() {
297 | div = element("div");
298 | attr(div, "id", "_editor");
299 | },
300 | m(target, anchor) {
301 | insert(target, div, anchor);
302 | },
303 | p: noop,
304 | i: noop,
305 | o: noop,
306 | d(detaching) {
307 | if (detaching) detach(div);
308 | }
309 | };
310 | }
311 |
312 | const INPUT_EVENT_DEBOUNCE_WAIT = 300;
313 |
314 | function instance_1($$self, $$props, $$invalidate) {
315 | let { editor = null } = $$props;
316 | let { value = "" } = $$props;
317 | let { config = () => ({}) } = $$props;
318 | let { disabled = false } = $$props;
319 |
320 | // Instance variables
321 | let instance = null;
322 |
323 | let lastEditorData = "";
324 | let editorElement;
325 | const dispatch = createEventDispatcher();
326 |
327 | function watchValue(x) {
328 | if (instance && x !== lastEditorData) {
329 | instance.setData(x);
330 | }
331 | }
332 |
333 | onMount(() => {
334 | // If value is passed then add it to config
335 | if (value) {
336 | Object.assign(config, { initialData: value });
337 | }
338 |
339 | // Get dom element to mount initialised editor instance
340 | editorElement = document.getElementById("_editor");
341 |
342 | editor.create(editorElement, config).then(editor => {
343 | // Save the reference to the instance for future use.
344 | instance = editor;
345 |
346 | // Set initial disabled state.
347 | editor.isReadOnly = disabled;
348 |
349 | // Let the world know the editor is ready.
350 | dispatch("ready", editor);
351 |
352 | setUpEditorEvents();
353 | }).catch(error => {
354 | console.error(error);
355 | });
356 | });
357 |
358 | onDestroy(() => {
359 | if (instance) {
360 | instance.destroy();
361 | instance = null;
362 | }
363 |
364 | // Note: By the time the editor is destroyed (promise resolved, editor#destroy fired)
365 | // the Vue component will not be able to emit any longer.
366 | // So emitting #destroy a bit earlier.
367 | dispatch("destroy", instance);
368 | });
369 |
370 | function setUpEditorEvents() {
371 | const emitInputEvent = evt => {
372 | // Cache the last editor data. This kind of data is a result of typing,
373 | // editor command execution, collaborative changes to the document, etc.
374 | // This data is compared when the component value changes in a 2-way binding.
375 | const data = $$invalidate(0, value = lastEditorData = instance.getData());
376 |
377 | dispatch("input", { data, evt, instance });
378 | };
379 |
380 | // Debounce emitting the #input event. When data is huge, instance#getData()
381 | // takes a lot of time to execute on every single key press and ruins the UX.
382 | instance.model.document.on("change:data", justDebounceIt(emitInputEvent, INPUT_EVENT_DEBOUNCE_WAIT));
383 |
384 | instance.editing.view.document.on("focus", evt => {
385 | dispatch("focus", { evt, instance });
386 | });
387 |
388 | instance.editing.view.document.on("blur", evt => {
389 | dispatch("blur", { evt, instance });
390 | });
391 | }
392 |
393 | $$self.$$set = $$props => {
394 | if ("editor" in $$props) $$invalidate(1, editor = $$props.editor);
395 | if ("value" in $$props) $$invalidate(0, value = $$props.value);
396 | if ("config" in $$props) $$invalidate(2, config = $$props.config);
397 | if ("disabled" in $$props) $$invalidate(3, disabled = $$props.disabled);
398 | };
399 |
400 | $$self.$$.update = () => {
401 | if ($$self.$$.dirty & /*value*/ 1) {
402 | watchValue(value);
403 | }
404 | };
405 |
406 | return [value, editor, config, disabled];
407 | }
408 |
409 | class Ckeditor extends SvelteComponent {
410 | constructor(options) {
411 | super();
412 |
413 | init(this, options, instance_1, create_fragment, safe_not_equal, {
414 | editor: 1,
415 | value: 0,
416 | config: 2,
417 | disabled: 3
418 | });
419 | }
420 | }
421 |
422 | export default Ckeditor;
423 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ckeditor5-svelte",
3 | "version": "0.0.10",
4 | "description": "Svelte3 component for CKEditor5",
5 | "homepage": "https://github.com/techlab23/ckeditor5-svelte",
6 | "author": "Shirish Nigam ",
7 | "license": "GPL-2.0-or-later",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/techlab23/ckeditor5-svelte"
11 | },
12 | "publishConfig": {
13 | "registry": "https://registry.npmjs.org/"
14 | },
15 | "svelte": "src/index.js",
16 | "module": "dist/index.mjs",
17 | "main": "dist/index.js",
18 | "scripts": {
19 | "build": "rollup -c",
20 | "prepublishOnly": "npm run build"
21 | },
22 | "keywords": [
23 | "wysiwyg",
24 | "rich text",
25 | "editor",
26 | "html",
27 | "contentEditable",
28 | "editing",
29 | "svelte",
30 | "svelte.js",
31 | "svelte component",
32 | "svelte3 component",
33 | "ckeditor",
34 | "ckeditor5",
35 | "ckeditor 5"
36 | ],
37 | "files": [
38 | "src",
39 | "dist"
40 | ],
41 | "devDependencies": {
42 | "@rollup/plugin-commonjs": "^17.1.0",
43 | "rollup": "^2.38.4",
44 | "rollup-plugin-node-resolve": "^5.2.0",
45 | "rollup-plugin-svelte": "^7.1.0",
46 | "svelte": "^3.32.1"
47 | },
48 | "dependencies": {
49 | "just-debounce-it": "^1.1.0"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import resolve from 'rollup-plugin-node-resolve';
3 | import commonjs from '@rollup/plugin-commonjs';
4 | import pkg from './package.json';
5 |
6 | export default {
7 | input: 'src/Ckeditor.svelte',
8 | output: [
9 | { file: pkg.module, format: 'es' },
10 | { file: pkg.main, format: 'umd', name: 'Ckeditor' },
11 | ],
12 | plugins: [svelte(), resolve(), commonjs()],
13 | };
14 |
--------------------------------------------------------------------------------
/samples/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | yarn.lock
4 | package-lock.json
--------------------------------------------------------------------------------
/samples/README.md:
--------------------------------------------------------------------------------
1 | *Psst — looking for a shareable component template? Go here --> [sveltejs/component-template](https://github.com/sveltejs/component-template)*
2 |
3 | ---
4 |
5 | # svelte app
6 |
7 | This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template.
8 |
9 | To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit):
10 |
11 | ```bash
12 | npx degit sveltejs/template svelte-app
13 | cd svelte-app
14 | ```
15 |
16 | *Note that you will need to have [Node.js](https://nodejs.org) installed.*
17 |
18 |
19 | ## Get started
20 |
21 | Install the dependencies...
22 |
23 | ```bash
24 | cd svelte-app
25 | npm install
26 | ```
27 |
28 | ...then start [Rollup](https://rollupjs.org):
29 |
30 | ```bash
31 | npm run dev
32 | ```
33 |
34 | Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
35 |
36 |
37 | ## Deploying to the web
38 |
39 | ### With [now](https://zeit.co/now)
40 |
41 | Install `now` if you haven't already:
42 |
43 | ```bash
44 | npm install -g now
45 | ```
46 |
47 | Then, from within your project folder:
48 |
49 | ```bash
50 | cd public
51 | now
52 | ```
53 |
54 | As an alternative, use the [Now desktop client](https://zeit.co/download) and simply drag the unzipped project folder to the taskbar icon.
55 |
56 | ### With [surge](https://surge.sh/)
57 |
58 | Install `surge` if you haven't already:
59 |
60 | ```bash
61 | npm install -g surge
62 | ```
63 |
64 | Then, from within your project folder:
65 |
66 | ```bash
67 | npm run build
68 | surge public
69 | ```
70 |
--------------------------------------------------------------------------------
/samples/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "svelte-app",
3 | "version": "1.0.0",
4 | "devDependencies": {
5 | "npm-run-all": "^4.1.5",
6 | "rollup": "^2.38.4",
7 | "rollup-plugin-commonjs": "^10.0.0",
8 | "rollup-plugin-css-only": "^3.1.0",
9 | "rollup-plugin-livereload": "^2.0.0",
10 | "rollup-plugin-node-resolve": "^5.2.0",
11 | "rollup-plugin-svelte": "^7.1.0",
12 | "rollup-plugin-terser": "^7.0.2",
13 | "sirv-cli": "^1.0.11",
14 | "svelte": "^3.32.1"
15 | },
16 | "dependencies": {
17 | "@ckeditor/ckeditor5-build-decoupled-document": "^25.0.0"
18 | },
19 | "scripts": {
20 | "build": "rollup -c",
21 | "autobuild": "rollup -c -w",
22 | "dev": "run-p start:dev autobuild",
23 | "start": "sirv public --single",
24 | "start:dev": "sirv public --single --dev"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/samples/public/bundle.css:
--------------------------------------------------------------------------------
1 | .preview-area.svelte-1ep30s{margin-top:40px;margin-left:10px}
--------------------------------------------------------------------------------
/samples/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/techlab23/ckeditor5-svelte/03632ac9151383c034e2918f3630f14988a4ea4e/samples/public/favicon.png
--------------------------------------------------------------------------------
/samples/public/global.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | position: relative;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | body {
8 | color: #333;
9 | margin: 0;
10 | padding: 8px;
11 | box-sizing: border-box;
12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
13 | }
14 |
15 | a {
16 | color: rgb(0,100,200);
17 | text-decoration: none;
18 | }
19 |
20 | a:hover {
21 | text-decoration: underline;
22 | }
23 |
24 | a:visited {
25 | color: rgb(0,80,160);
26 | }
27 |
28 | label {
29 | display: block;
30 | }
31 |
32 | input, button, select, textarea {
33 | font-family: inherit;
34 | font-size: inherit;
35 | padding: 0.4em;
36 | margin: 0 0 0.5em 0;
37 | box-sizing: border-box;
38 | border: 1px solid #ccc;
39 | border-radius: 2px;
40 | }
41 |
42 | input:disabled {
43 | color: #ccc;
44 | }
45 |
46 | input[type="range"] {
47 | height: 0;
48 | }
49 |
50 | button {
51 | color: #333;
52 | background-color: #f4f4f4;
53 | outline: none;
54 | }
55 |
56 | button:active {
57 | background-color: #ddd;
58 | }
59 |
60 | button:focus {
61 | border-color: #666;
62 | }
63 |
--------------------------------------------------------------------------------
/samples/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Svelte app
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/samples/public/public/bundle.css:
--------------------------------------------------------------------------------
1 | .preview-area.svelte-1ep30s{margin-top:40px;margin-left:10px}
--------------------------------------------------------------------------------
/samples/rollup.config.js:
--------------------------------------------------------------------------------
1 | import svelte from 'rollup-plugin-svelte';
2 | import resolve from 'rollup-plugin-node-resolve';
3 | import commonjs from '@rollup/plugin-commonjs';
4 | import livereload from 'rollup-plugin-livereload';
5 | import { terser } from 'rollup-plugin-terser';
6 | import css from 'rollup-plugin-css-only';
7 |
8 | const production = !process.env.ROLLUP_WATCH;
9 |
10 | export default {
11 | input: 'src/main.js',
12 | output: {
13 | sourcemap: true,
14 | format: 'iife',
15 | name: 'app',
16 | file: 'public/bundle.js',
17 | },
18 | plugins: [
19 | css({ output: 'bundle.css' }),
20 | svelte({
21 | // enable run-time checks when not in production
22 | compilerOptions: {
23 | dev: !production,
24 | },
25 | // we'll extract any component CSS out into
26 | // a separate file — better for performance
27 | // css: (css) => {
28 | // css.write('public/bundle.css');
29 | // },
30 | }),
31 |
32 | // If you have external dependencies installed from
33 | // npm, you'll most likely need these plugins. In
34 | // some cases you'll need additional configuration —
35 | // consult the documentation for details:
36 | // https://github.com/rollup/rollup-plugin-commonjs
37 | resolve({
38 | browser: true,
39 | dedupe: (importee) =>
40 | importee === 'svelte' || importee.startsWith('svelte/'),
41 | }),
42 | commonjs(),
43 |
44 | // Watch the `public` directory and refresh the
45 | // browser on changes when not in production
46 | !production && livereload('public'),
47 |
48 | // If we're building for production (npm run build
49 | // instead of npm run dev), minify
50 | production && terser(),
51 | ],
52 | watch: {
53 | clearScreen: false,
54 | },
55 | };
56 |
--------------------------------------------------------------------------------
/samples/src/App.svelte:
--------------------------------------------------------------------------------
1 |
41 |
42 |
43 |
48 |
49 |
--------------------------------------------------------------------------------
/samples/src/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.svelte";
2 |
3 | const app = new App({
4 | target: document.body
5 | });
6 |
7 | export default app;
8 |
--------------------------------------------------------------------------------
/src/Ckeditor.svelte:
--------------------------------------------------------------------------------
1 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Ckeditor.svelte';
2 |
--------------------------------------------------------------------------------