@firestitch/html-editor 12.6.0 → 12.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/app/modules/html-editor/classes/plugin.d.ts +7 -7
  2. package/app/modules/html-editor/components/html-editor/html-editor.component.d.ts +57 -59
  3. package/app/modules/html-editor/consts/paragraph-buttons.const.d.ts +1 -1
  4. package/app/modules/html-editor/consts/rich-buttons.const.d.ts +1 -1
  5. package/app/modules/html-editor/consts/text-buttons.const.d.ts +1 -1
  6. package/app/modules/html-editor/enums/default-plugin.enum.d.ts +16 -16
  7. package/app/modules/html-editor/fs-html-editor.module.d.ts +43 -43
  8. package/app/modules/html-editor/injects/config.inject.d.ts +3 -3
  9. package/app/modules/html-editor/interfaces/html-editor-config.d.ts +40 -40
  10. package/app/modules/html-editor/interfaces/plugin-button.d.ts +12 -12
  11. package/app/modules/html-editor/interfaces/plugin-config.d.ts +5 -5
  12. package/app/modules/html-editor/plugins/checklist.plugin.d.ts +7 -7
  13. package/app/modules/html-editor/plugins/code.plugin.d.ts +9 -9
  14. package/app/modules/html-editor/plugins/configs/mention-plugin.config.d.ts +13 -13
  15. package/app/modules/html-editor/plugins/configs/screen-record-plugin.config.d.ts +7 -7
  16. package/app/modules/html-editor/plugins/mention.plugin.d.ts +15 -15
  17. package/app/modules/html-editor/plugins/realtime.plugin.d.ts +7 -7
  18. package/app/modules/html-editor/plugins/screen-record.plugin.d.ts +11 -11
  19. package/app/modules/html-editor/services/froala-loader.service.d.ts +21 -21
  20. package/app/modules/html-renderer/components/html-renderer/html-renderer.component.d.ts +12 -12
  21. package/app/modules/html-renderer/fs-html-renderer.module.d.ts +8 -8
  22. package/bundles/firestitch-html-editor.umd.js +1332 -1381
  23. package/bundles/firestitch-html-editor.umd.js.map +1 -1
  24. package/esm2015/app/modules/html-editor/classes/plugin.js +4 -4
  25. package/esm2015/app/modules/html-editor/components/html-editor/html-editor.component.js +462 -512
  26. package/esm2015/app/modules/html-editor/consts/paragraph-buttons.const.js +9 -9
  27. package/esm2015/app/modules/html-editor/consts/rich-buttons.const.js +6 -6
  28. package/esm2015/app/modules/html-editor/consts/text-buttons.const.js +18 -18
  29. package/esm2015/app/modules/html-editor/enums/default-plugin.enum.js +1 -1
  30. package/esm2015/app/modules/html-editor/fs-html-editor.module.js +68 -68
  31. package/esm2015/app/modules/html-editor/injects/config.inject.js +3 -3
  32. package/esm2015/app/modules/html-editor/interfaces/html-editor-config.js +1 -1
  33. package/esm2015/app/modules/html-editor/interfaces/plugin-button.js +1 -1
  34. package/esm2015/app/modules/html-editor/interfaces/plugin-config.js +1 -1
  35. package/esm2015/app/modules/html-editor/plugins/checklist.plugin.js +34 -34
  36. package/esm2015/app/modules/html-editor/plugins/code.plugin.js +62 -62
  37. package/esm2015/app/modules/html-editor/plugins/configs/mention-plugin.config.js +1 -1
  38. package/esm2015/app/modules/html-editor/plugins/configs/screen-record-plugin.config.js +1 -1
  39. package/esm2015/app/modules/html-editor/plugins/mention.plugin.js +86 -86
  40. package/esm2015/app/modules/html-editor/plugins/realtime.plugin.js +12 -12
  41. package/esm2015/app/modules/html-editor/plugins/screen-record.plugin.js +88 -88
  42. package/esm2015/app/modules/html-editor/services/froala-loader.service.js +89 -89
  43. package/esm2015/app/modules/html-renderer/components/html-renderer/html-renderer.component.js +28 -28
  44. package/esm2015/app/modules/html-renderer/fs-html-renderer.module.js +25 -25
  45. package/esm2015/firestitch-html-editor.js +4 -4
  46. package/esm2015/public_api.js +13 -13
  47. package/fesm2015/firestitch-html-editor.js +934 -983
  48. package/fesm2015/firestitch-html-editor.js.map +1 -1
  49. package/firestitch-html-editor.d.ts +5 -5
  50. package/package.json +1 -1
  51. package/public_api.d.ts +18 -18
  52. package/styles.scss +4 -0
@@ -1,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, Optional, Inject, Component, ChangeDetectionStrategy, Input, forwardRef, HostBinding, ViewChild, NgModule } from '@angular/core';
3
- import * as i4 from '@angular/common';
2
+ import { InjectionToken, Injectable, Optional, Inject, forwardRef, Component, ChangeDetectionStrategy, HostBinding, ViewChild, Input, NgModule } from '@angular/core';
3
+ import * as i3 from '@angular/common';
4
4
  import { DOCUMENT, CommonModule } from '@angular/common';
5
5
  import * as i2 from '@firestitch/label';
6
6
  import { FsLabelModule } from '@firestitch/label';
7
- import * as i5 from '@firestitch/skeleton';
7
+ import * as i4 from '@firestitch/skeleton';
8
8
  import { FsSkeletonModule } from '@firestitch/skeleton';
9
9
  import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
10
10
  import { FileProcessor, FsFile } from '@firestitch/file';
@@ -16,1018 +16,969 @@ import * as i1 from '@angular/platform-browser';
16
16
  import Tribute from 'tributejs';
17
17
  import { __awaiter } from 'tslib';
18
18
 
19
- const RichButtons = [
20
- 'insertTable',
21
- 'insertImage',
22
- 'insertLink',
23
- 'insertVideo',
19
+ const RichButtons = [
20
+ 'insertTable',
21
+ 'insertImage',
22
+ 'insertLink',
23
+ 'insertVideo',
24
24
  ];
25
25
 
26
- const TextButtons = [
27
- 'paragraphFormat',
28
- 'code',
29
- 'bold',
30
- 'italic',
31
- 'underline',
32
- 'strikeThrough',
33
- 'subscript',
34
- 'superscript',
35
- 'fontFamily',
36
- 'fontSize',
37
- 'textColor',
38
- 'backgroundColor',
39
- 'inlineClass',
40
- 'inlineStyle',
41
- 'clearFormatting',
42
- 'quote',
26
+ const TextButtons = [
27
+ 'paragraphFormat',
28
+ 'code',
29
+ 'bold',
30
+ 'italic',
31
+ 'underline',
32
+ 'strikeThrough',
33
+ 'subscript',
34
+ 'superscript',
35
+ 'fontFamily',
36
+ 'fontSize',
37
+ 'textColor',
38
+ 'backgroundColor',
39
+ 'inlineClass',
40
+ 'inlineStyle',
41
+ 'clearFormatting',
42
+ 'quote',
43
43
  ];
44
44
 
45
- const ParagraphButtons = [
46
- 'align',
47
- 'formatOL',
48
- 'formatUL',
49
- 'checklist',
50
- 'indent',
51
- 'outdent',
52
- 'lineHeight'
45
+ const ParagraphButtons = [
46
+ 'align',
47
+ 'formatOL',
48
+ 'formatUL',
49
+ 'checklist',
50
+ 'indent',
51
+ 'outdent',
52
+ 'lineHeight'
53
53
  ];
54
54
 
55
- const FS_HTML_EDITOR_DEFAULT_CONFIG = new InjectionToken('fs-html-editor.default-config');
55
+ const FS_HTML_EDITOR_DEFAULT_CONFIG = new InjectionToken('fs-html-editor.default-config');
56
56
  const FS_HTML_EDITOR_CONFIG = new InjectionToken('fs-html-editor.config');
57
57
 
58
- class FsFroalaLoaderService {
59
- constructor(_defaultConfig, _document) {
60
- this._defaultConfig = _defaultConfig;
61
- this._document = _document;
62
- this._froalaLoaded = new BehaviorSubject(false);
63
- this._froalaPluginsLoaded = new BehaviorSubject(false);
64
- this._sourceLoader = fsSourceLoader;
65
- this._loaded$ = combineLatest([this._froalaLoaded, this._froalaPluginsLoaded])
66
- .pipe(map(([FroalaReady, pluginsRead]) => {
67
- return pluginsRead && FroalaReady;
68
- }), shareReplay(1));
69
- this._sourceLoader.setDocument(this._document);
70
- this._load();
71
- }
72
- get loaded$() {
73
- return this._loaded$;
74
- }
75
- get FroalaEditor() {
76
- return this._FroalaEditor;
77
- }
78
- _load() {
79
- const baseDir = '/assets/froala/';
80
- this._sourceLoader.registerResources({
81
- froala: [
82
- `${baseDir}js/froala_editor.min.js`,
83
- `${baseDir}css/froala_editor.pkgd.min.css`,
84
- ],
85
- froala_align: `${baseDir}js/plugins/align.min.js`,
86
- froala_colors: `${baseDir}js/plugins/colors.min.js`,
87
- froala_image: `${baseDir}js/plugins/image.min.js`,
88
- froala_link: `${baseDir}js/plugins/link.min.js`,
89
- froala_lists: `${baseDir}js/plugins/lists.min.js`,
90
- froala_paragraph_format: `${baseDir}js/plugins/paragraph_format.min.js`,
91
- froala_table: `${baseDir}js/plugins/table.min.js`,
92
- froala_url: `${baseDir}js/plugins/url.min.js`,
93
- froala_video: `${baseDir}js/plugins/video.min.js`,
94
- froala_quote: `${baseDir}js/plugins/quote.min.js`,
95
- froala_draggable: `${baseDir}js/plugins/draggable.min.js`,
96
- froala_font_size: `${baseDir}js/plugins/font_size.min.js`,
97
- froala_quick_insert: `${baseDir}js/plugins/quick_insert.min.js`,
98
- froala_line_height: `${baseDir}js/plugins/line_height.min.js`
99
- });
100
- this._sourceLoader.loadResource('froala')
101
- .pipe(tap(() => {
102
- this._FroalaEditor = window.FroalaEditor;
103
- this._froalaDone();
104
- }), concatMap(() => {
105
- return this._loadPlugins();
106
- }), tap(() => {
107
- this._froalaPluginsDone();
108
- }))
109
- .subscribe();
110
- }
111
- _loadPlugins() {
112
- const resources = this._defaultConfig
113
- .froalaPlugins
114
- .map((pluginName) => `froala_${pluginName}`);
115
- return this._sourceLoader.loadResources(resources);
116
- }
117
- _froalaDone() {
118
- this._froalaLoaded.next(true);
119
- }
120
- _froalaPluginsDone() {
121
- this._froalaPluginsLoaded.next(true);
122
- }
123
- }
124
- FsFroalaLoaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFroalaLoaderService, deps: [{ token: FS_HTML_EDITOR_CONFIG, optional: true }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
125
- FsFroalaLoaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFroalaLoaderService, providedIn: 'root' });
126
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFroalaLoaderService, decorators: [{
127
- type: Injectable,
128
- args: [{
129
- providedIn: 'root',
130
- }]
131
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
132
- type: Optional
133
- }, {
134
- type: Inject,
135
- args: [FS_HTML_EDITOR_CONFIG]
136
- }] }, { type: Document, decorators: [{
137
- type: Inject,
138
- args: [DOCUMENT]
58
+ class FsFroalaLoaderService {
59
+ constructor(_defaultConfig, _document) {
60
+ this._defaultConfig = _defaultConfig;
61
+ this._document = _document;
62
+ this._froalaLoaded = new BehaviorSubject(false);
63
+ this._froalaPluginsLoaded = new BehaviorSubject(false);
64
+ this._sourceLoader = fsSourceLoader;
65
+ this._loaded$ = combineLatest([this._froalaLoaded, this._froalaPluginsLoaded])
66
+ .pipe(map(([FroalaReady, pluginsRead]) => {
67
+ return pluginsRead && FroalaReady;
68
+ }), shareReplay(1));
69
+ this._sourceLoader.setDocument(this._document);
70
+ this._load();
71
+ }
72
+ get loaded$() {
73
+ return this._loaded$;
74
+ }
75
+ get FroalaEditor() {
76
+ return this._FroalaEditor;
77
+ }
78
+ _load() {
79
+ const baseDir = '/assets/froala/';
80
+ this._sourceLoader.registerResources({
81
+ froala: [
82
+ `${baseDir}js/froala_editor.min.js`,
83
+ `${baseDir}css/froala_editor.pkgd.min.css`,
84
+ ],
85
+ froala_align: `${baseDir}js/plugins/align.min.js`,
86
+ froala_colors: `${baseDir}js/plugins/colors.min.js`,
87
+ froala_image: `${baseDir}js/plugins/image.min.js`,
88
+ froala_link: `${baseDir}js/plugins/link.min.js`,
89
+ froala_lists: `${baseDir}js/plugins/lists.min.js`,
90
+ froala_paragraph_format: `${baseDir}js/plugins/paragraph_format.min.js`,
91
+ froala_table: `${baseDir}js/plugins/table.min.js`,
92
+ froala_url: `${baseDir}js/plugins/url.min.js`,
93
+ froala_video: `${baseDir}js/plugins/video.min.js`,
94
+ froala_quote: `${baseDir}js/plugins/quote.min.js`,
95
+ froala_draggable: `${baseDir}js/plugins/draggable.min.js`,
96
+ froala_font_size: `${baseDir}js/plugins/font_size.min.js`,
97
+ froala_quick_insert: `${baseDir}js/plugins/quick_insert.min.js`,
98
+ froala_line_height: `${baseDir}js/plugins/line_height.min.js`
99
+ });
100
+ this._sourceLoader.loadResource('froala')
101
+ .pipe(tap(() => {
102
+ this._FroalaEditor = window.FroalaEditor;
103
+ this._froalaDone();
104
+ }), concatMap(() => {
105
+ return this._loadPlugins();
106
+ }), tap(() => {
107
+ this._froalaPluginsDone();
108
+ }))
109
+ .subscribe();
110
+ }
111
+ _loadPlugins() {
112
+ const resources = this._defaultConfig
113
+ .froalaPlugins
114
+ .map((pluginName) => `froala_${pluginName}`);
115
+ return this._sourceLoader.loadResources(resources);
116
+ }
117
+ _froalaDone() {
118
+ this._froalaLoaded.next(true);
119
+ }
120
+ _froalaPluginsDone() {
121
+ this._froalaPluginsLoaded.next(true);
122
+ }
123
+ }
124
+ FsFroalaLoaderService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFroalaLoaderService, deps: [{ token: FS_HTML_EDITOR_CONFIG, optional: true }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Injectable });
125
+ FsFroalaLoaderService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFroalaLoaderService, providedIn: 'root' });
126
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsFroalaLoaderService, decorators: [{
127
+ type: Injectable,
128
+ args: [{
129
+ providedIn: 'root',
130
+ }]
131
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
132
+ type: Optional
133
+ }, {
134
+ type: Inject,
135
+ args: [FS_HTML_EDITOR_CONFIG]
136
+ }] }, { type: Document, decorators: [{
137
+ type: Inject,
138
+ args: [DOCUMENT]
139
139
  }] }]; } });
