@firestitch/html-editor 12.0.2 → 12.0.3

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