@firestitch/html-editor 9.4.5 → 9.5.0

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