UNPKG

10.5 kBJavaScriptView Raw
1import { EventEmitter, Directive, Output, Input, ContentChildren, Component, forwardRef, NgZone, ViewChild, NgModule } from '@angular/core';
2import { NG_VALUE_ACCESSOR } from '@angular/forms';
3import { CommonModule } from '@angular/common';
4
5/**
6 * CKGroup component
7 * Usage :
8 * <ckeditor [(ngModel)]="data" [config]="{...}" debounce="500">
9 * <ckbutton [name]="'SaveButton'" [command]="'saveCommand'" (click)="save($event)"
10 * [icon]="'/save.png'" [toolbar]="'customGroup,1'" [label]="'Save'">
11 * </ckbutton>
12 * </ckeditor>
13 */
14class 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}
41CKButtonDirective.decorators = [
42 { type: Directive, args: [{
43 selector: 'ckbutton',
44 },] }
45];
46CKButtonDirective.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 * CKGroup component
57 * Usage :
58 * <ckeditor [(ngModel)]="data" [config]="{...}" debounce="500">
59 * <ckgroup [name]="'exampleGroup2'" [previous]="'1'" [subgroupOf]="'exampleGroup1'">
60 * .
61 * .
62 * </ckgroup>
63 * </ckeditor>
64 */
65class CKGroupDirective {
66 ngAfterContentInit() {
67 // Reconfigure each button's toolbar property within ckgroup to hold its parent's name
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 // Initialize each button within ckgroup
73 this.toolbarButtons.forEach((button) => {
74 button.initialize(editor);
75 });
76 }
77}
78CKGroupDirective.decorators = [
79 { type: Directive, args: [{
80 selector: 'ckgroup',
81 },] }
82];
83CKGroupDirective.propDecorators = {
84 name: [{ type: Input }],
85 previous: [{ type: Input }],
86 subgroupOf: [{ type: Input }],
87 toolbarButtons: [{ type: ContentChildren, args: [CKButtonDirective,] }]
88};
89
90// Imports
91/**
92 * CKEditor component
93 * Usage :
94 * <ckeditor [(ngModel)]="data" [config]="{...}" debounce="500"></ckeditor>
95 */
96class CKEditorComponent {
97 /**
98 * Constructor
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 * On component destroy
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 * On component view init
144 */
145 ngAfterViewInit() {
146 if (this.destroyed) {
147 return;
148 }
149 this.ckeditorInit(this.config || {});
150 }
151 /**
152 * On component view checked
153 */
154 ngAfterViewChecked() {
155 this.ckeditorInit(this.config || {});
156 }
157 /**
158 * Value update process
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 * CKEditor init
170 */
171 ckeditorInit(config) {
172 if (typeof CKEDITOR === 'undefined') {
173 console.warn('CKEditor 4.x is missing (http://ckeditor.com/)');
174 }
175 else {
176 // Check textarea exists
177 if (this.instance || !this.documentContains(this.host.nativeElement)) {
178 return;
179 }
180 if (this.readonly) {
181 config.readOnly = this.readonly;
182 }
183 // CKEditor replace textarea
184 this.instance = CKEDITOR.replace(this.host.nativeElement, config);
185 // Set initial value
186 this.instance.setData(this.value);
187 // listen for instanceReady event
188 this.instance.on('instanceReady', (evt) => {
189 // if value has changed while instance loading
190 // update instance with current component value
191 if (this.instance.getData() !== this.value) {
192 this.instance.setData(this.value);
193 }
194 // send the evt to the EventEmitter
195 this.ready.emit(evt);
196 });
197 // CKEditor change event
198 this.instance.on('change', (evt) => {
199 this.onTouched();
200 const value = this.instance.getData();
201 if (this.value !== value) {
202 // Debounce update
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 // Live update
212 }
213 else {
214 this.updateValue(value);
215 }
216 }
217 // Original ckeditor event dispatch
218 this.editorChange.emit(evt);
219 });
220 // CKEditor blur event
221 this.instance.on('blur', (evt) => {
222 this.blur.emit(evt);
223 });
224 // CKEditor focus event
225 this.instance.on('focus', (evt) => {
226 this.focus.emit(evt);
227 });
228 // CKEditor contentDom event
229 this.instance.on('contentDom', (evt) => {
230 this.contentDom.emit(evt);
231 });
232 // CKEditor fileUploadRequest event
233 this.instance.on('fileUploadRequest', (evt) => {
234 this.fileUploadRequest.emit(evt);
235 });
236 // CKEditor fileUploadResponse event
237 this.instance.on('fileUploadResponse', (evt) => {
238 this.fileUploadResponse.emit(evt);
239 });
240 // CKEditor paste event
241 this.instance.on('paste', (evt) => {
242 this.paste.emit(evt);
243 });
244 // CKEditor drop event
245 this.instance.on('drop', (evt) => {
246 this.drop.emit(evt);
247 });
248 // Add Toolbar Groups to Editor. This will also add Buttons within groups.
249 this.toolbarGroups.forEach((group) => {
250 group.initialize(this);
251 });
252 // Add Toolbar Buttons to Editor.
253 this.toolbarButtons.forEach((button) => {
254 button.initialize(this);
255 });
256 }
257 }
258 /**
259 * Implements ControlValueAccessor
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}
276CKEditorComponent.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];
289CKEditorComponent.ctorParameters = () => [
290 { type: NgZone }
291];
292CKEditorComponent.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 * CKEditorModule
314 */
315class CKEditorModule {
316}
317CKEditorModule.decorators = [
318 { type: NgModule, args: [{
319 imports: [CommonModule],
320 declarations: [CKEditorComponent, CKButtonDirective, CKGroupDirective],
321 exports: [CKEditorComponent, CKButtonDirective, CKGroupDirective],
322 },] }
323];
324
325/**
326 * Generated bundle index. Do not edit.
327 */
328
329export { CKEditorComponent, CKEditorModule, CKButtonDirective as ɵa, CKGroupDirective as ɵb };
330//# sourceMappingURL=ng2-ckeditor.js.map