140
140
 
141
- class FsHtmlRendererComponent {
142
- constructor(sanitized, _cdRef) {
143
- this.sanitized = sanitized;
144
- this._cdRef = _cdRef;
145
- }
146
- set setHtml(html) {
147
- this.trustedHtml = this.sanitized.bypassSecurityTrustHtml(html || '');
148
- this._cdRef.markForCheck();
149
- }
150
- }
151
- FsHtmlRendererComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererComponent, deps: [{ token: i1.DomSanitizer }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
152
- FsHtmlRendererComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FsHtmlRendererComponent, selector: "fs-html-renderer", inputs: { setHtml: ["html", "setHtml"] }, ngImport: i0, template: "<span class=\"fr-view fs-html-editor-default\" [innerHtml]=\"trustedHtml\"></span>\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
153
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererComponent, decorators: [{
154
- type: Component,
155
- args: [{
156
- selector: 'fs-html-renderer',
157
- templateUrl: 'html-renderer.component.html',
158
- styleUrls: ['html-renderer.component.scss'],
159
- changeDetection: ChangeDetectionStrategy.OnPush,
160
- }]
161
- }], ctorParameters: function () { return [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { setHtml: [{
162
- type: Input,
163
- args: ['html']
141
+ class FsHtmlEditorComponent {
142
+ constructor(_defaultConfig, _cdRef, _fr) {
143
+ this._defaultConfig = _defaultConfig;
144
+ this._cdRef = _cdRef;
145
+ this._fr = _fr;
146
+ this.classFocused = false;
147
+ this.classDisabled = false;
148
+ this.config = {};
149
+ this.initialized = false;
150
+ this._initialize$ = new ReplaySubject();
151
+ this._froalaReady$ = new BehaviorSubject(null);
152
+ this._destroy$ = new Subject();
153
+ this.onChange = (data) => { };
154
+ this.onTouched = () => { };
155
+ }
156
+ get el() {
157
+ return this.elRef.nativeElement;
158
+ }
159
+ get html() {
160
+ return this._html;
161
+ }
162
+ get editor() {
163
+ return this._editor;
164
+ }
165
+ get froalaLoaded$() {
166
+ return this._fr.loaded$;
167
+ }
168
+ ngOnInit() {
169
+ this.config = this.config || {};
170
+ this.config.autofocus = this.config.autofocus !== false && !this.config.disabled;
171
+ this._listenLazyInit();
172
+ }
173
+ ngAfterViewInit() {
174
+ this._initialize$.next();
175
+ }
176
+ hasContent() {
177
+ const el = document.createElement('div');
178
+ if (el.querySelector('img')) {
179
+ return true;
180
+ }
181
+ el.innerHTML = this._html;
182
+ return !!el.innerText.length;
183
+ }
184
+ initialize(options = {}) {
185
+ const config = this._createConfig();
186
+ this._initPlugins(config);
187
+ this._initButtons(config);
188
+ this._editor = new this._fr.FroalaEditor(this.el, this._createOptions(), () => {
189
+ this._froalaReady$.next({ config, options });
190
+ });
191
+ }
192
+ _processImageUpload(blob) {
193
+ const processor = new FileProcessor();
194
+ const file = new FsFile(blob);
195
+ const config = {
196
+ orientate: true,
197
+ quality: this.config.image.quality,
198
+ format: this.config.image.format,
199
+ maxWidth: this.config.image.width,
200
+ maxHeight: this.config.image.height,
201
+ minWidth: this.config.image.minWidth,
202
+ minHeight: this.config.image.minHeight,
203
+ };
204
+ return processor.processFile(file, config)
205
+ .pipe(switchMap((fsFile) => {
206
+ return this.config.image.upload(fsFile.file);
207
+ }));
208
+ }
209
+ updateSize() {
210
+ // Hack: To trigger the toolbar button size modes
211
+ window.dispatchEvent(new Event('resize'));
212
+ }
213
+ validate(control) {
214
+ const err = {};
215
+ if (this.config.maxLength && this._html) {
216
+ const maxLength = this.config.maxLength;
217
+ const length = this._html.length;
218
+ if (length > maxLength) {
219
+ err.maxLengthError = `Must be ${maxLength} characters or fewer. You entered ${length} characters.`;
220
+ }
221
+ }
222
+ return Object.keys(err).length ? err : null;
223
+ }
224
+ focus(options) {
225
+ options = options ? options : {};
226
+ if (options.cursorPosition === 'end') {
227
+ this.editor.selection.setAtEnd(this.editor.$el.get(0));
228
+ }
229
+ else {
230
+ this.editor.selection.setAtStart(this.editor.$el.get(0));
231
+ }
232
+ this.editor.selection.restore();
233
+ const elSelection = this.editor.selection.element();
234
+ if (elSelection) {
235
+ elSelection.scrollIntoView({ block: 'center' });
236
+ }
237
+ }
238
+ clear() {
239
+ this.writeValue('');
240
+ }
241
+ disable() {
242
+ this.classDisabled = true;
243
+ }
244
+ setHtml(html) {
245
+ this.writeValue(html);
246
+ }
247
+ writeValue(html) {
248
+ this._html = html || '';
249
+ if (Array.isArray(this._html)) {
250
+ this._html = this._html.pop();
251
+ }
252
+ this._html = this._html
253
+ .replace(/<(li)>\s?<(div)>/g, '<li>')
254
+ .replace(/<\/(div)><\/(li)>/g, '</li>');
255
+ if (this.editor && this.editor.html) {
256
+ try {
257
+ this.editor.html.set(this._html);
258
+ }
259
+ catch (e) {
260
+ }
261
+ }
262
+ this._cdRef.markForCheck();
263
+ }
264
+ registerOnChange(fn) {
265
+ this.onChange = fn;
266
+ }
267
+ registerOnTouched(fn) {
268
+ this.onTouched = fn;
269
+ }
270
+ ngOnDestroy() {
271
+ this._initialize$.complete();
272
+ this._destroy$.next();
273
+ this._destroy$.complete();
274
+ this.destroy();
275
+ }
276
+ destroy() {
277
+ if (this.editor) {
278
+ this.editor.destroy();
279
+ }
280
+ this.initialized = false;
281
+ this._cdRef.markForCheck();
282
+ this.el.innerHTML = '';
283
+ }
284
+ _createConfig() {
285
+ return merge({ froalaConfig: {} }, this._defaultConfig, this.config);
286
+ }
287
+ _change(html) {
288
+ this._html = html;
289
+ this.onChange(html);
290
+ }
291
+ _initButtons(config) {
292
+ (config.buttons || [])
293
+ .forEach((button) => {
294
+ /*
295
+ Svg Keys:
296
+ ["add", "advancedImageEditor", "alignCenter", "alignJustify", "alignLeft", "alignRight",
297
+ "anchors", "back", "backgroundColor", "blockquote", "bold", "cellBackground",
298
+ "cellBorderColor", "cellOptions", "cellStyle", "clearFormatting", "close", "codeView",
299
+ "cogs", "columns", "editLink", "exitFullscreen", "fontAwesome", "fontFamily",
300
+ "fontSize", "fullscreen", "help", "horizontalLine", "imageAltText", "imageCaption",
301
+ "imageClass", "imageDisplay", "imageManager", "imageSize", "indent", "inlineClass",
302
+ "inlineStyle", "insertEmbed", "insertFile", "insertImage", "insertLink", "insertMore",
303
+ "insertTable", "insertVideo", "upload", "italic", "search", "lineHeight", "linkStyles",
304
+ "mention", "more", "openLink", "orderedList", "outdent", "pageBreaker",
305
+ "paragraphFormat", "paragraphMore", "paragraphStyle", "pdfExport", "print",
306
+ "redo", "removeTable", "remove", "replaceImage", "row", "selectAll", "smile",
307
+ "spellcheck", "star", "strikeThrough", "subscript", "superscript", "symbols", "tags",
308
+ "tableHeader", "tableStyle", "textColor", "textMore", "underline", "undo", "unlink",
309
+ "unorderedList", "verticalAlignBottom", "verticalAlignMiddle", "verticalAlignTop"]
310
+ */
311
+ var _a, _b, _c;
312
+ if (button.svgKey) {
313
+ this._fr.FroalaEditor.DefineIcon(button.name, { SVG_KEY: button.svgKey });
314
+ }
315
+ this._fr.FroalaEditor.RegisterCommand(button.name, {
316
+ title: button.title,
317
+ focus: (_a = button.focus) !== null && _a !== void 0 ? _a : true,
318
+ undo: (_b = button.undo) !== null && _b !== void 0 ? _b : true,
319
+ refreshAfterCallback: (_c = button.refreshAfterCallback) !== null && _c !== void 0 ? _c : true,
320
+ callback: function () {
321
+ button.click(this);
322
+ }
323
+ });
324
+ });
325
+ }
326
+ _initPlugins(config) {
327
+ (config.plugins || []).forEach((plugin) => {
328
+ this._fr.FroalaEditor.PLUGINS[plugin.config.name] = function (editor) {
329
+ plugin.editor = editor;
330
+ plugin.initialize();
331
+ return plugin;
332
+ };
333
+ (plugin.config.buttons || []).forEach((button) => {
334
+ this._fr.FroalaEditor.DefineIcon(button.name, {
335
+ NAME: button.name,
336
+ PATH: button.svgPath,
337
+ });
338
+ this._fr.FroalaEditor.RegisterCommand(button.name, {
339
+ icon: button.name,
340
+ title: button.tooltip,
341
+ undo: button.undo,
342
+ focus: button.focus,
343
+ showOnMobile: button.showOnMobile,
344
+ refreshAfterCallback: button.refreshAfterCallback,
345
+ callback: function () {
346
+ if (button.click) {
347
+ button.click(this);
348
+ }
349
+ },
350
+ refresh: function (button) {
351
+ if (button.refresh) {
352
+ button.refresh(this, button);
353
+ }
354
+ }
355
+ });
356
+ });
357
+ });
358
+ }
359
+ _createOptions() {
360
+ var _a, _b;
361
+ const config = this._createConfig();
362
+ return merge(
363
+ // For some reason editor store somewhere pointer on default config object and dublicate options each time on init
364
+ // Extra merge level fixed this problem and allow to init config properly without legacy data
365
+ {}, {
366
+ shortcutsEnabled: ['show', 'bold', 'italic', 'underline', 'indent', 'outdent', 'undo', 'redo', 'insertImage', 'createLink'],
367
+ key: config.activationKey,
368
+ placeholderText: config.placeholder,
369
+ linkAlwaysBlank: true,
370
+ tabSpaces: 2,
371
+ typingTimer: 250,
372
+ tooltips: false,
373
+ wordPasteModal: false,
374
+ imageDefaultWidth: 0,
375
+ imageDefaultAlign: 'left',
376
+ quickInsertEnabled: false,
377
+ paragraphDefaultSelection: 'Format',
378
+ videoUpload: false,
379
+ imagePaste: !!((_a = config.image) === null || _a === void 0 ? void 0 : _a.upload),
380
+ imageUpload: !!((_b = config.image) === null || _b === void 0 ? void 0 : _b.upload),
381
+ paragraphFormat: {
382
+ N: 'Normal',
383
+ H1: 'Heading 1',
384
+ H2: 'Heading 2',
385
+ H3: 'Heading 3',
386
+ H4: 'Heading 4',
387
+ BLOCKQUOTE: 'Quote',
388
+ },
389
+ lineHeights: {
390
+ Default: '',
391
+ '0.5': '0.5',
392
+ 'Single': '1',
393
+ '1.15': '1.15',
394
+ '1.5': '1.5',
395
+ 'Double': '2'
396
+ },
397
+ paragraphFormatSelection: true,
398
+ toolbarButtonsXS: {
399
+ moreText: {
400
+ buttons: TextButtons,
401
+ buttonsVisible: 1,
402
+ },
403
+ moreParagraph: {
404
+ buttons: ParagraphButtons,
405
+ buttonsVisible: 2,
406
+ },
407
+ moreRich: {
408
+ buttons: RichButtons,
409
+ buttonsVisible: 0,
410
+ },
411
+ },
412
+ toolbarButtons: {
413
+ moreText: {
414
+ buttons: TextButtons,
415
+ buttonsVisible: 3,
416
+ },
417
+ moreParagraph: {
418
+ buttons: ParagraphButtons,
419
+ buttonsVisible: 5,
420
+ },
421
+ moreRich: {
422
+ buttons: RichButtons,
423
+ buttonsVisible: 3,
424
+ },
425
+ },
426
+ }, config.froalaConfig);
427
+ }
428
+ _listenLazyInit() {
429
+ this.froalaLoaded$
430
+ .pipe(filter((ready) => ready), switchMap(() => this._initialize$), tap(() => {
431
+ const selection = window.getSelection();
432
+ const options = {};
433
+ if (selection.baseNode) {
434
+ options.selection = {
435
+ node: selection.baseNode.nodeValue,
436
+ offset: selection.baseOffset,
437
+ };
438
+ }
439
+ this.initialize(options);
440
+ }), switchMap(() => this._froalaReady$), filter((data) => !!data), tap(({ config, options }) => {
441
+ this._setupFroala(config, options);
442
+ }))
443
+ .subscribe();
444
+ }
445
+ _contentChanged() {
446
+ const editorHTML = this._editor.html.get();
447
+ if (this.html !== editorHTML) {
448
+ this._change(editorHTML);
449
+ }
450
+ }
451
+ _setupFroala(config, options) {
452
+ this._cdRef.markForCheck();
453
+ this.setHtml(this._html);
454
+ if (config.disabled) {
455
+ this.disable();
456
+ }
457
+ if (config.froalaConfig.events) {
458
+ if (config.froalaConfig.events.initialized) {
459
+ config.froalaConfig.events.initialized();
460
+ }
461
+ }
462
+ this._editor.events.on('focus', () => {
463
+ this.classFocused = true;
464
+ this._cdRef.markForCheck();
465
+ });
466
+ this._editor.events.on('blur', () => {
467
+ this.classFocused = false;
468
+ this._cdRef.markForCheck();
469
+ });
470
+ this._editor.events.on('click', () => {
471
+ if (this.config.initOnClick && !this.initialized) {
472
+ this.initialized = true;
473
+ this._cdRef.markForCheck();
474
+ }
475
+ });
476
+ fromEventPattern((handler) => {
477
+ this._editor.events.on('contentChanged', handler);
478
+ }, () => { })
479
+ .pipe(startWith(this._html), map(() => this.editor.html.get()), distinctUntilChanged(), skip(1))
480
+ .subscribe(() => {
481
+ this._contentChanged();
482
+ });
483
+ this._editor.events.on('paste.afterCleanup', (html) => {
484
+ var div = document.createElement('div');
485
+ div.innerHTML = html;
486
+ div.querySelectorAll('*')
487
+ .forEach((el) => {
488
+ for (var i = 0; i < el.attributes.length; i++) {
489
+ const name = el.attributes[0].name;
490
+ if (name !== 'href') {
491
+ el.removeAttribute(name);
492
+ }
493
+ }
494
+ });
495
+ return div.innerHTML;
496
+ });
497
+ this._editor.events.on('keydown', () => {
498
+ this.onTouched();
499
+ });
500
+ if (this.config.image && this.config.image.upload) {
501
+ this._editor.events.on('image.beforePasteUpload', (image) => {
502
+ fetch(image.getAttribute('src'))
503
+ .then((res) => {
504
+ res.blob()
505
+ .then((blob) => {
506
+ this._processImageUpload(blob)
507
+ .pipe(takeUntil(this._destroy$))
508
+ .subscribe((url) => {
509
+ image.setAttribute('src', url);
510
+ image.removeAttribute('data-fr-image-pasted');
511
+ this._contentChanged();
512
+ });
513
+ });
514
+ });
515
+ return false;
516
+ });
517
+ this._editor.events.on('image.beforeUpload', (blobs) => {
518
+ this._processImageUpload(blobs[0])
519
+ .pipe(takeUntil(this._destroy$))
520
+ .subscribe((url) => {
521
+ this.editor.image.insert(url, null, null, this.editor.image.get());
522
+ });
523
+ return false;
524
+ });
525
+ }
526
+ if (this.el.querySelector('.fr-second-toolbar')) {
527
+ this.el.querySelector('.fr-second-toolbar').remove();
528
+ }
529
+ if (this.config.autofocus && !this.config.initOnClick) {
530
+ this.focus();
531
+ }
532
+ }
533
+ }
534
+ FsHtmlEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorComponent, deps: [{ token: FS_HTML_EDITOR_CONFIG, optional: true }, { token: i0.ChangeDetectorRef }, { token: FsFroalaLoaderService }], target: i0.ɵɵFactoryTarget.Component });
535
+ FsHtmlEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FsHtmlEditorComponent, selector: "fs-html-editor", inputs: { config: "config", hint: "hint" }, host: { properties: { "class.focused": "this.classFocused", "class.disabled": "this.classDisabled" } }, providers: [
536
+ {
537
+ provide: NG_VALUE_ACCESSOR,
538
+ useExisting: forwardRef(() => FsHtmlEditorComponent),
539
+ multi: true
540
+ },
541
+ {
542
+ provide: NG_VALIDATORS,
543
+ useExisting: forwardRef(() => FsHtmlEditorComponent),
544
+ multi: true
545
+ },
546
+ ], viewQueries: [{ propertyName: "elRef", first: true, predicate: ["elRef"], descendants: true }], ngImport: i0, template: "<fs-label-field>\n <fs-label *ngIf=\"config.label\">{{config.label}}</fs-label>\n <div \n class=\"html-editor-container fs-html-editor-default\" \n [ngClass]=\"{ \n initialized: initialized,\n 'init-on-click': config.initOnClick\n }\"> \n <ng-container *fsSkeleton=\"(froalaLoaded$ | async) !== false\"></ng-container> \n <div #elRef></div>\n \n <div class=\"bottom-line\"></div>\n <div class=\"disabled-line\"></div>\n </div>\n \n <fs-label-message>\n <div class=\"fs-form-message\">\n <div class=\"fs-form-hint\">{{hint}}</div>\n </div>\n </fs-label-message>\n</fs-label-field>\n", styles: [":host ::ng-deep .fr-box.fr-basic .fr-wrapper{border:0;border-bottom:1px solid #949494;margin-bottom:1px;background-color:transparent}:host ::ng-deep .fr-box.fr-basic .fr-element{padding:0;font-family:inherit;color:inherit;font-size:inherit;line-height:inherit;min-height:auto}:host ::ng-deep .fr-more-toolbar,:host ::ng-deep .fr-toolbar,:host ::ng-deep .fr-dropdown:after,:host ::ng-deep .fr-dropdown-menu .fr-dropdown-wrapper{transition:none!important}:host ::ng-deep .fr-toolbar-open .fr-more-toolbar{display:block}:host ::ng-deep .fr-more-toolbar{display:none}:host ::ng-deep .fr-toolbar.fr-top{position:sticky;z-index:2;border-radius:0;background-color:#fff}:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp{margin:0 20px 0 0}:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp:nth-child(1):after,:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp:nth-child(2):after{content:\"\";position:absolute;top:9px;height:30px;border-left:1px solid #e5e5e5;margin-left:10px}:host ::ng-deep .fr-toolbar.fr-top div:first-of-type:before{border:none}:host ::ng-deep .fr-toolbar.fr-top.fr-toolbar-open .fr-newline{height:auto}:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp:first-child{margin-left:0}:host ::ng-deep .fr-toolbar.fr-top.fr-top{border:0}:host ::ng-deep .fr-toolbar.fr-top .fr-newline{margin:0}:host ::ng-deep .fr-toolbar.fr-top .fr-more-toolbar{z-index:auto;display:flex;justify-content:center;padding-left:0!important}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn{z-index:auto}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn.fr-dropdown:after{right:3px}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn.fr-dropdown.fr-selection span{margin-right:24px}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn.fr-open{border-radius:4px;margin:4px 2px}:host ::ng-deep .fr-view ol,:host ::ng-deep .fr-view ul{list-style-position:unset}:host ::ng-deep .html-editor-container.init-on-click:not(.initialized) .fr-toolbar{display:none}:host.disabled ::ng-deep .fr-box.fr-basic{opacity:.5;pointer-events:none}:host.disabled ::ng-deep .fr-box.fr-basic .fr-wrapper{border:none}:host.disabled ::ng-deep .disabled-line{display:block}::ng-deep .fr-popup{z-index:1001!important;transform:translate(-180px)}::ng-deep .fr-video-by-url-layer .fr-checkbox-line{display:none}.disabled-line{display:none;position:absolute;bottom:-1px;z-index:1;background-image:linear-gradient(90deg,rgba(0,0,0,.42) 0,rgba(0,0,0,.42) 33%,transparent 0);background-size:4px 100%;background-repeat:repeat-x;height:1px;width:100%}.bottom-line{opacity:0;transform-origin:50%;transform:scaleX(.5);transition:background-color .3s cubic-bezier(.55,0,.55,.2);width:100%;border-bottom:2px solid #949494;position:absolute;bottom:-1px;z-index:1}:host{position:relative;display:block}:host.focused .bottom-line{opacity:1;display:block;transform:scaleX(1);transition:transform .3s cubic-bezier(.25,.8,.25,1),opacity .1s cubic-bezier(.25,.8,.25,1),background-color .3s cubic-bezier(.25,.8,.25,1)}::ng-deep .fs-html-editor-mention-container{position:absolute;top:0;left:0;height:auto;max-height:300px;max-width:500px;overflow:auto;display:block;z-index:999999;box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f;border-bottom-left-radius:4px;border-bottom-right-radius:4px;background:#fff}::ng-deep .fs-html-editor-mention-container ul{margin:0;padding:0;list-style:none}::ng-deep .fs-html-editor-mention-container li{padding:0 16px;cursor:pointer;line-height:48px}::ng-deep .fs-html-editor-mention-container li.highlight,::ng-deep .fs-html-editor-mention-container li:hover{background:#F5F5F5}::ng-deep .fs-html-editor-mention-container li.no-match{cursor:default}\n"], components: [{ type: i2.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["bottomMargin", "topMargin", "labelMargin"] }, { type: i2.FsLabelComponent, selector: "fs-label" }, { type: i2.FsLabelMessageComponent, selector: "fs-label-message" }], directives: [{ type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i4.FsSkeletonContentDirective, selector: "[fsSkeleton]", inputs: ["fsSkeleton", "fsSkeletonPattern"] }], pipes: { "async": i3.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
547
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorComponent, decorators: [{
548
+ type: Component,
549
+ args: [{
550
+ selector: 'fs-html-editor',
551
+ templateUrl: 'html-editor.component.html',
552
+ styleUrls: ['html-editor.component.scss'],
553
+ providers: [
554
+ {
555
+ provide: NG_VALUE_ACCESSOR,
556
+ useExisting: forwardRef(() => FsHtmlEditorComponent),
557
+ multi: true
558
+ },
559
+ {
560
+ provide: NG_VALIDATORS,
561
+ useExisting: forwardRef(() => FsHtmlEditorComponent),
562
+ multi: true
563
+ },
564
+ ],
565
+ changeDetection: ChangeDetectionStrategy.OnPush,
566
+ }]
567
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
568
+ type: Optional
569
+ }, {
570
+ type: Inject,
571
+ args: [FS_HTML_EDITOR_CONFIG]
572
+ }] }, { type: i0.ChangeDetectorRef }, { type: FsFroalaLoaderService }]; }, propDecorators: { classFocused: [{
573
+ type: HostBinding,
574
+ args: ['class.focused']
575
+ }], classDisabled: [{
576
+ type: HostBinding,
577
+ args: ['class.disabled']
578
+ }], elRef: [{
579
+ type: ViewChild,
580
+ args: ['elRef']
581
+ }], config: [{
582
+ type: Input
583
+ }], hint: [{
584
+ type: Input
164
585
  }] } });
