@firestitch/html-editor 9.5.6 → 9.5.9

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