@firestitch/html-editor 9.4.2 → 9.5.0

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