165
586
 
166
- class FsHtmlEditorComponent {
167
- constructor(_defaultConfig, _cdRef, _fr) {
168
- this._defaultConfig = _defaultConfig;
169
- this._cdRef = _cdRef;
170
- this._fr = _fr;
171
- this.classFocused = false;
172
- this.classDisabled = false;
173
- this.config = {};
174
- this.initialized = false;
175
- this._initialize$ = new ReplaySubject();
176
- this._froalaReady$ = new BehaviorSubject(null);
177
- this._destroy$ = new Subject();
178
- this.onChange = (data) => { };
179
- this.onTouched = () => { };
180
- }
181
- get el() {
182
- return this.elRef.nativeElement;
183
- }
184
- get html() {
185
- return this._html;
186
- }
187
- get editor() {
188
- return this._editor;
189
- }
190
- get froalaLoaded$() {
191
- return this._fr.loaded$;
192
- }
193
- ngOnInit() {
194
- this.config = this.config || {};
195
- this.config.autofocus = this.config.autofocus !== false && !this.config.disabled;
196
- this.initialized = !this.config.initOnClick;
197
- this._listenLazyInit();
198
- }
199
- ngAfterViewInit() {
200
- if (!this.config.initOnClick || !this.hasContent()) {
201
- this.initialized = true;
202
- this._initialize$.next();
203
- }
204
- }
205
- hasContent() {
206
- const el = document.createElement('div');
207
- if (el.querySelector('img')) {
208
- return true;
209
- }
210
- el.innerHTML = this._html;
211
- return !!el.innerText.length;
212
- }
213
- initialize(options = {}) {
214
- const config = this._createConfig();
215
- this._initPlugins(config);
216
- this._initButtons(config);
217
- this._editor = new this._fr.FroalaEditor(this.el, this._createOptions(), () => {
218
- this._froalaReady$.next({ config, options });
219
- });
220
- }
221
- _processImageUpload(blob) {
222
- const processor = new FileProcessor();
223
- const file = new FsFile(blob);
224
- const config = {
225
- orientate: true,
226
- quality: this.config.image.quality,
227
- format: this.config.image.format,
228
- maxWidth: this.config.image.width,
229
- maxHeight: this.config.image.height,
230
- minWidth: this.config.image.minWidth,
231
- minHeight: this.config.image.minHeight,
232
- };
233
- return processor.processFile(file, config)
234
- .pipe(switchMap((fsFile) => {
235
- return this.config.image.upload(fsFile.file);
236
- }));
237
- }
238
- uninitializedClick(event) {
239
- if (!event.defaultPrevented) {
240
- const target = event.target;
241
- if (target && target.nodeName === 'A' && target.getAttribute('href')) {
242
- const targetTarget = target.getAttribute('target');
243
- target.setAttribute('target', '_blank');
244
- setTimeout(() => {
245
- if (targetTarget) {
246
- target.setAttribute('target', targetTarget);
247
- }
248
- else {
249
- target.removeAttribute('target');
250
- }
251
- });
252
- }
253
- else {
254
- if (this.config.initClick) {
255
- this.config.initClick(event);
256
- }
257
- this._initialize$.next();
258
- this.initialized = true;
259
- }
260
- }
261
- }
262
- updateSize() {
263
- // Hack: To trigger the toolbar button size modes
264
- window.dispatchEvent(new Event('resize'));
265
- }
266
- validate(control) {
267
- const err = {};
268
- if (this.config.maxLength && this._html) {
269
- const maxLength = this.config.maxLength;
270
- const length = this._html.length;
271
- if (length > maxLength) {
272
- err.maxLengthError = `Must be ${maxLength} characters or fewer. You entered ${length} characters.`;
273
- }
274
- }
275
- return Object.keys(err).length ? err : null;
276
- }
277
- focus(options) {
278
- options = options ? options : {};
279
- if (options.cursorPosition === 'end') {
280
- this.editor.selection.setAtEnd(this.editor.$el.get(0));
281
- }
282
- else {
283
- this.editor.selection.setAtStart(this.editor.$el.get(0));
284
- }
285
- this.editor.selection.restore();
286
- const elSelection = this.editor.selection.element();
287
- if (elSelection) {
288
- elSelection.scrollIntoView({ block: 'center' });
289
- }
290
- }
291
- clear() {
292
- this.writeValue('');
293
- }
294
- disable() {
295
- this.classDisabled = true;
296
- }
297
- setHtml(html) {
298
- this.writeValue(html);
299
- }
300
- writeValue(html) {
301
- this._html = html || '';
302
- if (Array.isArray(this._html)) {
303
- this._html = this._html.pop();
304
- }
305
- this._html = this._html
306
- .replace(/<(li)>\s?<(div)>/g, '<li>')
307
- .replace(/<\/(div)><\/(li)>/g, '</li>');
308
- if (this.editor && this.editor.html) {
309
- try {
310
- this.editor.html.set(this._html);
311
- }
312
- catch (e) {
313
- }
314
- }
315
- this._cdRef.markForCheck();
316
- }
317
- registerOnChange(fn) {
318
- this.onChange = fn;
319
- }
320
- registerOnTouched(fn) {
321
- this.onTouched = fn;
322
- }
323
- ngOnDestroy() {
324
- this._initialize$.complete();
325
- this._destroy$.next();
326
- this._destroy$.complete();
327
- this.destroy();
328
- }
329
- destroy() {
330
- if (this.editor) {
331
- this.editor.destroy();
332
- }
333
- this.initialized = false;
334
- this._cdRef.markForCheck();
335
- this.el.innerHTML = '';
336
- }
337
- _createConfig() {
338
- return merge({ froalaConfig: {} }, this._defaultConfig, this.config);
339
- }
340
- _change(html) {
341
- this._html = html;
342
- this.onChange(html);
343
- }
344
- _initButtons(config) {
345
- (config.buttons || [])
346
- .forEach((button) => {
347
- /*
348
- Svg Keys:
349
- ["add", "advancedImageEditor", "alignCenter", "alignJustify", "alignLeft", "alignRight",
350
- "anchors", "back", "backgroundColor", "blockquote", "bold", "cellBackground",
351
- "cellBorderColor", "cellOptions", "cellStyle", "clearFormatting", "close", "codeView",
352
- "cogs", "columns", "editLink", "exitFullscreen", "fontAwesome", "fontFamily",
353
- "fontSize", "fullscreen", "help", "horizontalLine", "imageAltText", "imageCaption",
354
- "imageClass", "imageDisplay", "imageManager", "imageSize", "indent", "inlineClass",
355
- "inlineStyle", "insertEmbed", "insertFile", "insertImage", "insertLink", "insertMore",
356
- "insertTable", "insertVideo", "upload", "italic", "search", "lineHeight", "linkStyles",
357
- "mention", "more", "openLink", "orderedList", "outdent", "pageBreaker",
358
- "paragraphFormat", "paragraphMore", "paragraphStyle", "pdfExport", "print",
359
- "redo", "removeTable", "remove", "replaceImage", "row", "selectAll", "smile",
360
- "spellcheck", "star", "strikeThrough", "subscript", "superscript", "symbols", "tags",
361
- "tableHeader", "tableStyle", "textColor", "textMore", "underline", "undo", "unlink",
362
- "unorderedList", "verticalAlignBottom", "verticalAlignMiddle", "verticalAlignTop"]
363
- */
364
- var _a, _b, _c;
365
- if (button.svgKey) {
366
- this._fr.FroalaEditor.DefineIcon(button.name, { SVG_KEY: button.svgKey });
367
- }
368
- this._fr.FroalaEditor.RegisterCommand(button.name, {
369
- title: button.title,
370
- focus: (_a = button.focus) !== null && _a !== void 0 ? _a : true,
371
- undo: (_b = button.undo) !== null && _b !== void 0 ? _b : true,
372
- refreshAfterCallback: (_c = button.refreshAfterCallback) !== null && _c !== void 0 ? _c : true,
373
- callback: function () {
374
- button.click(this);
375
- }
376
- });
377
- });
378
- }
379
- _initPlugins(config) {
380
- (config.plugins || []).forEach((plugin) => {
381
- this._fr.FroalaEditor.PLUGINS[plugin.config.name] = function (editor) {
382
- plugin.editor = editor;
383
- plugin.initialize();
384
- return plugin;
385
- };
386
- (plugin.config.buttons || []).forEach((button) => {
387
- this._fr.FroalaEditor.DefineIcon(button.name, {
388
- NAME: button.name,
389
- PATH: button.svgPath,
390
- });
391
- this._fr.FroalaEditor.RegisterCommand(button.name, {
392
- icon: button.name,
393
- title: button.tooltip,
394
- undo: button.undo,
395
- focus: button.focus,
396
- showOnMobile: button.showOnMobile,
397
- refreshAfterCallback: button.refreshAfterCallback,
398
- callback: function () {
399
- if (button.click) {
400
- button.click(this);
401
- }
402
- },
403
- refresh: function (button) {
404
- if (button.refresh) {
405
- button.refresh(this, button);
406
- }
407
- }
408
- });
409
- });
410
- });
411
- }
412
- _createOptions() {
413
- var _a, _b;
414
- const config = this._createConfig();
415
- return merge(
416
- // For some reason editor store somewhere pointer on default config object and dublicate options each time on init
417
- // Extra merge level fixed this problem and allow to init config properly without legacy data
418
- {}, {
419
- shortcutsEnabled: ['show', 'bold', 'italic', 'underline', 'indent', 'outdent', 'undo', 'redo', 'insertImage', 'createLink'],
420
- key: config.activationKey,
421
- placeholderText: config.placeholder,
422
- linkAlwaysBlank: true,
423
- tabSpaces: 2,
424
- typingTimer: 250,
425
- tooltips: false,
426
- wordPasteModal: false,
427
- imageDefaultWidth: 0,
428
- imageDefaultAlign: 'left',
429
- quickInsertEnabled: false,
430
- paragraphDefaultSelection: 'Format',
431
- videoUpload: false,
432
- imagePaste: !!((_a = config.image) === null || _a === void 0 ? void 0 : _a.upload),
433
- imageUpload: !!((_b = config.image) === null || _b === void 0 ? void 0 : _b.upload),
434
- paragraphFormat: {
435
- N: 'Normal',
436
- H1: 'Heading 1',
437
- H2: 'Heading 2',
438
- H3: 'Heading 3',
439
- H4: 'Heading 4',
440
- BLOCKQUOTE: 'Quote',
441
- },
442
- lineHeights: {
443
- Default: '',
444
- '0.5': '0.5',
445
- 'Single': '1',
446
- '1.15': '1.15',
447
- '1.5': '1.5',
448
- 'Double': '2'
449
- },
450
- paragraphFormatSelection: true,
451
- toolbarButtonsXS: {
452
- moreText: {
453
- buttons: TextButtons,
454
- buttonsVisible: 1,
455
- },
456
- moreParagraph: {
457
- buttons: ParagraphButtons,
458
- buttonsVisible: 2,
459
- },
460
- moreRich: {
461
- buttons: RichButtons,
462
- buttonsVisible: 0,
463
- },
464
- },
465
- toolbarButtons: {
466
- moreText: {
467
- buttons: TextButtons,
468
- buttonsVisible: 3,
469
- },
470
- moreParagraph: {
471
- buttons: ParagraphButtons,
472
- buttonsVisible: 5,
473
- },
474
- moreRich: {
475
- buttons: RichButtons,
476
- buttonsVisible: 3,
477
- },
478
- },
479
- }, config.froalaConfig);
480
- }
481
- _listenLazyInit() {
482
- this.froalaLoaded$
483
- .pipe(filter((ready) => ready), switchMap(() => this._initialize$), tap(() => {
484
- const selection = window.getSelection();
485
- const options = {};
486
- if (selection.baseNode) {
487
- options.selection = {
488
- node: selection.baseNode.nodeValue,
489
- offset: selection.baseOffset,
490
- };
491
- }
492
- this.initialize(options);
493
- }), switchMap(() => this._froalaReady$), filter((data) => !!data), tap(({ config, options }) => {
494
- this._setupFroala(config, options);
495
- }))
496
- .subscribe();
497
- }
498
- _contentChanged() {
499
- const editorHTML = this._editor.html.get();
500
- if (this.html !== editorHTML) {
501
- this._change(editorHTML);
502
- }
503
- }
504
- _setupFroala(config, options) {
505
- this._cdRef.markForCheck();
506
- this.setHtml(this._html);
507
- if (config.disabled) {
508
- this.disable();
509
- }
510
- if (config.froalaConfig.events) {
511
- if (config.froalaConfig.events.initialized) {
512
- config.froalaConfig.events.initialized();
513
- }
514
- }
515
- this._editor.events.on('focus', () => {
516
- this.classFocused = true;
517
- this._cdRef.markForCheck();
518
- });
519
- this._editor.events.on('blur', () => {
520
- this.classFocused = false;
521
- this._cdRef.markForCheck();
522
- });
523
- fromEventPattern((handler) => {
524
- this._editor.events.on('contentChanged', handler);
525
- }, () => { })
526
- .pipe(startWith(this._html), map(() => this.editor.html.get()), distinctUntilChanged(), skip(1))
527
- .subscribe(() => {
528
- this._contentChanged();
529
- });
530
- this._editor.events.on('paste.afterCleanup', (html) => {
531
- var div = document.createElement('div');
532
- div.innerHTML = html;
533
- div.querySelectorAll('*')
534
- .forEach((el) => {
535
- for (var i = 0; i < el.attributes.length; i++) {
536
- const name = el.attributes[0].name;
537
- if (name !== 'href') {
538
- el.removeAttribute(name);
539
- }
540
- }
541
- });
542
- return div.innerHTML;
543
- });
544
- this._editor.events.on('keydown', () => {
545
- this.onTouched();
546
- });
547
- if (this.config.image && this.config.image.upload) {
548
- this._editor.events.on('image.beforePasteUpload', (image) => {
549
- fetch(image.getAttribute('src'))
550
- .then((res) => {
551
- res.blob()
552
- .then((blob) => {
553
- this._processImageUpload(blob)
554
- .pipe(takeUntil(this._destroy$))
555
- .subscribe((url) => {
556
- image.setAttribute('src', url);
557
- image.removeAttribute('data-fr-image-pasted');
558
- this._contentChanged();
559
- });
560
- });
561
- });
562
- return false;
563
- });
564
- this._editor.events.on('image.beforeUpload', (blobs) => {
565
- this._processImageUpload(blobs[0])
566
- .pipe(takeUntil(this._destroy$))
567
- .subscribe((url) => {
568
- this.editor.image.insert(url, null, null, this.editor.image.get());
569
- });
570
- return false;
571
- });
572
- }
573
- if (this.el.querySelector('.fr-second-toolbar')) {
574
- this.el.querySelector('.fr-second-toolbar').remove();
575
- }
576
- const selection = options.selection;
577
- if (selection) {
578
- const node = Array.from(this.el.querySelectorAll('.fr-element *')).find((node) => {
579
- return selection.node === node.textContent;
580
- });
581
- if (node) {
582
- const range = document.createRange();
583
- const sel = window.getSelection();
584
- range.setStart(this._getTextNode(node), selection.offset);
585
- range.collapse(true);
586
- sel.removeAllRanges();
587
- sel.addRange(range);
588
- }
589
- else if (this.config.autofocus) {
590
- this.focus();
591
- }
592
- }
593
- else if (this.config.autofocus) {
594
- this.focus();
595
- }
596
- }
597
- _getTextNode(node) {
598
- if (node) {
599
- if (node.nodeType === Node.TEXT_NODE) {
600
- return node;
601
- }
602
- if (node.childNodes) {
603
- return this._getTextNode(node.childNodes[0]);
604
- }
605
- }
606
- }
607
- }
608
- FsHtmlEditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorComponent, deps: [{ token: FS_HTML_EDITOR_CONFIG, optional: true }, { token: i0.ChangeDetectorRef }, { token: FsFroalaLoaderService }], target: i0.ɵɵFactoryTarget.Component });
609
- FsHtmlEditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FsHtmlEditorComponent, selector: "fs-html-editor", inputs: { config: "config", hint: "hint" }, host: { properties: { "class.focused": "this.classFocused", "class.disabled": "this.classDisabled" } }, providers: [
610
- {
611
- provide: NG_VALUE_ACCESSOR,
612
- useExisting: forwardRef(() => FsHtmlEditorComponent),
613
- multi: true
614
- },
615
- {
616
- provide: NG_VALIDATORS,
617
- useExisting: forwardRef(() => FsHtmlEditorComponent),
618
- multi: true
619
- },
620
- ], viewQueries: [{ propertyName: "elRef", first: true, predicate: ["elRef"], descendants: true }], ngImport: i0, template: "<fs-label-field>\n <fs-label *ngIf=\"config.label\">{{config.label}}</fs-label>\n <div class=\"fs-html-editor-default\">\n <ng-container *ngIf=\"initialized\">\n <ng-container *fsSkeleton=\"(froalaLoaded$ | async) !== false\">\n </ng-container>\n </ng-container>\n \n <div #elRef></div>\n \n <div class=\"bottom-line\"></div>\n <div class=\"disabled-line\"></div>\n <fs-html-renderer\n *ngIf=\"!initialized\"\n [html]=\"html\"\n (click)=\"uninitializedClick($event)\">\n </fs-html-renderer>\n </div>\n \n <fs-label-message>\n <div class=\"fs-form-message\">\n <div class=\"fs-form-hint\">{{hint}}</div>\n </div>\n </fs-label-message>\n</fs-label-field>\n", styles: [":host ::ng-deep .fr-box.fr-basic .fr-wrapper{border:0;border-bottom:1px solid #949494;margin-bottom:1px;background-color:transparent}:host ::ng-deep .fr-box.fr-basic .fr-element{padding:0;font-family:inherit;color:inherit;font-size:inherit;line-height:inherit;min-height:auto}:host ::ng-deep .fr-more-toolbar,:host ::ng-deep .fr-toolbar,:host ::ng-deep .fr-dropdown:after,:host ::ng-deep .fr-dropdown-menu .fr-dropdown-wrapper{transition:none!important}:host ::ng-deep .fr-toolbar-open .fr-more-toolbar{display:block}:host ::ng-deep .fr-more-toolbar{display:none}:host ::ng-deep .fr-toolbar.fr-top{position:sticky;z-index:2;border-radius:0;background-color:#fff}:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp{margin:0 20px 0 0}:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp:nth-child(1):after,:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp:nth-child(2):after{content:\"\";position:absolute;top:9px;height:30px;border-left:1px solid #e5e5e5;margin-left:10px}:host ::ng-deep .fr-toolbar.fr-top div:first-of-type:before{border:none}:host ::ng-deep .fr-toolbar.fr-top.fr-toolbar-open .fr-newline{height:auto}:host ::ng-deep .fr-toolbar.fr-top .fr-btn-grp:first-child{margin-left:0}:host ::ng-deep .fr-toolbar.fr-top.fr-top{border:0}:host ::ng-deep .fr-toolbar.fr-top .fr-newline{margin:0}:host ::ng-deep .fr-toolbar.fr-top .fr-more-toolbar{z-index:auto;display:flex;justify-content:center;padding-left:0!important}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn{z-index:auto}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn.fr-dropdown:after{right:3px}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn.fr-dropdown.fr-selection span{margin-right:24px}:host ::ng-deep .fr-toolbar.fr-top .fr-command.fr-btn.fr-open{border-radius:4px;margin:4px 2px}:host ::ng-deep .fr-view ol,:host ::ng-deep .fr-view ul{list-style-position:unset}:host.disabled ::ng-deep .fr-box.fr-basic{opacity:.5;pointer-events:none}:host.disabled ::ng-deep .fr-box.fr-basic .fr-wrapper{border:none}:host.disabled ::ng-deep .disabled-line{display:block}::ng-deep .fr-popup{z-index:1001!important;transform:translate(-180px)}::ng-deep .fr-video-by-url-layer .fr-checkbox-line{display:none}.disabled-line{display:none;position:absolute;bottom:-1px;z-index:1;background-image:linear-gradient(90deg,rgba(0,0,0,.42) 0,rgba(0,0,0,.42) 33%,transparent 0);background-size:4px 100%;background-repeat:repeat-x;height:1px;width:100%}.bottom-line{opacity:0;transform-origin:50%;transform:scaleX(.5);transition:background-color .3s cubic-bezier(.55,0,.55,.2);width:100%;border-bottom:2px solid #949494;position:absolute;bottom:-1px;z-index:1}:host{position:relative;display:block}:host.focused .bottom-line{opacity:1;display:block;transform:scaleX(1);transition:transform .3s cubic-bezier(.25,.8,.25,1),opacity .1s cubic-bezier(.25,.8,.25,1),background-color .3s cubic-bezier(.25,.8,.25,1)}::ng-deep .fs-html-editor-mention-container{position:absolute;top:0;left:0;height:auto;max-height:300px;max-width:500px;overflow:auto;display:block;z-index:999999;box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f;border-bottom-left-radius:4px;border-bottom-right-radius:4px;background:#fff}::ng-deep .fs-html-editor-mention-container ul{margin:0;padding:0;list-style:none}::ng-deep .fs-html-editor-mention-container li{padding:0 16px;cursor:pointer;line-height:48px}::ng-deep .fs-html-editor-mention-container li.highlight,::ng-deep .fs-html-editor-mention-container li:hover{background:#F5F5F5}::ng-deep .fs-html-editor-mention-container li.no-match{cursor:default}\n"], components: [{ type: i2.FsLabelFieldComponent, selector: "fs-label-field", inputs: ["bottomMargin", "topMargin", "labelMargin"] }, { type: i2.FsLabelComponent, selector: "fs-label" }, { type: FsHtmlRendererComponent, selector: "fs-html-renderer", inputs: ["html"] }, { type: i2.FsLabelMessageComponent, selector: "fs-label-message" }], directives: [{ type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.FsSkeletonContentDirective, selector: "[fsSkeleton]", inputs: ["fsSkeleton", "fsSkeletonPattern"] }], pipes: { "async": i4.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush });
621
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorComponent, decorators: [{
622
- type: Component,
623
- args: [{
624
- selector: 'fs-html-editor',
625
- templateUrl: 'html-editor.component.html',
626
- styleUrls: ['html-editor.component.scss'],
627
- providers: [
628
- {
629
- provide: NG_VALUE_ACCESSOR,
630
- useExisting: forwardRef(() => FsHtmlEditorComponent),
631
- multi: true
632
- },
633
- {
634
- provide: NG_VALIDATORS,
635
- useExisting: forwardRef(() => FsHtmlEditorComponent),
636
- multi: true
637
- },
638
- ],
639
- changeDetection: ChangeDetectionStrategy.OnPush,
640
- }]
641
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
642
- type: Optional
643
- }, {
644
- type: Inject,
645
- args: [FS_HTML_EDITOR_CONFIG]
646
- }] }, { type: i0.ChangeDetectorRef }, { type: FsFroalaLoaderService }]; }, propDecorators: { classFocused: [{
647
- type: HostBinding,
648
- args: ['class.focused']
649
- }], classDisabled: [{
650
- type: HostBinding,
651
- args: ['class.disabled']
652
- }], elRef: [{
653
- type: ViewChild,
654
- args: ['elRef']
655
- }], config: [{
656
- type: Input
657
- }], hint: [{
658
- type: Input
587
+ class FsHtmlRendererComponent {
588
+ constructor(sanitized, _cdRef) {
589
+ this.sanitized = sanitized;
590
+ this._cdRef = _cdRef;
591
+ }
592
+ set setHtml(html) {
593
+ this.trustedHtml = this.sanitized.bypassSecurityTrustHtml(html || '');
594
+ this._cdRef.markForCheck();
595
+ }
596
+ }
597
+ FsHtmlRendererComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererComponent, deps: [{ token: i1.DomSanitizer }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
598
+ FsHtmlRendererComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.16", type: FsHtmlRendererComponent, selector: "fs-html-renderer", inputs: { setHtml: ["html", "setHtml"] }, ngImport: i0, template: "<span class=\"fr-view fs-html-editor-default\" [innerHtml]=\"trustedHtml\"></span>\n", styles: [""], changeDetection: i0.ChangeDetectionStrategy.OnPush });
599
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererComponent, decorators: [{
600
+ type: Component,
601
+ args: [{
602
+ selector: 'fs-html-renderer',
603
+ templateUrl: 'html-renderer.component.html',
604
+ styleUrls: ['html-renderer.component.scss'],
605
+ changeDetection: ChangeDetectionStrategy.OnPush,
606
+ }]
607
+ }], ctorParameters: function () { return [{ type: i1.DomSanitizer }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { setHtml: [{
608
+ type: Input,
609
+ args: ['html']
659
610
  }] } });
660
611
 
661
- class FsHtmlRendererModule {
662
- }
663
- FsHtmlRendererModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
664
- FsHtmlRendererModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, declarations: [FsHtmlRendererComponent], imports: [CommonModule], exports: [FsHtmlRendererComponent] });
665
- FsHtmlRendererModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, imports: [[
666
- CommonModule,
667
- ]] });
668
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, decorators: [{
669
- type: NgModule,
670
- args: [{
671
- imports: [
672
- CommonModule,
673
- ],
674
- exports: [
675
- FsHtmlRendererComponent,
676
- ],
677
- declarations: [
678
- FsHtmlRendererComponent,
679
- ],
680
- }]
612
+ class FsHtmlRendererModule {
613
+ }
614
+ FsHtmlRendererModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
615
+ FsHtmlRendererModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, declarations: [FsHtmlRendererComponent], imports: [CommonModule], exports: [FsHtmlRendererComponent] });
616
+ FsHtmlRendererModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, imports: [[
617
+ CommonModule,
618
+ ]] });
619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlRendererModule, decorators: [{
620
+ type: NgModule,
621
+ args: [{
622
+ imports: [
623
+ CommonModule,
624
+ ],
625
+ exports: [
626
+ FsHtmlRendererComponent,
627
+ ],
628
+ declarations: [
629
+ FsHtmlRendererComponent,
630
+ ],
631
+ }]
681
632
  }] });
