@firestitch/html-editor 9.4.5 → 9.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +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 -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 +1003 -994
  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 -423
  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 +56 -56
  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 +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 +456 -446
  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 +61 -61
  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 +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 +924 -916
  60. package/fesm2015/firestitch-html-editor.js.map +1 -1
  61. package/fesm5/firestitch-html-editor.js +1003 -993
  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,957 +3,965 @@ 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
- font_size: 'plugins/font_size.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
- }
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
+ }
129
130
  const ResourceLoader = resourceLoaderFactory();
130
131
 
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])
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._ready$ = 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 ready$() {
152
+ return this._ready$;
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])
201
202
  ], FsFroalaLoaderService);
202
203
 
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
- .subscribe((url) => {
303
- image.setAttribute('src', url);
304
- image.removeAttribute('data-fr-image-pasted');
305
- });
306
- });
307
- });
308
- return false;
309
- });
310
- this._editor.events.on('image.beforeUpload', (blobs) => {
311
- this._processImageUpload(blobs[0]).subscribe((url) => {
312
- this.editor.image.insert(url, null, null, this.editor.image.get());
313
- });
314
- return false;
315
- });
316
- }
317
- if (this.el.querySelector('.fr-second-toolbar')) {
318
- this.el.querySelector('.fr-second-toolbar').remove();
319
- }
320
- const selection = options.selection;
321
- if (selection) {
322
- const node = Array.from(this.el.querySelectorAll('.fr-element *')).find((node) => {
323
- return selection.node === node.textContent;
324
- });
325
- if (node) {
326
- const range = document.createRange();
327
- const sel = window.getSelection();
328
- range.setStart(this._getTextNode(node), selection.offset);
329
- range.collapse(true);
330
- sel.removeAllRanges();
331
- sel.addRange(range);
332
- }
333
- else if (this.config.autofocus) {
334
- this.focus();
335
- }
336
- }
337
- else if (this.config.autofocus) {
338
- this.focus();
339
- }
340
- });
341
- }
342
- _processImageUpload(blob) {
343
- return this.config.image.upload(blob)
344
- .pipe(takeUntil(this._destroy$));
345
- }
346
- _getTextNode(node) {
347
- if (node) {
348
- if (node.nodeType === Node.TEXT_NODE) {
349
- return node;
350
- }
351
- if (node.childNodes) {
352
- return this._getTextNode(node.childNodes[0]);
353
- }
354
- }
355
- }
356
- uninitializedClick(event) {
357
- if (!event.defaultPrevented) {
358
- const target = event.target;
359
- if (target && target.nodeName === 'A' && target.getAttribute('href')) {
360
- const targetTarget = target.getAttribute('target');
361
- target.setAttribute('target', '_blank');
362
- setTimeout(() => {
363
- if (targetTarget) {
364
- target.setAttribute('target', targetTarget);
365
- }
366
- else {
367
- target.removeAttribute('target');
368
- }
369
- });
370
- }
371
- else {
372
- if (this.config.initClick) {
373
- this.config.initClick(event);
374
- }
375
- this._initialize$.next();
376
- this.initialized = true;
377
- }
378
- }
379
- }
380
- updateSize() {
381
- // Hack: To trigger the toolbar button size modes
382
- window.dispatchEvent(new Event('resize'));
383
- }
384
- validate(control) {
385
- const err = {};
386
- if (this.config.maxLength && this._html) {
387
- const maxLength = this.config.maxLength;
388
- const length = this._html.length;
389
- if (length > maxLength) {
390
- err.maxLengthError = `Must be ${maxLength} characters or fewer. You entered ${length} characters.`;
391
- }
392
- }
393
- return Object.keys(err).length ? err : null;
394
- }
395
- focus(options) {
396
- options = options ? options : {};
397
- if (options.cursorPosition === 'end') {
398
- this.editor.selection.setAtEnd(this.editor.$el.get(0));
399
- }
400
- else {
401
- this.editor.selection.setAtStart(this.editor.$el.get(0));
402
- }
403
- this.editor.selection.restore();
404
- const elSelection = this.editor.selection.element();
405
- if (elSelection) {
406
- elSelection.scrollIntoView({ block: 'center' });
407
- }
408
- }
409
- clear() {
410
- this.writeValue('');
411
- }
412
- disable() {
413
- this.classDisabled = true;
414
- }
415
- setHtml(html) {
416
- this.writeValue(html);
417
- }
418
- writeValue(html) {
419
- this._html = html || '';
420
- this._cdRef.markForCheck();
421
- // SP-T2298 timeout needed for the case, when froala was already initated and
422
- // second instance opened in dialog/drawer. In this case init step pass much faster, writeValue trigger
423
- // after init and froala ignore new html. At the same time froala was initied but editor not yet, and next
424
- // code doesn't work without timeout. We've got time range when too late for initiate value, and to early
425
- // for change event.
426
- setTimeout(() => {
427
- if (this.editor && this.editor.html) {
428
- try {
429
- this.editor.html.set(this._html);
430
- }
431
- catch (e) {
432
- }
433
- }
434
- });
435
- }
436
- registerOnChange(fn) {
437
- this.onChange = fn;
438
- }
439
- registerOnTouched(fn) {
440
- this.onTouched = fn;
441
- }
442
- ngOnDestroy() {
443
- this._initialize$.complete();
444
- this._destroy$.next();
445
- this._destroy$.complete();
446
- this.destroy();
447
- }
448
- destroy() {
449
- if (this.editor) {
450
- this.editor.destroy();
451
- }
452
- this.initialized = false;
453
- this._cdRef.markForCheck();
454
- this.el.innerHTML = '';
455
- }
456
- _createConfig() {
457
- return merge({ froalaConfig: {} }, this._defaultConfig, this.config);
458
- }
459
- _change(html) {
460
- this._html = html;
461
- this.onChange(html);
462
- }
463
- _initPlugins(config) {
464
- (config.plugins || []).forEach((plugin) => {
465
- this._fr.FroalaEditor.PLUGINS[plugin.config.name] = function (editor) {
466
- plugin.editor = editor;
467
- plugin.initialize();
468
- return plugin;
469
- };
470
- (plugin.config.buttons || []).forEach((button) => {
471
- this._fr.FroalaEditor.DefineIcon(button.name, {
472
- NAME: button.name,
473
- PATH: button.svgPath,
474
- });
475
- this._fr.FroalaEditor.RegisterCommand(button.name, {
476
- icon: button.name,
477
- title: button.tooltip,
478
- undo: button.undo,
479
- focus: button.focus,
480
- showOnMobile: button.showOnMobile,
481
- refreshAfterCallback: button.refreshAfterCallback,
482
- callback: function () {
483
- if (button.click) {
484
- button.click(this);
485
- }
486
- },
487
- refresh: function (button) {
488
- if (button.refresh) {
489
- button.refresh(this, button);
490
- }
491
- }
492
- });
493
- });
494
- });
495
- }
496
- _createOptions() {
497
- const config = this._createConfig();
498
- return merge(
499
- // For some reason editor store somewhere pointer on default config object and dublicate options each time on init
500
- // Extra merge level fixed this problem and allow to init config properly without legacy data
501
- {}, {
502
- key: config.activationKey,
503
- placeholderText: config.placeholder,
504
- linkAlwaysBlank: true,
505
- tabSpaces: 2,
506
- typingTimer: 250,
507
- tooltips: false,
508
- wordPasteModal: false,
509
- imageDefaultWidth: 0,
510
- imageDefaultAlign: 'left',
511
- quickInsertEnabled: false,
512
- paragraphDefaultSelection: 'Format',
513
- videoUpload: false,
514
- paragraphFormat: {
515
- N: 'Normal',
516
- H1: 'Heading 1',
517
- H2: 'Heading 2',
518
- H3: 'Heading 3',
519
- H4: 'Heading 4',
520
- BLOCKQUOTE: 'Quote',
521
- },
522
- paragraphFormatSelection: true,
523
- toolbarButtonsXS: {
524
- moreText: {
525
- buttons: TextButtons,
526
- buttonsVisible: 1,
527
- },
528
- moreParagraph: {
529
- buttons: ParagraphButtons,
530
- buttonsVisible: 2,
531
- },
532
- moreRich: {
533
- buttons: RichButtons,
534
- buttonsVisible: 0,
535
- },
536
- },
537
- toolbarButtons: {
538
- moreText: {
539
- buttons: TextButtons,
540
- buttonsVisible: 3,
541
- },
542
- moreParagraph: {
543
- buttons: ParagraphButtons,
544
- buttonsVisible: 5,
545
- },
546
- moreRich: {
547
- buttons: RichButtons,
548
- buttonsVisible: 3,
549
- },
550
- },
551
- }, config.froalaConfig);
552
- }
553
- _listenLazyInit() {
554
- this.froalaReady$
555
- .pipe(filter((ready) => ready), switchMap(() => this._initialize$))
556
- .subscribe(() => {
557
- const selection = window.getSelection();
558
- const options = {};
559
- if (selection.baseNode) {
560
- options.selection = {
561
- node: selection.baseNode.nodeValue,
562
- offset: selection.baseOffset,
563
- };
564
- }
565
- this.initialize(options);
566
- });
567
- }
568
- };
569
- FsHtmlEditorComponent.ctorParameters = () => [
570
- { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FS_HTML_EDITOR_CONFIG,] }] },
571
- { type: ChangeDetectorRef },
572
- { type: FsFroalaLoaderService }
573
- ];
574
- __decorate([
575
- HostBinding('class.focused'),
576
- __metadata("design:type", Object)
577
- ], FsHtmlEditorComponent.prototype, "classFocused", void 0);
578
- __decorate([
579
- HostBinding('class.disabled'),
580
- __metadata("design:type", Object)
581
- ], FsHtmlEditorComponent.prototype, "classDisabled", void 0);
582
- __decorate([
583
- ViewChild('elRef'),
584
- __metadata("design:type", ElementRef)
585
- ], FsHtmlEditorComponent.prototype, "elRef", void 0);
586
- __decorate([
587
- Input(),
588
- __metadata("design:type", Object)
589
- ], FsHtmlEditorComponent.prototype, "config", void 0);
590
- FsHtmlEditorComponent = FsHtmlEditorComponent_1 = __decorate([
591
- Component({
592
- selector: 'fs-html-editor',
593
- 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",
594
- providers: [
595
- {
596
- provide: NG_VALUE_ACCESSOR,
597
- useExisting: forwardRef(() => FsHtmlEditorComponent_1),
598
- multi: true
599
- },
600
- {
601
- provide: NG_VALIDATORS,
602
- useExisting: forwardRef(() => FsHtmlEditorComponent_1),
603
- multi: true
604
- },
605
- ],
606
- changeDetection: ChangeDetectionStrategy.OnPush,
607
- 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 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}"]
608
- }),
609
- __param(0, Optional()), __param(0, Inject(FS_HTML_EDITOR_CONFIG)),
610
- __metadata("design:paramtypes", [Object, ChangeDetectorRef,
611
- FsFroalaLoaderService])
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._destroy$ = new Subject();
216
+ this.onChange = (data) => { };
217
+ this.onTouched = () => { };
218
+ }
219
+ get el() {
220
+ return this.elRef.nativeElement;
221
+ }
222
+ get html() {
223
+ return this._html;
224
+ }
225
+ get editor() {
226
+ return this._editor;
227
+ }
228
+ get froalaReady$() {
229
+ return this._fr.ready$;
230
+ }
231
+ ngOnInit() {
232
+ this.config = this.config || {};
233
+ this.config.autofocus = this.config.autofocus !== false && !this.config.disabled;
234
+ this.initialized = !this.config.initOnClick;
235
+ this._listenLazyInit();
236
+ }
237
+ ngAfterViewInit() {
238
+ if (!this.config.initOnClick || !this.hasContent()) {
239
+ this.initialized = true;
240
+ this._initialize$.next();
241
+ }
242
+ }
243
+ hasContent() {
244
+ const el = document.createElement('div');
245
+ if (el.querySelector('img')) {
246
+ return true;
247
+ }
248
+ el.innerHTML = this._html;
249
+ return !!el.innerText.length;
250
+ }
251
+ initialize(options = {}) {
252
+ const config = this._createConfig();
253
+ this._initPlugins(config);
254
+ this.el.innerHTML = this._html;
255
+ this._editor = new this._fr.FroalaEditor(this.el, this._createOptions(), () => {
256
+ this._cdRef.markForCheck();
257
+ if (config.disabled) {
258
+ this.disable();
259
+ }
260
+ if (config.froalaConfig.events) {
261
+ if (config.froalaConfig.events.initialized) {
262
+ config.froalaConfig.events.initialized();
263
+ }
264
+ }
265
+ this._editor.events.on('focus', () => {
266
+ this.classFocused = true;
267
+ this._cdRef.markForCheck();
268
+ });
269
+ this._editor.events.on('blur', () => {
270
+ this.classFocused = false;
271
+ this._cdRef.markForCheck();
272
+ });
273
+ this._editor.events.on('contentChanged', () => {
274
+ const editorHTML = this._editor.html.get();
275
+ if (this.html !== editorHTML) {
276
+ this._change(editorHTML);
277
+ }
278
+ });
279
+ this._editor.events.on('paste.afterCleanup', (html) => {
280
+ var div = document.createElement('div');
281
+ div.innerHTML = html;
282
+ div.querySelectorAll('*')
283
+ .forEach((el) => {
284
+ for (var i = 0; i < el.attributes.length; i++) {
285
+ const name = el.attributes[0].name;
286
+ if (name !== 'href') {
287
+ el.removeAttribute(name);
288
+ }
289
+ }
290
+ });
291
+ return div.innerHTML;
292
+ });
293
+ this._editor.events.on('keydown', () => {
294
+ this.onTouched();
295
+ });
296
+ if (this.config.image && this.config.image.upload) {
297
+ this._editor.events.on('image.beforePasteUpload', (image) => {
298
+ fetch(image.getAttribute('src'))
299
+ .then((res) => {
300
+ res.blob()
301
+ .then((blob) => {
302
+ this._processImageUpload(blob)
303
+ .pipe(takeUntil(this._destroy$))
304
+ .subscribe((url) => {
305
+ image.setAttribute('src', url);
306
+ image.removeAttribute('data-fr-image-pasted');
307
+ });
308
+ });
309
+ });
310
+ return false;
311
+ });
312
+ this._editor.events.on('image.beforeUpload', (blobs) => {
313
+ this._processImageUpload(blobs[0])
314
+ .pipe(takeUntil(this._destroy$))
315
+ .subscribe((url) => {
316
+ this.editor.image.insert(url, null, null, this.editor.image.get());
317
+ });
318
+ return false;
319
+ });
320
+ }
321
+ if (this.el.querySelector('.fr-second-toolbar')) {
322
+ this.el.querySelector('.fr-second-toolbar').remove();
323
+ }
324
+ const selection = options.selection;
325
+ if (selection) {
326
+ const node = Array.from(this.el.querySelectorAll('.fr-element *')).find((node) => {
327
+ return selection.node === node.textContent;
328
+ });
329
+ if (node) {
330
+ const range = document.createRange();
331
+ const sel = window.getSelection();
332
+ range.setStart(this._getTextNode(node), selection.offset);
333
+ range.collapse(true);
334
+ sel.removeAllRanges();
335
+ sel.addRange(range);
336
+ }
337
+ else if (this.config.autofocus) {
338
+ this.focus();
339
+ }
340
+ }
341
+ else if (this.config.autofocus) {
342
+ this.focus();
343
+ }
344
+ });
345
+ }
346
+ _processImageUpload(blob) {
347
+ const processor = new FileProcessor();
348
+ const file = new FsFile(blob);
349
+ return processor.process([file], this.config.image)
350
+ .pipe(switchMap(([f]) => {
351
+ return this.config.image.upload(f.file);
352
+ }));
353
+ }
354
+ _getTextNode(node) {
355
+ if (node) {
356
+ if (node.nodeType === Node.TEXT_NODE) {
357
+ return node;
358
+ }
359
+ if (node.childNodes) {
360
+ return this._getTextNode(node.childNodes[0]);
361
+ }
362
+ }
363
+ }
364
+ uninitializedClick(event) {
365
+ if (!event.defaultPrevented) {
366
+ const target = event.target;
367
+ if (target && target.nodeName === 'A' && target.getAttribute('href')) {
368
+ const targetTarget = target.getAttribute('target');
369
+ target.setAttribute('target', '_blank');
370
+ setTimeout(() => {
371
+ if (targetTarget) {
372
+ target.setAttribute('target', targetTarget);
373
+ }
374
+ else {
375
+ target.removeAttribute('target');
376
+ }
377
+ });
378
+ }
379
+ else {
380
+ if (this.config.initClick) {
381
+ this.config.initClick(event);
382
+ }
383
+ this._initialize$.next();
384
+ this.initialized = true;
385
+ }
386
+ }
387
+ }
388
+ updateSize() {
389
+ // Hack: To trigger the toolbar button size modes
390
+ window.dispatchEvent(new Event('resize'));
391
+ }
392
+ validate(control) {
393
+ const err = {};
394
+ if (this.config.maxLength && this._html) {
395
+ const maxLength = this.config.maxLength;
396
+ const length = this._html.length;
397
+ if (length > maxLength) {
398
+ err.maxLengthError = `Must be ${maxLength} characters or fewer. You entered ${length} characters.`;
399
+ }
400
+ }
401
+ return Object.keys(err).length ? err : null;
402
+ }
403
+ focus(options) {
404
+ options = options ? options : {};
405
+ if (options.cursorPosition === 'end') {
406
+ this.editor.selection.setAtEnd(this.editor.$el.get(0));
407
+ }
408
+ else {
409
+ this.editor.selection.setAtStart(this.editor.$el.get(0));
410
+ }
411
+ this.editor.selection.restore();
412
+ const elSelection = this.editor.selection.element();
413
+ if (elSelection) {
414
+ elSelection.scrollIntoView({ block: 'center' });
415
+ }
416
+ }
417
+ clear() {
418
+ this.writeValue('');
419
+ }
420
+ disable() {
421
+ this.classDisabled = true;
422
+ }
423
+ setHtml(html) {
424
+ this.writeValue(html);
425
+ }
426
+ writeValue(html) {
427
+ this._html = html || '';
428
+ this._cdRef.markForCheck();
429
+ // SP-T2298 timeout needed for the case, when froala was already initated and
430
+ // second instance opened in dialog/drawer. In this case init step pass much faster, writeValue trigger
431
+ // after init and froala ignore new html. At the same time froala was initied but editor not yet, and next
432
+ // code doesn't work without timeout. We've got time range when too late for initiate value, and to early
433
+ // for change event.
434
+ setTimeout(() => {
435
+ if (this.editor && this.editor.html) {
436
+ try {
437
+ this.editor.html.set(this._html);
438
+ }
439
+ catch (e) {
440
+ }
441
+ }
442
+ });
443
+ }
444
+ registerOnChange(fn) {
445
+ this.onChange = fn;
446
+ }
447
+ registerOnTouched(fn) {
448
+ this.onTouched = fn;
449
+ }
450
+ ngOnDestroy() {
451
+ this._initialize$.complete();
452
+ this._destroy$.next();
453
+ this._destroy$.complete();
454
+ this.destroy();
455
+ }
456
+ destroy() {
457
+ if (this.editor) {
458
+ this.editor.destroy();
459
+ }
460
+ this.initialized = false;
461
+ this._cdRef.markForCheck();
462
+ this.el.innerHTML = '';
463
+ }
464
+ _createConfig() {
465
+ return merge({ froalaConfig: {} }, this._defaultConfig, this.config);
466
+ }
467
+ _change(html) {
468
+ this._html = html;
469
+ this.onChange(html);
470
+ }
471
+ _initPlugins(config) {
472
+ (config.plugins || []).forEach((plugin) => {
473
+ this._fr.FroalaEditor.PLUGINS[plugin.config.name] = function (editor) {
474
+ plugin.editor = editor;
475
+ plugin.initialize();
476
+ return plugin;
477
+ };
478
+ (plugin.config.buttons || []).forEach((button) => {
479
+ this._fr.FroalaEditor.DefineIcon(button.name, {
480
+ NAME: button.name,
481
+ PATH: button.svgPath,
482
+ });
483
+ this._fr.FroalaEditor.RegisterCommand(button.name, {
484
+ icon: button.name,
485
+ title: button.tooltip,
486
+ undo: button.undo,
487
+ focus: button.focus,
488
+ showOnMobile: button.showOnMobile,
489
+ refreshAfterCallback: button.refreshAfterCallback,
490
+ callback: function () {
491
+ if (button.click) {
492
+ button.click(this);
493
+ }
494
+ },
495
+ refresh: function (button) {
496
+ if (button.refresh) {
497
+ button.refresh(this, button);
498
+ }
499
+ }
500
+ });
501
+ });
502
+ });
503
+ }
504
+ _createOptions() {
505
+ const config = this._createConfig();
506
+ return merge(
507
+ // For some reason editor store somewhere pointer on default config object and dublicate options each time on init
508
+ // Extra merge level fixed this problem and allow to init config properly without legacy data
509
+ {}, {
510
+ key: config.activationKey,
511
+ placeholderText: config.placeholder,
512
+ linkAlwaysBlank: true,
513
+ tabSpaces: 2,
514
+ typingTimer: 250,
515
+ tooltips: false,
516
+ wordPasteModal: false,
517
+ imageDefaultWidth: 0,
518
+ imageDefaultAlign: 'left',
519
+ quickInsertEnabled: false,
520
+ paragraphDefaultSelection: 'Format',
521
+ videoUpload: false,
522
+ paragraphFormat: {
523
+ N: 'Normal',
524
+ H1: 'Heading 1',
525
+ H2: 'Heading 2',
526
+ H3: 'Heading 3',
527
+ H4: 'Heading 4',
528
+ BLOCKQUOTE: 'Quote',
529
+ },
530
+ paragraphFormatSelection: true,
531
+ toolbarButtonsXS: {
532
+ moreText: {
533
+ buttons: TextButtons,
534
+ buttonsVisible: 1,
535
+ },
536
+ moreParagraph: {
537
+ buttons: ParagraphButtons,
538
+ buttonsVisible: 2,
539
+ },
540
+ moreRich: {
541
+ buttons: RichButtons,
542
+ buttonsVisible: 0,
543
+ },
544
+ },
545
+ toolbarButtons: {
546
+ moreText: {
547
+ buttons: TextButtons,
548
+ buttonsVisible: 3,
549
+ },
550
+ moreParagraph: {
551
+ buttons: ParagraphButtons,
552
+ buttonsVisible: 5,
553
+ },
554
+ moreRich: {
555
+ buttons: RichButtons,
556
+ buttonsVisible: 3,
557
+ },
558
+ },
559
+ }, config.froalaConfig);
560
+ }
561
+ _listenLazyInit() {
562
+ this.froalaReady$
563
+ .pipe(filter((ready) => ready), switchMap(() => this._initialize$))
564
+ .subscribe(() => {
565
+ const selection = window.getSelection();
566
+ const options = {};
567
+ if (selection.baseNode) {
568
+ options.selection = {
569
+ node: selection.baseNode.nodeValue,
570
+ offset: selection.baseOffset,
571
+ };
572
+ }
573
+ this.initialize(options);
574
+ });
575
+ }
576
+ };
577
+ FsHtmlEditorComponent.ctorParameters = () => [
578
+ { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FS_HTML_EDITOR_CONFIG,] }] },
579
+ { type: ChangeDetectorRef },
580
+ { type: FsFroalaLoaderService }
581
+ ];
582
+ __decorate([
583
+ HostBinding('class.focused'),
584
+ __metadata("design:type", Object)
585
+ ], FsHtmlEditorComponent.prototype, "classFocused", void 0);
586
+ __decorate([
587
+ HostBinding('class.disabled'),
588
+ __metadata("design:type", Object)
589
+ ], FsHtmlEditorComponent.prototype, "classDisabled", void 0);
590
+ __decorate([
591
+ ViewChild('elRef'),
592
+ __metadata("design:type", ElementRef)
593
+ ], FsHtmlEditorComponent.prototype, "elRef", void 0);
594
+ __decorate([
595
+ Input(),
596
+ __metadata("design:type", Object)
597
+ ], FsHtmlEditorComponent.prototype, "config", void 0);
598
+ FsHtmlEditorComponent = FsHtmlEditorComponent_1 = __decorate([
599
+ Component({
600
+ selector: 'fs-html-editor',
601
+ 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",
602
+ providers: [
603
+ {
604
+ provide: NG_VALUE_ACCESSOR,
605
+ useExisting: forwardRef(() => FsHtmlEditorComponent_1),
606
+ multi: true
607
+ },
608
+ {
609
+ provide: NG_VALIDATORS,
610
+ useExisting: forwardRef(() => FsHtmlEditorComponent_1),
611
+ multi: true
612
+ },
613
+ ],
614
+ changeDetection: ChangeDetectionStrategy.OnPush,
615
+ 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}"]
616
+ }),
617
+ __param(0, Optional()), __param(0, Inject(FS_HTML_EDITOR_CONFIG)),
618
+ __metadata("design:paramtypes", [Object, ChangeDetectorRef,
619
+ FsFroalaLoaderService])
612
620
  ], FsHtmlEditorComponent);
