@firestitch/html-editor 13.0.2 → 13.1.0

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