682
633
 
683
- class FsHtmlEditorModule {
684
- static forRoot(config = {}) {
685
- return {
686
- ngModule: FsHtmlEditorModule,
687
- providers: [
688
- { provide: FS_HTML_EDITOR_DEFAULT_CONFIG, useValue: config },
689
- {
690
- provide: FS_HTML_EDITOR_CONFIG,
691
- useFactory: FsHtmlEditorConfigFactory,
692
- deps: [FS_HTML_EDITOR_DEFAULT_CONFIG]
693
- }
694
- ]
695
- };
696
- }
697
- }
698
- FsHtmlEditorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
699
- FsHtmlEditorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, declarations: [FsHtmlEditorComponent], imports: [CommonModule,
700
- FsSkeletonModule,
701
- FsLabelModule,
702
- FsHtmlRendererModule], exports: [FsHtmlEditorComponent] });
703
- FsHtmlEditorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, imports: [[
704
- CommonModule,
705
- FsSkeletonModule,
706
- FsLabelModule,
707
- FsHtmlRendererModule,
708
- ]] });
709
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, decorators: [{
710
- type: NgModule,
711
- args: [{
712
- imports: [
713
- CommonModule,
714
- FsSkeletonModule,
715
- FsLabelModule,
716
- FsHtmlRendererModule,
717
- ],
718
- exports: [
719
- FsHtmlEditorComponent,
720
- ],
721
- declarations: [
722
- FsHtmlEditorComponent,
723
- ],
724
- }]
725
- }] });
726
- function FsHtmlEditorConfigFactory(config) {
727
- return Object.assign({ froalaPlugins: [
728
- "align" /* Align */,
729
- "colors" /* Colors */,
730
- "image" /* Image */,
731
- "link" /* Link */,
732
- "lists" /* Lists */,
733
- "paragraph_format" /* ParagraphFormat */,
734
- "quote" /* Quote */,
735
- "table" /* Table */,
736
- "url" /* Url */,
737
- "video" /* Video */,
738
- "draggable" /* Draggable */,
739
- "font_size" /* FontSize */,
740
- "line_height" /* LineHeight */,
741
- ] }, config);
634
+ class FsHtmlEditorModule {
635
+ static forRoot(config = {}) {
636
+ return {
637
+ ngModule: FsHtmlEditorModule,
638
+ providers: [
639
+ { provide: FS_HTML_EDITOR_DEFAULT_CONFIG, useValue: config },
640
+ {
641
+ provide: FS_HTML_EDITOR_CONFIG,
642
+ useFactory: FsHtmlEditorConfigFactory,
643
+ deps: [FS_HTML_EDITOR_DEFAULT_CONFIG]
644
+ }
645
+ ]
646
+ };
647
+ }
648
+ }
649
+ FsHtmlEditorModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
650
+ FsHtmlEditorModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, declarations: [FsHtmlEditorComponent], imports: [CommonModule,
651
+ FsSkeletonModule,
652
+ FsLabelModule,
653
+ FsHtmlRendererModule], exports: [FsHtmlEditorComponent] });
654
+ FsHtmlEditorModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, imports: [[
655
+ CommonModule,
656
+ FsSkeletonModule,
657
+ FsLabelModule,
658
+ FsHtmlRendererModule,
659
+ ]] });
660
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.16", ngImport: i0, type: FsHtmlEditorModule, decorators: [{
661
+ type: NgModule,
662
+ args: [{
663
+ imports: [
664
+ CommonModule,
665
+ FsSkeletonModule,
666
+ FsLabelModule,
667
+ FsHtmlRendererModule,
668
+ ],
669
+ exports: [
670
+ FsHtmlEditorComponent,
671
+ ],
672
+ declarations: [
673
+ FsHtmlEditorComponent,
674
+ ],
675
+ }]
676
+ }] });
677
+ function FsHtmlEditorConfigFactory(config) {
678
+ return Object.assign({ froalaPlugins: [
679
+ "align" /* Align */,
680
+ "colors" /* Colors */,
681
+ "image" /* Image */,
682
+ "link" /* Link */,
683
+ "lists" /* Lists */,
684
+ "paragraph_format" /* ParagraphFormat */,
685
+ "quote" /* Quote */,
686
+ "table" /* Table */,
687
+ "url" /* Url */,
688
+ "video" /* Video */,
689
+ "draggable" /* Draggable */,
690
+ "font_size" /* FontSize */,
691
+ "line_height" /* LineHeight */,
692
+ ] }, config);
742
693
  }
