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