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