743
694
 
744
- class Plugin {
745
- initialize() { }
746
- destroy() { }
695
+ class Plugin {
696
+ initialize() { }
697
+ destroy() { }
747
698
  }
748
699
 
749
- class MentionPlugin extends Plugin {
750
- constructor(config) {
751
- super();
752
- this.config = config;
753
- this._guid = guid();
754
- this.selected = (event) => {
755
- if (this.config.selected) {
756
- if (MentionPlugin._currentGuid === this._guid) {
757
- this.config.selected(event.detail.item.original);
758
- }
759
- }
760
- };
761
- this.config = Object.assign(Object.assign({}, config), { buttons: [
762
- {
763
- name: config.name,
764
- tooltip: config.tooltip,
765
- svgPath: config.iconPath,
766
- click: (editor) => {
767
- this._closeAll();
768
- this._tribute.showMenuForCollection(editor.el);
769
- }
770
- }
771
- ] });
772
- this._tribute = new Tribute({
773
- values: debounce(this._loadValues.bind(this), 200),
774
- searchOpts: {
775
- pre: '',
776
- post: '',
777
- skip: true
778
- },
779
- containerClass: `fs-html-editor-mention-container ${this.config.containerClass || ''}`,
780
- itemClass: `fs-html-editor-mention-menu-item ${this.config.menuItemClass || ''}`,
781
- trigger: this.config.trigger,
782
- allowSpaces: true,
783
- menuItemTemplate: (item) => {
784
- return this.config.menuItemTemplate(item.original);
785
- },
786
- selectTemplate: (item) => {
787
- const template = this.config.selectedTemplate(item.original);
788
- let p = document.createElement('p');
789
- p.innerHTML = template;
790
- let node = p.firstElementChild;
791
- if (!node) {
792
- node = document.createElement('span');
793
- node.innerHTML = template;
794
- }
795
- node.setAttribute('contenteditable', 'false');
796
- node.classList.add('fr-deletable');
797
- return node.outerHTML;
798
- },
799
- });
800
- MentionPlugin._tributes.push(this._tribute);
801
- }
802
- initialize() {
803
- this._tribute.attach(this.editor.el);
804
- this.editor.events.on('keydown', (e) => {
805
- if (e.key === 'Enter' && this._tribute.isActive) {
806
- return false;
807
- }
808
- }, true);
809
- this.editor.el.addEventListener("tribute-replaced", this.selected);
810
- }
811
- destroy() {
812
- this.editor.el.removeEventListener("tribute-replaced", this.selected);
813
- }
814
- _closeAll() {
815
- MentionPlugin._tributes.forEach((tribute) => {
816
- if (tribute.menu) {
817
- tribute.hideMenu();
818
- }
819
- });
820
- }
821
- _loadValues(keyword, cb) {
822
- MentionPlugin._currentGuid = this._guid;
823
- return this.config.fetch(keyword)
824
- .subscribe((data) => {
825
- cb(data);
826
- });
827
- }
828
- }
829
- MentionPlugin._currentGuid = null;
700
+ class MentionPlugin extends Plugin {
701
+ constructor(config) {
702
+ super();
703
+ this.config = config;
704
+ this._guid = guid();
705
+ this.selected = (event) => {
706
+ if (this.config.selected) {
707
+ if (MentionPlugin._currentGuid === this._guid) {
708
+ this.config.selected(event.detail.item.original);
709
+ }
710
+ }
711
+ };
712
+ this.config = Object.assign(Object.assign({}, config), { buttons: [
713
+ {
714
+ name: config.name,
715
+ tooltip: config.tooltip,
716
+ svgPath: config.iconPath,
717
+ click: (editor) => {
718
+ this._closeAll();
719
+ this._tribute.showMenuForCollection(editor.el);
720
+ }
721
+ }
722
+ ] });
723
+ this._tribute = new Tribute({
724
+ values: debounce(this._loadValues.bind(this), 200),
725
+ searchOpts: {
726
+ pre: '',
727
+ post: '',
728
+ skip: true
729
+ },
730
+ containerClass: `fs-html-editor-mention-container ${this.config.containerClass || ''}`,
731
+ itemClass: `fs-html-editor-mention-menu-item ${this.config.menuItemClass || ''}`,
732
+ trigger: this.config.trigger,
733
+ allowSpaces: true,
734
+ menuItemTemplate: (item) => {
735
+ return this.config.menuItemTemplate(item.original);
736
+ },
737
+ selectTemplate: (item) => {
738
+ const template = this.config.selectedTemplate(item.original);
739
+ let p = document.createElement('p');
740
+ p.innerHTML = template;
741
+ let node = p.firstElementChild;
742
+ if (!node) {
743
+ node = document.createElement('span');
744
+ node.innerHTML = template;
745
+ }
746
+ node.setAttribute('contenteditable', 'false');
747
+ node.classList.add('fr-deletable');
748
+ return node.outerHTML;
749
+ },
750
+ });
751
+ MentionPlugin._tributes.push(this._tribute);
752
+ }
753
+ initialize() {
754
+ this._tribute.attach(this.editor.el);
755
+ this.editor.events.on('keydown', (e) => {
756
+ if (e.key === 'Enter' && this._tribute.isActive) {
757
+ return false;
758
+ }
759
+ }, true);
760
+ this.editor.el.addEventListener("tribute-replaced", this.selected);
761
+ }
762
+ destroy() {
763
+ this.editor.el.removeEventListener("tribute-replaced", this.selected);
764
+ }
765
+ _closeAll() {
766
+ MentionPlugin._tributes.forEach((tribute) => {
767
+ if (tribute.menu) {
768
+ tribute.hideMenu();
769
+ }
770
+ });
771
+ }
772
+ _loadValues(keyword, cb) {
773
+ MentionPlugin._currentGuid = this._guid;
774
+ return this.config.fetch(keyword)
775
+ .subscribe((data) => {
776
+ cb(data);
777
+ });
778
+ }
779
+ }
780
+ MentionPlugin._currentGuid = null;
830
781
  MentionPlugin._tributes = [];
831
782
 
832
- class ChecklistPlugin extends Plugin {
833
- constructor(config = { name: 'checklist' }) {
834
- super();
835
- this.config = config;
836
- this.config = Object.assign(Object.assign({}, config), { name: 'checklist', buttons: [
837
- {
838
- name: 'checklist',
839
- svgPath: 'M8.4,10.3l-1.2,1.2l4,4L20,6.7l-1.2-1.2l-7.6,7.6L8.4,10.3z M18.2,18.2H5.8V5.8h8.9V4H5.8C4.8,4,4,4.8,4,5.8v12.4c0,1,0.8,1.8,1.8,1.8h12.4c1,0,1.8-0.8,1.8-1.8v-7.1h-1.8V18.2z',
840
- click: (editor) => {
841
- editor.html.insert('<ul class="checklist"><li></li></ul>');
842
- }
843
- }
844
- ] });
845
- }
846
- initialize() {
847
- this.editor.events.on('click', (e) => {
848
- const li = e.target;
849
- if (li.nodeName === 'LI' && e.offsetX < 0) {
850
- const items = [li, ...li.querySelectorAll('li')];
851
- if (li.classList.contains('checked')) {
852
- items.forEach((item) => {
853
- item.classList.remove('checked');
854
- });
855
- }
856
- else {
857
- items.forEach((item) => {
858
- item.classList.add('checked');
859
- });
860
- }
861
- }
862
- }, false);
863
- }
783
+ class ChecklistPlugin extends Plugin {
784
+ constructor(config = { name: 'checklist' }) {
785
+ super();
786
+ this.config = config;
787
+ this.config = Object.assign(Object.assign({}, config), { name: 'checklist', buttons: [
788
+ {
789
+ name: 'checklist',
790
+ svgPath: 'M8.4,10.3l-1.2,1.2l4,4L20,6.7l-1.2-1.2l-7.6,7.6L8.4,10.3z M18.2,18.2H5.8V5.8h8.9V4H5.8C4.8,4,4,4.8,4,5.8v12.4c0,1,0.8,1.8,1.8,1.8h12.4c1,0,1.8-0.8,1.8-1.8v-7.1h-1.8V18.2z',
791
+ click: (editor) => {
792
+ editor.html.insert('<ul class="checklist"><li></li></ul>');
793
+ }
794
+ }
795
+ ] });
796
+ }
797
+ initialize() {
798
+ this.editor.events.on('click', (e) => {
799
+ const li = e.target;
800
+ if (li.nodeName === 'LI' && e.offsetX < 0) {
801
+ const items = [li, ...li.querySelectorAll('li')];
802
+ if (li.classList.contains('checked')) {
803
+ items.forEach((item) => {
804
+ item.classList.remove('checked');
805
+ });
806
+ }
807
+ else {
808
+ items.forEach((item) => {
809
+ item.classList.add('checked');
810
+ });
811
+ }
812
+ }
813
+ }, false);
814
+ }
864
815
  }
865
816
 
866
- class CodePlugin extends Plugin {
867
- constructor(config = { name: 'code' }) {
868
- super();
869
- this.config = config;
870
- this.config = Object.assign(Object.assign({}, config), { name: 'code', buttons: [
871
- {
872
- name: 'code',
873
- svgPath: 'M8.9,7.3L4.2,12l4.7,4.7l1.1-1.1L6.4,12L10,8.4L8.9,7.3z M15.1,7.3L14,8.4l3.6,3.6L14,15.6l1.1,1.1l4.7-4.7L15.1,7.3z',
874
- click: (editor) => {
875
- const node = editor.selection.get();
876
- const codeEl = this._getCodeEl(node.baseNode);
877
- if (codeEl) {
878
- codeEl.classList.remove('code');
879
- }
880
- else {
881
- editor.html.insert('<p class="code">' + editor.selection.get().toString().replace(/\n{1,}/g, '<br>') + '</p>');
882
- }
883
- }
884
- }
885
- ] });
886
- }
887
- initialize() {
888
- this.editor.events.on('keydown', (e) => {
889
- if (e.keyCode === 13) {
890
- const selection = this.editor.selection.get();
891
- if (selection && this._getCodeEl(selection.baseNode)) {
892
- e.preventDefault();
893
- e.stopPropagation();
894
- e.stopImmediatePropagation();
895
- let br = '<br>';
896
- const base = selection.baseNode;
897
- if (base.nodeName === '#text' && selection.baseOffset === base.length) {
898
- if (!(base.nextSibling && base.nextSibling.nodeName === 'BR')) {
899
- br += '<br>';
900
- }
901
- }
902
- else {
903
- const el = Array.from(base.childNodes).splice(selection.baseOffset - 1, 1).pop();
904
- if (el && el.nodeName !== 'BR') {
905
- br += '<br>';
906
- }
907
- }
908
- this.editor.html.insert(br);
909
- return false;
910
- }
911
- }
912
- }, true);
913
- }
914
- destroy() { }
915
- _getCodeEl(el) {
916
- if (el) {
917
- if (el.classList && el.classList.contains('code')) {
918
- return el;
919
- }
920
- if (el.parentElement) {
921
- return this._getCodeEl(el.parentElement);
922
- }
923
- }
924
- return null;
925
- }
817
+ class CodePlugin extends Plugin {
818
+ constructor(config = { name: 'code' }) {
819
+ super();
820
+ this.config = config;
821
+ this.config = Object.assign(Object.assign({}, config), { name: 'code', buttons: [
822
+ {
823
+ name: 'code',
824
+ svgPath: 'M8.9,7.3L4.2,12l4.7,4.7l1.1-1.1L6.4,12L10,8.4L8.9,7.3z M15.1,7.3L14,8.4l3.6,3.6L14,15.6l1.1,1.1l4.7-4.7L15.1,7.3z',
825
+ click: (editor) => {
826
+ const node = editor.selection.get();
827
+ const codeEl = this._getCodeEl(node.baseNode);
828
+ if (codeEl) {
829
+ codeEl.classList.remove('code');
830
+ }
831
+ else {
832
+ editor.html.insert('<p class="code">' + editor.selection.get().toString().replace(/\n{1,}/g, '<br>') + '</p>');
833
+ }
834
+ }
835
+ }
836
+ ] });
837
+ }
838
+ initialize() {
839
+ this.editor.events.on('keydown', (e) => {
840
+ if (e.keyCode === 13) {
841
+ const selection = this.editor.selection.get();
842
+ if (selection && this._getCodeEl(selection.baseNode)) {
843
+ e.preventDefault();
844
+ e.stopPropagation();
845
+ e.stopImmediatePropagation();
846
+ let br = '<br>';
847
+ const base = selection.baseNode;
848
+ if (base.nodeName === '#text' && selection.baseOffset === base.length) {
849
+ if (!(base.nextSibling && base.nextSibling.nodeName === 'BR')) {
850
+ br += '<br>';
851
+ }
852
+ }
853
+ else {
854
+ const el = Array.from(base.childNodes).splice(selection.baseOffset - 1, 1).pop();
855
+ if (el && el.nodeName !== 'BR') {
856
+ br += '<br>';
857
+ }
858
+ }
859
+ this.editor.html.insert(br);
860
+ return false;
861
+ }
862
+ }
863
+ }, true);
864
+ }
865
+ destroy() { }
866
+ _getCodeEl(el) {
867
+ if (el) {
868
+ if (el.classList && el.classList.contains('code')) {
869
+ return el;
870
+ }
871
+ if (el.parentElement) {
872
+ return this._getCodeEl(el.parentElement);
873
+ }
874
+ }
875
+ return null;
876
+ }
926
877
  }
927
878
 
928
- class ScreenRecordPlugin extends Plugin {
929
- constructor(config = {}) {
930
- super();
931
- this.config = config;
932
- this.config = Object.assign(Object.assign({}, config), { name: config.name || 'screenRecord', buttons: [
933
- {
934
- name: 'screenRecord',
879
+ class ScreenRecordPlugin extends Plugin {
880
+ constructor(config = {}) {
881
+ super();
882
+ this.config = config;
883
+ this.config = Object.assign(Object.assign({}, config), { name: config.name || 'screenRecord', buttons: [
884
+ {
885
+ name: 'screenRecord',
935
886
  svgPath: `M14.7,7.7v6.1H7.1V7.7H14.7 M16.3,9.6V6.9c0-0.4-0.3-0.8-0.8-0.8H6.4c-0.4,0-0.8,0.3-0.8,0.8v7.6c0,0.4,0.3,0.8,0.8,0.8h9.1c0.4,0,0.8-0.3,0.8-0.8v-2.7l1.7,1.7c0.3,0.3,0.8,0.3,1.1,0c0.1-0.1,0.2-0.3,0.2-0.5V8.4c0-0.4-0.3-0.8-0.8-0.8
936
887
  c-0.2,0-0.4,0.1-0.5,0.2L16.3,9.6z M21.5,1.6H2.9c-0.7,0-1.3,0.7-1.3,1.6v14.6c0,0.9,0.6,1.6,1.3,1.6h7.6v1.1l-5,1c-0.2,0-0.4,0.3-0.4,0.6c0,0.3,0.2,0.4,0.4,0.4c0,0,0,0,0.1,0l5.3-1h2.6l5.3,1c0,0,0,0,0.1,0c0.2,0,0.4-0.2,0.4-0.4
937
- c0-0.3-0.1-0.6-0.4-0.6l-5-1v-1.1h7.6c0.7,0,1.3-0.7,1.3-1.6V3.2C22.9,2.3,22.3,1.6,21.5,1.6z M21.1,17.3H3.3V3.7h17.8L21.1,17.3L21.1,17.3z`,
938
- tooltip: 'Screen Record',
939
- click: (editor) => {
940
- navigator.mediaDevices.getDisplayMedia({ video: true })
941
- .then((stream) => {
942
- const chunks = [];
943
- const options = { mimeType: 'video/webm; codecs=vp9' };
944
- let mediaRecorder = new MediaRecorder(stream, options);
945
- stream.addEventListener('inactive', (e) => {
946
- mediaRecorder.stop();
947
- mediaRecorder = null;
948
- stream.getTracks().forEach((track) => track.stop());
949
- stream = null;
950
- const blob = new Blob(chunks, { type: 'video/webm' });
951
- config.upload(blob)
952
- .subscribe((url) => {
953
- editor.html.insert(`<span class="fr-screen-record fr-deletable fr-draggable"><video controls style="max-width:${config.maxWidth}"><source src="${url}" type="video/webm"></video></span>`);
954
- });
955
- });
956
- mediaRecorder.addEventListener('dataavailable', (event) => {
957
- if (event.data && event.data.size > 0) {
958
- chunks.push(event.data);
959
- }
960
- });
961
- mediaRecorder.start(10);
962
- })
963
- .catch((e) => { });
964
- }
965
- }
966
- ] });
967
- }
968
- initialize() {
969
- return __awaiter(this, void 0, void 0, function* () {
970
- const FroalaEditor = window.FroalaEditor;
971
- this.editor.events.on('mouseup', (e) => {
972
- const el = this._getEl(e.target);
973
- if (el) {
974
- this.editor.popups.hideAll();
975
- this._activeEl = el;
976
- this._showPopup(el);
977
- }
978
- });
979
- FroalaEditor.POPUP_TEMPLATES["screenRecordPlugin.popup"] = '[_BUTTONS_]';
980
- FroalaEditor.DefineIcon('popupClose', { NAME: 'trash', SVG_KEY: 'remove' });
981
- FroalaEditor.RegisterCommand('popupClose', {
982
- title: 'Remove',
983
- undo: false,
984
- focus: false,
985
- callback: () => {
986
- if (this._activeEl) {
987
- this._activeEl.remove();
988
- }
989
- }
990
- });
991
- });
992
- }
993
- _createPopup() {
994
- const template = {
995
- buttons: `<div class="fr-buttons">${this.editor.button.buildList(['popupClose'])}</div>`,
996
- };
997
- return this.editor.popups.create('screenRecordPlugin.popup', template);
998
- }
999
- _showPopup(el) {
1000
- var $popup = this.editor.popups.get('screenRecordPlugin.popup');
1001
- if (!$popup) {
1002
- $popup = this._createPopup();
1003
- }
1004
- this.editor.popups.setContainer('screenRecordPlugin.popup', this.editor.$(el));
1005
- const left = el.offsetLeft + el.offsetWidth / 2;
1006
- this.editor.popups.show('screenRecordPlugin.popup', left, null);
1007
- }
1008
- _getEl(el) {
1009
- if (el && el.classList) {
1010
- if (el.classList.contains('fr-screen-record'))
1011
- return el;
1012
- return this._getEl(el.parentNode);
1013
- }
1014
- }
888
+ c0-0.3-0.1-0.6-0.4-0.6l-5-1v-1.1h7.6c0.7,0,1.3-0.7,1.3-1.6V3.2C22.9,2.3,22.3,1.6,21.5,1.6z M21.1,17.3H3.3V3.7h17.8L21.1,17.3L21.1,17.3z`,
889
+ tooltip: 'Screen Record',
890
+ click: (editor) => {
891
+ navigator.mediaDevices.getDisplayMedia({ video: true })
892
+ .then((stream) => {
893
+ const chunks = [];
894
+ const options = { mimeType: 'video/webm; codecs=vp9' };
895
+ let mediaRecorder = new MediaRecorder(stream, options);
896
+ stream.addEventListener('inactive', (e) => {
897
+ mediaRecorder.stop();
898
+ mediaRecorder = null;
899
+ stream.getTracks().forEach((track) => track.stop());
900
+ stream = null;
901
+ const blob = new Blob(chunks, { type: 'video/webm' });
902
+ config.upload(blob)
903
+ .subscribe((url) => {
904
+ editor.html.insert(`<span class="fr-screen-record fr-deletable fr-draggable"><video controls style="max-width:${config.maxWidth}"><source src="${url}" type="video/webm"></video></span>`);
905
+ });
906
+ });
907
+ mediaRecorder.addEventListener('dataavailable', (event) => {
908
+ if (event.data && event.data.size > 0) {
909
+ chunks.push(event.data);
910
+ }
911
+ });
912
+ mediaRecorder.start(10);
913
+ })
914
+ .catch((e) => { });
915
+ }
916
+ }
917
+ ] });
918
+ }
919
+ initialize() {
920
+ return __awaiter(this, void 0, void 0, function* () {
921
+ const FroalaEditor = window.FroalaEditor;
922
+ this.editor.events.on('mouseup', (e) => {
923
+ const el = this._getEl(e.target);
924
+ if (el) {
925
+ this.editor.popups.hideAll();
926
+ this._activeEl = el;
927
+ this._showPopup(el);
928
+ }
929
+ });
930
+ FroalaEditor.POPUP_TEMPLATES["screenRecordPlugin.popup"] = '[_BUTTONS_]';
931
+ FroalaEditor.DefineIcon('popupClose', { NAME: 'trash', SVG_KEY: 'remove' });
932
+ FroalaEditor.RegisterCommand('popupClose', {
933
+ title: 'Remove',
934
+ undo: false,
935
+ focus: false,
936
+ callback: () => {
937
+ if (this._activeEl) {
938
+ this._activeEl.remove();
939
+ }
940
+ }
941
+ });
942
+ });
943
+ }
944
+ _createPopup() {
945
+ const template = {
946
+ buttons: `<div class="fr-buttons">${this.editor.button.buildList(['popupClose'])}</div>`,
947
+ };
948
+ return this.editor.popups.create('screenRecordPlugin.popup', template);
949
+ }
950
+ _showPopup(el) {
951
+ var $popup = this.editor.popups.get('screenRecordPlugin.popup');
952
+ if (!$popup) {
953
+ $popup = this._createPopup();
954
+ }
955
+ this.editor.popups.setContainer('screenRecordPlugin.popup', this.editor.$(el));
956
+ const left = el.offsetLeft + el.offsetWidth / 2;
957
+ this.editor.popups.show('screenRecordPlugin.popup', left, null);
958
+ }
959
+ _getEl(el) {
960
+ if (el && el.classList) {
961
+ if (el.classList.contains('fr-screen-record'))
962
+ return el;
963
+ return this._getEl(el.parentNode);
964
+ }
965
+ }
1015
966
  }
1016
967
 
1017
- class RealtimePlugin extends Plugin {
1018
- constructor(config = { name: 'realtime' }) {
1019
- super();
1020
- this.config = config;
1021
- this.config = Object.assign(Object.assign({}, config), { name: 'realtime' });
1022
- }
1023
- initialize() {
1024
- this.editor.events.on('click', (e) => {
1025
- }, false);
1026
- }
968
+ class RealtimePlugin extends Plugin {
969
+ constructor(config = { name: 'realtime' }) {
970
+ super();
971
+ this.config = config;
972
+ this.config = Object.assign(Object.assign({}, config), { name: 'realtime' });
973
+ }
974
+ initialize() {
975
+ this.editor.events.on('click', (e) => {
976
+ }, false);
977
+ }
1027
978
  }
1028
979
 
1029
- /**
1030
- * Generated bundle index. Do not edit.
980
+ /**
981
+ * Generated bundle index. Do not edit.
1031
982
  */
1032
983
 
1033
984
  export { ChecklistPlugin, CodePlugin, FS_HTML_EDITOR_CONFIG, FsHtmlEditorComponent, FsHtmlEditorModule, FsHtmlRendererComponent, FsHtmlRendererModule, MentionPlugin, ParagraphButtons, RealtimePlugin, RichButtons, ScreenRecordPlugin, TextButtons };