613
621
 
614
- let FsHtmlRendererComponent = class FsHtmlRendererComponent {
615
- constructor(sanitized, _cdRef) {
616
- this.sanitized = sanitized;
617
- this._cdRef = _cdRef;
618
- }
619
- set setHtml(html) {
620
- this.trustedHtml = this.sanitized.bypassSecurityTrustHtml(html);
621
- this._cdRef.markForCheck();
622
- }
623
- };
624
- FsHtmlRendererComponent.ctorParameters = () => [
625
- { type: DomSanitizer },
626
- { type: ChangeDetectorRef }
627
- ];
628
- __decorate([
629
- Input('html'),
630
- __metadata("design:type", Object),
631
- __metadata("design:paramtypes", [Object])
632
- ], FsHtmlRendererComponent.prototype, "setHtml", null);
633
- FsHtmlRendererComponent = __decorate([
634
- Component({
635
- selector: 'fs-html-renderer',
636
- template: "<div class=\"fr-view fs-html-editor-default\" [innerHtml]=\"trustedHtml\"></div>\n",
637
- changeDetection: ChangeDetectionStrategy.OnPush,
638
- styles: [""]
639
- }),
640
- __metadata("design:paramtypes", [DomSanitizer,
641
- ChangeDetectorRef])
622
+ let FsHtmlRendererComponent = class FsHtmlRendererComponent {
623
+ constructor(sanitized, _cdRef) {
624
+ this.sanitized = sanitized;
625
+ this._cdRef = _cdRef;
626
+ }
627
+ set setHtml(html) {
628
+ this.trustedHtml = this.sanitized.bypassSecurityTrustHtml(html);
629
+ this._cdRef.markForCheck();
630
+ }
631
+ };
632
+ FsHtmlRendererComponent.ctorParameters = () => [
633
+ { type: DomSanitizer },
634
+ { type: ChangeDetectorRef }
635
+ ];
636
+ __decorate([
637
+ Input('html'),
638
+ __metadata("design:type", Object),
639
+ __metadata("design:paramtypes", [Object])
640
+ ], FsHtmlRendererComponent.prototype, "setHtml", null);
641
+ FsHtmlRendererComponent = __decorate([
642
+ Component({
643
+ selector: 'fs-html-renderer',
644
+ template: "<div class=\"fr-view fs-html-editor-default\" [innerHtml]=\"trustedHtml\"></div>\n",
645
+ changeDetection: ChangeDetectionStrategy.OnPush,
646
+ styles: [""]
647
+ }),
648
+ __metadata("design:paramtypes", [DomSanitizer,
649
+ ChangeDetectorRef])
642
650
  ], FsHtmlRendererComponent);
643
651
 
644
- var FsHtmlEditorModule_1;
645
- let FsHtmlEditorModule = FsHtmlEditorModule_1 = class FsHtmlEditorModule {
646
- static forRoot(config = {}) {
647
- return {
648
- ngModule: FsHtmlEditorModule_1,
649
- providers: [
650
- { provide: FS_HTML_EDITOR_DEFAULT_CONFIG, useValue: config },
651
- {
652
- provide: FS_HTML_EDITOR_CONFIG,
653
- useFactory: FsHtmlEditorConfigFactory,
654
- deps: [FS_HTML_EDITOR_DEFAULT_CONFIG]
655
- }
656
- ]
657
- };
658
- }
659
- };
660
- FsHtmlEditorModule = FsHtmlEditorModule_1 = __decorate([
661
- NgModule({
662
- imports: [
663
- CommonModule,
664
- FsSkeletonModule,
665
- ],
666
- exports: [
667
- FsHtmlEditorComponent,
668
- FsHtmlRendererComponent,
669
- ],
670
- declarations: [
671
- FsHtmlEditorComponent,
672
- FsHtmlRendererComponent,
673
- ],
674
- })
675
- ], FsHtmlEditorModule);
676
- function FsHtmlEditorConfigFactory(config) {
677
- return Object.assign({ defaultPlugins: [
678
- "align" /* Align */,
679
- "colors" /* Colors */,
680
- "image" /* Image */,
681
- "link" /* Link */,
682
- "lists" /* Lists */,
683
- "paragraph_format" /* ParagraphFormat */,
684
- "quote" /* Quote */,
685
- "table" /* Table */,
686
- "url" /* Url */,
687
- "video" /* Video */,
688
- "draggable" /* Draggable */,
689
- "font_size" /* FontSize */,
690
- ] }, config);
652
+ var FsHtmlEditorModule_1;
653
+ let FsHtmlEditorModule = FsHtmlEditorModule_1 = class FsHtmlEditorModule {
654
+ static forRoot(config = {}) {
655
+ return {
656
+ ngModule: FsHtmlEditorModule_1,
657
+ providers: [
658
+ { provide: FS_HTML_EDITOR_DEFAULT_CONFIG, useValue: config },
659
+ {
660
+ provide: FS_HTML_EDITOR_CONFIG,
661
+ useFactory: FsHtmlEditorConfigFactory,
662
+ deps: [FS_HTML_EDITOR_DEFAULT_CONFIG]
663
+ }
664
+ ]
665
+ };
666
+ }
667
+ };
668
+ FsHtmlEditorModule = FsHtmlEditorModule_1 = __decorate([
669
+ NgModule({
670
+ imports: [
671
+ CommonModule,
672
+ FsSkeletonModule,
673
+ ],
674
+ exports: [
675
+ FsHtmlEditorComponent,
676
+ FsHtmlRendererComponent,
677
+ ],
678
+ declarations: [
679
+ FsHtmlEditorComponent,
680
+ FsHtmlRendererComponent,
681
+ ],
682
+ })
683
+ ], FsHtmlEditorModule);
684
+ function FsHtmlEditorConfigFactory(config) {
685
+ return Object.assign({ defaultPlugins: [
686
+ "align" /* Align */,
687
+ "colors" /* Colors */,
688
+ "image" /* Image */,
689
+ "link" /* Link */,
690
+ "lists" /* Lists */,
691
+ "paragraph_format" /* ParagraphFormat */,
692
+ "quote" /* Quote */,
693
+ "table" /* Table */,
694
+ "url" /* Url */,
695
+ "video" /* Video */,
696
+ "draggable" /* Draggable */,
697
+ "font_size" /* FontSize */,
698
+ ] }, config);
691
699
  }
692
700
 
693
- class Plugin {
694
- initialize() { }
695
- destroy() { }
701
+ class Plugin {
702
+ initialize() { }
703
+ destroy() { }
696
704
  }
697
705
 
698
- class MentionPlugin extends Plugin {
699
- constructor(config) {
700
- super();
701
- this.config = config;
702
- this.config = Object.assign(Object.assign({}, config), { buttons: [
703
- {
704
- name: config.name,
705
- tooltip: config.tooltip,
706
- svgPath: config.iconPath,
707
- click: (editor) => {
708
- this._closeAll();
709
- this._tribute.showMenuForCollection(editor.el);
710
- }
711
- }
712
- ] });
713
- this._tribute = new Tribute({
714
- values: debounce(this._loadValues.bind(this), 200),
715
- searchOpts: {
716
- pre: '',
717
- post: '',
718
- skip: true
719
- },
720
- containerClass: `fs-html-editor-mention-container ${this.config.containerClass || ''}`,
721
- itemClass: `fs-html-editor-mention-menu-item ${this.config.menuItemClass || ''}`,
722
- trigger: this.config.trigger,
723
- allowSpaces: true,
724
- menuItemTemplate: (item) => {
725
- return this.config.menuItemTemplate(item.original);
726
- },
727
- selectTemplate: (item) => {
728
- const template = this.config.selectedTemplate(item.original);
729
- let p = document.createElement('p');
730
- p.innerHTML = template;
731
- let node = p.firstElementChild;
732
- if (!node) {
733
- node = document.createElement('span');
734
- node.innerHTML = template;
735
- }
736
- node.setAttribute('contenteditable', 'false');
737
- node.classList.add('fr-deletable');
738
- return node.outerHTML;
739
- },
740
- });
741
- MentionPlugin._tributes.push(this._tribute);
742
- }
743
- initialize() {
744
- this._tribute.attach(this.editor.el);
745
- this.editor.events.on('keydown', (e) => {
746
- if (e.key === 'Enter' && this._tribute.isActive) {
747
- return false;
748
- }
749
- }, true);
750
- }
751
- destroy() { }
752
- _closeAll() {
753
- MentionPlugin._tributes.forEach((tribute) => {
754
- if (tribute.menu) {
755
- tribute.hideMenu();
756
- }
757
- });
758
- }
759
- _loadValues(keyword, cb) {
760
- return this.config.fetch(keyword)
761
- .subscribe((data) => {
762
- cb(data);
763
- });
764
- }
765
- }
706
+ class MentionPlugin extends Plugin {
707
+ constructor(config) {
708
+ super();
709
+ this.config = config;
710
+ this.config = Object.assign(Object.assign({}, config), { buttons: [
711
+ {
712
+ name: config.name,
713
+ tooltip: config.tooltip,
714
+ svgPath: config.iconPath,
715
+ click: (editor) => {
716
+ this._closeAll();
717
+ this._tribute.showMenuForCollection(editor.el);
718
+ }
719
+ }
720
+ ] });
721
+ this._tribute = new Tribute({
722
+ values: debounce(this._loadValues.bind(this), 200),
723
+ searchOpts: {
724
+ pre: '',
725
+ post: '',
726
+ skip: true
727
+ },
728
+ containerClass: `fs-html-editor-mention-container ${this.config.containerClass || ''}`,
729
+ itemClass: `fs-html-editor-mention-menu-item ${this.config.menuItemClass || ''}`,
730
+ trigger: this.config.trigger,
731
+ allowSpaces: true,
732
+ menuItemTemplate: (item) => {
733
+ return this.config.menuItemTemplate(item.original);
734
+ },
735
+ selectTemplate: (item) => {
736
+ const template = this.config.selectedTemplate(item.original);
737
+ let p = document.createElement('p');
738
+ p.innerHTML = template;
739
+ let node = p.firstElementChild;
740
+ if (!node) {
741
+ node = document.createElement('span');
742
+ node.innerHTML = template;
743
+ }
744
+ node.setAttribute('contenteditable', 'false');
745
+ node.classList.add('fr-deletable');
746
+ return node.outerHTML;
747
+ },
748
+ });
749
+ MentionPlugin._tributes.push(this._tribute);
750
+ }
751
+ initialize() {
752
+ this._tribute.attach(this.editor.el);
753
+ this.editor.events.on('keydown', (e) => {
754
+ if (e.key === 'Enter' && this._tribute.isActive) {
755
+ return false;
756
+ }
757
+ }, true);
758
+ }
759
+ destroy() { }
760
+ _closeAll() {
761
+ MentionPlugin._tributes.forEach((tribute) => {
762
+ if (tribute.menu) {
763
+ tribute.hideMenu();
764
+ }
765
+ });
766
+ }
767
+ _loadValues(keyword, cb) {
768
+ return this.config.fetch(keyword)
769
+ .subscribe((data) => {
770
+ cb(data);
771
+ });
772
+ }
773
+ }
766
774
  MentionPlugin._tributes = [];
767
775
 
768
- class ChecklistPlugin extends Plugin {
769
- constructor(config = { name: 'checklist' }) {
770
- super();
771
- this.config = config;
772
- this.config = Object.assign(Object.assign({}, config), { name: 'checklist', buttons: [
773
- {
774
- name: 'checklist',
775
- 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',
776
- click: (editor) => {
777
- editor.html.insert('<ul class="checklist"><li></li></ul>');
778
- }
779
- }
780
- ] });
781
- }
782
- initialize() {
783
- this.editor.events.on('click', (e) => {
784
- const li = e.target;
785
- if (li.nodeName === 'LI' && e.offsetX < 0) {
786
- const items = [li, ...li.querySelectorAll('li')];
787
- if (li.classList.contains('checked')) {
788
- items.forEach((item) => {
789
- item.classList.remove('checked');
790
- });
791
- }
792
- else {
793
- items.forEach((item) => {
794
- item.classList.add('checked');
795
- });
796
- }
797
- }
798
- }, false);
799
- }
776
+ class ChecklistPlugin extends Plugin {
777
+ constructor(config = { name: 'checklist' }) {
778
+ super();
779
+ this.config = config;
780
+ this.config = Object.assign(Object.assign({}, config), { name: 'checklist', buttons: [
781
+ {
782
+ name: 'checklist',
783
+ 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',
784
+ click: (editor) => {
785
+ editor.html.insert('<ul class="checklist"><li></li></ul>');
786
+ }
787
+ }
788
+ ] });
789
+ }
790
+ initialize() {
791
+ this.editor.events.on('click', (e) => {
792
+ const li = e.target;
793
+ if (li.nodeName === 'LI' && e.offsetX < 0) {
794
+ const items = [li, ...li.querySelectorAll('li')];
795
+ if (li.classList.contains('checked')) {
796
+ items.forEach((item) => {
797
+ item.classList.remove('checked');
798
+ });
799
+ }
800
+ else {
801
+ items.forEach((item) => {
802
+ item.classList.add('checked');
803
+ });
804
+ }
805
+ }
806
+ }, false);
807
+ }
800
808
  }
801
809
 
802
- class CodePlugin extends Plugin {
803
- constructor(config = { name: 'code' }) {
804
- super();
805
- this.config = config;
806
- this.config = Object.assign(Object.assign({}, config), { name: 'code', buttons: [
807
- {
808
- name: 'code',
809
- 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',
810
- click: (editor) => {
811
- const node = editor.selection.get();
812
- const codeEl = this._getCodeEl(node.baseNode);
813
- if (codeEl) {
814
- codeEl.classList.remove('code');
815
- }
816
- else {
817
- editor.html.insert('<p class="code">' + editor.selection.get().toString().replace(/\n{1,}/g, '<br>') + '</p>');
818
- }
819
- }
820
- }
821
- ] });
822
- }
823
- initialize() {
824
- this.editor.events.on('keydown', (e) => {
825
- if (e.keyCode === 13) {
826
- const selection = this.editor.selection.get();
827
- if (selection && this._getCodeEl(selection.baseNode)) {
828
- e.preventDefault();
829
- e.stopPropagation();
830
- e.stopImmediatePropagation();
831
- let br = '<br>';
832
- const base = selection.baseNode;
833
- if (base.nodeName === '#text' && selection.baseOffset === base.length) {
834
- if (!(base.nextSibling && base.nextSibling.nodeName === 'BR')) {
835
- br += '<br>';
836
- }
837
- }
838
- else {
839
- const el = Array.from(base.childNodes).splice(selection.baseOffset - 1, 1).pop();
840
- if (el && el.nodeName !== 'BR') {
841
- br += '<br>';
842
- }
843
- }
844
- this.editor.html.insert(br);
845
- return false;
846
- }
847
- }
848
- }, true);
849
- }
850
- destroy() { }
851
- _getCodeEl(el) {
852
- if (el) {
853
- if (el.classList && el.classList.contains('code')) {
854
- return el;
855
- }
856
- if (el.parentElement) {
857
- return this._getCodeEl(el.parentElement);
858
- }
859
- }
860
- return null;
861
- }
810
+ class CodePlugin extends Plugin {
811
+ constructor(config = { name: 'code' }) {
812
+ super();
813
+ this.config = config;
814
+ this.config = Object.assign(Object.assign({}, config), { name: 'code', buttons: [
815
+ {
816
+ name: 'code',
817
+ 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',
818
+ click: (editor) => {
819
+ const node = editor.selection.get();
820
+ const codeEl = this._getCodeEl(node.baseNode);
821
+ if (codeEl) {
822
+ codeEl.classList.remove('code');
823
+ }
824
+ else {
825
+ editor.html.insert('<p class="code">' + editor.selection.get().toString().replace(/\n{1,}/g, '<br>') + '</p>');
826
+ }
827
+ }
828
+ }
829
+ ] });
830
+ }
831
+ initialize() {
832
+ this.editor.events.on('keydown', (e) => {
833
+ if (e.keyCode === 13) {
834
+ const selection = this.editor.selection.get();
835
+ if (selection && this._getCodeEl(selection.baseNode)) {
836
+ e.preventDefault();
837
+ e.stopPropagation();
838
+ e.stopImmediatePropagation();
839
+ let br = '<br>';
840
+ const base = selection.baseNode;
841
+ if (base.nodeName === '#text' && selection.baseOffset === base.length) {
842
+ if (!(base.nextSibling && base.nextSibling.nodeName === 'BR')) {
843
+ br += '<br>';
844
+ }
845
+ }
846
+ else {
847
+ const el = Array.from(base.childNodes).splice(selection.baseOffset - 1, 1).pop();
848
+ if (el && el.nodeName !== 'BR') {
849
+ br += '<br>';
850
+ }
851
+ }
852
+ this.editor.html.insert(br);
853
+ return false;
854
+ }
855
+ }
856
+ }, true);
857
+ }
858
+ destroy() { }
859
+ _getCodeEl(el) {
860
+ if (el) {
861
+ if (el.classList && el.classList.contains('code')) {
862
+ return el;
863
+ }
864
+ if (el.parentElement) {
865
+ return this._getCodeEl(el.parentElement);
866
+ }
867
+ }
868
+ return null;
869
+ }
862
870
  }
863
871
 
864
- class ScreenRecordPlugin extends Plugin {
865
- constructor(config = {}) {
866
- super();
867
- this.config = config;
868
- this.config = Object.assign(Object.assign({}, config), { name: config.name || 'screenRecord', buttons: [
869
- {
870
- name: 'screenRecord',
872
+ class ScreenRecordPlugin extends Plugin {
873
+ constructor(config = {}) {
874
+ super();
875
+ this.config = config;
876
+ this.config = Object.assign(Object.assign({}, config), { name: config.name || 'screenRecord', buttons: [
877
+ {
878
+ name: 'screenRecord',
871
879
  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
872
880
  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
873
- 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`,
874
- tooltip: 'Screen Record',
875
- click: (editor) => {
876
- navigator.mediaDevices.getDisplayMedia({ video: true })
877
- .then((stream) => {
878
- const chunks = [];
879
- const options = { mimeType: 'video/webm; codecs=vp9' };
880
- let mediaRecorder = new MediaRecorder(stream, options);
881
- stream.addEventListener('inactive', (e) => {
882
- mediaRecorder.stop();
883
- mediaRecorder = null;
884
- stream.getTracks().forEach((track) => track.stop());
885
- stream = null;
886
- const blob = new Blob(chunks, { type: 'video/webm' });
887
- config.upload(blob)
888
- .subscribe((url) => {
889
- 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>`);
890
- });
891
- });
892
- mediaRecorder.addEventListener('dataavailable', (event) => {
893
- if (event.data && event.data.size > 0) {
894
- chunks.push(event.data);
895
- }
896
- });
897
- mediaRecorder.start(10);
898
- })
899
- .catch((e) => { });
900
- }
901
- }
902
- ] });
903
- }
904
- initialize() {
905
- return __awaiter(this, void 0, void 0, function* () {
906
- yield ResourceLoader.loadStyles('froala')
907
- .toPromise();
908
- const FroalaEditor = window.FroalaEditor;
909
- this.editor.events.on('mouseup', (e) => {
910
- const el = this._getEl(e.target);
911
- if (el) {
912
- this.editor.popups.hideAll();
913
- this._activeEl = el;
914
- this._showPopup(el);
915
- }
916
- });
917
- FroalaEditor.POPUP_TEMPLATES["screenRecordPlugin.popup"] = '[_BUTTONS_]';
918
- FroalaEditor.DefineIcon('popupClose', { NAME: 'trash', SVG_KEY: 'remove' });
919
- FroalaEditor.RegisterCommand('popupClose', {
920
- title: 'Remove',
921
- undo: false,
922
- focus: false,
923
- callback: () => {
924
- if (this._activeEl) {
925
- this._activeEl.remove();
926
- }
927
- }
928
- });
929
- });
930
- }
931
- _createPopup() {
932
- const template = {
933
- buttons: `<div class="fr-buttons">${this.editor.button.buildList(['popupClose'])}</div>`,
934
- };
935
- return this.editor.popups.create('screenRecordPlugin.popup', template);
936
- }
937
- _showPopup(el) {
938
- var $popup = this.editor.popups.get('screenRecordPlugin.popup');
939
- if (!$popup) {
940
- $popup = this._createPopup();
941
- }
942
- this.editor.popups.setContainer('screenRecordPlugin.popup', this.editor.$(el));
943
- const left = el.offsetLeft + el.offsetWidth / 2;
944
- this.editor.popups.show('screenRecordPlugin.popup', left, null);
945
- }
946
- _getEl(el) {
947
- if (el && el.classList) {
948
- if (el.classList.contains('fr-screen-record'))
949
- return el;
950
- return this._getEl(el.parentNode);
951
- }
952
- }
881
+ 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`,
882
+ tooltip: 'Screen Record',
883
+ click: (editor) => {
884
+ navigator.mediaDevices.getDisplayMedia({ video: true })
885
+ .then((stream) => {
886
+ const chunks = [];
887
+ const options = { mimeType: 'video/webm; codecs=vp9' };
888
+ let mediaRecorder = new MediaRecorder(stream, options);
889
+ stream.addEventListener('inactive', (e) => {
890
+ mediaRecorder.stop();
891
+ mediaRecorder = null;
892
+ stream.getTracks().forEach((track) => track.stop());
893
+ stream = null;
894
+ const blob = new Blob(chunks, { type: 'video/webm' });
895
+ config.upload(blob)
896
+ .subscribe((url) => {
897
+ 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>`);
898
+ });
899
+ });
900
+ mediaRecorder.addEventListener('dataavailable', (event) => {
901
+ if (event.data && event.data.size > 0) {
902
+ chunks.push(event.data);
903
+ }
904
+ });
905
+ mediaRecorder.start(10);
906
+ })
907
+ .catch((e) => { });
908
+ }
909
+ }
910
+ ] });
911
+ }
912
+ initialize() {
913
+ return __awaiter(this, void 0, void 0, function* () {
914
+ yield ResourceLoader.loadStyles('froala')
915
+ .toPromise();
916
+ const FroalaEditor = window.FroalaEditor;
917
+ this.editor.events.on('mouseup', (e) => {
918
+ const el = this._getEl(e.target);
919
+ if (el) {
920
+ this.editor.popups.hideAll();
921
+ this._activeEl = el;
922
+ this._showPopup(el);
923
+ }
924
+ });
925
+ FroalaEditor.POPUP_TEMPLATES["screenRecordPlugin.popup"] = '[_BUTTONS_]';
926
+ FroalaEditor.DefineIcon('popupClose', { NAME: 'trash', SVG_KEY: 'remove' });
927
+ FroalaEditor.RegisterCommand('popupClose', {
928
+ title: 'Remove',
929
+ undo: false,
930
+ focus: false,
931
+ callback: () => {
932
+ if (this._activeEl) {
933
+ this._activeEl.remove();
934
+ }
935
+ }
936
+ });
937
+ });
938
+ }
939
+ _createPopup() {
940
+ const template = {
941
+ buttons: `<div class="fr-buttons">${this.editor.button.buildList(['popupClose'])}</div>`,
942
+ };
943
+ return this.editor.popups.create('screenRecordPlugin.popup', template);
944
+ }
945
+ _showPopup(el) {
946
+ var $popup = this.editor.popups.get('screenRecordPlugin.popup');
947
+ if (!$popup) {
948
+ $popup = this._createPopup();
949
+ }
950
+ this.editor.popups.setContainer('screenRecordPlugin.popup', this.editor.$(el));
951
+ const left = el.offsetLeft + el.offsetWidth / 2;
952
+ this.editor.popups.show('screenRecordPlugin.popup', left, null);
953
+ }
954
+ _getEl(el) {
955
+ if (el && el.classList) {
956
+ if (el.classList.contains('fr-screen-record'))
957
+ return el;
958
+ return this._getEl(el.parentNode);
959
+ }
960
+ }
953
961
  }
954
962
 
955
- /**
956
- * Generated bundle index. Do not edit.
963
+ /**
964
+ * Generated bundle index. Do not edit.
957
965
  */
958
966
 
959
967
  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 };