1 | import { EventEmitter, Directive, Output, Input, ContentChildren, Component, forwardRef, NgZone, ViewChild, NgModule } from '@angular/core';
|
2 | import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
3 | import { CommonModule } from '@angular/common';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 | class CKButtonDirective {
|
15 | constructor() {
|
16 | this.click = new EventEmitter();
|
17 | }
|
18 | initialize(editor) {
|
19 | editor.instance.addCommand(this.command, {
|
20 | exec: (edit) => {
|
21 | this.click.emit(edit);
|
22 | return true;
|
23 | },
|
24 | });
|
25 | editor.instance.ui.addButton(this.name, {
|
26 | label: this.label,
|
27 | command: this.command,
|
28 | toolbar: this.toolbar,
|
29 | icon: this.icon,
|
30 | });
|
31 | }
|
32 | ngOnInit() {
|
33 | if (!this.name) {
|
34 | throw new Error('Attribute "name" is required on <ckbutton>');
|
35 | }
|
36 | if (!this.command) {
|
37 | throw new Error('Attribute "command" is required on <ckbutton>');
|
38 | }
|
39 | }
|
40 | }
|
41 | CKButtonDirective.decorators = [
|
42 | { type: Directive, args: [{
|
43 | selector: 'ckbutton',
|
44 | },] }
|
45 | ];
|
46 | CKButtonDirective.propDecorators = {
|
47 | click: [{ type: Output }],
|
48 | label: [{ type: Input }],
|
49 | command: [{ type: Input }],
|
50 | toolbar: [{ type: Input }],
|
51 | name: [{ type: Input }],
|
52 | icon: [{ type: Input }]
|
53 | };
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 | class CKGroupDirective {
|
66 | ngAfterContentInit() {
|
67 |
|
68 | this.toolbarButtons.forEach((button) => (button.toolbar = this.name));
|
69 | }
|
70 | initialize(editor) {
|
71 | editor.instance.ui.addToolbarGroup(this.name, this.previous, this.subgroupOf);
|
72 |
|
73 | this.toolbarButtons.forEach((button) => {
|
74 | button.initialize(editor);
|
75 | });
|
76 | }
|
77 | }
|
78 | CKGroupDirective.decorators = [
|
79 | { type: Directive, args: [{
|
80 | selector: 'ckgroup',
|
81 | },] }
|
82 | ];
|
83 | CKGroupDirective.propDecorators = {
|
84 | name: [{ type: Input }],
|
85 | previous: [{ type: Input }],
|
86 | subgroupOf: [{ type: Input }],
|
87 | toolbarButtons: [{ type: ContentChildren, args: [CKButtonDirective,] }]
|
88 | };
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | class CKEditorComponent {
|
97 | |
98 |
|
99 |
|
100 | constructor(zone) {
|
101 | this.zone = zone;
|
102 | this.change = new EventEmitter();
|
103 | this.editorChange = new EventEmitter();
|
104 | this.ready = new EventEmitter();
|
105 | this.blur = new EventEmitter();
|
106 | this.focus = new EventEmitter();
|
107 | this.contentDom = new EventEmitter();
|
108 | this.fileUploadRequest = new EventEmitter();
|
109 | this.fileUploadResponse = new EventEmitter();
|
110 | this.paste = new EventEmitter();
|
111 | this.drop = new EventEmitter();
|
112 | this._value = '';
|
113 | this.destroyed = false;
|
114 | }
|
115 | get value() {
|
116 | return this._value;
|
117 | }
|
118 | set value(v) {
|
119 | if (v !== this._value) {
|
120 | this._value = v;
|
121 | this.onChange(v);
|
122 | }
|
123 | }
|
124 | ngOnChanges(changes) {
|
125 | if (changes.readonly && this.instance) {
|
126 | this.instance.setReadOnly(changes.readonly.currentValue);
|
127 | }
|
128 | }
|
129 | |
130 |
|
131 |
|
132 | ngOnDestroy() {
|
133 | this.destroyed = true;
|
134 | this.zone.runOutsideAngular(() => {
|
135 | if (this.instance) {
|
136 | CKEDITOR.removeAllListeners();
|
137 | this.instance.destroy();
|
138 | this.instance = null;
|
139 | }
|
140 | });
|
141 | }
|
142 | |
143 |
|
144 |
|
145 | ngAfterViewInit() {
|
146 | if (this.destroyed) {
|
147 | return;
|
148 | }
|
149 | this.ckeditorInit(this.config || {});
|
150 | }
|
151 | |
152 |
|
153 |
|
154 | ngAfterViewChecked() {
|
155 | this.ckeditorInit(this.config || {});
|
156 | }
|
157 | |
158 |
|
159 |
|
160 | updateValue(value) {
|
161 | this.zone.run(() => {
|
162 | this.value = value;
|
163 | this.onChange(value);
|
164 | this.onTouched();
|
165 | this.change.emit(value);
|
166 | });
|
167 | }
|
168 | |
169 |
|
170 |
|
171 | ckeditorInit(config) {
|
172 | if (typeof CKEDITOR === 'undefined') {
|
173 | console.warn('CKEditor 4.x is missing (http://ckeditor.com/)');
|
174 | }
|
175 | else {
|
176 |
|
177 | if (this.instance || !this.documentContains(this.host.nativeElement)) {
|
178 | return;
|
179 | }
|
180 | if (this.readonly) {
|
181 | config.readOnly = this.readonly;
|
182 | }
|
183 |
|
184 | this.instance = CKEDITOR.replace(this.host.nativeElement, config);
|
185 |
|
186 | this.instance.setData(this.value);
|
187 |
|
188 | this.instance.on('instanceReady', (evt) => {
|
189 |
|
190 |
|
191 | if (this.instance.getData() !== this.value) {
|
192 | this.instance.setData(this.value);
|
193 | }
|
194 |
|
195 | this.ready.emit(evt);
|
196 | });
|
197 |
|
198 | this.instance.on('change', (evt) => {
|
199 | this.onTouched();
|
200 | const value = this.instance.getData();
|
201 | if (this.value !== value) {
|
202 |
|
203 | if (this.debounce) {
|
204 | if (this.debounceTimeout) {
|
205 | clearTimeout(this.debounceTimeout);
|
206 | }
|
207 | this.debounceTimeout = window.setTimeout(() => {
|
208 | this.updateValue(value);
|
209 | this.debounceTimeout = null;
|
210 | }, parseInt(this.debounce));
|
211 |
|
212 | }
|
213 | else {
|
214 | this.updateValue(value);
|
215 | }
|
216 | }
|
217 |
|
218 | this.editorChange.emit(evt);
|
219 | });
|
220 |
|
221 | this.instance.on('blur', (evt) => {
|
222 | this.blur.emit(evt);
|
223 | });
|
224 |
|
225 | this.instance.on('focus', (evt) => {
|
226 | this.focus.emit(evt);
|
227 | });
|
228 |
|
229 | this.instance.on('contentDom', (evt) => {
|
230 | this.contentDom.emit(evt);
|
231 | });
|
232 |
|
233 | this.instance.on('fileUploadRequest', (evt) => {
|
234 | this.fileUploadRequest.emit(evt);
|
235 | });
|
236 |
|
237 | this.instance.on('fileUploadResponse', (evt) => {
|
238 | this.fileUploadResponse.emit(evt);
|
239 | });
|
240 |
|
241 | this.instance.on('paste', (evt) => {
|
242 | this.paste.emit(evt);
|
243 | });
|
244 |
|
245 | this.instance.on('drop', (evt) => {
|
246 | this.drop.emit(evt);
|
247 | });
|
248 |
|
249 | this.toolbarGroups.forEach((group) => {
|
250 | group.initialize(this);
|
251 | });
|
252 |
|
253 | this.toolbarButtons.forEach((button) => {
|
254 | button.initialize(this);
|
255 | });
|
256 | }
|
257 | }
|
258 | |
259 |
|
260 |
|
261 | writeValue(value) {
|
262 | this._value = value;
|
263 | if (this.instance)
|
264 | this.instance.setData(value);
|
265 | }
|
266 | registerOnChange(fn) {
|
267 | this.onChange = fn;
|
268 | }
|
269 | registerOnTouched(fn) {
|
270 | this.onTouched = fn;
|
271 | }
|
272 | documentContains(node) {
|
273 | return document.contains ? document.contains(node) : document.body.contains(node);
|
274 | }
|
275 | }
|
276 | CKEditorComponent.decorators = [
|
277 | { type: Component, args: [{
|
278 | selector: 'ckeditor',
|
279 | providers: [
|
280 | {
|
281 | provide: NG_VALUE_ACCESSOR,
|
282 | useExisting: forwardRef(() => CKEditorComponent),
|
283 | multi: true,
|
284 | },
|
285 | ],
|
286 | template: `<textarea #host></textarea>`
|
287 | },] }
|
288 | ];
|
289 | CKEditorComponent.ctorParameters = () => [
|
290 | { type: NgZone }
|
291 | ];
|
292 | CKEditorComponent.propDecorators = {
|
293 | config: [{ type: Input }],
|
294 | readonly: [{ type: Input }],
|
295 | debounce: [{ type: Input }],
|
296 | change: [{ type: Output }],
|
297 | editorChange: [{ type: Output }],
|
298 | ready: [{ type: Output }],
|
299 | blur: [{ type: Output }],
|
300 | focus: [{ type: Output }],
|
301 | contentDom: [{ type: Output }],
|
302 | fileUploadRequest: [{ type: Output }],
|
303 | fileUploadResponse: [{ type: Output }],
|
304 | paste: [{ type: Output }],
|
305 | drop: [{ type: Output }],
|
306 | host: [{ type: ViewChild, args: ['host', { static: false },] }],
|
307 | toolbarButtons: [{ type: ContentChildren, args: [CKButtonDirective,] }],
|
308 | toolbarGroups: [{ type: ContentChildren, args: [CKGroupDirective,] }],
|
309 | value: [{ type: Input }]
|
310 | };
|
311 |
|
312 |
|
313 |
|
314 |
|
315 | class CKEditorModule {
|
316 | }
|
317 | CKEditorModule.decorators = [
|
318 | { type: NgModule, args: [{
|
319 | imports: [CommonModule],
|
320 | declarations: [CKEditorComponent, CKButtonDirective, CKGroupDirective],
|
321 | exports: [CKEditorComponent, CKButtonDirective, CKGroupDirective],
|
322 | },] }
|
323 | ];
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 | export { CKEditorComponent, CKEditorModule, CKButtonDirective as ɵa, CKGroupDirective as ɵb };
|
330 |
|